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.validation.constraints.Size;
30
import javax.xml.bind.annotation.XmlAccessType;
31
import javax.xml.bind.annotation.XmlAccessorType;
32
import javax.xml.bind.annotation.XmlElement;
33
import javax.xml.bind.annotation.XmlElementWrapper;
34
import javax.xml.bind.annotation.XmlTransient;
35
import javax.xml.bind.annotation.XmlType;
36
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
37

    
38
import org.apache.log4j.Logger;
39
import org.hibernate.annotations.Cascade;
40
import org.hibernate.annotations.CascadeType;
41
import org.hibernate.annotations.IndexColumn;
42
import org.hibernate.envers.Audited;
43
import org.hibernate.search.annotations.Analyze;
44
import org.hibernate.search.annotations.Field;
45
import org.hibernate.search.annotations.FieldBridge;
46
import org.hibernate.search.annotations.Fields;
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")
111
    @Match(value=MatchMode.CACHE, cacheReplaceMode=ReplaceMode.ALL)
112
    @NotEmpty(groups = Level2.class) // implictly NotNull
113
    @Size(max = 800)  //see #1592
114
    @Fields({
115
        @Field(store=Store.YES),
116
        @Field(name = "titleCache__sort", analyze = Analyze.NO, store=Store.YES)
117
    })
118
    @FieldBridge(impl=StripHtmlBridge.class)
119
    protected String titleCache;
120

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

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

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

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

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

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

    
169
    @XmlTransient
170
    @Transient
171
    protected S cacheStrategy;
172

    
173
    protected IdentifiableEntity(){
174
        initListener();
175
    }
176

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

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

    
200
//******************************** CACHE *****************************************************/
201

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

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

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

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

    
244
//**************************************************************************************
245

    
246
    @Override
247
    public LSID getLsid(){
248
        return this.lsid;
249
    }
250
    @Override
251
    public void setLsid(LSID lsid){
252
        this.lsid = lsid;
253
    }
254
    @Override
255
    public Set<Rights> getRights() {
256
        if(rights == null) {
257
            this.rights = new HashSet<Rights>();
258
        }
259
        return this.rights;
260
    }
261

    
262
    @Override
263
    public void addRights(Rights right){
264
        getRights().add(right);
265
    }
266
    @Override
267
    public void removeRights(Rights right){
268
        getRights().remove(right);
269
    }
270

    
271

    
272
    @Override
273
    public List<Credit> getCredits() {
274
        if(credits == null) {
275
            this.credits = new ArrayList<Credit>();
276
        }
277
        return this.credits;
278
    }
279

    
280
    @Override
281
    public Credit getCredits(Integer index){
282
        return getCredits().get(index);
283
    }
284

    
285
    @Override
286
    public void addCredit(Credit credit){
287
        getCredits().add(credit);
288
    }
289

    
290

    
291
    @Override
292
    public void addCredit(Credit credit, int index){
293
        getCredits().add(index, credit);
294
    }
295

    
296
    @Override
297
    public void removeCredit(Credit credit){
298
        getCredits().remove(credit);
299
    }
300

    
301
    @Override
302
    public void removeCredit(int index){
303
        getCredits().remove(index);
304
    }
305

    
306
    /* (non-Javadoc)
307
     * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#getIdentifiers()
308
     */
309
    @Override
310
    public List<Identifier> getIdentifiers(){
311
        if(this.identifiers == null) {
312
            this.identifiers = new ArrayList<Identifier>();
313
        }
314
        return this.identifiers;
315
    }
316
    /**
317
     * @param type
318
     * @return a set of identifier value strings
319
     */
320
    public Set<String> getIdentifiers(DefinedTerm type){
321
       return getIdentifiers(type.getUuid());
322
    }
323
    /**
324
     * @param identifierTypeUuid
325
     * @return a set of identifier value strings
326
     */
327
    public Set<String> getIdentifiers(UUID identifierTypeUuid){
328
        Set<String> result = new HashSet<String>();
329
        for (Identifier identifier : getIdentifiers()){
330
            if (identifier.getType().getUuid().equals(identifierTypeUuid)){
331
                result.add(identifier.getIdentifier());
332
            }
333
        }
334
        return result;
335
    }
336

    
337
    @Override
338
    public Identifier addIdentifier(String identifier, DefinedTerm identifierType){
339
    	Identifier result = Identifier.NewInstance(this, identifier, identifierType);
340
    	return result;
341
    }
342

    
343
     @Override
344
    public void addIdentifier(int index, Identifier identifier){
345
        if (identifier != null){
346
        	if (identifier.getIdentifiedObj() != null && ! identifier.getIdentifiedObj().equals(this)){
347
        		identifier.getIdentifiedObj().removeIdentifier(identifier);
348
        	}
349
        	identifier.setIdentifiedObj(this);
350
        	//deduplication
351
        	int oldIndex = getIdentifiers().indexOf(identifier);
352
        	if(oldIndex > -1){
353
        		getIdentifiers().remove(identifier);
354
        		if (oldIndex < index){
355
        			index--;
356
        		}
357
        	}
358
        	getIdentifiers().add(index, identifier);
359
        }
360
    }
361

    
362
    @Override
363
    public void addIdentifier(Identifier identifier){
364
        addIdentifier(getIdentifiers().size(), identifier);
365
    }
366

    
367
    @Override
368
    public void removeIdentifier(Identifier identifier){
369
        if (identifier != null){
370
        	identifier.setIdentifiedObj(null);
371
            getIdentifiers().remove(identifier);
372
        }
373
    }
374
    @Override
375
    public void removeIdentifier(int index){
376
    	getIdentifiers().remove(index);
377
    }
378

    
379
    @Override
380
    public Set<Extension> getExtensions(){
381
        if(extensions == null) {
382
            this.extensions = new HashSet<Extension>();
383
        }
384
        return this.extensions;
385
    }
386
    /**
387
     * @param type
388
     * @return a Set of extension value strings
389
     */
390
    public Set<String> getExtensions(ExtensionType type){
391
       return getExtensions(type.getUuid());
392
    }
393
    /**
394
     * @param extensionTypeUuid
395
     * @return a Set of extension value strings
396
     */
397
    public Set<String> getExtensions(UUID extensionTypeUuid){
398
        Set<String> result = new HashSet<String>();
399
        for (Extension extension : getExtensions()){
400
            if (extension.getType().getUuid().equals(extensionTypeUuid)){
401
                result.add(extension.getValue());
402
            }
403
        }
404
        return result;
405
    }
406

    
407
    public void addExtension(String value, ExtensionType extensionType){
408
        Extension.NewInstance(this, value, extensionType);
409
    }
410

    
411
    @Override
412
    public void addExtension(Extension extension){
413
        if (extension != null){
414
            extension.setExtendedObj(this);
415
            getExtensions().add(extension);
416
        }
417
    }
418
    @Override
419
    public void removeExtension(Extension extension){
420
        if (extension != null){
421
            extension.setExtendedObj(null);
422
            getExtensions().remove(extension);
423
        }
424
    }
425

    
426
    @Override
427
    public boolean isProtectedTitleCache() {
428
        return protectedTitleCache;
429
    }
430

    
431
    @Override
432
    public void setProtectedTitleCache(boolean protectedTitleCache) {
433
        this.protectedTitleCache = protectedTitleCache;
434
    }
435

    
436
    @Override
437
    public Set<IdentifiableSource> getSources() {
438
        if(sources == null) {
439
            this.sources = new HashSet<IdentifiableSource>();
440
        }
441
        return this.sources;
442
    }
443

    
444
    @Override
445
    public void addSource(IdentifiableSource source) {
446
        if (source != null){
447
            IdentifiableEntity<?> oldSourcedObj = source.getSourcedObj();
448
            if (oldSourcedObj != null && oldSourcedObj != this){
449
                oldSourcedObj.getSources().remove(source);
450
            }
451
            getSources().add(source);
452
            source.setSourcedObj(this);
453
        }
454
    }
455

    
456
    @Override
457
    public void addSources(Set<IdentifiableSource> sources) {
458
        if (sources != null){
459
        	for (IdentifiableSource source: sources){
460
	            IdentifiableEntity<?> oldSourcedObj = source.getSourcedObj();
461
	            if (oldSourcedObj != null && oldSourcedObj != this){
462
	                oldSourcedObj.getSources().remove(source);
463
	            }
464
	            getSources().add(source);
465
	            source.setSourcedObj(this);
466
        	}
467
        }
468
    }
469

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

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

    
485

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

    
496

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

    
502
//******************************** TO STRING *****************************************************/
503

    
504
    /* (non-Javadoc)
505
     * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#toString()
506
     */
507
     @Override
508
    public String toString() {
509
        String result;
510
        if (titleCache == null){
511
            result = super.toString();
512
        }else{
513
            result = this.titleCache;
514
        }
515
        return result;
516
    }
517

    
518

    
519
    public int compareTo(IdentifiableEntity identifiableEntity) {
520

    
521
         int result = 0;
522

    
523
         if (identifiableEntity == null) {
524
             throw new NullPointerException("Cannot compare to null.");
525
         }
526

    
527
         // First, compare the name cache.
528
         // TODO: Avoid using instanceof operator
529
         // Use Class.getDeclaredMethod() instead to find out whether class has getNameCache() method?
530

    
531
         String specifiedNameCache = "";
532
         String thisNameCache = "";
533
         String specifiedTitleCache = "";
534
         String thisTitleCache = "";
535
         String specifiedReferenceTitleCache = "";
536
         String thisReferenceTitleCache = "";
537
         String thisGenusString = "";
538
         String specifiedGenusString = "";
539
         int thisrank_order = 0;
540

    
541
         //TODO we can remove all the deproxies here except for the first one
542
         identifiableEntity = HibernateProxyHelper.deproxy(identifiableEntity, IdentifiableEntity.class);
543
         if(identifiableEntity instanceof NonViralName) {
544
             specifiedNameCache = HibernateProxyHelper.deproxy(identifiableEntity, NonViralName.class).getNameCache();
545
             specifiedTitleCache = identifiableEntity.getTitleCache();
546
            if (identifiableEntity instanceof BotanicalName){
547
            	 if (((BotanicalName)identifiableEntity).isAutonym()){
548
            		 boolean isProtected = false;
549
            		 String oldNameCache = ((BotanicalName) identifiableEntity).getNameCache();
550
            		 if ( ((BotanicalName)identifiableEntity).isProtectedNameCache()){
551
            			 isProtected = true;
552
            		 }
553
            		 ((BotanicalName)identifiableEntity).setProtectedNameCache(false);
554
            		 ((BotanicalName)identifiableEntity).setNameCache(null, false);
555
            		 specifiedNameCache = ((BotanicalName) identifiableEntity).getNameCache();
556
            		 ((BotanicalName)identifiableEntity).setNameCache(oldNameCache, isProtected);
557

    
558
            	 }
559
             }
560

    
561
         } else if(identifiableEntity instanceof TaxonBase) {
562
             TaxonBase taxonBase = HibernateProxyHelper.deproxy(identifiableEntity, TaxonBase.class);
563

    
564
             TaxonNameBase<?,?> taxonNameBase = taxonBase.getName();
565

    
566

    
567
             NonViralName nonViralName = HibernateProxyHelper.deproxy(taxonNameBase, NonViralName.class);
568
             specifiedNameCache = nonViralName.getNameCache();
569
             specifiedTitleCache = taxonNameBase.getTitleCache();
570

    
571
             specifiedReferenceTitleCache = ((TaxonBase)identifiableEntity).getSec().getTitleCache();
572
             Reference reference = taxonBase.getSec();
573
             if (reference != null) {
574
                 reference = HibernateProxyHelper.deproxy(reference, Reference.class);
575
                 specifiedReferenceTitleCache = reference.getTitleCache();
576
             }
577
         }
578

    
579
         if(this.isInstanceOf(NonViralName.class)) {
580
             thisNameCache = HibernateProxyHelper.deproxy(this, NonViralName.class).getNameCache();
581
             thisTitleCache = getTitleCache();
582

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

    
605
         // Compare name cache of taxon names
606

    
607

    
608

    
609
         if (!specifiedNameCache.equals("") && !thisNameCache.equals("")) {
610
             result = thisNameCache.compareTo(specifiedNameCache);
611
         }
612

    
613
         // Compare title cache of taxon names
614

    
615
         if ((result == 0) && (!specifiedTitleCache.equals("") || !thisTitleCache.equals(""))) {
616
             result = thisTitleCache.compareTo(specifiedTitleCache);
617
         }
618

    
619
         // Compare title cache of taxon references
620

    
621
         if ((result == 0) && (!specifiedReferenceTitleCache.equals("") || !thisReferenceTitleCache.equals(""))) {
622
             result = thisReferenceTitleCache.compareTo(specifiedReferenceTitleCache);
623
         }
624

    
625
         return result;
626
     }
627

    
628
        /**
629
         * Returns the {@link eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy cache strategy} used to generate
630
         * several strings corresponding to <i>this</i> identifiable entity
631
         * (in particular taxon name caches and author strings).
632
         *
633
         * @return  the cache strategy used for <i>this</i> identifiable entity
634
         * @see     eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy
635
         */
636
        public S getCacheStrategy() {
637
            return this.cacheStrategy;
638
        }
639
        /**
640
         * @see 	#getCacheStrategy()
641
         */
642

    
643
        public void setCacheStrategy(S cacheStrategy) {
644
            this.cacheStrategy = cacheStrategy;
645
        }
646

    
647
        @Override
648
        public String generateTitle() {
649
            if (getCacheStrategy() == null){
650
                //logger.warn("No CacheStrategy defined for "+ this.getClass() + ": " + this.getUuid());
651
                return this.getClass() + ": " + this.getUuid();
652
            }else{
653
                return getCacheStrategy().getTitleCache(this);
654
            }
655
        }
656

    
657
//****************** CLONE ************************************************/
658

    
659
    /* (non-Javadoc)
660
     * @see eu.etaxonomy.cdm.model.common.AnnotatableEntity#clone()
661
     */
662
    @Override
663
    public Object clone() throws CloneNotSupportedException{
664
        IdentifiableEntity<?> result = (IdentifiableEntity<?>)super.clone();
665

    
666
        //Extensions
667
        result.extensions = new HashSet<Extension>();
668
        for (Extension extension : getExtensions() ){
669
            Extension newExtension = (Extension)extension.clone();
670
            result.addExtension(newExtension);
671
        }
672

    
673
        //Identifier
674
        result.identifiers = new ArrayList<Identifier>();
675
        for (Identifier<?> identifier : getIdentifiers() ){
676
        	Identifier<?> newIdentifier = (Identifier<?>)identifier.clone();
677
            result.addIdentifier(newIdentifier);
678
        }
679

    
680
        //OriginalSources
681
        result.sources = new HashSet<IdentifiableSource>();
682
        for (IdentifiableSource source : getSources()){
683
            IdentifiableSource newSource = (IdentifiableSource)source.clone();
684
            result.addSource(newSource);
685
        }
686

    
687
        //Rights
688
        result.rights = new HashSet<Rights>();
689
        for(Rights rights : getRights()) {
690
            result.addRights(rights);
691
        }
692

    
693

    
694
        //Credits
695
        result.credits = new ArrayList<Credit>();
696
        for(Credit credit : getCredits()) {
697
            result.addCredit(credit);
698
        }
699

    
700
        //no changes to: lsid, titleCache, protectedTitleCache
701

    
702
        //empty titleCache
703
        if (! protectedTitleCache){
704
            result.titleCache = null;
705
        }
706

    
707
        result.initListener();
708
        return result;
709
    }
710

    
711

    
712
}
(36-36/72)