2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
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.
10 package eu
.etaxonomy
.cdm
.model
.common
;
13 import java
.util
.HashSet
;
16 import javax
.persistence
.Column
;
17 import javax
.persistence
.Embedded
;
18 import javax
.persistence
.FetchType
;
19 import javax
.persistence
.MappedSuperclass
;
20 import javax
.persistence
.OneToMany
;
21 import javax
.persistence
.PrePersist
;
22 import javax
.persistence
.PreUpdate
;
23 import javax
.persistence
.Transient
;
24 import javax
.xml
.bind
.annotation
.XmlAccessType
;
25 import javax
.xml
.bind
.annotation
.XmlAccessorType
;
26 import javax
.xml
.bind
.annotation
.XmlElement
;
27 import javax
.xml
.bind
.annotation
.XmlElementWrapper
;
28 import javax
.xml
.bind
.annotation
.XmlTransient
;
29 import javax
.xml
.bind
.annotation
.XmlType
;
30 import javax
.xml
.bind
.annotation
.adapters
.XmlJavaTypeAdapter
;
32 import org
.apache
.log4j
.Logger
;
33 import org
.hibernate
.annotations
.Cascade
;
34 import org
.hibernate
.annotations
.CascadeType
;
35 import org
.hibernate
.search
.annotations
.Field
;
36 import org
.hibernate
.search
.annotations
.FieldBridge
;
37 import org
.hibernate
.search
.annotations
.Fields
;
39 import eu
.etaxonomy
.cdm
.jaxb
.FormattedTextAdapter
;
40 import eu
.etaxonomy
.cdm
.jaxb
.LSIDAdapter
;
41 import eu
.etaxonomy
.cdm
.model
.media
.Rights
;
42 import eu
.etaxonomy
.cdm
.model
.name
.NonViralName
;
43 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameBase
;
44 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonBase
;
47 * 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.
48 * All subclasses inherit the ability to store additional properties that are stored as {@link Extension Extensions}, basically a string value with a type term.
49 * Any number of right statements can be attached as well as multiple {@link OriginalSource} objects.
50 * 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).
51 * A Taxon for example that was taken from 2 sources like FaunaEuropaea and IPNI would have two originalSource objects.
52 * 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.
56 * @created 08-Nov-2007 13:06:27
58 @XmlAccessorType(XmlAccessType
.FIELD
)
59 @XmlType(name
= "IdentifiableEntity", propOrder
= {
62 "protectedTitleCache",
68 public abstract class IdentifiableEntity
extends AnnotatableEntity
69 implements ISourceable
, IIdentifiableEntity
, Comparable
<IdentifiableEntity
> {
70 private static final long serialVersionUID
= -5610995424730659058L;
71 private static final Logger logger
= Logger
.getLogger(IdentifiableEntity
.class);
74 public static final boolean PROTECTED
= true;
76 public static final boolean NOT_PROTECTED
= false;
78 @XmlElement(name
= "LSID", type
= String
.class)
79 @XmlJavaTypeAdapter(LSIDAdapter
.class)
83 @XmlElement(name
= "TitleCache", required
= true)
84 @XmlJavaTypeAdapter(FormattedTextAdapter
.class)
85 @Column(length
=255, name
="titleCache")
86 @Fields({@Field(index
= org
.hibernate
.search
.annotations
.Index
.TOKENIZED
),
87 @Field(name
= "titleCache_forSort", index
= org
.hibernate
.search
.annotations
.Index
.UN_TOKENIZED
)
89 @FieldBridge(impl
=StripHtmlBridge
.class)
90 private String titleCache
;
92 //if true titleCache will not be automatically generated/updated
93 @XmlElement(name
= "ProtectedTitleCache")
94 private boolean protectedTitleCache
;
96 @XmlElementWrapper(name
= "Rights")
97 @XmlElement(name
= "Rights")
98 @OneToMany(fetch
= FetchType
.LAZY
)
99 @Cascade({CascadeType
.SAVE_UPDATE
})
100 private Set
<Rights
> rights
= new HashSet
<Rights
>();
102 @XmlElementWrapper(name
= "Extensions")
103 @XmlElement(name
= "Extension")
104 @OneToMany(fetch
= FetchType
.LAZY
)
105 @Cascade({CascadeType
.SAVE_UPDATE
})
106 private Set
<Extension
> extensions
= new HashSet
<Extension
>();
108 @XmlElementWrapper(name
= "Sources")
109 @XmlElement(name
= "OriginalSource")
110 @OneToMany(fetch
= FetchType
.LAZY
)
111 @Cascade({CascadeType
.SAVE_UPDATE
})
112 private Set
<OriginalSource
> sources
= new HashSet
<OriginalSource
>();
116 * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#getLsid()
118 public LSID
getLsid(){
122 * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#setLsid(java.lang.String)
124 public void setLsid(LSID lsid
){
129 * By default, we expect most cdm objects to be abstract things
130 * i.e. unable to return a data representation.
132 * Specific subclasses (e.g. Sequence) can override if necessary.
134 public byte[] getData() {
139 * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#generateTitle()
141 public abstract String
generateTitle();
144 * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#getTitleCache()
147 public String
getTitleCache(){
148 if (protectedTitleCache
){
149 return this.titleCache
;
151 // is title dirty, i.e. equal NULL?
152 if (titleCache
== null){
153 this.setTitleCache(generateTitle(),protectedTitleCache
) ; //for truncating
158 * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#setTitleCache(java.lang.String)
160 public void setTitleCache(String titleCache
){
161 setTitleCache(titleCache
, PROTECTED
);
165 * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#setTitleCache(java.lang.String, boolean)
167 public void setTitleCache(String titleCache
, boolean protectCache
){
168 //TODO truncation of title cache
169 if (titleCache
!= null && titleCache
.length() > 254){
170 logger
.warn("Truncation of title cache: " + this.toString() + "/" + titleCache
);
171 titleCache
= titleCache
.substring(0, 249) + "...";
173 this.titleCache
= titleCache
;
174 this.setProtectedTitleCache(protectCache
);
178 * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#getRights()
180 public Set
<Rights
> getRights() {
185 * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#addRights(eu.etaxonomy.cdm.model.media.Rights)
187 public void addRights(Rights right
){
188 this.rights
.add(right
);
191 * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#removeRights(eu.etaxonomy.cdm.model.media.Rights)
193 public void removeRights(Rights right
){
194 this.rights
.remove(right
);
198 * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#getExtensions()
200 public Set
<Extension
> getExtensions(){
201 return this.extensions
;
205 * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#addExtension(eu.etaxonomy.cdm.model.common.Extension)
207 public void addExtension(Extension extension
){
208 this.extensions
.add(extension
);
211 * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#removeExtension(eu.etaxonomy.cdm.model.common.Extension)
213 public void removeExtension(Extension extension
){
214 this.extensions
.remove(extension
);
219 * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#isProtectedTitleCache()
221 public boolean isProtectedTitleCache() {
222 return protectedTitleCache
;
226 * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#setProtectedTitleCache(boolean)
228 public void setProtectedTitleCache(boolean protectedTitleCache
) {
229 this.protectedTitleCache
= protectedTitleCache
;
233 * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#getSources()
235 public Set
<OriginalSource
> getSources() {
239 * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#addSource(eu.etaxonomy.cdm.model.common.OriginalSource)
241 public void addSource(OriginalSource source
) {
243 IdentifiableEntity oldSourcedObj
= source
.getSourcedObj();
244 if (oldSourcedObj
!= null && oldSourcedObj
!= this){
245 oldSourcedObj
.getSources().remove(source
);
247 this.sources
.add(source
);
248 source
.setSourcedObj(this);
252 * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#removeSource(eu.etaxonomy.cdm.model.common.OriginalSource)
254 public void removeSource(OriginalSource source
) {
255 this.sources
.remove(source
);
259 * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#toString()
262 public String
toString() {
264 if (titleCache
== null){
265 result
= super.toString();
267 result
= this.titleCache
;
272 public int compareTo(IdentifiableEntity identifiableEntity
) {
276 if (identifiableEntity
== null) {
277 throw new NullPointerException("Cannot compare to null.");
280 // First, compare the name cache.
281 // TODO: Avoid using instanceof operator
282 // Use Class.getDeclaredMethod() instead to find out whether class has getNameCache() method?
284 // Compare name cache
285 String specifiedNameCache
= "";
286 String thisNameCache
= "";
288 if(identifiableEntity
instanceof NonViralName
) {
289 specifiedNameCache
= ((NonViralName
<?
>)identifiableEntity
).getNameCache();
290 } else if(identifiableEntity
instanceof TaxonBase
) {
291 TaxonNameBase
<?
,?
> taxonNameBase
= ((TaxonBase
)identifiableEntity
).getName();
292 specifiedNameCache
= ((NonViralName
<?
>)taxonNameBase
).getNameCache();
295 if(this instanceof NonViralName
) {
296 thisNameCache
= ((NonViralName
<?
>)this).getNameCache();
297 } else if(this instanceof TaxonBase
) {
298 TaxonNameBase
<?
,?
> taxonNameBase
= ((TaxonBase
)this).getName();
299 thisNameCache
= ((NonViralName
<?
>)taxonNameBase
).getNameCache();
302 if (!specifiedNameCache
.equals("") && !thisNameCache
.equals("")) {
303 result
= thisNameCache
.compareTo(specifiedNameCache
);
306 // Compare title cache
308 String thisTitleCache
= getTitleCache();
309 String specifiedTitleCache
= identifiableEntity
.getTitleCache();
310 result
= thisTitleCache
.compareTo(specifiedTitleCache
);
316 //****************** CLONE ************************************************/
319 * @see eu.etaxonomy.cdm.model.common.AnnotatableEntity#clone()
322 public Object
clone() throws CloneNotSupportedException
{
323 IdentifiableEntity result
= (IdentifiableEntity
)super.clone();
326 result
.extensions
= new HashSet
<Extension
>();
327 for (Extension extension
: this.extensions
){
328 Extension newExtension
= (Extension
)extension
.clone();
329 result
.addExtension(newExtension
);
333 result
.sources
= new HashSet
<OriginalSource
>();
334 for (OriginalSource originalSource
: this.sources
){
335 OriginalSource newSource
= (OriginalSource
)originalSource
.clone();
336 result
.addSource(newSource
);
340 result
.rights
= new HashSet
<Rights
>();
341 for(Rights rights
: this.rights
) {
342 result
.addRights(rights
);
345 //result.setLsid(lsid);
346 //result.setTitleCache(titleCache);
347 //result.setProtectedTitleCache(protectedTitleCache); //must be after setTitleCache
349 //no changes to: lsid, titleCache, protectedTitleCache
352 if (! protectedTitleCache
){