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.commons.lang.StringUtils;
|
38
|
import org.apache.log4j.Logger;
|
39
|
import org.hibernate.annotations.Cascade;
|
40
|
import org.hibernate.annotations.CascadeType;
|
41
|
import org.hibernate.envers.Audited;
|
42
|
import org.hibernate.search.annotations.Analyze;
|
43
|
import org.hibernate.search.annotations.Field;
|
44
|
import org.hibernate.search.annotations.FieldBridge;
|
45
|
import org.hibernate.search.annotations.Fields;
|
46
|
import org.hibernate.search.annotations.Index;
|
47
|
import org.hibernate.search.annotations.SortableField;
|
48
|
import org.hibernate.search.annotations.Store;
|
49
|
import org.hibernate.validator.constraints.NotEmpty;
|
50
|
|
51
|
import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
|
52
|
import eu.etaxonomy.cdm.hibernate.search.StripHtmlBridge;
|
53
|
import eu.etaxonomy.cdm.jaxb.FormattedTextAdapter;
|
54
|
import eu.etaxonomy.cdm.jaxb.LSIDAdapter;
|
55
|
import eu.etaxonomy.cdm.model.media.Rights;
|
56
|
import eu.etaxonomy.cdm.model.name.BotanicalName;
|
57
|
import eu.etaxonomy.cdm.model.name.NonViralName;
|
58
|
import eu.etaxonomy.cdm.model.name.TaxonNameBase;
|
59
|
import eu.etaxonomy.cdm.model.reference.Reference;
|
60
|
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
|
61
|
import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
|
62
|
import eu.etaxonomy.cdm.strategy.match.Match;
|
63
|
import eu.etaxonomy.cdm.strategy.match.Match.ReplaceMode;
|
64
|
import eu.etaxonomy.cdm.strategy.match.MatchMode;
|
65
|
import eu.etaxonomy.cdm.strategy.merge.Merge;
|
66
|
import eu.etaxonomy.cdm.strategy.merge.MergeMode;
|
67
|
import eu.etaxonomy.cdm.validation.Level2;
|
68
|
|
69
|
/**
|
70
|
* 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.
|
71
|
* All subclasses inherit the ability to store additional properties that are stored as {@link Extension Extensions}, basically a string value with a type term.
|
72
|
* Any number of right statements can be attached as well as multiple {@link OriginalSourceBase} objects.
|
73
|
* 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).
|
74
|
* A Taxon for example that was taken from 2 sources like FaunaEuropaea and IPNI would have two originalSource objects.
|
75
|
* 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.
|
76
|
*
|
77
|
* @author m.doering
|
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 = 7912083412108359559L;
|
96
|
|
97
|
private static final Logger logger = Logger.getLogger(IdentifiableEntity.class);
|
98
|
|
99
|
@XmlTransient
|
100
|
public static final boolean PROTECTED = true;
|
101
|
@XmlTransient
|
102
|
public static final boolean NOT_PROTECTED = false;
|
103
|
|
104
|
@XmlElement(name = "LSID", type = String.class)
|
105
|
@XmlJavaTypeAdapter(LSIDAdapter.class)
|
106
|
@Embedded
|
107
|
private LSID lsid;
|
108
|
|
109
|
@XmlElement(name = "TitleCache", required = true)
|
110
|
@XmlJavaTypeAdapter(FormattedTextAdapter.class)
|
111
|
@Column(name="titleCache", length=800) //see #1592
|
112
|
@Match(value=MatchMode.CACHE, cacheReplaceMode=ReplaceMode.ALL)
|
113
|
@NotEmpty(groups = Level2.class) // implictly NotNull
|
114
|
@Fields({
|
115
|
@Field(store=Store.YES),
|
116
|
// If the field is only needed for sorting and nothing else, you may configure it as
|
117
|
// un-indexed and un-stored, thus avoid unnecessary index growth.
|
118
|
@Field(name = "titleCache__sort", analyze = Analyze.NO, store=Store.NO, index = Index.NO)
|
119
|
})
|
120
|
@SortableField(forField = "titleCache__sort")
|
121
|
@FieldBridge(impl=StripHtmlBridge.class)
|
122
|
protected String titleCache;
|
123
|
|
124
|
//if true titleCache will not be automatically generated/updated
|
125
|
@XmlElement(name = "ProtectedTitleCache")
|
126
|
protected boolean protectedTitleCache;
|
127
|
|
128
|
@XmlElementWrapper(name = "Rights", nillable = true)
|
129
|
@XmlElement(name = "Rights")
|
130
|
@OneToMany(fetch = FetchType.LAZY, orphanRemoval=true)
|
131
|
@Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE})
|
132
|
//TODO
|
133
|
@Merge(MergeMode.ADD_CLONE)
|
134
|
@NotNull
|
135
|
private Set<Rights> rights = new HashSet<Rights>();
|
136
|
|
137
|
@XmlElementWrapper(name = "Credits", nillable = true)
|
138
|
@XmlElement(name = "Credit")
|
139
|
@OrderColumn(name="sortIndex")
|
140
|
@OneToMany(fetch = FetchType.LAZY, orphanRemoval=true)
|
141
|
@Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE})
|
142
|
//TODO
|
143
|
@Merge(MergeMode.ADD_CLONE)
|
144
|
@NotNull
|
145
|
private List<Credit> credits = new ArrayList<Credit>();
|
146
|
|
147
|
@XmlElementWrapper(name = "Extensions", nillable = true)
|
148
|
@XmlElement(name = "Extension")
|
149
|
@OneToMany(fetch = FetchType.LAZY, orphanRemoval=true)
|
150
|
@Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE})
|
151
|
@Merge(MergeMode.ADD_CLONE)
|
152
|
@NotNull
|
153
|
private Set<Extension> extensions = new HashSet<Extension>();
|
154
|
|
155
|
@XmlElementWrapper(name = "Identifiers", nillable = true)
|
156
|
@XmlElement(name = "Identifier")
|
157
|
@OrderColumn(name="sortIndex")
|
158
|
@OneToMany(fetch = FetchType.LAZY, orphanRemoval=true)
|
159
|
@Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE})
|
160
|
@Merge(MergeMode.ADD_CLONE)
|
161
|
@NotNull
|
162
|
private List<Identifier> identifiers = new ArrayList<Identifier>();
|
163
|
|
164
|
@XmlElementWrapper(name = "Sources", nillable = true)
|
165
|
@XmlElement(name = "IdentifiableSource")
|
166
|
@OneToMany(fetch = FetchType.LAZY, orphanRemoval=true)
|
167
|
@Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE})
|
168
|
@Merge(MergeMode.ADD_CLONE)
|
169
|
@NotNull
|
170
|
private Set<IdentifiableSource> sources = new HashSet<IdentifiableSource>();
|
171
|
|
172
|
@XmlTransient
|
173
|
@Transient
|
174
|
protected S cacheStrategy;
|
175
|
|
176
|
protected IdentifiableEntity(){
|
177
|
initListener();
|
178
|
}
|
179
|
|
180
|
@Override
|
181
|
public void initListener(){
|
182
|
PropertyChangeListener listener = new PropertyChangeListener() {
|
183
|
@Override
|
184
|
public void propertyChange(PropertyChangeEvent ev) {
|
185
|
if (! "titleCache".equals(ev.getPropertyName()) && !"cacheStrategy".equals(ev.getPropertyName()) && ! isProtectedTitleCache()){
|
186
|
titleCache = null;
|
187
|
}
|
188
|
}
|
189
|
};
|
190
|
addPropertyChangeListener(listener);
|
191
|
}
|
192
|
|
193
|
/**
|
194
|
* By default, we expect most cdm objects to be abstract things
|
195
|
* i.e. unable to return a data representation.
|
196
|
*
|
197
|
* Specific subclasses (e.g. Sequence) can override if necessary.
|
198
|
*/
|
199
|
@Override
|
200
|
public byte[] getData() {
|
201
|
return null;
|
202
|
}
|
203
|
|
204
|
//******************************** CACHE *****************************************************/
|
205
|
|
206
|
// @Transient - must not be transient, since this property needs to to be included in all serializations produced by the remote layer
|
207
|
@Override
|
208
|
public String getTitleCache(){
|
209
|
if (protectedTitleCache){
|
210
|
return this.titleCache;
|
211
|
}
|
212
|
// is title dirty, i.e. equal NULL?
|
213
|
if (titleCache == null){
|
214
|
this.titleCache = generateTitle();
|
215
|
this.titleCache = getTruncatedCache(this.titleCache) ;
|
216
|
}
|
217
|
//removed due to #5849
|
218
|
// if(StringUtils.isBlank(titleCache)){
|
219
|
// titleCache = this.toString();
|
220
|
// }
|
221
|
return titleCache;
|
222
|
}
|
223
|
|
224
|
@Deprecated
|
225
|
@Override
|
226
|
public void setTitleCache(String titleCache){
|
227
|
//TODO shouldn't we call setTitleCache(String, boolean),but is this conformant with Java Bean Specification?
|
228
|
this.titleCache = getTruncatedCache(titleCache);
|
229
|
}
|
230
|
|
231
|
@Override
|
232
|
public void setTitleCache(String titleCache, boolean protectCache){
|
233
|
titleCache = getTruncatedCache(titleCache);
|
234
|
this.titleCache = titleCache;
|
235
|
this.protectedTitleCache = protectCache;
|
236
|
}
|
237
|
|
238
|
/**
|
239
|
* @param cache
|
240
|
* @return
|
241
|
*/
|
242
|
@Transient
|
243
|
protected String getTruncatedCache(String cache) {
|
244
|
int maxLength = 800;
|
245
|
if (cache != null && cache.length() > maxLength){
|
246
|
logger.warn("Truncation of cache: " + this.toString() + "/" + cache);
|
247
|
cache = cache.substring(0, maxLength - 4) + "..."; //TODO do we need -4 or is -3 enough
|
248
|
}
|
249
|
return cache;
|
250
|
}
|
251
|
|
252
|
|
253
|
@Override
|
254
|
public boolean isProtectedTitleCache() {
|
255
|
return protectedTitleCache;
|
256
|
}
|
257
|
|
258
|
@Override
|
259
|
public void setProtectedTitleCache(boolean protectedTitleCache) {
|
260
|
this.protectedTitleCache = protectedTitleCache;
|
261
|
}
|
262
|
|
263
|
/**
|
264
|
*
|
265
|
* @return true, if the current state of the titleCache (without generating it new)
|
266
|
* is <code>null</code> or the empty string. This is primarily meant for internal use.
|
267
|
*/
|
268
|
public boolean hasEmptyTitleCache(){
|
269
|
return this.titleCache == null || "".equals(this.titleCache);
|
270
|
}
|
271
|
|
272
|
//**************************************************************************************
|
273
|
|
274
|
@Override
|
275
|
public LSID getLsid(){
|
276
|
return this.lsid;
|
277
|
}
|
278
|
@Override
|
279
|
public void setLsid(LSID lsid){
|
280
|
this.lsid = lsid;
|
281
|
}
|
282
|
@Override
|
283
|
public Set<Rights> getRights() {
|
284
|
if(rights == null) {
|
285
|
this.rights = new HashSet<Rights>();
|
286
|
}
|
287
|
return this.rights;
|
288
|
}
|
289
|
|
290
|
@Override
|
291
|
public void addRights(Rights right){
|
292
|
getRights().add(right);
|
293
|
}
|
294
|
@Override
|
295
|
public void removeRights(Rights right){
|
296
|
getRights().remove(right);
|
297
|
}
|
298
|
|
299
|
|
300
|
@Override
|
301
|
public List<Credit> getCredits() {
|
302
|
if(credits == null) {
|
303
|
this.credits = new ArrayList<Credit>();
|
304
|
}
|
305
|
return this.credits;
|
306
|
}
|
307
|
|
308
|
@Override
|
309
|
public Credit getCredits(Integer index){
|
310
|
return getCredits().get(index);
|
311
|
}
|
312
|
|
313
|
@Override
|
314
|
public void addCredit(Credit credit){
|
315
|
getCredits().add(credit);
|
316
|
}
|
317
|
|
318
|
|
319
|
@Override
|
320
|
public void addCredit(Credit credit, int index){
|
321
|
getCredits().add(index, credit);
|
322
|
}
|
323
|
|
324
|
@Override
|
325
|
public void removeCredit(Credit credit){
|
326
|
getCredits().remove(credit);
|
327
|
}
|
328
|
|
329
|
@Override
|
330
|
public void removeCredit(int index){
|
331
|
getCredits().remove(index);
|
332
|
}
|
333
|
|
334
|
@Override
|
335
|
public boolean replaceCredit(Credit newObject, Credit oldObject){
|
336
|
return replaceInList(this.credits, newObject, oldObject);
|
337
|
}
|
338
|
|
339
|
|
340
|
@Override
|
341
|
public List<Identifier> getIdentifiers(){
|
342
|
if(this.identifiers == null) {
|
343
|
this.identifiers = new ArrayList<Identifier>();
|
344
|
}
|
345
|
return this.identifiers;
|
346
|
}
|
347
|
/**
|
348
|
* @param type
|
349
|
* @return a set of identifier value strings
|
350
|
*/
|
351
|
public Set<String> getIdentifiers(DefinedTerm type){
|
352
|
return getIdentifiers(type.getUuid());
|
353
|
}
|
354
|
/**
|
355
|
* @param identifierTypeUuid
|
356
|
* @return a set of identifier value strings
|
357
|
*/
|
358
|
public Set<String> getIdentifiers(UUID identifierTypeUuid){
|
359
|
Set<String> result = new HashSet<String>();
|
360
|
for (Identifier<?> identifier : getIdentifiers()){
|
361
|
if (identifier.getType().getUuid().equals(identifierTypeUuid)){
|
362
|
result.add(identifier.getIdentifier());
|
363
|
}
|
364
|
}
|
365
|
return result;
|
366
|
}
|
367
|
|
368
|
@Override
|
369
|
public Identifier addIdentifier(String identifier, DefinedTerm identifierType){
|
370
|
Identifier<?> result = Identifier.NewInstance(identifier, identifierType);
|
371
|
addIdentifier(result);
|
372
|
return result;
|
373
|
}
|
374
|
|
375
|
@Override
|
376
|
public void addIdentifier(int index, Identifier identifier){
|
377
|
if (identifier != null){
|
378
|
//deduplication
|
379
|
int oldIndex = getIdentifiers().indexOf(identifier);
|
380
|
if(oldIndex > -1){
|
381
|
getIdentifiers().remove(identifier);
|
382
|
if (oldIndex < index){
|
383
|
index--;
|
384
|
}
|
385
|
}
|
386
|
getIdentifiers().add(index, identifier);
|
387
|
}
|
388
|
}
|
389
|
|
390
|
@Override
|
391
|
public void addIdentifier(Identifier identifier){
|
392
|
addIdentifier(getIdentifiers().size(), identifier);
|
393
|
}
|
394
|
|
395
|
@Override
|
396
|
public void removeIdentifier(Identifier identifier){
|
397
|
if (identifier != null){
|
398
|
getIdentifiers().remove(identifier);
|
399
|
}
|
400
|
}
|
401
|
@Override
|
402
|
public void removeIdentifier(int index){
|
403
|
getIdentifiers().remove(index);
|
404
|
}
|
405
|
|
406
|
@Override
|
407
|
public boolean replaceIdentifier(Identifier newObject, Identifier oldObject){
|
408
|
return replaceInList(this.identifiers, newObject, oldObject);
|
409
|
}
|
410
|
|
411
|
|
412
|
@Override
|
413
|
public Set<Extension> getExtensions(){
|
414
|
if(extensions == null) {
|
415
|
this.extensions = new HashSet<Extension>();
|
416
|
}
|
417
|
return this.extensions;
|
418
|
}
|
419
|
/**
|
420
|
* @param type
|
421
|
* @return a Set of extension value strings
|
422
|
*/
|
423
|
public Set<String> getExtensions(ExtensionType type){
|
424
|
return getExtensions(type.getUuid());
|
425
|
}
|
426
|
/**
|
427
|
* @param extensionTypeUuid
|
428
|
* @return a Set of extension value strings
|
429
|
*/
|
430
|
public Set<String> getExtensions(UUID extensionTypeUuid){
|
431
|
Set<String> result = new HashSet<String>();
|
432
|
for (Extension extension : getExtensions()){
|
433
|
if (extension.getType().getUuid().equals(extensionTypeUuid)){
|
434
|
result.add(extension.getValue());
|
435
|
}
|
436
|
}
|
437
|
return result;
|
438
|
}
|
439
|
|
440
|
public void addExtension(String value, ExtensionType extensionType){
|
441
|
Extension.NewInstance(this, value, extensionType);
|
442
|
}
|
443
|
|
444
|
@Override
|
445
|
public void addExtension(Extension extension){
|
446
|
if (extension != null){
|
447
|
getExtensions().add(extension);
|
448
|
}
|
449
|
}
|
450
|
@Override
|
451
|
public void removeExtension(Extension extension){
|
452
|
if (extension != null){
|
453
|
getExtensions().remove(extension);
|
454
|
}
|
455
|
}
|
456
|
|
457
|
|
458
|
@Override
|
459
|
public Set<IdentifiableSource> getSources() {
|
460
|
if(sources == null) {
|
461
|
this.sources = new HashSet<IdentifiableSource>();
|
462
|
}
|
463
|
return this.sources;
|
464
|
}
|
465
|
|
466
|
@Override
|
467
|
public void addSource(IdentifiableSource source) {
|
468
|
if (source != null){
|
469
|
getSources().add(source);
|
470
|
}
|
471
|
}
|
472
|
|
473
|
@Override
|
474
|
public void addSources(Set<IdentifiableSource> sources) {
|
475
|
if (sources != null){
|
476
|
for (IdentifiableSource source: sources){
|
477
|
getSources().add(source);
|
478
|
}
|
479
|
}
|
480
|
}
|
481
|
|
482
|
@Override
|
483
|
public void removeSources() {
|
484
|
this.sources.clear();
|
485
|
}
|
486
|
|
487
|
@Override
|
488
|
public IdentifiableSource addSource(OriginalSourceType type, String id, String idNamespace, Reference citation, String microCitation) {
|
489
|
if (id == null && idNamespace == null && citation == null && microCitation == null){
|
490
|
return null;
|
491
|
}
|
492
|
IdentifiableSource source = IdentifiableSource.NewInstance(type, id, idNamespace, citation, microCitation);
|
493
|
addSource(source);
|
494
|
return source;
|
495
|
}
|
496
|
|
497
|
|
498
|
@Override
|
499
|
public IdentifiableSource addImportSource(String id, String idNamespace, Reference citation, String microCitation) {
|
500
|
if (id == null && idNamespace == null && citation == null && microCitation == null){
|
501
|
return null;
|
502
|
}
|
503
|
IdentifiableSource source = IdentifiableSource.NewInstance(OriginalSourceType.Import, id, idNamespace, citation, microCitation);
|
504
|
addSource(source);
|
505
|
return source;
|
506
|
}
|
507
|
|
508
|
|
509
|
@Override
|
510
|
public void removeSource(IdentifiableSource source) {
|
511
|
getSources().remove(source);
|
512
|
}
|
513
|
|
514
|
//******************************** TO STRING *****************************************************/
|
515
|
|
516
|
@Override
|
517
|
public String toString() {
|
518
|
String result;
|
519
|
if (StringUtils.isBlank(titleCache)){
|
520
|
result = super.toString();
|
521
|
}else{
|
522
|
result = this.titleCache;
|
523
|
}
|
524
|
return result;
|
525
|
}
|
526
|
|
527
|
|
528
|
public int compareTo(IdentifiableEntity identifiableEntity) {
|
529
|
|
530
|
int result = 0;
|
531
|
|
532
|
if (identifiableEntity == null) {
|
533
|
throw new NullPointerException("Cannot compare to null.");
|
534
|
}
|
535
|
|
536
|
// First, compare the name cache.
|
537
|
// TODO: Avoid using instanceof operator
|
538
|
// Use Class.getDeclaredMethod() instead to find out whether class has getNameCache() method?
|
539
|
|
540
|
String specifiedNameCache = "";
|
541
|
String thisNameCache = "";
|
542
|
String specifiedTitleCache = "";
|
543
|
String thisTitleCache = "";
|
544
|
String specifiedReferenceTitleCache = "";
|
545
|
String thisReferenceTitleCache = "";
|
546
|
String thisGenusString = "";
|
547
|
String specifiedGenusString = "";
|
548
|
int thisrank_order = 0;
|
549
|
final String HYBRID_SIGN = "\u00D7";
|
550
|
final String QUOT_SIGN = "[\\u02BA\\u0022\\u0022]";
|
551
|
//TODO we can remove all the deproxies here except for the first one
|
552
|
identifiableEntity = HibernateProxyHelper.deproxy(identifiableEntity, IdentifiableEntity.class);
|
553
|
if(identifiableEntity instanceof NonViralName) {
|
554
|
specifiedNameCache = HibernateProxyHelper.deproxy(identifiableEntity, NonViralName.class).getNameCache();
|
555
|
specifiedTitleCache = identifiableEntity.getTitleCache();
|
556
|
if (identifiableEntity instanceof BotanicalName){
|
557
|
if (((BotanicalName)identifiableEntity).isAutonym()){
|
558
|
boolean isProtected = false;
|
559
|
String oldNameCache = ((BotanicalName) identifiableEntity).getNameCache();
|
560
|
if ( ((BotanicalName)identifiableEntity).isProtectedNameCache()){
|
561
|
isProtected = true;
|
562
|
}
|
563
|
((BotanicalName)identifiableEntity).setProtectedNameCache(false);
|
564
|
((BotanicalName)identifiableEntity).setNameCache(null, false);
|
565
|
specifiedNameCache = ((BotanicalName) identifiableEntity).getNameCache();
|
566
|
((BotanicalName)identifiableEntity).setNameCache(oldNameCache, isProtected);
|
567
|
|
568
|
}
|
569
|
}
|
570
|
|
571
|
} else if(identifiableEntity instanceof TaxonBase) {
|
572
|
TaxonBase taxonBase = HibernateProxyHelper.deproxy(identifiableEntity, TaxonBase.class);
|
573
|
|
574
|
TaxonNameBase<?,?> taxonNameBase = taxonBase.getName();
|
575
|
|
576
|
|
577
|
NonViralName nonViralName = HibernateProxyHelper.deproxy(taxonNameBase, NonViralName.class);
|
578
|
specifiedNameCache = nonViralName.getNameCache();
|
579
|
specifiedTitleCache = taxonNameBase.getTitleCache();
|
580
|
|
581
|
specifiedReferenceTitleCache = ((TaxonBase)identifiableEntity).getSec().getTitleCache();
|
582
|
Reference reference = taxonBase.getSec();
|
583
|
if (reference != null) {
|
584
|
reference = HibernateProxyHelper.deproxy(reference, Reference.class);
|
585
|
specifiedReferenceTitleCache = reference.getTitleCache();
|
586
|
}
|
587
|
}
|
588
|
|
589
|
if(this.isInstanceOf(NonViralName.class)) {
|
590
|
thisNameCache = HibernateProxyHelper.deproxy(this, NonViralName.class).getNameCache();
|
591
|
thisTitleCache = getTitleCache();
|
592
|
|
593
|
if (this instanceof BotanicalName){
|
594
|
if (((BotanicalName)this).isAutonym()){
|
595
|
boolean isProtected = false;
|
596
|
String oldNameCache = ((BotanicalName) this).getNameCache();
|
597
|
if ( ((BotanicalName)this).isProtectedNameCache()){
|
598
|
isProtected = true;
|
599
|
}
|
600
|
((BotanicalName)this).setProtectedNameCache(false);
|
601
|
((BotanicalName)this).setNameCache(null, false);
|
602
|
thisNameCache = ((BotanicalName) this).getNameCache();
|
603
|
((BotanicalName)this).setNameCache(oldNameCache, isProtected);
|
604
|
}
|
605
|
}
|
606
|
} else if(this.isInstanceOf(TaxonBase.class)) {
|
607
|
TaxonNameBase<?,?> taxonNameBase= HibernateProxyHelper.deproxy(this, TaxonBase.class).getName();
|
608
|
NonViralName nonViralName = HibernateProxyHelper.deproxy(taxonNameBase, NonViralName.class);
|
609
|
thisNameCache = nonViralName.getNameCache();
|
610
|
thisTitleCache = taxonNameBase.getTitleCache();
|
611
|
thisReferenceTitleCache = ((TaxonBase)this).getSec().getTitleCache();
|
612
|
thisGenusString = nonViralName.getGenusOrUninomial();
|
613
|
}
|
614
|
|
615
|
// Compare name cache of taxon names
|
616
|
|
617
|
|
618
|
|
619
|
if (!specifiedNameCache.equals("") && !thisNameCache.equals("")) {
|
620
|
|
621
|
thisNameCache = thisNameCache.replaceAll(HYBRID_SIGN, "");
|
622
|
thisNameCache = thisNameCache.replaceAll(QUOT_SIGN, "");
|
623
|
|
624
|
|
625
|
specifiedNameCache = specifiedNameCache.replaceAll(HYBRID_SIGN, "");
|
626
|
specifiedNameCache = specifiedNameCache.replaceAll(QUOT_SIGN, "");
|
627
|
|
628
|
|
629
|
result = thisNameCache.compareTo(specifiedNameCache);
|
630
|
}
|
631
|
|
632
|
// Compare title cache of taxon names
|
633
|
|
634
|
if ((result == 0) && (!specifiedTitleCache.equals("") || !thisTitleCache.equals(""))) {
|
635
|
thisTitleCache = thisTitleCache.replaceAll(HYBRID_SIGN, "");
|
636
|
thisTitleCache = thisTitleCache.replaceAll(QUOT_SIGN, "");
|
637
|
|
638
|
specifiedTitleCache = specifiedTitleCache.replaceAll(HYBRID_SIGN, "");
|
639
|
specifiedTitleCache = specifiedTitleCache.replaceAll(QUOT_SIGN, "");
|
640
|
result = thisTitleCache.compareTo(specifiedTitleCache);
|
641
|
}
|
642
|
|
643
|
// Compare title cache of taxon references
|
644
|
|
645
|
if ((result == 0) && (!specifiedReferenceTitleCache.equals("") || !thisReferenceTitleCache.equals(""))) {
|
646
|
result = thisReferenceTitleCache.compareTo(specifiedReferenceTitleCache);
|
647
|
}
|
648
|
|
649
|
return result;
|
650
|
}
|
651
|
|
652
|
/**
|
653
|
* Returns the {@link eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy cache strategy} used to generate
|
654
|
* several strings corresponding to <i>this</i> identifiable entity
|
655
|
* (in particular taxon name caches and author strings).
|
656
|
*
|
657
|
* @return the cache strategy used for <i>this</i> identifiable entity
|
658
|
* @see eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy
|
659
|
*/
|
660
|
public S getCacheStrategy() {
|
661
|
return this.cacheStrategy;
|
662
|
}
|
663
|
/**
|
664
|
* @see #getCacheStrategy()
|
665
|
*/
|
666
|
|
667
|
public void setCacheStrategy(S cacheStrategy) {
|
668
|
this.cacheStrategy = cacheStrategy;
|
669
|
}
|
670
|
|
671
|
@Override
|
672
|
public String generateTitle() {
|
673
|
if (getCacheStrategy() == null){
|
674
|
//logger.warn("No CacheStrategy defined for "+ this.getClass() + ": " + this.getUuid());
|
675
|
return this.getClass() + ": " + this.getUuid();
|
676
|
}else{
|
677
|
return getCacheStrategy().getTitleCache(this);
|
678
|
}
|
679
|
}
|
680
|
|
681
|
//****************** CLONE ************************************************/
|
682
|
|
683
|
@Override
|
684
|
public Object clone() throws CloneNotSupportedException{
|
685
|
IdentifiableEntity<?> result = (IdentifiableEntity<?>)super.clone();
|
686
|
|
687
|
//Extensions
|
688
|
result.extensions = new HashSet<Extension>();
|
689
|
for (Extension extension : getExtensions() ){
|
690
|
Extension newExtension = (Extension)extension.clone();
|
691
|
result.addExtension(newExtension);
|
692
|
}
|
693
|
|
694
|
//Identifier
|
695
|
result.identifiers = new ArrayList<Identifier>();
|
696
|
for (Identifier<?> identifier : getIdentifiers() ){
|
697
|
Identifier<?> newIdentifier = (Identifier<?>)identifier.clone();
|
698
|
result.addIdentifier(newIdentifier);
|
699
|
}
|
700
|
|
701
|
//OriginalSources
|
702
|
result.sources = new HashSet<IdentifiableSource>();
|
703
|
for (IdentifiableSource source : getSources()){
|
704
|
IdentifiableSource newSource = (IdentifiableSource)source.clone();
|
705
|
result.addSource(newSource);
|
706
|
}
|
707
|
|
708
|
//Rights
|
709
|
result.rights = new HashSet<Rights>();
|
710
|
for(Rights rights : getRights()) {
|
711
|
Rights newRights = (Rights)rights.clone();
|
712
|
result.addRights(newRights);
|
713
|
}
|
714
|
|
715
|
|
716
|
//Credits
|
717
|
result.credits = new ArrayList<Credit>();
|
718
|
for(Credit credit : getCredits()) {
|
719
|
Credit newCredit = (Credit)credit.clone();
|
720
|
result.addCredit(newCredit);
|
721
|
}
|
722
|
|
723
|
//no changes to: lsid, titleCache, protectedTitleCache
|
724
|
|
725
|
//empty titleCache
|
726
|
if (! protectedTitleCache){
|
727
|
result.titleCache = null;
|
728
|
}
|
729
|
|
730
|
result.initListener();
|
731
|
return result;
|
732
|
}
|
733
|
|
734
|
|
735
|
}
|