Project

General

Profile

Download (16.4 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
* Copyright (C) 2007 EDIT
3
* European Distributed Institute of Taxonomy 
4
* http://www.e-taxonomy.eu
5
* 
6
* The contents of this file are subject to the Mozilla Public License Version 1.1
7
* See LICENSE.TXT at the top of this package for the full license terms.
8
*/
9

    
10
package eu.etaxonomy.cdm.model.location;
11

    
12
import java.util.ArrayList;
13
import java.util.HashMap;
14
import java.util.HashSet;
15
import java.util.List;
16
import java.util.Map;
17
import java.util.Set;
18
import java.util.UUID;
19

    
20
import javax.persistence.Entity;
21
import javax.persistence.FetchType;
22
import javax.persistence.JoinTable;
23
import javax.persistence.ManyToMany;
24
import javax.persistence.ManyToOne;
25
import javax.persistence.Transient;
26
import javax.xml.bind.annotation.XmlAccessType;
27
import javax.xml.bind.annotation.XmlAccessorType;
28
import javax.xml.bind.annotation.XmlElement;
29
import javax.xml.bind.annotation.XmlElementWrapper;
30
import javax.xml.bind.annotation.XmlIDREF;
31
import javax.xml.bind.annotation.XmlRootElement;
32
import javax.xml.bind.annotation.XmlSchemaType;
33
import javax.xml.bind.annotation.XmlSeeAlso;
34
import javax.xml.bind.annotation.XmlType;
35

    
36
import org.apache.commons.lang.StringUtils;
37
import org.apache.log4j.Logger;
38
import org.hibernate.annotations.Cascade;
39
import org.hibernate.annotations.CascadeType;
40
import org.hibernate.envers.Audited;
41
import org.hibernate.search.annotations.Indexed;
42

    
43
import eu.etaxonomy.cdm.common.CdmUtils;
44
import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
45
import eu.etaxonomy.cdm.model.common.DefinedTermBase;
46
import eu.etaxonomy.cdm.model.common.Language;
47
import eu.etaxonomy.cdm.model.common.OrderedTermBase;
48
import eu.etaxonomy.cdm.model.common.Representation;
49
import eu.etaxonomy.cdm.model.common.TermVocabulary;
50
import eu.etaxonomy.cdm.model.common.TimePeriod;
51
import eu.etaxonomy.cdm.model.media.Media;
52

    
53
/**
54
 * @author m.doering
55
 * @version 1.0
56
 * @created 08-Nov-2007 13:06:36
57
 */
58
@XmlAccessorType(XmlAccessType.PROPERTY)
59
@XmlType(name = "NamedArea", propOrder = {
60
	"kindOf",
61
	"generalizationOf",
62
	"partOf",
63
	"includes",
64
    "validPeriod",
65
    "shape",
66
    "pointApproximation",
67
    "waterbodiesOrCountries",
68
    "type",
69
    "level"
70
})
71
@XmlRootElement(name = "NamedArea")
72
@XmlSeeAlso({
73
	TdwgArea.class,
74
	Continent.class,
75
	WaterbodyOrCountry.class
76
})
77
@Entity
78
@Indexed(index = "eu.etaxonomy.cdm.model.common.DefinedTermBase")
79
@Audited
80
public class NamedArea extends OrderedTermBase<NamedArea> implements Cloneable {
81
	private static final long serialVersionUID = 6248434369557403036L;
82
	@SuppressWarnings("unused")
83
	private static final Logger logger = Logger.getLogger(NamedArea.class);
84
	
85
	private static Map<UUID, NamedArea> termMap = null;		
86

    
87
//************************* FACTORY METHODS ****************************************/
88
	
89
	/**
90
	 * Factory method
91
	 * @return
92
	 */
93
	public static NamedArea NewInstance(){
94
		return new NamedArea();
95
	}
96

    
97
	/**
98
	 * Factory method
99
	 * @return
100
	 */
101
	public static NamedArea NewInstance(String term, String label, String labelAbbrev){
102
		return new NamedArea(term, label, labelAbbrev);
103
	}
104
	
105
//**************************** VARIABLES *******************************/
106
	
107
	//description of time valid context of this area. e.g. year range
108
	private TimePeriod validPeriod = TimePeriod.NewInstance();
109
	
110
	//Binary shape definition for user's defined area as polygon
111
	@ManyToOne(fetch = FetchType.LAZY)
112
	@Cascade(CascadeType.SAVE_UPDATE)
113
	private Media shape;
114
	
115
	private Point pointApproximation;
116
	
117
	@ManyToMany(fetch = FetchType.LAZY)
118
    @JoinTable(name="DefinedTermBase_WaterbodyOrCountry")
119
	private Set<WaterbodyOrCountry> waterbodiesOrCountries = new HashSet<WaterbodyOrCountry>();
120
	
121
	@ManyToOne(fetch = FetchType.LAZY)
122
	private NamedAreaType type;
123
	
124
	@ManyToOne(fetch = FetchType.LAZY)
125
	private NamedAreaLevel level;
126

    
127
//*************************** CONSTRUCTOR ******************************************/
128
	
129
	/**
130
	 * Constructor
131
	 */
132
	public NamedArea() {
133
	}
134
	
135
	public NamedArea(String term, String label, String labelAbbrev) {
136
		super(term, label, labelAbbrev);
137
	}
138
	
139
//********************************* GETTER /SETTER *********************************************/	
140

    
141
	@XmlElement(name = "NamedAreaType")
142
	@XmlIDREF
143
	@XmlSchemaType(name = "IDREF")
144
	public NamedAreaType getType(){
145
		return this.type;
146
	}
147
	
148
	public void setType(NamedAreaType type){
149
		this.type = type;
150
	}
151

    
152
	@XmlElement(name = "NamedAreaLevel")
153
	@XmlIDREF
154
	@XmlSchemaType(name = "IDREF")
155
	public NamedAreaLevel getLevel(){
156
		return this.level;
157
	}
158
	
159
	public void setLevel(NamedAreaLevel level){
160
		this.level = level;
161
	}
162

    
163
	@XmlElement(name = "ValidPeriod")
164
	public TimePeriod getValidPeriod(){
165
		return this.validPeriod;
166
	}
167
	
168
	public void setValidPeriod(TimePeriod validPeriod){
169
		this.validPeriod = validPeriod;
170
	}
171

    
172
	@XmlElement(name = "Shape")
173
	@XmlIDREF
174
	@XmlSchemaType(name = "IDREF")
175
	public Media getShape(){
176
		return this.shape;
177
	}
178
	public void setShape(Media shape){
179
		this.shape = shape;
180
	}
181

    
182
	@XmlElementWrapper(name = "WaterbodiesOrCountries")
183
	@XmlElement(name = "WaterbodiesOrCountry")
184
	@XmlIDREF
185
	@XmlSchemaType(name = "IDREF")
186
	public Set<WaterbodyOrCountry> getWaterbodiesOrCountries() {
187
		return waterbodiesOrCountries;
188
	}
189
	
190
	public void addWaterbodyOrCountry(WaterbodyOrCountry waterbodyOrCountry) {
191
		this.waterbodiesOrCountries.add(waterbodyOrCountry);
192
	}
193
	
194
	public void removeWaterbodyOrCountry(WaterbodyOrCountry waterbodyOrCountry) {
195
		this.waterbodiesOrCountries.remove(waterbodyOrCountry);
196
	}
197
	
198
	@XmlElement(name = "PointApproximation")
199
	public Point getPointApproximation() {
200
		return pointApproximation;
201
	}
202
	public void setPointApproximation(Point pointApproximation) {
203
		this.pointApproximation = pointApproximation;
204
	}
205
	
206
	@XmlElement(name = "KindOf", namespace = "http://etaxonomy.eu/cdm/model/common/1.0")
207
    @XmlIDREF
208
    @XmlSchemaType(name = "IDREF")
209
	public NamedArea getKindOf(){
210
		return super.getKindOf();
211
	}
212

    
213
	public void setKindOf(NamedArea kindOf){
214
		super.setKindOf(kindOf);
215
	}
216
	
217
	@XmlElement(name = "PartOf", namespace = "http://etaxonomy.eu/cdm/model/common/1.0")
218
	@XmlIDREF
219
    @XmlSchemaType(name = "IDREF")
220
    @Override
221
	public NamedArea getPartOf(){
222
		return super.getPartOf();
223
	}
224
	
225
	/**
226
	 * FIXME this method is a workaround for a casting problem in the getPartOf implementation
227
	 * 
228
	 * the partOf instance variable is typically a proxy object of type DefinedTermBase, thus
229
	 * does not coincide with the return value of NamedArea and a ClassCastException is thrown.
230
	 * 
231
	 * It is not clear why this only occurs in the editor and not in the webservice where the same
232
	 * method gets called and should lead to the same results.
233
	 * 
234
	 * Seems to be a bigger problem although its origin is buggy behaviour of the javassist implementation.
235
	 */
236
	@Deprecated
237
	@Transient
238
	public NamedArea getPartOfWorkaround(){
239
		Object area = super.getPartOf();
240
		
241
		if(!(area instanceof NamedArea)){
242
			area = HibernateProxyHelper.deproxy(area, NamedArea.class);
243
		}
244
		
245
		return (NamedArea) area;
246
	}
247
	
248
	public void setPartOf(NamedArea partOf){
249
		this.partOf = partOf;
250
	}
251
	
252
	@XmlElementWrapper(name = "Generalizations", namespace = "http://etaxonomy.eu/cdm/model/common/1.0")
253
	@XmlElement(name = "GeneralizationOf", namespace = "http://etaxonomy.eu/cdm/model/common/1.0")
254
    @XmlIDREF
255
    @XmlSchemaType(name = "IDREF")
256
	public Set<NamedArea> getGeneralizationOf(){
257
		return super.getGeneralizationOf();
258
	}
259
	
260
	protected void setGeneralizationOf(Set<NamedArea> value){
261
		super.setGeneralizationOf(value);
262
	}
263
	
264
	@XmlElementWrapper(name = "Includes", namespace = "http://etaxonomy.eu/cdm/model/common/1.0")
265
	@XmlElement(name = "Include", namespace = "http://etaxonomy.eu/cdm/model/common/1.0")
266
	@XmlIDREF
267
    @XmlSchemaType(name = "IDREF")
268
	public Set<NamedArea> getIncludes(){
269
		return super.getIncludes();
270
	}
271
	
272
	protected void setIncludes(Set<NamedArea> includes) {
273
		super.setIncludes(includes);
274
	}
275
	
276

    
277
	/* (non-Javadoc)
278
	 * @see eu.etaxonomy.cdm.model.common.DefinedTermBase#readCsvLine(java.util.List)
279
	 */
280
	@Override
281
	public NamedArea readCsvLine(Class<NamedArea> termClass, List<String> csvLine, Map<UUID,DefinedTermBase> terms) {
282
		NamedArea newInstance = super.readCsvLine(termClass, csvLine, terms);
283
		
284
		String levelString = (String)csvLine.get(6);
285
		
286
		if(levelString != null && levelString.length() != 0) {
287
			UUID levelUuid = UUID.fromString(levelString);
288
			NamedAreaLevel level = (NamedAreaLevel)terms.get(levelUuid);
289
			newInstance.setLevel(level);
290
		}
291
		
292
		String partOfString = (String)csvLine.get(7);
293
	
294
		if(partOfString != null && partOfString.length() != 0) {
295
			UUID partOfUuid = UUID.fromString(partOfString);
296
			NamedArea partOf = (NamedArea)terms.get(partOfUuid);
297
			partOf.addIncludes(newInstance);
298
		} 
299
		return newInstance;
300
	}
301
	
302

    
303
	
304
	
305
	/* (non-Javadoc)
306
	 * @see eu.etaxonomy.cdm.model.common.DefinedTermBase#resetTerms()
307
	 */
308
	@Override
309
	public void resetTerms(){
310
		termMap = null;
311
	}
312

    
313
	
314
	@Override
315
	protected void setDefaultTerms(TermVocabulary<NamedArea> termVocabulary) {
316
		termMap = new HashMap<UUID, NamedArea>();
317
		for (NamedArea term : termVocabulary.getTerms()){
318
			termMap.put(term.getUuid(), term);
319
		}
320
	}
321
	
322
// ************** Hierarchie List ****************************	
323
	
324
/*	public boolean equals(NamedArea area){
325
		boolean result = false;
326
		if (this.getLabel().toString().compareTo(area.getLabel().toString()) == 0){
327
			result = true;
328
		}
329
		return result;
330
	}*/
331
	
332
//	public int compareTo(NamedArea area){
333
//		return getLabel().compareTo(area.getLabel());
334
//	}
335
	
336
	
337
	
338
	/**
339
	 * This method returns a sorted tree structure which sorts areas by it's level and within the same level
340
	 * alphabetically (TODO to be tested).
341
	 * The structure returned is a tree with alternating nodes that represent an area and an areaLevel.
342
	 * This way also area the have children belonging to different levels can be handled.<BR>
343
	 * The root node is always an empty area node which holds the list of top level areaLevels.
344
	 * AreaLevels with no level defined are handled as if they have a separate level (level="null").
345
	 * 
346
	 * @param areaList
347
	 * @return
348
	 */
349
	public static NamedAreaNode getHiearchieList(List<NamedArea> areaList){
350
		NamedAreaNode result = new NamedAreaNode();
351
		for (NamedArea area : areaList){
352
			List<NamedArea> areaHierarchie  = area.getAllLevelList();
353
			mergeIntoResult(result, areaHierarchie);
354
		}
355
		return result;
356
	}
357
	
358
	
359
	public static class LevelNode {
360
		NamedAreaLevel level;
361
		List<NamedAreaNode> areaList = new ArrayList<NamedAreaNode>();
362

    
363
		public NamedAreaNode add(NamedArea area) {
364
			NamedAreaNode node = new NamedAreaNode();
365
			node.area = area;
366
			areaList.add(node);
367
			return node;
368

    
369
		}
370

    
371
		public NamedAreaNode getNamedAreaNode(NamedArea area) {
372
			for (NamedAreaNode node : areaList) {
373
				if (node.area.equals(area)) {
374
					return node;
375
				}
376
			}
377
			return null;
378
		}
379

    
380
		public String toString() {
381
			return toString(false, 0);
382
		}
383
		public String toString(boolean recursive, int identation) {
384
			String result = level == null? "" :level.getTitleCache();
385
			if (recursive == false){
386
				return result;
387
			}else{
388
				int areaSize = this.areaList.size();
389
				if (areaSize > 0){
390
					result = "\n" + StringUtils.leftPad("", identation) + result  + "[";
391
				}
392
				boolean isFirst = true;
393
				for (NamedAreaNode level: this.areaList){
394
					if (isFirst){
395
						isFirst = false;
396
					}else{
397
						result += ",";
398
					}
399
					result += level.toString(recursive, identation+1);
400
				}
401
				if (areaSize > 0){
402
					result += "]";
403
					
404
				}
405
				return result;
406
			}
407
		}
408

    
409
	}
410

    
411
	public static class NamedAreaNode {
412
		NamedArea area;
413
		List<LevelNode> levelList = new ArrayList<LevelNode>();
414
		
415
		public LevelNode getLevelNode(NamedAreaLevel level) {
416
			for (LevelNode node : levelList) {
417
				if (node.level != null &&  node.level.equals(level)) {
418
					return node;
419
				}
420
			}
421
			return null;
422
		}
423

    
424
		public List<NamedAreaNode> getList(NamedAreaLevel level) {
425
			LevelNode node = getLevelNode(level);
426
			if (node == null) {
427
				return new ArrayList<NamedAreaNode>();
428
			} else {
429
				return node.areaList;
430
			}
431
		};
432

    
433
		public boolean contains(NamedAreaLevel level) {
434
			if (getList(level).size() > 0) {
435
				return true;
436
			} else {
437
				return false;
438
			}
439
		}
440

    
441
		public LevelNode add(NamedAreaLevel level) {
442
			LevelNode node = new LevelNode();
443
			node.level = level;
444
			levelList.add(node);
445
			return node;
446
		}
447

    
448
		public String toString() {
449
			return toString(false, 0);
450
		}
451
		
452
		public String toString(boolean recursive, int identation) {
453
			String result = "";
454
			if (area != null) {
455
				result = area.getTitleCache();
456
			}
457
			if (recursive){
458
				int levelSize = this.levelList.size();
459
				if (levelSize > 0){
460
					result = "\n" + StringUtils.leftPad("", identation) + result  + "[";
461
				}
462
				boolean isFirst = true;
463
				for (LevelNode level: this.levelList){
464
					if (isFirst){
465
						isFirst = false;
466
					}else{
467
						result += ";";
468
					}
469
					result += level.toString(recursive, identation+1);
470
				}
471
				if (levelSize > 0){
472
					result += "]";
473
					
474
				}
475
				return result;
476
			}else{
477
				int levelSize = this.levelList.size();
478
				return result + "[" + levelSize + " sublevel(s)]";
479
			}
480
		}
481
	}
482

    
483
	private static void mergeIntoResult(NamedAreaNode root, List<NamedArea> areaHierarchie) {
484
		if (areaHierarchie.isEmpty()) {
485
			return;
486
		}
487
		NamedArea highestArea = areaHierarchie.get(0);
488
		NamedAreaLevel level = highestArea.getLevel();
489
		NamedAreaNode namedAreaNode;
490
		if (! root.contains(level)) {
491
			LevelNode node = root.add(level);
492
			namedAreaNode = node.add(highestArea);
493
			//NEW
494
//			root.area = highestArea;
495
		} else {
496
			LevelNode levelNode = root.getLevelNode(level);
497
			namedAreaNode = levelNode.getNamedAreaNode(highestArea);
498
			if (namedAreaNode == null) {
499
				namedAreaNode = levelNode.add(highestArea);
500
			}
501
		}
502
		List<NamedArea> newList = areaHierarchie.subList(1, areaHierarchie.size());
503
		mergeIntoResult(namedAreaNode, newList);
504

    
505
	}
506

    
507
	@Transient
508
	public List<NamedArea> getAllLevelList() {
509
		List<NamedArea> result = new ArrayList<NamedArea>();
510
		NamedArea copyArea = this;
511
		result.add(copyArea);		
512
		while (copyArea.getPartOf() != null) {
513
			copyArea = copyArea.getPartOf();
514
			result.add(0, copyArea);
515
		}
516
		return result;
517
	}
518
	
519
// ******************* toString **********************************/	
520

    
521
	/* (non-Javadoc)
522
	 * @see eu.etaxonomy.cdm.model.common.TermBase#toString()
523
	 */
524
	public String toString(){
525
		String result, label, level = "";
526
		
527
		if (this.level != null){
528
			level = this.level.getLabel();
529
		}else{
530
			level = "no level";
531
		}
532
		label = this.getLabel();
533
		result = "[" + level + ", " + label + "]";
534
		
535
		return result;
536
	}
537
	
538
	
539

    
540
	/**
541
	 * Returns the label of the named area together with the area level label and the abbreviated label
542
	 * @param namedArea the area
543
	 * @param language the preferred language
544
	 * @return
545
	 */
546
	public static String labelWithLevel(NamedArea namedArea, Language language) {
547
		NamedArea area = (NamedArea) HibernateProxyHelper.deproxy(namedArea);
548
		
549
		StringBuilder title = new StringBuilder();
550
		Representation representation = area.getPreferredRepresentation(language);
551
		if (representation != null){
552
			String areaString = getPreferredAreaLabel(namedArea, representation);
553
			
554
			title.append(areaString);
555
			if (area.getLevel() == null){
556
				title.append(" - ");
557
				title.append(area.getClass().getSimpleName());
558
			}else{
559
				title.append(" - ");
560
				Representation levelRepresentation = area.getLevel().getPreferredRepresentation(language);
561
				String levelString = getPreferredAreaLabel(area.getLevel(), levelRepresentation);
562
				title.append(levelString);
563
			}
564
		}
565
		return title.toString();
566
	}
567

    
568
	/**
569
	 * @param definedTerm
570
	 * @param representation
571
	 * @return
572
	 */
573
	private static String getPreferredAreaLabel(DefinedTermBase<?> definedTerm, Representation representation) {
574
		String areaString = null;
575
		if (representation != null){
576
			areaString = representation.getLabel();
577
			if (StringUtils.isBlank(areaString)){
578
				areaString = representation.getAbbreviatedLabel();
579
			}
580
			if (StringUtils.isBlank(areaString)){
581
				areaString = representation.getText();
582
			}
583
		}
584
		if (StringUtils.isBlank(areaString)){
585
			areaString = definedTerm.getTitleCache();
586
		}
587
		if (StringUtils.isBlank(areaString)){
588
			areaString = "no title";
589
		}
590
		return areaString;
591
	}
592
	
593
	//*********************************** CLONE *****************************************/
594

    
595
	/** 
596
	 * Clones <i>this</i> NamedArea. This is a shortcut that enables to create
597
	 * a new instance that differs only slightly from <i>this</i> NamedArea by
598
	 * modifying only some of the attributes.
599
	 * 
600
	 * @see eu.etaxonomy.cdm.model.common.OrderedTermBase#clone()
601
	 * @see java.lang.Object#clone()
602
	 */
603
	@Override
604
	public Object clone() {
605
		NamedArea result;
606
		
607
			result = (NamedArea)super.clone();
608
			//no changes to level, pointApproximation, shape, type, validPeriod and waterbodiesOrCountries
609
			return result;
610
		
611
	}
612
		
613
	
614
}
(2-2/10)