root/trunk/cdmlib/cdmlib-model/src/main/java/eu/etaxonomy/cdm/model/location/NamedArea.java

Revision 13000, 16.7 kB (checked in by a.mueller, 8 months ago)

maybe fixing NPE problem

  • Property svn:keywords set to Id
Line 
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
10package eu.etaxonomy.cdm.model.location;
11
12import java.util.ArrayList;
13import java.util.HashMap;
14import java.util.HashSet;
15import java.util.List;
16import java.util.Map;
17import java.util.Set;
18import java.util.UUID;
19
20import javax.persistence.Entity;
21import javax.persistence.FetchType;
22import javax.persistence.JoinTable;
23import javax.persistence.ManyToMany;
24import javax.persistence.ManyToOne;
25import javax.persistence.Transient;
26import javax.xml.bind.annotation.XmlAccessType;
27import javax.xml.bind.annotation.XmlAccessorType;
28import javax.xml.bind.annotation.XmlElement;
29import javax.xml.bind.annotation.XmlElementWrapper;
30import javax.xml.bind.annotation.XmlIDREF;
31import javax.xml.bind.annotation.XmlRootElement;
32import javax.xml.bind.annotation.XmlSchemaType;
33import javax.xml.bind.annotation.XmlSeeAlso;
34import javax.xml.bind.annotation.XmlType;
35
36import org.apache.commons.lang.StringUtils;
37import org.apache.log4j.Logger;
38import org.hibernate.annotations.Cascade;
39import org.hibernate.annotations.CascadeType;
40import org.hibernate.envers.Audited;
41import org.hibernate.search.annotations.Indexed;
42
43import eu.etaxonomy.cdm.common.CdmUtils;
44import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
45import eu.etaxonomy.cdm.model.common.CdmBase;
46import eu.etaxonomy.cdm.model.common.DefinedTermBase;
47import eu.etaxonomy.cdm.model.common.Language;
48import eu.etaxonomy.cdm.model.common.OrderedTermBase;
49import eu.etaxonomy.cdm.model.common.Representation;
50import eu.etaxonomy.cdm.model.common.TermVocabulary;
51import eu.etaxonomy.cdm.model.common.TimePeriod;
52import eu.etaxonomy.cdm.model.media.Media;
53
54/**
55 * @author m.doering
56 * @version 1.0
57 * @created 08-Nov-2007 13:06:36
58 */
59@XmlAccessorType(XmlAccessType.PROPERTY)
60@XmlType(name = "NamedArea", propOrder = {
61        "kindOf",
62        "generalizationOf",
63        "partOf",
64        "includes",
65    "validPeriod",
66    "shape",
67    "pointApproximation",
68    "waterbodiesOrCountries",
69    "type",
70    "level"
71})
72@XmlRootElement(name = "NamedArea")
73@XmlSeeAlso({
74        TdwgArea.class,
75        Continent.class,
76        WaterbodyOrCountry.class
77})
78@Entity
79@Indexed(index = "eu.etaxonomy.cdm.model.common.DefinedTermBase")
80@Audited
81public class NamedArea extends OrderedTermBase<NamedArea> implements Cloneable {
82        private static final long serialVersionUID = 6248434369557403036L;
83        @SuppressWarnings("unused")
84        private static final Logger logger = Logger.getLogger(NamedArea.class);
85       
86        private static Map<UUID, NamedArea> termMap = null;             
87
88//************************* FACTORY METHODS ****************************************/
89       
90        /**
91         * Factory method
92         * @return
93         */
94        public static NamedArea NewInstance(){
95                return new NamedArea();
96        }
97
98        /**
99         * Factory method
100         * @return
101         */
102        public static NamedArea NewInstance(String term, String label, String labelAbbrev){
103                return new NamedArea(term, label, labelAbbrev);
104        }
105       
106//**************************** VARIABLES *******************************/
107       
108        //description of time valid context of this area. e.g. year range
109        private TimePeriod validPeriod = TimePeriod.NewInstance();
110       
111        //Binary shape definition for user's defined area as polygon
112        @ManyToOne(fetch = FetchType.LAZY)
113        @Cascade(CascadeType.SAVE_UPDATE)
114        private Media shape;
115       
116        private Point pointApproximation;
117       
118        @ManyToMany(fetch = FetchType.LAZY)
119    @JoinTable(name="DefinedTermBase_WaterbodyOrCountry")
120        private Set<WaterbodyOrCountry> waterbodiesOrCountries = new HashSet<WaterbodyOrCountry>();
121       
122        @ManyToOne(fetch = FetchType.LAZY)
123        private NamedAreaType type;
124       
125        @ManyToOne(fetch = FetchType.LAZY)
126        private NamedAreaLevel level;
127
128//*************************** CONSTRUCTOR ******************************************/
129       
130        /**
131         * Constructor
132         */
133        public NamedArea() {
134        }
135       
136        public NamedArea(String term, String label, String labelAbbrev) {
137                super(term, label, labelAbbrev);
138        }
139       
140//********************************* GETTER /SETTER *********************************************/       
141
142        @XmlElement(name = "NamedAreaType")
143        @XmlIDREF
144        @XmlSchemaType(name = "IDREF")
145        public NamedAreaType getType(){
146                return this.type;
147        }
148       
149        public void setType(NamedAreaType type){
150                this.type = type;
151        }
152
153        @XmlElement(name = "NamedAreaLevel")
154        @XmlIDREF
155        @XmlSchemaType(name = "IDREF")
156        public NamedAreaLevel getLevel(){
157                return this.level;
158        }
159       
160        public void setLevel(NamedAreaLevel level){
161                this.level = level;
162        }
163
164        @XmlElement(name = "ValidPeriod")
165        public TimePeriod getValidPeriod(){
166                return this.validPeriod;
167        }
168       
169        public void setValidPeriod(TimePeriod validPeriod){
170                this.validPeriod = validPeriod;
171        }
172
173        @XmlElement(name = "Shape")
174        @XmlIDREF
175        @XmlSchemaType(name = "IDREF")
176        public Media getShape(){
177                return this.shape;
178        }
179        public void setShape(Media shape){
180                this.shape = shape;
181        }
182
183        @XmlElementWrapper(name = "WaterbodiesOrCountries")
184        @XmlElement(name = "WaterbodiesOrCountry")
185        @XmlIDREF
186        @XmlSchemaType(name = "IDREF")
187        public Set<WaterbodyOrCountry> getWaterbodiesOrCountries() {
188                return waterbodiesOrCountries;
189        }
190       
191        public void addWaterbodyOrCountry(WaterbodyOrCountry waterbodyOrCountry) {
192                this.waterbodiesOrCountries.add(waterbodyOrCountry);
193        }
194       
195        public void removeWaterbodyOrCountry(WaterbodyOrCountry waterbodyOrCountry) {
196                this.waterbodiesOrCountries.remove(waterbodyOrCountry);
197        }
198       
199        @XmlElement(name = "PointApproximation")
200        public Point getPointApproximation() {
201                return pointApproximation;
202        }
203        public void setPointApproximation(Point pointApproximation) {
204                this.pointApproximation = pointApproximation;
205        }
206       
207        @XmlElement(name = "KindOf", namespace = "http://etaxonomy.eu/cdm/model/common/1.0")
208    @XmlIDREF
209    @XmlSchemaType(name = "IDREF")
210        public NamedArea getKindOf(){
211                return super.getKindOf();
212        }
213
214        public void setKindOf(NamedArea kindOf){
215                super.setKindOf(kindOf);
216        }
217       
218        @XmlElement(name = "PartOf", namespace = "http://etaxonomy.eu/cdm/model/common/1.0")
219        @XmlIDREF
220    @XmlSchemaType(name = "IDREF")
221    @Override
222        public NamedArea getPartOf(){
223                return super.getPartOf();
224        }
225       
226        /**
227         * FIXME this method is a workaround for a casting problem in the getPartOf implementation
228         *
229         * the partOf instance variable is typically a proxy object of type DefinedTermBase, thus
230         * does not coincide with the return value of NamedArea and a ClassCastException is thrown.
231         *
232         * It is not clear why this only occurs in the editor and not in the webservice where the same
233         * method gets called and should lead to the same results.
234         *
235         * Seems to be a bigger problem although its origin is buggy behaviour of the javassist implementation.
236         */
237        @Deprecated
238        @Transient
239        public NamedArea getPartOfWorkaround(){
240                Object area = super.getPartOf();
241               
242                if(!(area instanceof NamedArea)){
243                        area = HibernateProxyHelper.deproxy(area, NamedArea.class);
244                }
245               
246                return (NamedArea) area;
247        }
248       
249        public void setPartOf(NamedArea partOf){
250                this.partOf = partOf;
251        }
252       
253        @XmlElementWrapper(name = "Generalizations", namespace = "http://etaxonomy.eu/cdm/model/common/1.0")
254        @XmlElement(name = "GeneralizationOf", namespace = "http://etaxonomy.eu/cdm/model/common/1.0")
255    @XmlIDREF
256    @XmlSchemaType(name = "IDREF")
257        public Set<NamedArea> getGeneralizationOf(){
258                return super.getGeneralizationOf();
259        }
260       
261        protected void setGeneralizationOf(Set<NamedArea> value){
262                super.setGeneralizationOf(value);
263        }
264       
265        @XmlElementWrapper(name = "Includes", namespace = "http://etaxonomy.eu/cdm/model/common/1.0")
266        @XmlElement(name = "Include", namespace = "http://etaxonomy.eu/cdm/model/common/1.0")
267        @XmlIDREF
268    @XmlSchemaType(name = "IDREF")
269        public Set<NamedArea> getIncludes(){
270                return super.getIncludes();
271        }
272       
273        protected void setIncludes(Set<NamedArea> includes) {
274                super.setIncludes(includes);
275        }
276       
277
278        /* (non-Javadoc)
279         * @see eu.etaxonomy.cdm.model.common.DefinedTermBase#readCsvLine(java.util.List)
280         */
281        @Override
282        public NamedArea readCsvLine(Class<NamedArea> termClass, List<String> csvLine, Map<UUID,DefinedTermBase> terms) {
283                NamedArea newInstance = super.readCsvLine(termClass, csvLine, terms);
284               
285                String levelString = (String)csvLine.get(6);
286               
287                if(levelString != null && levelString.length() != 0) {
288                        UUID levelUuid = UUID.fromString(levelString);
289                        NamedAreaLevel level = (NamedAreaLevel)terms.get(levelUuid);
290                        newInstance.setLevel(level);
291                }
292               
293                String partOfString = (String)csvLine.get(7);
294       
295                if(partOfString != null && partOfString.length() != 0) {
296                        UUID partOfUuid = UUID.fromString(partOfString);
297                        NamedArea partOf = (NamedArea)terms.get(partOfUuid);
298                        partOf.addIncludes(newInstance);
299                } 
300                return newInstance;
301        }
302       
303
304       
305       
306        /* (non-Javadoc)
307         * @see eu.etaxonomy.cdm.model.common.DefinedTermBase#resetTerms()
308         */
309        @Override
310        public void resetTerms(){
311                termMap = null;
312        }
313
314       
315        @Override
316        protected void setDefaultTerms(TermVocabulary<NamedArea> termVocabulary) {
317                termMap = new HashMap<UUID, NamedArea>();
318                for (NamedArea term : termVocabulary.getTerms()){
319                        termMap.put(term.getUuid(), term);
320                }
321        }
322       
323// ************** Hierarchie List **************************** 
324       
325/*      public boolean equals(NamedArea area){
326                boolean result = false;
327                if (this.getLabel().toString().compareTo(area.getLabel().toString()) == 0){
328                        result = true;
329                }
330                return result;
331        }*/
332       
333//      public int compareTo(NamedArea area){
334//              return getLabel().compareTo(area.getLabel());
335//      }
336       
337       
338       
339        /**
340         * This method returns a sorted tree structure which sorts areas by it's level and within the same level
341         * alphabetically (TODO to be tested).
342         * The structure returned is a tree with alternating nodes that represent an area and an areaLevel.
343         * This way also area the have children belonging to different levels can be handled.<BR>
344         * The root node is always an empty area node which holds the list of top level areaLevels.
345         * AreaLevels with no level defined are handled as if they have a separate level (level="null").
346         *
347         * @param areaList
348         * @return
349         */
350        public static NamedAreaNode getHiearchieList(List<NamedArea> areaList){
351                NamedAreaNode result = new NamedAreaNode();
352                for (NamedArea area : areaList){
353                        List<NamedArea> areaHierarchie  = area.getAllLevelList();
354                        mergeIntoResult(result, areaHierarchie);
355                }
356                return result;
357        }
358       
359       
360        public static class LevelNode {
361                NamedAreaLevel level;
362                List<NamedAreaNode> areaList = new ArrayList<NamedAreaNode>();
363
364                public NamedAreaNode add(NamedArea area) {
365                        NamedAreaNode node = new NamedAreaNode();
366                        node.area = area;
367                        areaList.add(node);
368                        return node;
369
370                }
371
372                public NamedAreaNode getNamedAreaNode(NamedArea area) {
373                        for (NamedAreaNode node : areaList) {
374                                if (node.area.equals(area)) {
375                                        return node;
376                                }
377                        }
378                        return null;
379                }
380
381                public String toString() {
382                        return toString(false, 0);
383                }
384                public String toString(boolean recursive, int identation) {
385                        String result = level == null? "" :level.getTitleCache();
386                        if (recursive == false){
387                                return result;
388                        }else{
389                                int areaSize = this.areaList.size();
390                                if (areaSize > 0){
391                                        result = "\n" + StringUtils.leftPad("", identation) + result  + "[";
392                                }
393                                boolean isFirst = true;
394                                for (NamedAreaNode level: this.areaList){
395                                        if (isFirst){
396                                                isFirst = false;
397                                        }else{
398                                                result += ",";
399                                        }
400                                        result += level.toString(recursive, identation+1);
401                                }
402                                if (areaSize > 0){
403                                        result += "]";
404                                       
405                                }
406                                return result;
407                        }
408                }
409
410        }
411
412        public static class NamedAreaNode {
413                NamedArea area;
414                List<LevelNode> levelList = new ArrayList<LevelNode>();
415               
416                public LevelNode getLevelNode(NamedAreaLevel level) {
417                        for (LevelNode node : levelList) {
418                                if (node.level != null &&  node.level.equals(level)) {
419                                        return node;
420                                }
421                        }
422                        return null;
423                }
424
425                public List<NamedAreaNode> getList(NamedAreaLevel level) {
426                        LevelNode node = getLevelNode(level);
427                        if (node == null) {
428                                return new ArrayList<NamedAreaNode>();
429                        } else {
430                                return node.areaList;
431                        }
432                };
433
434                public boolean contains(NamedAreaLevel level) {
435                        if (getList(level).size() > 0) {
436                                return true;
437                        } else {
438                                return false;
439                        }
440                }
441
442                public LevelNode add(NamedAreaLevel level) {
443                        LevelNode node = new LevelNode();
444                        node.level = level;
445                        levelList.add(node);
446                        return node;
447                }
448
449                public String toString() {
450                        return toString(false, 0);
451                }
452               
453                public String toString(boolean recursive, int identation) {
454                        String result = "";
455                        if (area != null) {
456                                result = area.getTitleCache();
457                        }
458                        if (recursive){
459                                int levelSize = this.levelList.size();
460                                if (levelSize > 0){
461                                        result = "\n" + StringUtils.leftPad("", identation) + result  + "[";
462                                }
463                                boolean isFirst = true;
464                                for (LevelNode level: this.levelList){
465                                        if (isFirst){
466                                                isFirst = false;
467                                        }else{
468                                                result += ";";
469                                        }
470                                        result += level.toString(recursive, identation+1);
471                                }
472                                if (levelSize > 0){
473                                        result += "]";
474                                       
475                                }
476                                return result;
477                        }else{
478                                int levelSize = this.levelList.size();
479                                return result + "[" + levelSize + " sublevel(s)]";
480                        }
481                }
482        }
483
484        private static void mergeIntoResult(NamedAreaNode root, List<NamedArea> areaHierarchie) {
485                if (areaHierarchie.isEmpty()) {
486                        return;
487                }
488                NamedArea highestArea = areaHierarchie.get(0);
489                NamedAreaLevel level = highestArea.getLevel();
490                NamedAreaNode namedAreaNode;
491                if (! root.contains(level)) {
492                        LevelNode node = root.add(level);
493                        namedAreaNode = node.add(highestArea);
494                        //NEW
495//                      root.area = highestArea;
496                } else {
497                        LevelNode levelNode = root.getLevelNode(level);
498                        namedAreaNode = levelNode.getNamedAreaNode(highestArea);
499                        if (namedAreaNode == null) {
500                                namedAreaNode = levelNode.add(highestArea);
501                        }
502                }
503                List<NamedArea> newList = areaHierarchie.subList(1, areaHierarchie.size());
504                mergeIntoResult(namedAreaNode, newList);
505
506        }
507
508        @Transient
509        public List<NamedArea> getAllLevelList() {
510                List<NamedArea> result = new ArrayList<NamedArea>();
511                NamedArea copyArea = this;
512                result.add(copyArea);           
513                while (copyArea.getPartOf() != null) {
514                        copyArea = copyArea.getPartOf();
515                        result.add(0, copyArea);
516                }
517                return result;
518        }
519       
520// ******************* toString **********************************/     
521
522        /* (non-Javadoc)
523         * @see eu.etaxonomy.cdm.model.common.TermBase#toString()
524         */
525        public String toString(){
526                String result, label, level = "";
527               
528                if (this.level != null){
529                        level = this.level.getLabel();
530                }else{
531                        level = "no level";
532                }
533                label = this.getLabel();
534                result = "[" + level + ", " + label + "]";
535               
536                return result;
537        }
538       
539       
540
541        /**
542         * Returns the label of the named area together with the area level label and the abbreviated label.
543         * This is kind of a formatter method which may be moved to a better place in future.
544         * @param namedArea the area
545         * @param language the preferred language
546         * @return null if namedArea == null, the labelWithLevel otherwise
547         */
548        public static String labelWithLevel(NamedArea namedArea, Language language) {
549                if (namedArea == null){
550                        return null;
551                }
552                NamedArea area = CdmBase.deproxy(namedArea, NamedArea.class);
553               
554                StringBuilder title = new StringBuilder();
555                Representation representation = area.getPreferredRepresentation(language);
556                if (representation != null){
557                        String areaString = getPreferredAreaLabel(namedArea, representation);
558                       
559                        title.append(areaString);
560                        if (area.getLevel() == null){
561                                title.append(" - ");
562                                title.append(area.getClass().getSimpleName());
563                        }else{
564                                title.append(" - ");
565                                Representation levelRepresentation = area.getLevel().getPreferredRepresentation(language);
566                                String levelString = getPreferredAreaLabel(area.getLevel(), levelRepresentation);
567                                title.append(levelString);
568                        }
569                }
570                return title.toString();
571        }
572
573        /**
574         * @param definedTerm
575         * @param representation
576         * @return
577         */
578        private static String getPreferredAreaLabel(DefinedTermBase<?> definedTerm, Representation representation) {
579                String areaString = null;
580                if (representation != null){
581                        areaString = representation.getLabel();
582                        if (StringUtils.isBlank(areaString)){
583                                areaString = representation.getAbbreviatedLabel();
584                        }
585                        if (StringUtils.isBlank(areaString)){
586                                areaString = representation.getText();
587                        }
588                }
589                if (StringUtils.isBlank(areaString)){
590                        areaString = definedTerm == null ? null : definedTerm.getTitleCache();
591                }
592                if (StringUtils.isBlank(areaString)){
593                        areaString = "no title";
594                }
595                return areaString;
596        }
597       
598        //*********************************** CLONE *****************************************/
599
600        /**
601         * Clones <i>this</i> NamedArea. This is a shortcut that enables to create
602         * a new instance that differs only slightly from <i>this</i> NamedArea by
603         * modifying only some of the attributes.
604         *
605         * @see eu.etaxonomy.cdm.model.common.OrderedTermBase#clone()
606         * @see java.lang.Object#clone()
607         */
608        @Override
609        public Object clone() {
610                NamedArea result;
611               
612                        result = (NamedArea)super.clone();
613                        //no changes to level, pointApproximation, shape, type, validPeriod and waterbodiesOrCountries
614                        return result;
615               
616        }
617               
618       
619}
Note: See TracBrowser for help on using the browser.