merge-update from trunk
[cdmlib.git] / cdmlib-model / src / main / java / eu / etaxonomy / cdm / model / taxon / TaxonBase.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.taxon;
11
12 import java.lang.reflect.Method;
13
14 import javax.persistence.Entity;
15 import javax.persistence.FetchType;
16 import javax.persistence.ManyToOne;
17 import javax.persistence.Transient;
18 import javax.validation.constraints.NotNull;
19 import javax.xml.bind.annotation.XmlAccessType;
20 import javax.xml.bind.annotation.XmlAccessorType;
21 import javax.xml.bind.annotation.XmlAttribute;
22 import javax.xml.bind.annotation.XmlElement;
23 import javax.xml.bind.annotation.XmlIDREF;
24 import javax.xml.bind.annotation.XmlSchemaType;
25 import javax.xml.bind.annotation.XmlType;
26
27 import org.apache.log4j.Logger;
28 import org.hibernate.annotations.Cascade;
29 import org.hibernate.annotations.CascadeType;
30 import org.hibernate.annotations.Index;
31 import org.hibernate.annotations.Table;
32 import org.hibernate.envers.Audited;
33 import org.hibernate.search.annotations.ClassBridge;
34 import org.hibernate.search.annotations.ClassBridges;
35 import org.hibernate.search.annotations.IndexedEmbedded;
36 import org.hibernate.search.annotations.Store;
37
38 import eu.etaxonomy.cdm.hibernate.search.AcceptedTaxonBridge;
39 import eu.etaxonomy.cdm.hibernate.search.ClassInfoBridge;
40 import eu.etaxonomy.cdm.model.common.IPublishable;
41 import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
42 import eu.etaxonomy.cdm.model.name.HomotypicalGroup;
43 import eu.etaxonomy.cdm.model.name.TaxonNameBase;
44 import eu.etaxonomy.cdm.model.reference.Reference;
45 import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
46 import eu.etaxonomy.cdm.validation.Level2;
47 import eu.etaxonomy.cdm.validation.Level3;
48 import eu.etaxonomy.cdm.validation.annotation.TaxonNameCannotBeAcceptedAndSynonym;
49
50 /**
51 * The upmost (abstract) class for the use of a {@link eu.etaxonomy.cdm.model.name.TaxonNameBase taxon name} in a {@link eu.etaxonomy.cdm.model.reference.Reference reference}
52 * or within a taxonomic view/treatment either as a {@link Taxon taxon}
53 * ("accepted" respectively "correct" name) or as a (junior) {@link Synonym synonym}.
54 * Within a taxonomic view/treatment or a reference a taxon name can be used
55 * only in one of both described meanings. The reference using the taxon name
56 * is generally cited with "sec." (secundum, sensu). For instance:
57 * "<i>Juncus longirostris</i> Kuvaev sec. Kirschner, J. et al. 2002".
58 * <P>
59 * This class corresponds to: <ul>
60 * <li> TaxonConcept according to the TDWG ontology
61 * <li> TaxonConcept according to the TCS
62 * </ul>
63 *
64 * @author m.doering
65 * @created 08-Nov-2007 13:06:56
66 */
67 @XmlAccessorType(XmlAccessType.FIELD)
68 @XmlType(name = "TaxonBase", propOrder = {
69 "name",
70 "sec",
71 "doubtful",
72 "appendedPhrase",
73 "useNameCache",
74 "publish"
75 })
76 @Entity
77 @Audited
78 //@PreFilter("hasPermission(filterObject, 'edit')")
79 @Table(appliesTo="TaxonBase", indexes = { @Index(name = "taxonBaseTitleCacheIndex", columnNames = { "titleCache" }) })
80 @TaxonNameCannotBeAcceptedAndSynonym(groups = Level3.class)
81 @ClassBridges({
82 @ClassBridge(name="classInfo",
83 index = org.hibernate.search.annotations.Index.YES,
84 store = Store.YES,
85 impl = ClassInfoBridge.class),
86 @ClassBridge(name="accTaxon", // TODO rename to acceptedTaxon, since we are usually not using abbreviations for field names
87 index = org.hibernate.search.annotations.Index.YES,
88 store = Store.YES,
89 impl = AcceptedTaxonBridge.class),
90 @ClassBridge(impl = eu.etaxonomy.cdm.hibernate.search.NomenclaturalSortOrderBrigde.class)
91 })
92 public abstract class TaxonBase<S extends IIdentifiableEntityCacheStrategy> extends IdentifiableEntity<S> implements IPublishable, Cloneable {
93 private static final long serialVersionUID = -3589185949928938529L;
94 private static final Logger logger = Logger.getLogger(TaxonBase.class);
95
96 private static Method methodTaxonNameAddTaxonBase;
97
98 static {
99 try {
100 methodTaxonNameAddTaxonBase = TaxonNameBase.class.getDeclaredMethod("addTaxonBase", TaxonBase.class);
101 methodTaxonNameAddTaxonBase.setAccessible(true);
102 } catch (Exception e) {
103 logger.error(e);
104 for(StackTraceElement ste : e.getStackTrace()) {
105 logger.error(ste);
106 }
107 }
108 }
109
110 //The assignment to the Taxon or to the Synonym class is not definitive
111 @XmlAttribute(name = "isDoubtful")
112 private boolean doubtful;
113
114
115 @XmlElement(name = "Name", required = true)
116 @XmlIDREF
117 @XmlSchemaType(name = "IDREF")
118 @ManyToOne(fetch = FetchType.LAZY)
119 @IndexedEmbedded
120 @Cascade(CascadeType.SAVE_UPDATE)
121 @NotNull(groups = Level2.class)
122 private TaxonNameBase<?,?> name;
123
124 // The concept reference
125 @XmlElement(name = "Sec")
126 @XmlIDREF
127 @XmlSchemaType(name = "IDREF")
128 @ManyToOne(fetch = FetchType.LAZY)
129 @Cascade(CascadeType.SAVE_UPDATE)
130 @NotNull(groups = Level2.class)
131 @IndexedEmbedded
132 private Reference<?> sec;
133
134
135 @XmlElement(name = "AppendedPhrase")
136 private String appendedPhrase;
137
138 @XmlAttribute(name= "UseNameCache")
139 private boolean useNameCache = false;
140
141 @XmlAttribute(name = "publish")
142 private boolean publish = true;
143
144
145 // ************* CONSTRUCTORS *************/
146 /**
147 * Class constructor: creates a new empty (abstract) taxon.
148 *
149 * @see #TaxonBase(TaxonNameBase, Reference)
150 */
151 protected TaxonBase(){
152 super();
153 }
154
155 /**
156 * Class constructor: creates a new (abstract) taxon with the
157 * {@link eu.etaxonomy.cdm.model.name.TaxonNameBase taxon name} used and the {@link eu.etaxonomy.cdm.model.reference.Reference reference}
158 * using it.
159 *
160 * @param taxonNameBase the taxon name used
161 * @param sec the reference using the taxon name
162 * @see #TaxonBase()
163 */
164 protected TaxonBase(TaxonNameBase taxonNameBase, Reference sec){
165 super();
166 if (taxonNameBase != null){
167 this.invokeSetMethod(methodTaxonNameAddTaxonBase, taxonNameBase);
168 }
169 this.setSec(sec);
170 }
171
172 //********* METHODS **************************************/
173
174 /**
175 * Generates and returns the string with the full scientific name (including
176 * authorship) of the {@link eu.etaxonomy.cdm.model.name.TaxonNameBase taxon name} used in <i>this</i>
177 * (abstract) taxon as well as the title of the {@link eu.etaxonomy.cdm.model.reference.Reference reference} using
178 * this taxon name. This string may be stored in the inherited
179 * {@link eu.etaxonomy.cdm.model.common.IdentifiableEntity#getTitleCache() titleCache} attribute.
180 * This method overrides the generic and inherited generateTitle() method
181 * from {@link eu.etaxonomy.cdm.model.common.IdentifiableEntity IdentifiableEntity}.
182 *
183 * @return the string with the full scientific name of the taxon name
184 * and with the title of the reference involved in <i>this</i> (abstract) taxon
185 * @see eu.etaxonomy.cdm.model.common.IdentifiableEntity#generateTitle()
186 * @see eu.etaxonomy.cdm.model.common.IdentifiableEntity#getTitleCache()
187 */
188 // @Override
189 // public String generateTitle() {
190 // String title;
191 // if (name != null && name.getTitleCache() != null){
192 // title = name.getTitleCache() + " sec. ";
193 // if (sec != null){
194 // title += sec.getTitleCache();
195 // }else{
196 // title += "???";
197 // }
198 // }else{
199 // title = this.toString();
200 // }
201 // return title;
202 // }
203
204 /**
205 * Returns the {@link TaxonNameBase taxon name} used in <i>this</i> (abstract) taxon.
206 */
207 public TaxonNameBase getName(){
208 return this.name;
209 }
210
211 /*
212 * @see #getName
213 */
214 public void setName(TaxonNameBase name) {
215 if (this.name != null){
216 this.name.getTaxonBases().remove(this);
217 }
218 if(name != null) {
219 name.getTaxonBases().add(this);
220 }
221 this.name = name;
222 }
223
224 /**
225 * Returns the {@link eu.etaxonomy.cdm.model.name.HomotypicalGroup homotypical group} of the
226 * {@link eu.etaxonomy.cdm.model.name.TaxonNameBase taxon name} used in <i>this</i> (abstract) taxon.
227 */
228 @Transient
229 public HomotypicalGroup getHomotypicGroup(){
230 if (this.getName() == null){
231 return null;
232 }else{
233 return this.getName().getHomotypicalGroup();
234 }
235 }
236
237 /**
238 * Returns the boolean value indicating whether the assignment of <i>this</i>
239 * (abstract) taxon to the {@link Taxon Taxon} or to the {@link Synonym Synonym} class
240 * is definitive (false) or not (true). If this flag is set the use of <i>this</i> (abstract)
241 * taxon as an "accepted/correct" name or as a (junior) "synonym" might
242 * still change in the course of taxonomical working process.
243 */
244 public boolean isDoubtful(){
245 return this.doubtful;
246 }
247 /**
248 * @see #isDoubtful()
249 */
250 public void setDoubtful(boolean doubtful){
251 this.doubtful = doubtful;
252 }
253
254
255 /**
256 * Returns the boolean value indicating if this taxon should be withheld (<code>publish=false</code>) or not
257 * (<code>publish=true</code>) during any publication process to the general public.
258 * This publish flag implementation is preliminary and may be replaced by a more general
259 * implementation of READ rights in future.<BR>
260 * The default value is <code>true</code>.
261 */
262 @Override
263 public boolean isPublish() {
264 return publish;
265 }
266
267 @Override
268 public void setPublish(boolean publish) {
269 this.publish = publish;
270 }
271
272 /**
273 * Returns the {@link eu.etaxonomy.cdm.model.reference.Reference reference} of <i>this</i> (abstract) taxon.
274 * This is the reference or the treatment using the {@link TaxonNameBase taxon name}
275 * in <i>this</i> (abstract) taxon.
276 */
277 public Reference getSec() {
278 return sec;
279 }
280
281 /**
282 * @see #getSec()
283 */
284 public void setSec(Reference sec) {
285 this.sec = sec;
286 }
287
288
289
290 /**
291 * An appended phrase is a phrase that is added to the {@link eu.etaxonomy.cdm.model.name.TaxonNameBase taxon name}
292 * 's title cache to be used just in this taxon. E.g. the phrase "sensu latu" may be added
293 * to the name to describe this taxon more precisely.
294 * If {@link #isUseNameCache()}
295 * @return the appendedPhrase
296 */
297 public String getAppendedPhrase() {
298 return appendedPhrase;
299 }
300
301 /**
302 * @param appendedPhrase the appendedPhrase to set
303 */
304 public void setAppendedPhrase(String appendedPhrase) {
305 this.appendedPhrase = appendedPhrase;
306 }
307
308 /**
309 * @return the useNameCache
310 */
311 public boolean isUseNameCache() {
312 return useNameCache;
313 }
314
315 /**
316 * @param useNameCache the useNameCache to set
317 */
318 public void setUseNameCache(boolean useNameCache) {
319 this.useNameCache = useNameCache;
320 }
321
322 @Transient
323 public abstract boolean isOrphaned();
324 //*********************** CLONE ********************************************************/
325
326 /**
327 * Clones <i>this</i> taxon. This is a shortcut that enables to create
328 * a new instance with empty taxon name and sec reference.
329 *
330 * @see eu.etaxonomy.cdm.model.media.IdentifiableEntity#clone()
331 * @see java.lang.Object#clone()
332 */
333 @Override
334 public Object clone() {
335 TaxonBase result;
336 try {
337 result = (TaxonBase)super.clone();
338 result.setSec(null);
339
340 return result;
341 } catch (CloneNotSupportedException e) {
342 logger.warn("Object does not implement cloneable");
343 e.printStackTrace();
344 return null;
345 }
346
347
348 }
349
350
351 }