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
|
|
20
|
import javax.persistence.Column;
|
21
|
import javax.persistence.Embedded;
|
22
|
import javax.persistence.FetchType;
|
23
|
import javax.persistence.MappedSuperclass;
|
24
|
import javax.persistence.OneToMany;
|
25
|
import javax.persistence.Transient;
|
26
|
import javax.validation.constraints.NotNull;
|
27
|
import javax.validation.constraints.Size;
|
28
|
import javax.xml.bind.annotation.XmlAccessType;
|
29
|
import javax.xml.bind.annotation.XmlAccessorType;
|
30
|
import javax.xml.bind.annotation.XmlElement;
|
31
|
import javax.xml.bind.annotation.XmlElementWrapper;
|
32
|
import javax.xml.bind.annotation.XmlTransient;
|
33
|
import javax.xml.bind.annotation.XmlType;
|
34
|
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
35
|
|
36
|
import org.apache.log4j.Logger;
|
37
|
import org.hibernate.annotations.Cascade;
|
38
|
import org.hibernate.annotations.CascadeType;
|
39
|
import org.hibernate.annotations.IndexColumn;
|
40
|
import org.hibernate.search.annotations.Field;
|
41
|
import org.hibernate.search.annotations.FieldBridge;
|
42
|
import org.hibernate.search.annotations.Fields;
|
43
|
import org.hibernate.validator.constraints.NotEmpty;
|
44
|
|
45
|
import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
|
46
|
import eu.etaxonomy.cdm.hibernate.StripHtmlBridge;
|
47
|
import eu.etaxonomy.cdm.jaxb.FormattedTextAdapter;
|
48
|
import eu.etaxonomy.cdm.jaxb.LSIDAdapter;
|
49
|
import eu.etaxonomy.cdm.model.media.Rights;
|
50
|
import eu.etaxonomy.cdm.model.name.NonViralName;
|
51
|
import eu.etaxonomy.cdm.model.name.TaxonNameBase;
|
52
|
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
|
53
|
import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
|
54
|
import eu.etaxonomy.cdm.strategy.match.Match;
|
55
|
import eu.etaxonomy.cdm.strategy.match.MatchMode;
|
56
|
import eu.etaxonomy.cdm.strategy.match.Match.ReplaceMode;
|
57
|
import eu.etaxonomy.cdm.strategy.merge.Merge;
|
58
|
import eu.etaxonomy.cdm.strategy.merge.MergeMode;
|
59
|
import eu.etaxonomy.cdm.validation.Level2;
|
60
|
|
61
|
/**
|
62
|
* 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.
|
63
|
* All subclasses inherit the ability to store additional properties that are stored as {@link Extension Extensions}, basically a string value with a type term.
|
64
|
* Any number of right statements can be attached as well as multiple {@link OriginalSourceBase} objects.
|
65
|
* 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).
|
66
|
* A Taxon for example that was taken from 2 sources like FaunaEuropaea and IPNI would have two originalSource objects.
|
67
|
* 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.
|
68
|
*
|
69
|
* @author m.doering
|
70
|
* @version 1.0
|
71
|
* @created 08-Nov-2007 13:06:27
|
72
|
*/
|
73
|
@XmlAccessorType(XmlAccessType.FIELD)
|
74
|
@XmlType(name = "IdentifiableEntity", propOrder = {
|
75
|
"lsid",
|
76
|
"titleCache",
|
77
|
"protectedTitleCache",
|
78
|
"rights",
|
79
|
"extensions",
|
80
|
"credits",
|
81
|
"sources"
|
82
|
})
|
83
|
@MappedSuperclass
|
84
|
public abstract class IdentifiableEntity<S extends IIdentifiableEntityCacheStrategy> extends AnnotatableEntity
|
85
|
implements IIdentifiableEntity /*, ISourceable<IdentifiableSource> */ {
|
86
|
private static final long serialVersionUID = -5610995424730659058L;
|
87
|
private static final Logger logger = Logger.getLogger(IdentifiableEntity.class);
|
88
|
|
89
|
@XmlTransient
|
90
|
public static final boolean PROTECTED = true;
|
91
|
@XmlTransient
|
92
|
public static final boolean NOT_PROTECTED = false;
|
93
|
|
94
|
@XmlElement(name = "LSID", type = String.class)
|
95
|
@XmlJavaTypeAdapter(LSIDAdapter.class)
|
96
|
@Embedded
|
97
|
private LSID lsid;
|
98
|
|
99
|
@XmlElement(name = "TitleCache", required = true)
|
100
|
@XmlJavaTypeAdapter(FormattedTextAdapter.class)
|
101
|
@Column(length=255, name="titleCache")
|
102
|
@Fields({@Field(name = "titleCache_tokenized",index = org.hibernate.search.annotations.Index.TOKENIZED),
|
103
|
@Field(index = org.hibernate.search.annotations.Index.UN_TOKENIZED)
|
104
|
})
|
105
|
@FieldBridge(impl=StripHtmlBridge.class)
|
106
|
@Match(value=MatchMode.CACHE, cacheReplaceMode=ReplaceMode.ALL)
|
107
|
@NotEmpty(groups = Level2.class) // implictly NotNull
|
108
|
@Size(max = 255)
|
109
|
protected String titleCache;
|
110
|
|
111
|
//if true titleCache will not be automatically generated/updated
|
112
|
@XmlElement(name = "ProtectedTitleCache")
|
113
|
protected boolean protectedTitleCache;
|
114
|
|
115
|
@XmlElementWrapper(name = "Rights", nillable = true)
|
116
|
@XmlElement(name = "Rights")
|
117
|
@OneToMany(fetch = FetchType.LAZY)
|
118
|
@Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE, CascadeType.DELETE_ORPHAN})
|
119
|
//TODO
|
120
|
@Merge(MergeMode.ADD_CLONE)
|
121
|
private Set<Rights> rights;
|
122
|
|
123
|
@XmlElementWrapper(name = "Credits", nillable = true)
|
124
|
@XmlElement(name = "Credit")
|
125
|
@IndexColumn(name="sortIndex", base = 0)
|
126
|
@OneToMany(fetch = FetchType.LAZY)
|
127
|
@Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE, CascadeType.DELETE_ORPHAN})
|
128
|
//TODO
|
129
|
@Merge(MergeMode.ADD_CLONE)
|
130
|
private List<Credit> credits;
|
131
|
|
132
|
@XmlElementWrapper(name = "Extensions", nillable = true)
|
133
|
@XmlElement(name = "Extension")
|
134
|
@OneToMany(fetch = FetchType.LAZY)
|
135
|
@Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE, CascadeType.DELETE_ORPHAN})
|
136
|
@Merge(MergeMode.ADD_CLONE)
|
137
|
private Set<Extension> extensions;
|
138
|
|
139
|
@XmlElementWrapper(name = "Sources", nillable = true)
|
140
|
@XmlElement(name = "IdentifiableSource")
|
141
|
@OneToMany(fetch = FetchType.LAZY)
|
142
|
@Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE, CascadeType.DELETE_ORPHAN})
|
143
|
@Merge(MergeMode.ADD_CLONE)
|
144
|
private Set<IdentifiableSource> sources;
|
145
|
|
146
|
@XmlTransient
|
147
|
@Transient
|
148
|
protected S cacheStrategy;
|
149
|
|
150
|
protected IdentifiableEntity(){
|
151
|
initListener();
|
152
|
}
|
153
|
|
154
|
protected void initListener(){
|
155
|
PropertyChangeListener listener = new PropertyChangeListener() {
|
156
|
public void propertyChange(PropertyChangeEvent e) {
|
157
|
if (!e.getPropertyName().equals("titleCache") && ! isProtectedTitleCache()){
|
158
|
titleCache = null;
|
159
|
}
|
160
|
}
|
161
|
};
|
162
|
addPropertyChangeListener(listener);
|
163
|
}
|
164
|
|
165
|
/**
|
166
|
* By default, we expect most cdm objects to be abstract things
|
167
|
* i.e. unable to return a data representation.
|
168
|
*
|
169
|
* Specific subclasses (e.g. Sequence) can override if necessary.
|
170
|
*/
|
171
|
public byte[] getData() {
|
172
|
return null;
|
173
|
}
|
174
|
|
175
|
//******************************** CACHE *****************************************************/
|
176
|
|
177
|
|
178
|
/* (non-Javadoc)
|
179
|
* @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#getTitleCache()
|
180
|
*/
|
181
|
// @Transient - must not be transient, since this property needs to to be included in all serializations produced by the remote layer
|
182
|
public String getTitleCache(){
|
183
|
if (protectedTitleCache){
|
184
|
return this.titleCache;
|
185
|
}
|
186
|
// is title dirty, i.e. equal NULL?
|
187
|
if (titleCache == null){
|
188
|
this.titleCache = generateTitle();
|
189
|
this.titleCache = getTruncatedCache(this.titleCache) ;
|
190
|
}
|
191
|
return titleCache;
|
192
|
}
|
193
|
/* (non-Javadoc)
|
194
|
* @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#setTitleCache(java.lang.String)
|
195
|
*/
|
196
|
public void setTitleCache(String titleCache){
|
197
|
setTitleCache(titleCache, PROTECTED);
|
198
|
}
|
199
|
|
200
|
/* (non-Javadoc)
|
201
|
* @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#setTitleCache(java.lang.String, boolean)
|
202
|
*/
|
203
|
public void setTitleCache(String titleCache, boolean protectCache){
|
204
|
titleCache = getTruncatedCache(titleCache);
|
205
|
this.titleCache = titleCache;
|
206
|
this.protectedTitleCache = protectCache;
|
207
|
}
|
208
|
|
209
|
|
210
|
/**
|
211
|
* @param cache
|
212
|
* @return
|
213
|
*/
|
214
|
@Transient
|
215
|
protected String getTruncatedCache(String cache) {
|
216
|
if (cache != null && cache.length() > 252){
|
217
|
logger.warn("Truncation of cache: " + this.toString() + "/" + cache);
|
218
|
cache = cache.substring(0, 252) + "...";
|
219
|
}
|
220
|
return cache;
|
221
|
}
|
222
|
|
223
|
//**************************************************************************************
|
224
|
|
225
|
/* (non-Javadoc)
|
226
|
* @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#getLsid()
|
227
|
*/
|
228
|
public LSID getLsid(){
|
229
|
return this.lsid;
|
230
|
}
|
231
|
/* (non-Javadoc)
|
232
|
* @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#setLsid(java.lang.String)
|
233
|
*/
|
234
|
public void setLsid(LSID lsid){
|
235
|
this.lsid = lsid;
|
236
|
}
|
237
|
/* (non-Javadoc)
|
238
|
* @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#getRights()
|
239
|
*/
|
240
|
public Set<Rights> getRights() {
|
241
|
if(rights == null) {
|
242
|
this.rights = new HashSet<Rights>();
|
243
|
}
|
244
|
return this.rights;
|
245
|
}
|
246
|
|
247
|
/* (non-Javadoc)
|
248
|
* @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#addRights(eu.etaxonomy.cdm.model.media.Rights)
|
249
|
*/
|
250
|
public void addRights(Rights right){
|
251
|
getRights().add(right);
|
252
|
}
|
253
|
/* (non-Javadoc)
|
254
|
* @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#removeRights(eu.etaxonomy.cdm.model.media.Rights)
|
255
|
*/
|
256
|
public void removeRights(Rights right){
|
257
|
getRights().remove(right);
|
258
|
}
|
259
|
|
260
|
|
261
|
public List<Credit> getCredits() {
|
262
|
if(credits == null) {
|
263
|
this.credits = new ArrayList<Credit>();
|
264
|
}
|
265
|
return this.credits;
|
266
|
}
|
267
|
|
268
|
/* (non-Javadoc)
|
269
|
* @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#getCredits(int)
|
270
|
*/
|
271
|
public Credit getCredits(int index){
|
272
|
return getCredits().get(index);
|
273
|
}
|
274
|
|
275
|
/* (non-Javadoc)
|
276
|
* @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#addCredit(eu.etaxonomy.cdm.model.common.Credit)
|
277
|
*/
|
278
|
public void addCredit(Credit credit){
|
279
|
getCredits().add(credit);
|
280
|
}
|
281
|
|
282
|
|
283
|
/* (non-Javadoc)
|
284
|
* @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#addCredit(eu.etaxonomy.cdm.model.common.Credit, int)
|
285
|
*/
|
286
|
public void addCredit(Credit credit, int index){
|
287
|
getCredits().add(index, credit);
|
288
|
}
|
289
|
|
290
|
/* (non-Javadoc)
|
291
|
* @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#removeCredit(eu.etaxonomy.cdm.model.common.Credit)
|
292
|
*/
|
293
|
public void removeCredit(Credit credit){
|
294
|
getCredits().remove(credit);
|
295
|
}
|
296
|
|
297
|
/* (non-Javadoc)
|
298
|
* @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#removeCredit(int)
|
299
|
*/
|
300
|
public void removeCredit(int index){
|
301
|
getCredits().remove(index);
|
302
|
}
|
303
|
|
304
|
|
305
|
/* (non-Javadoc)
|
306
|
* @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#getExtensions()
|
307
|
*/
|
308
|
public Set<Extension> getExtensions(){
|
309
|
if(extensions == null) {
|
310
|
this.extensions = new HashSet<Extension>();
|
311
|
}
|
312
|
return this.extensions;
|
313
|
}
|
314
|
|
315
|
public void addExtension(String value, ExtensionType extensionType){
|
316
|
Extension.NewInstance(this, value, extensionType);
|
317
|
}
|
318
|
|
319
|
/* (non-Javadoc)
|
320
|
* @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#addExtension(eu.etaxonomy.cdm.model.common.Extension)
|
321
|
*/
|
322
|
public void addExtension(Extension extension){
|
323
|
if (extension != null){
|
324
|
extension.setExtendedObj(this);
|
325
|
getExtensions().add(extension);
|
326
|
}
|
327
|
}
|
328
|
/* (non-Javadoc)
|
329
|
* @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#removeExtension(eu.etaxonomy.cdm.model.common.Extension)
|
330
|
*/
|
331
|
public void removeExtension(Extension extension){
|
332
|
if (extension != null){
|
333
|
extension.setExtendedObj(null);
|
334
|
getExtensions().remove(extension);
|
335
|
}
|
336
|
}
|
337
|
|
338
|
|
339
|
/* (non-Javadoc)
|
340
|
* @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#isProtectedTitleCache()
|
341
|
*/
|
342
|
public boolean isProtectedTitleCache() {
|
343
|
return protectedTitleCache;
|
344
|
}
|
345
|
|
346
|
/* (non-Javadoc)
|
347
|
* @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#setProtectedTitleCache(boolean)
|
348
|
*/
|
349
|
public void setProtectedTitleCache(boolean protectedTitleCache) {
|
350
|
this.protectedTitleCache = protectedTitleCache;
|
351
|
}
|
352
|
|
353
|
/* (non-Javadoc)
|
354
|
* @see eu.etaxonomy.cdm.model.common.ISourceable#getSources()
|
355
|
*/
|
356
|
public Set<IdentifiableSource> getSources() {
|
357
|
if(sources == null) {
|
358
|
this.sources = new HashSet<IdentifiableSource>();
|
359
|
}
|
360
|
return this.sources;
|
361
|
}
|
362
|
|
363
|
/* (non-Javadoc)
|
364
|
* @see eu.etaxonomy.cdm.model.common.ISourceable#addSource(eu.etaxonomy.cdm.model.common.OriginalSourceBase)
|
365
|
*/
|
366
|
public void addSource(IdentifiableSource source) {
|
367
|
if (source != null){
|
368
|
IdentifiableEntity oldSourcedObj = source.getSourcedObj();
|
369
|
if (oldSourcedObj != null && oldSourcedObj != this){
|
370
|
oldSourcedObj.getSources().remove(source);
|
371
|
}
|
372
|
getSources().add(source);
|
373
|
source.setSourcedObj(this);
|
374
|
}
|
375
|
}
|
376
|
|
377
|
/* (non-Javadoc)
|
378
|
* @see eu.etaxonomy.cdm.model.common.ISourceable#removeSource(eu.etaxonomy.cdm.model.common.IOriginalSource)
|
379
|
*/
|
380
|
public void removeSource(IdentifiableSource source) {
|
381
|
getSources().remove(source);
|
382
|
}
|
383
|
|
384
|
//******************************** TO STRING *****************************************************/
|
385
|
|
386
|
/* (non-Javadoc)
|
387
|
* @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#toString()
|
388
|
*/
|
389
|
@Override
|
390
|
public String toString() {
|
391
|
String result;
|
392
|
if (titleCache == null){
|
393
|
result = super.toString();
|
394
|
}else{
|
395
|
result = this.titleCache;
|
396
|
}
|
397
|
return result;
|
398
|
}
|
399
|
|
400
|
|
401
|
public int compareTo(IdentifiableEntity identifiableEntity) {
|
402
|
|
403
|
int result = 0;
|
404
|
|
405
|
if (identifiableEntity == null) {
|
406
|
throw new NullPointerException("Cannot compare to null.");
|
407
|
}
|
408
|
|
409
|
// First, compare the name cache.
|
410
|
// TODO: Avoid using instanceof operator
|
411
|
// Use Class.getDeclaredMethod() instead to find out whether class has getNameCache() method?
|
412
|
|
413
|
String specifiedNameCache = "";
|
414
|
String thisNameCache = "";
|
415
|
String specifiedTitleCache = "";
|
416
|
String thisTitleCache = "";
|
417
|
String specifiedReferenceTitleCache = "";
|
418
|
String thisReferenceTitleCache = "";
|
419
|
|
420
|
if(identifiableEntity instanceof NonViralName) {
|
421
|
specifiedNameCache = HibernateProxyHelper.deproxy(identifiableEntity, NonViralName.class).getNameCache();
|
422
|
specifiedTitleCache = identifiableEntity.getTitleCache();
|
423
|
|
424
|
} else if(identifiableEntity instanceof TaxonBase) {
|
425
|
TaxonBase taxonBase = HibernateProxyHelper.deproxy(identifiableEntity, TaxonBase.class);
|
426
|
|
427
|
TaxonNameBase<?,?> taxonNameBase = taxonBase.getName();
|
428
|
specifiedNameCache = HibernateProxyHelper.deproxy(taxonNameBase, NonViralName.class).getNameCache();
|
429
|
specifiedTitleCache = taxonNameBase.getTitleCache();
|
430
|
|
431
|
//specifiedReferenceTitleCache = ((TaxonBase)identifiableEntity).getSec().getTitleCache();
|
432
|
// ReferenceBase referenceBase = taxonBase.getSec();
|
433
|
// if (referenceBase != null) {
|
434
|
// FIXME: HibernateProxyHelper.deproxy(referenceBase, ReferenceBase.class) throws exception
|
435
|
// referenceBase = HibernateProxyHelper.deproxy(referenceBase, ReferenceBase.class);
|
436
|
// specifiedReferenceTitleCache = referenceBase.getTitleCache();
|
437
|
// }
|
438
|
}
|
439
|
|
440
|
if(this instanceof NonViralName) {
|
441
|
thisNameCache = HibernateProxyHelper.deproxy(this, NonViralName.class).getNameCache();
|
442
|
thisTitleCache = getTitleCache();
|
443
|
} else if(this instanceof TaxonBase) {
|
444
|
TaxonNameBase<?,?> taxonNameBase= HibernateProxyHelper.deproxy(this, TaxonBase.class).getName();
|
445
|
thisNameCache = HibernateProxyHelper.deproxy(taxonNameBase, NonViralName.class).getNameCache();
|
446
|
thisTitleCache = taxonNameBase.getTitleCache();
|
447
|
thisReferenceTitleCache = getTitleCache();
|
448
|
}
|
449
|
|
450
|
// Compare name cache of taxon names
|
451
|
|
452
|
if (!specifiedNameCache.equals("") && !thisNameCache.equals("")) {
|
453
|
result = thisNameCache.compareTo(specifiedNameCache);
|
454
|
}
|
455
|
|
456
|
// Compare title cache of taxon names
|
457
|
|
458
|
if ((result == 0) && (!specifiedTitleCache.equals("") || !thisTitleCache.equals(""))) {
|
459
|
result = thisTitleCache.compareTo(specifiedTitleCache);
|
460
|
}
|
461
|
|
462
|
// Compare title cache of taxon references
|
463
|
|
464
|
if ((result == 0) && (!specifiedReferenceTitleCache.equals("") || !thisReferenceTitleCache.equals(""))) {
|
465
|
result = thisReferenceTitleCache.compareTo(specifiedReferenceTitleCache);
|
466
|
}
|
467
|
|
468
|
return result;
|
469
|
}
|
470
|
|
471
|
/**
|
472
|
* Returns the {@link eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy cache strategy} used to generate
|
473
|
* several strings corresponding to <i>this</i> identifiable entity
|
474
|
* (in particular taxon name caches and author strings).
|
475
|
*
|
476
|
* @return the cache strategy used for <i>this</i> identifiable entity
|
477
|
* @see eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy
|
478
|
*/
|
479
|
public S getCacheStrategy() {
|
480
|
return this.cacheStrategy;
|
481
|
}
|
482
|
/**
|
483
|
* @see #getCacheStrategy()
|
484
|
*/
|
485
|
|
486
|
public void setCacheStrategy(S cacheStrategy) {
|
487
|
this.cacheStrategy = cacheStrategy;
|
488
|
}
|
489
|
|
490
|
public String generateTitle() {
|
491
|
if (cacheStrategy == null){
|
492
|
//logger.warn("No CacheStrategy defined for "+ this.getClass() + ": " + this.getUuid());
|
493
|
return this.getClass() + ": " + this.getUuid();
|
494
|
}else{
|
495
|
return cacheStrategy.getTitleCache(this);
|
496
|
}
|
497
|
}
|
498
|
|
499
|
//****************** CLONE ************************************************/
|
500
|
|
501
|
/* (non-Javadoc)
|
502
|
* @see eu.etaxonomy.cdm.model.common.AnnotatableEntity#clone()
|
503
|
*/
|
504
|
@Override
|
505
|
public Object clone() throws CloneNotSupportedException{
|
506
|
IdentifiableEntity result = (IdentifiableEntity)super.clone();
|
507
|
|
508
|
//Extensions
|
509
|
result.extensions = new HashSet<Extension>();
|
510
|
for (Extension extension : getExtensions() ){
|
511
|
Extension newExtension = (Extension)extension.clone();
|
512
|
result.addExtension(newExtension);
|
513
|
}
|
514
|
|
515
|
//OriginalSources
|
516
|
result.sources = new HashSet<IdentifiableSource>();
|
517
|
for (IdentifiableSource source : getSources()){
|
518
|
IdentifiableSource newSource = (IdentifiableSource)source.clone();
|
519
|
result.addSource(newSource);
|
520
|
}
|
521
|
|
522
|
//Rights
|
523
|
result.rights = new HashSet<Rights>();
|
524
|
for(Rights rights : getRights()) {
|
525
|
result.addRights(rights);
|
526
|
}
|
527
|
|
528
|
|
529
|
//Rights
|
530
|
result.credits = new ArrayList<Credit>();
|
531
|
for(Credit credit : getCredits()) {
|
532
|
result.addCredit(credit);
|
533
|
}
|
534
|
|
535
|
|
536
|
//result.setLsid(lsid);
|
537
|
//result.setTitleCache(titleCache);
|
538
|
//result.setProtectedTitleCache(protectedTitleCache); //must be after setTitleCache
|
539
|
|
540
|
//no changes to: lsid, titleCache, protectedTitleCache
|
541
|
|
542
|
//empty titleCache
|
543
|
if (! protectedTitleCache){
|
544
|
result.titleCache = null;
|
545
|
}
|
546
|
return result;
|
547
|
}
|
548
|
|
549
|
|
550
|
}
|