Project

General

Profile

Download (24.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.common;
11

    
12

    
13
import java.beans.PropertyChangeEvent;
14
import java.beans.PropertyChangeListener;
15
import java.util.ArrayList;
16
import java.util.HashSet;
17
import java.util.List;
18
import java.util.Set;
19
import java.util.UUID;
20

    
21
import javax.persistence.Column;
22
import javax.persistence.Embedded;
23
import javax.persistence.FetchType;
24
import javax.persistence.MappedSuperclass;
25
import javax.persistence.OneToMany;
26
import javax.persistence.OrderColumn;
27
import javax.persistence.Transient;
28
import javax.validation.constraints.NotNull;
29
import javax.xml.bind.annotation.XmlAccessType;
30
import javax.xml.bind.annotation.XmlAccessorType;
31
import javax.xml.bind.annotation.XmlElement;
32
import javax.xml.bind.annotation.XmlElementWrapper;
33
import javax.xml.bind.annotation.XmlTransient;
34
import javax.xml.bind.annotation.XmlType;
35
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
36

    
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.Analyze;
42
import org.hibernate.search.annotations.Field;
43
import org.hibernate.search.annotations.FieldBridge;
44
import org.hibernate.search.annotations.Fields;
45
import org.hibernate.search.annotations.Index;
46
import org.hibernate.search.annotations.SortableField;
47
import org.hibernate.search.annotations.Store;
48
import org.hibernate.validator.constraints.NotEmpty;
49

    
50
import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
51
import eu.etaxonomy.cdm.hibernate.search.StripHtmlBridge;
52
import eu.etaxonomy.cdm.jaxb.FormattedTextAdapter;
53
import eu.etaxonomy.cdm.jaxb.LSIDAdapter;
54
import eu.etaxonomy.cdm.model.media.Rights;
55
import eu.etaxonomy.cdm.model.name.BotanicalName;
56
import eu.etaxonomy.cdm.model.name.NonViralName;
57
import eu.etaxonomy.cdm.model.name.TaxonNameBase;
58
import eu.etaxonomy.cdm.model.reference.Reference;
59
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
60
import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
61
import eu.etaxonomy.cdm.strategy.match.Match;
62
import eu.etaxonomy.cdm.strategy.match.Match.ReplaceMode;
63
import eu.etaxonomy.cdm.strategy.match.MatchMode;
64
import eu.etaxonomy.cdm.strategy.merge.Merge;
65
import eu.etaxonomy.cdm.strategy.merge.MergeMode;
66
import eu.etaxonomy.cdm.validation.Level2;
67

    
68
/**
69
 * Superclass for the primary CDM classes that can be referenced from outside via LSIDs and contain a simple generated title string as a label for human reading.
70
 * All subclasses inherit the ability to store additional properties that are stored as {@link Extension Extensions}, basically a string value with a type term.
71
 * Any number of right statements can be attached as well as multiple {@link OriginalSourceBase} objects.
72
 * Original sources carry a reference to the source, an ID within that source and the original title/label of this object as it was used in that source (originalNameString).
73
 * A Taxon for example that was taken from 2 sources like FaunaEuropaea and IPNI would have two originalSource objects.
74
 * The originalSource representing that taxon as it was found in IPNI would contain IPNI as the reference, the IPNI id of the taxon and the name of the taxon exactly as it was used in IPNI.
75
 *
76
 * @author m.doering
77
 * @version 1.0
78
 * @created 08-Nov-2007 13:06:27
79
 */
80
@XmlAccessorType(XmlAccessType.FIELD)
81
@XmlType(name = "IdentifiableEntity", propOrder = {
82
    "lsid",
83
    "titleCache",
84
    "protectedTitleCache",
85
    "credits",
86
    "extensions",
87
    "identifiers",
88
    "rights",
89
    "sources"
90
})
91
@Audited
92
@MappedSuperclass
93
public abstract class IdentifiableEntity<S extends IIdentifiableEntityCacheStrategy> extends AnnotatableEntity
94
        implements IIdentifiableEntity /*, ISourceable<IdentifiableSource> */ {
95
    private static final long serialVersionUID = -5610995424730659058L;
96
    private static final Logger logger = Logger.getLogger(IdentifiableEntity.class);
97

    
98
    @XmlTransient
99
    public static final boolean PROTECTED = true;
100
    @XmlTransient
101
    public static final boolean NOT_PROTECTED = false;
102

    
103
    @XmlElement(name = "LSID", type = String.class)
104
    @XmlJavaTypeAdapter(LSIDAdapter.class)
105
    @Embedded
106
    private LSID lsid;
107

    
108
    @XmlElement(name = "TitleCache", required = true)
109
    @XmlJavaTypeAdapter(FormattedTextAdapter.class)
110
    @Column(name="titleCache", length=800) //see #1592
111
    @Match(value=MatchMode.CACHE, cacheReplaceMode=ReplaceMode.ALL)
112
    @NotEmpty(groups = Level2.class) // implictly NotNull
113
    @Fields({
114
        @Field(store=Store.YES),
115
        //  If the field is only needed for sorting and nothing else, you may configure it as
116
        //  un-indexed and un-stored, thus avoid unnecessary index growth.
117
        @Field(name = "titleCache__sort", analyze = Analyze.NO, store=Store.NO, index = Index.NO)
118
    })
119
    @SortableField(forField = "titleCache__sort")
120
    @FieldBridge(impl=StripHtmlBridge.class)
121
    protected String titleCache;
122

    
123
    //if true titleCache will not be automatically generated/updated
124
    @XmlElement(name = "ProtectedTitleCache")
125
    protected boolean protectedTitleCache;
126

    
127
    @XmlElementWrapper(name = "Rights", nillable = true)
128
    @XmlElement(name = "Rights")
129
    @OneToMany(fetch = FetchType.LAZY, orphanRemoval=true)
130
    @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE})
131
    //TODO
132
    @Merge(MergeMode.ADD_CLONE)
133
    @NotNull
134
    private Set<Rights> rights = new HashSet<Rights>();
135

    
136
    @XmlElementWrapper(name = "Credits", nillable = true)
137
    @XmlElement(name = "Credit")
138
    @OrderColumn(name="sortIndex")
139
    @OneToMany(fetch = FetchType.LAZY, orphanRemoval=true)
140
    @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE})
141
    //TODO
142
    @Merge(MergeMode.ADD_CLONE)
143
    @NotNull
144
    private List<Credit> credits = new ArrayList<Credit>();
145

    
146
    @XmlElementWrapper(name = "Extensions", nillable = true)
147
    @XmlElement(name = "Extension")
148
    @OneToMany(fetch = FetchType.LAZY, orphanRemoval=true)
149
    @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE})
150
    @Merge(MergeMode.ADD_CLONE)
151
    @NotNull
152
    private Set<Extension> extensions = new HashSet<Extension>();
153

    
154
    @XmlElementWrapper(name = "Identifiers", nillable = true)
155
    @XmlElement(name = "Identifier")
156
    @OrderColumn(name="sortIndex")
157
    @OneToMany(fetch = FetchType.LAZY, orphanRemoval=true)
158
    @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE})
159
    @Merge(MergeMode.ADD_CLONE)
160
    @NotNull
161
    private List<Identifier> identifiers = new ArrayList<Identifier>();
162

    
163
    @XmlElementWrapper(name = "Sources", nillable = true)
164
    @XmlElement(name = "IdentifiableSource")
165
    @OneToMany(fetch = FetchType.LAZY, orphanRemoval=true)
166
    @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE})
167
    @Merge(MergeMode.ADD_CLONE)
168
    @NotNull
169
    private Set<IdentifiableSource> sources = new HashSet<IdentifiableSource>();
170

    
171
    @XmlTransient
172
    @Transient
173
    protected S cacheStrategy;
174

    
175
    protected IdentifiableEntity(){
176
        initListener();
177
    }
178

    
179
    @Override
180
    public void initListener(){
181
        PropertyChangeListener listener = new PropertyChangeListener() {
182
            @Override
183
            public void propertyChange(PropertyChangeEvent ev) {
184
                if (! "titleCache".equals(ev.getPropertyName()) && !"cacheStrategy".equals(ev.getPropertyName()) && ! isProtectedTitleCache()){
185
                    titleCache = null;
186
                }
187
            }
188
        };
189
        addPropertyChangeListener(listener);
190
    }
191

    
192
    /**
193
     * By default, we expect most cdm objects to be abstract things
194
     * i.e. unable to return a data representation.
195
     *
196
     * Specific subclasses (e.g. Sequence) can override if necessary.
197
     */
198
    @Override
199
    public byte[] getData() {
200
        return null;
201
    }
202

    
203
//******************************** CACHE *****************************************************/
204

    
205
    // @Transient  - must not be transient, since this property needs to to be included in all serializations produced by the remote layer
206
    @Override
207
    public String getTitleCache(){
208
        if (protectedTitleCache){
209
            return this.titleCache;
210
        }
211
        // is title dirty, i.e. equal NULL?
212
        if (titleCache == null){
213
            this.titleCache = generateTitle();
214
            this.titleCache = getTruncatedCache(this.titleCache) ;
215
        }
216
        return titleCache;
217
    }
218

    
219
    @Deprecated
220
    @Override
221
    public void setTitleCache(String titleCache){
222
    	//TODO shouldn't we call setTitleCache(String, boolean),but is this conformant with Java Bean Specification?
223
    	this.titleCache = getTruncatedCache(titleCache);
224
    }
225

    
226
    @Override
227
    public void setTitleCache(String titleCache, boolean protectCache){
228
        titleCache = getTruncatedCache(titleCache);
229
        this.titleCache = titleCache;
230
        this.protectedTitleCache = protectCache;
231
    }
232

    
233
    /**
234
     * @param cache
235
     * @return
236
     */
237
    @Transient
238
    protected String getTruncatedCache(String cache) {
239
        int maxLength = 800;
240
    	if (cache != null && cache.length() > maxLength){
241
            logger.warn("Truncation of cache: " + this.toString() + "/" + cache);
242
            cache = cache.substring(0, maxLength - 4) + "...";   //TODO do we need -4 or is -3 enough
243
        }
244
        return cache;
245
    }
246

    
247

    
248
    @Override
249
    public boolean isProtectedTitleCache() {
250
        return protectedTitleCache;
251
    }
252

    
253
    @Override
254
    public void setProtectedTitleCache(boolean protectedTitleCache) {
255
        this.protectedTitleCache = protectedTitleCache;
256
    }
257

    
258
//**************************************************************************************
259

    
260
    @Override
261
    public LSID getLsid(){
262
        return this.lsid;
263
    }
264
    @Override
265
    public void setLsid(LSID lsid){
266
        this.lsid = lsid;
267
    }
268
    @Override
269
    public Set<Rights> getRights() {
270
        if(rights == null) {
271
            this.rights = new HashSet<Rights>();
272
        }
273
        return this.rights;
274
    }
275

    
276
    @Override
277
    public void addRights(Rights right){
278
        getRights().add(right);
279
    }
280
    @Override
281
    public void removeRights(Rights right){
282
        getRights().remove(right);
283
    }
284

    
285

    
286
    @Override
287
    public List<Credit> getCredits() {
288
        if(credits == null) {
289
            this.credits = new ArrayList<Credit>();
290
        }
291
        return this.credits;
292
    }
293

    
294
    @Override
295
    public Credit getCredits(Integer index){
296
        return getCredits().get(index);
297
    }
298

    
299
    @Override
300
    public void addCredit(Credit credit){
301
        getCredits().add(credit);
302
    }
303

    
304

    
305
    @Override
306
    public void addCredit(Credit credit, int index){
307
        getCredits().add(index, credit);
308
    }
309

    
310
    @Override
311
    public void removeCredit(Credit credit){
312
        getCredits().remove(credit);
313
    }
314

    
315
    @Override
316
    public void removeCredit(int index){
317
        getCredits().remove(index);
318
    }
319

    
320
    @Override
321
    public boolean replaceCredit(Credit newObject, Credit oldObject){
322
        return replaceInList(this.credits, newObject, oldObject);
323
    }
324

    
325

    
326
    @Override
327
    public List<Identifier> getIdentifiers(){
328
        if(this.identifiers == null) {
329
            this.identifiers = new ArrayList<Identifier>();
330
        }
331
        return this.identifiers;
332
    }
333
    /**
334
     * @param type
335
     * @return a set of identifier value strings
336
     */
337
    public Set<String> getIdentifiers(DefinedTerm type){
338
       return getIdentifiers(type.getUuid());
339
    }
340
    /**
341
     * @param identifierTypeUuid
342
     * @return a set of identifier value strings
343
     */
344
    public Set<String> getIdentifiers(UUID identifierTypeUuid){
345
        Set<String> result = new HashSet<String>();
346
        for (Identifier<?> identifier : getIdentifiers()){
347
            if (identifier.getType().getUuid().equals(identifierTypeUuid)){
348
                result.add(identifier.getIdentifier());
349
            }
350
        }
351
        return result;
352
    }
353

    
354
    @Override
355
    public Identifier addIdentifier(String identifier, DefinedTerm identifierType){
356
    	Identifier<?> result = Identifier.NewInstance(identifier, identifierType);
357
    	addIdentifier(result);
358
    	return result;
359
    }
360

    
361
     @Override
362
    public void addIdentifier(int index, Identifier identifier){
363
        if (identifier != null){
364
        	//deduplication
365
        	int oldIndex = getIdentifiers().indexOf(identifier);
366
        	if(oldIndex > -1){
367
        		getIdentifiers().remove(identifier);
368
        		if (oldIndex < index){
369
        			index--;
370
        		}
371
        	}
372
        	getIdentifiers().add(index, identifier);
373
        }
374
    }
375

    
376
    @Override
377
    public void addIdentifier(Identifier identifier){
378
        addIdentifier(getIdentifiers().size(), identifier);
379
    }
380

    
381
    @Override
382
    public void removeIdentifier(Identifier identifier){
383
        if (identifier != null){
384
            getIdentifiers().remove(identifier);
385
        }
386
    }
387
    @Override
388
    public void removeIdentifier(int index){
389
    	getIdentifiers().remove(index);
390
    }
391

    
392
    @Override
393
    public boolean replaceIdentifier(Identifier newObject, Identifier oldObject){
394
        return replaceInList(this.identifiers, newObject, oldObject);
395
    }
396

    
397

    
398
    @Override
399
    public Set<Extension> getExtensions(){
400
        if(extensions == null) {
401
            this.extensions = new HashSet<Extension>();
402
        }
403
        return this.extensions;
404
    }
405
    /**
406
     * @param type
407
     * @return a Set of extension value strings
408
     */
409
    public Set<String> getExtensions(ExtensionType type){
410
       return getExtensions(type.getUuid());
411
    }
412
    /**
413
     * @param extensionTypeUuid
414
     * @return a Set of extension value strings
415
     */
416
    public Set<String> getExtensions(UUID extensionTypeUuid){
417
        Set<String> result = new HashSet<String>();
418
        for (Extension extension : getExtensions()){
419
            if (extension.getType().getUuid().equals(extensionTypeUuid)){
420
                result.add(extension.getValue());
421
            }
422
        }
423
        return result;
424
    }
425

    
426
    public void addExtension(String value, ExtensionType extensionType){
427
        Extension.NewInstance(this, value, extensionType);
428
    }
429

    
430
    @Override
431
    public void addExtension(Extension extension){
432
        if (extension != null){
433
            getExtensions().add(extension);
434
        }
435
    }
436
    @Override
437
    public void removeExtension(Extension extension){
438
        if (extension != null){
439
            getExtensions().remove(extension);
440
        }
441
    }
442

    
443

    
444
    @Override
445
    public Set<IdentifiableSource> getSources() {
446
        if(sources == null) {
447
            this.sources = new HashSet<IdentifiableSource>();
448
        }
449
        return this.sources;
450
    }
451

    
452
    @Override
453
    public void addSource(IdentifiableSource source) {
454
        if (source != null){
455
            getSources().add(source);
456
        }
457
    }
458

    
459
    @Override
460
    public void addSources(Set<IdentifiableSource> sources) {
461
        if (sources != null){
462
        	for (IdentifiableSource source: sources){
463
	            getSources().add(source);
464
        	}
465
        }
466
    }
467

    
468
    @Override
469
    public void removeSources() {
470
       this.sources.clear();
471
    }
472

    
473
    @Override
474
    public IdentifiableSource addSource(OriginalSourceType type, String id, String idNamespace, Reference citation, String microCitation) {
475
        if (id == null && idNamespace == null && citation == null && microCitation == null){
476
            return null;
477
        }
478
        IdentifiableSource source = IdentifiableSource.NewInstance(type, id, idNamespace, citation, microCitation);
479
        addSource(source);
480
        return source;
481
    }
482

    
483

    
484
    @Override
485
    public IdentifiableSource addImportSource(String id, String idNamespace, Reference<?> citation, String microCitation) {
486
        if (id == null && idNamespace == null && citation == null && microCitation == null){
487
            return null;
488
        }
489
        IdentifiableSource source = IdentifiableSource.NewInstance(OriginalSourceType.Import, id, idNamespace, citation, microCitation);
490
        addSource(source);
491
        return source;
492
    }
493

    
494

    
495
    @Override
496
    public void removeSource(IdentifiableSource source) {
497
        getSources().remove(source);
498
    }
499

    
500
//******************************** TO STRING *****************************************************/
501

    
502
    @Override
503
    public String toString() {
504
        String result;
505
        if (titleCache == null){
506
            result = super.toString();
507
        }else{
508
            result = this.titleCache;
509
        }
510
        return result;
511
    }
512

    
513

    
514
    public int compareTo(IdentifiableEntity identifiableEntity) {
515

    
516
         int result = 0;
517

    
518
         if (identifiableEntity == null) {
519
             throw new NullPointerException("Cannot compare to null.");
520
         }
521

    
522
         // First, compare the name cache.
523
         // TODO: Avoid using instanceof operator
524
         // Use Class.getDeclaredMethod() instead to find out whether class has getNameCache() method?
525

    
526
         String specifiedNameCache = "";
527
         String thisNameCache = "";
528
         String specifiedTitleCache = "";
529
         String thisTitleCache = "";
530
         String specifiedReferenceTitleCache = "";
531
         String thisReferenceTitleCache = "";
532
         String thisGenusString = "";
533
         String specifiedGenusString = "";
534
         int thisrank_order = 0;
535
         final String HYBRID_SIGN = "\u00D7";
536
         final String QUOT_SIGN = "[\\u02BA\\u0022\\u0022]";
537
         //TODO we can remove all the deproxies here except for the first one
538
         identifiableEntity = HibernateProxyHelper.deproxy(identifiableEntity, IdentifiableEntity.class);
539
         if(identifiableEntity instanceof NonViralName) {
540
             specifiedNameCache = HibernateProxyHelper.deproxy(identifiableEntity, NonViralName.class).getNameCache();
541
             specifiedTitleCache = identifiableEntity.getTitleCache();
542
            if (identifiableEntity instanceof BotanicalName){
543
            	 if (((BotanicalName)identifiableEntity).isAutonym()){
544
            		 boolean isProtected = false;
545
            		 String oldNameCache = ((BotanicalName) identifiableEntity).getNameCache();
546
            		 if ( ((BotanicalName)identifiableEntity).isProtectedNameCache()){
547
            			 isProtected = true;
548
            		 }
549
            		 ((BotanicalName)identifiableEntity).setProtectedNameCache(false);
550
            		 ((BotanicalName)identifiableEntity).setNameCache(null, false);
551
            		 specifiedNameCache = ((BotanicalName) identifiableEntity).getNameCache();
552
            		 ((BotanicalName)identifiableEntity).setNameCache(oldNameCache, isProtected);
553

    
554
            	 }
555
             }
556

    
557
         } else if(identifiableEntity instanceof TaxonBase) {
558
             TaxonBase taxonBase = HibernateProxyHelper.deproxy(identifiableEntity, TaxonBase.class);
559

    
560
             TaxonNameBase<?,?> taxonNameBase = taxonBase.getName();
561

    
562

    
563
             NonViralName nonViralName = HibernateProxyHelper.deproxy(taxonNameBase, NonViralName.class);
564
             specifiedNameCache = nonViralName.getNameCache();
565
             specifiedTitleCache = taxonNameBase.getTitleCache();
566

    
567
             specifiedReferenceTitleCache = ((TaxonBase)identifiableEntity).getSec().getTitleCache();
568
             Reference reference = taxonBase.getSec();
569
             if (reference != null) {
570
                 reference = HibernateProxyHelper.deproxy(reference, Reference.class);
571
                 specifiedReferenceTitleCache = reference.getTitleCache();
572
             }
573
         }
574

    
575
         if(this.isInstanceOf(NonViralName.class)) {
576
             thisNameCache = HibernateProxyHelper.deproxy(this, NonViralName.class).getNameCache();
577
             thisTitleCache = getTitleCache();
578

    
579
             if (this instanceof BotanicalName){
580
            	 if (((BotanicalName)this).isAutonym()){
581
            		 boolean isProtected = false;
582
            		 String oldNameCache = ((BotanicalName) this).getNameCache();
583
            		 if ( ((BotanicalName)this).isProtectedNameCache()){
584
            			 isProtected = true;
585
            		 }
586
            		 ((BotanicalName)this).setProtectedNameCache(false);
587
            		 ((BotanicalName)this).setNameCache(null, false);
588
            		 thisNameCache = ((BotanicalName) this).getNameCache();
589
            		 ((BotanicalName)this).setNameCache(oldNameCache, isProtected);
590
            	 }
591
             }
592
         } else if(this.isInstanceOf(TaxonBase.class)) {
593
             TaxonNameBase<?,?> taxonNameBase= HibernateProxyHelper.deproxy(this, TaxonBase.class).getName();
594
             NonViralName nonViralName = HibernateProxyHelper.deproxy(taxonNameBase, NonViralName.class);
595
             thisNameCache = nonViralName.getNameCache();
596
             thisTitleCache = taxonNameBase.getTitleCache();
597
             thisReferenceTitleCache = ((TaxonBase)this).getSec().getTitleCache();
598
             thisGenusString = nonViralName.getGenusOrUninomial();
599
         }
600

    
601
         // Compare name cache of taxon names
602

    
603

    
604

    
605
         if (!specifiedNameCache.equals("") && !thisNameCache.equals("")) {
606

    
607
        	 thisNameCache = thisNameCache.replaceAll(HYBRID_SIGN, "");
608
        	 thisNameCache = thisNameCache.replaceAll(QUOT_SIGN, "");
609

    
610

    
611
        	 specifiedNameCache = specifiedNameCache.replaceAll(HYBRID_SIGN, "");
612
        	 specifiedNameCache = specifiedNameCache.replaceAll(QUOT_SIGN, "");
613

    
614

    
615
             result = thisNameCache.compareTo(specifiedNameCache);
616
         }
617

    
618
         // Compare title cache of taxon names
619

    
620
         if ((result == 0) && (!specifiedTitleCache.equals("") || !thisTitleCache.equals(""))) {
621
        	 thisTitleCache = thisTitleCache.replaceAll(HYBRID_SIGN, "");
622
        	 thisTitleCache = thisTitleCache.replaceAll(QUOT_SIGN, "");
623

    
624
        	 specifiedTitleCache = specifiedTitleCache.replaceAll(HYBRID_SIGN, "");
625
        	 specifiedTitleCache = specifiedTitleCache.replaceAll(QUOT_SIGN, "");
626
             result = thisTitleCache.compareTo(specifiedTitleCache);
627
         }
628

    
629
         // Compare title cache of taxon references
630

    
631
         if ((result == 0) && (!specifiedReferenceTitleCache.equals("") || !thisReferenceTitleCache.equals(""))) {
632
             result = thisReferenceTitleCache.compareTo(specifiedReferenceTitleCache);
633
         }
634

    
635
         return result;
636
     }
637

    
638
    /**
639
     * Returns the {@link eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy cache strategy} used to generate
640
     * several strings corresponding to <i>this</i> identifiable entity
641
     * (in particular taxon name caches and author strings).
642
     *
643
     * @return  the cache strategy used for <i>this</i> identifiable entity
644
     * @see     eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy
645
     */
646
    public S getCacheStrategy() {
647
        return this.cacheStrategy;
648
    }
649
    /**
650
     * @see 	#getCacheStrategy()
651
     */
652

    
653
    public void setCacheStrategy(S cacheStrategy) {
654
        this.cacheStrategy = cacheStrategy;
655
    }
656

    
657
    @Override
658
    public String generateTitle() {
659
        if (getCacheStrategy() == null){
660
            //logger.warn("No CacheStrategy defined for "+ this.getClass() + ": " + this.getUuid());
661
            return this.getClass() + ": " + this.getUuid();
662
        }else{
663
            return getCacheStrategy().getTitleCache(this);
664
        }
665
    }
666

    
667
//****************** CLONE ************************************************/
668

    
669
    @Override
670
    public Object clone() throws CloneNotSupportedException{
671
        IdentifiableEntity<?> result = (IdentifiableEntity<?>)super.clone();
672

    
673
        //Extensions
674
        result.extensions = new HashSet<Extension>();
675
        for (Extension extension : getExtensions() ){
676
            Extension newExtension = (Extension)extension.clone();
677
            result.addExtension(newExtension);
678
        }
679

    
680
        //Identifier
681
        result.identifiers = new ArrayList<Identifier>();
682
        for (Identifier<?> identifier : getIdentifiers() ){
683
        	Identifier<?> newIdentifier = (Identifier<?>)identifier.clone();
684
            result.addIdentifier(newIdentifier);
685
        }
686

    
687
        //OriginalSources
688
        result.sources = new HashSet<IdentifiableSource>();
689
        for (IdentifiableSource source : getSources()){
690
            IdentifiableSource newSource = (IdentifiableSource)source.clone();
691
            result.addSource(newSource);
692
        }
693

    
694
        //Rights
695
        result.rights = new HashSet<Rights>();
696
        for(Rights rights : getRights()) {
697
            result.addRights(rights);
698
        }
699

    
700

    
701
        //Credits
702
        result.credits = new ArrayList<Credit>();
703
        for(Credit credit : getCredits()) {
704
            result.addCredit(credit);
705
        }
706

    
707
        //no changes to: lsid, titleCache, protectedTitleCache
708

    
709
        //empty titleCache
710
        if (! protectedTitleCache){
711
            result.titleCache = null;
712
        }
713

    
714
        result.initListener();
715
        return result;
716
    }
717

    
718

    
719
}
(36-36/72)