f136502c83f6eef41b5e8718b5c2d3ec5e7ca2a4
[cdmlib.git] / cdmlib-model / src / main / java / eu / etaxonomy / cdm / model / common / IdentifiableEntity.java
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.util.HashSet;
14 import java.util.Set;
15
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;
31
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;
38
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;
45
46 /**
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.
53 *
54 * @author m.doering
55 * @version 1.0
56 * @created 08-Nov-2007 13:06:27
57 */
58 @XmlAccessorType(XmlAccessType.FIELD)
59 @XmlType(name = "IdentifiableEntity", propOrder = {
60 "lsid",
61 "titleCache",
62 "protectedTitleCache",
63 "rights",
64 "extensions",
65 "sources"
66 })
67 @MappedSuperclass
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);
72
73 @XmlTransient
74 public static final boolean PROTECTED = true;
75 @XmlTransient
76 public static final boolean NOT_PROTECTED = false;
77
78 @XmlElement(name = "LSID", type = String.class)
79 @XmlJavaTypeAdapter(LSIDAdapter.class)
80 @Embedded
81 private LSID lsid;
82
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)
88 })
89 @FieldBridge(impl=StripHtmlBridge.class)
90 private String titleCache;
91
92 //if true titleCache will not be automatically generated/updated
93 @XmlElement(name = "ProtectedTitleCache")
94 private boolean protectedTitleCache;
95
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>();
101
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>();
107
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>();
113
114
115 /* (non-Javadoc)
116 * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#getLsid()
117 */
118 public LSID getLsid(){
119 return this.lsid;
120 }
121 /* (non-Javadoc)
122 * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#setLsid(java.lang.String)
123 */
124 public void setLsid(LSID lsid){
125 this.lsid = lsid;
126 }
127
128 /**
129 * By default, we expect most cdm objects to be abstract things
130 * i.e. unable to return a data representation.
131 *
132 * Specific subclasses (e.g. Sequence) can override if necessary.
133 */
134 public byte[] getData() {
135 return null;
136 }
137
138 /* (non-Javadoc)
139 * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#generateTitle()
140 */
141 public abstract String generateTitle();
142
143 /* (non-Javadoc)
144 * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#getTitleCache()
145 */
146 //@Transient
147 public String getTitleCache(){
148 if (protectedTitleCache){
149 return this.titleCache;
150 }
151 // is title dirty, i.e. equal NULL?
152 if (titleCache == null){
153 this.setTitleCache(generateTitle(),protectedTitleCache) ; //for truncating
154 }
155 return titleCache;
156 }
157 /* (non-Javadoc)
158 * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#setTitleCache(java.lang.String)
159 */
160 public void setTitleCache(String titleCache){
161 setTitleCache(titleCache, PROTECTED);
162 }
163
164 /* (non-Javadoc)
165 * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#setTitleCache(java.lang.String, boolean)
166 */
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) + "...";
172 }
173 this.titleCache = titleCache;
174 this.setProtectedTitleCache(protectCache);
175 }
176
177 /* (non-Javadoc)
178 * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#getRights()
179 */
180 public Set<Rights> getRights() {
181 return this.rights;
182 }
183
184 /* (non-Javadoc)
185 * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#addRights(eu.etaxonomy.cdm.model.media.Rights)
186 */
187 public void addRights(Rights right){
188 this.rights.add(right);
189 }
190 /* (non-Javadoc)
191 * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#removeRights(eu.etaxonomy.cdm.model.media.Rights)
192 */
193 public void removeRights(Rights right){
194 this.rights.remove(right);
195 }
196
197 /* (non-Javadoc)
198 * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#getExtensions()
199 */
200 public Set<Extension> getExtensions(){
201 return this.extensions;
202 }
203
204 /* (non-Javadoc)
205 * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#addExtension(eu.etaxonomy.cdm.model.common.Extension)
206 */
207 public void addExtension(Extension extension){
208 this.extensions.add(extension);
209 }
210 /* (non-Javadoc)
211 * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#removeExtension(eu.etaxonomy.cdm.model.common.Extension)
212 */
213 public void removeExtension(Extension extension){
214 this.extensions.remove(extension);
215 }
216
217
218 /* (non-Javadoc)
219 * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#isProtectedTitleCache()
220 */
221 public boolean isProtectedTitleCache() {
222 return protectedTitleCache;
223 }
224
225 /* (non-Javadoc)
226 * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#setProtectedTitleCache(boolean)
227 */
228 public void setProtectedTitleCache(boolean protectedTitleCache) {
229 this.protectedTitleCache = protectedTitleCache;
230 }
231
232 /* (non-Javadoc)
233 * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#getSources()
234 */
235 public Set<OriginalSource> getSources() {
236 return this.sources;
237 }
238 /* (non-Javadoc)
239 * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#addSource(eu.etaxonomy.cdm.model.common.OriginalSource)
240 */
241 public void addSource(OriginalSource source) {
242 if (source != null){
243 IdentifiableEntity oldSourcedObj = source.getSourcedObj();
244 if (oldSourcedObj != null && oldSourcedObj != this){
245 oldSourcedObj.getSources().remove(source);
246 }
247 this.sources.add(source);
248 source.setSourcedObj(this);
249 }
250 }
251 /* (non-Javadoc)
252 * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#removeSource(eu.etaxonomy.cdm.model.common.OriginalSource)
253 */
254 public void removeSource(OriginalSource source) {
255 this.sources.remove(source);
256 }
257
258 /* (non-Javadoc)
259 * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#toString()
260 */
261 @Override
262 public String toString() {
263 String result;
264 if (titleCache == null){
265 result = super.toString();
266 }else{
267 result = this.titleCache;
268 }
269 return result;
270 }
271
272 public int compareTo(IdentifiableEntity identifiableEntity) {
273
274 int result = 0;
275
276 if (identifiableEntity == null) {
277 throw new NullPointerException("Cannot compare to null.");
278 }
279
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?
283
284 // Compare name cache
285 String specifiedNameCache = "";
286 String thisNameCache = "";
287
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();
293 }
294
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();
300 }
301
302 if (!specifiedNameCache.equals("") && !thisNameCache.equals("")) {
303 result = thisNameCache.compareTo(specifiedNameCache);
304 }
305
306 // Compare title cache
307 if (result == 0) {
308 String thisTitleCache = getTitleCache();
309 String specifiedTitleCache = identifiableEntity.getTitleCache();
310 result = thisTitleCache.compareTo(specifiedTitleCache);
311 }
312 return result;
313 }
314
315
316 //****************** CLONE ************************************************/
317
318 /* (non-Javadoc)
319 * @see eu.etaxonomy.cdm.model.common.AnnotatableEntity#clone()
320 */
321 @Override
322 public Object clone() throws CloneNotSupportedException{
323 IdentifiableEntity result = (IdentifiableEntity)super.clone();
324
325 //Extensions
326 result.extensions = new HashSet<Extension>();
327 for (Extension extension : this.extensions ){
328 Extension newExtension = (Extension)extension.clone();
329 result.addExtension(newExtension);
330 }
331
332 //OriginalSources
333 result.sources = new HashSet<OriginalSource>();
334 for (OriginalSource originalSource : this.sources){
335 OriginalSource newSource = (OriginalSource)originalSource.clone();
336 result.addSource(newSource);
337 }
338
339 //Rights
340 result.rights = new HashSet<Rights>();
341 for(Rights rights : this.rights) {
342 result.addRights(rights);
343 }
344
345 //result.setLsid(lsid);
346 //result.setTitleCache(titleCache);
347 //result.setProtectedTitleCache(protectedTitleCache); //must be after setTitleCache
348
349 //no changes to: lsid, titleCache, protectedTitleCache
350
351 //empty titleCache
352 if (! protectedTitleCache){
353 titleCache = null;
354 }
355 return result;
356 }
357 }