- added cascade saving to PreservationMethod of DerivedUnit
[cdmlib.git] / cdmlib-model / src / main / java / eu / etaxonomy / cdm / model / occurrence / DerivedUnit.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.occurrence;
11
12 import java.util.HashSet;
13 import java.util.Set;
14
15 import javax.persistence.Entity;
16 import javax.persistence.FetchType;
17 import javax.persistence.ManyToOne;
18 import javax.persistence.OneToMany;
19 import javax.persistence.Transient;
20 import javax.validation.constraints.Size;
21 import javax.xml.bind.annotation.XmlAccessType;
22 import javax.xml.bind.annotation.XmlAccessorType;
23 import javax.xml.bind.annotation.XmlElement;
24 import javax.xml.bind.annotation.XmlElementWrapper;
25 import javax.xml.bind.annotation.XmlIDREF;
26 import javax.xml.bind.annotation.XmlRootElement;
27 import javax.xml.bind.annotation.XmlSchemaType;
28 import javax.xml.bind.annotation.XmlType;
29
30 import org.apache.log4j.Logger;
31 import org.hibernate.annotations.Cascade;
32 import org.hibernate.annotations.CascadeType;
33 import org.hibernate.envers.Audited;
34 import org.hibernate.search.annotations.Analyze;
35 import org.hibernate.search.annotations.Field;
36 import org.hibernate.search.annotations.Indexed;
37 import org.hibernate.search.annotations.IndexedEmbedded;
38 import org.hibernate.validator.constraints.Length;
39
40 import eu.etaxonomy.cdm.model.molecular.DnaSample;
41 import eu.etaxonomy.cdm.model.name.SpecimenTypeDesignation;
42 import eu.etaxonomy.cdm.model.name.TaxonNameBase;
43 import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
44
45 /**
46 * A derived unit is regarded as derived from a field unit,
47 * so locality and gathering related information is captured as a separate FieldUnit object
48 * related to a specimen via a derivation event
49 *
50 * http://www.bgbm.org/biodivinf/docs/CollectionModel/ReprintTNR.pdf
51 * http://www.bgbm.org/biodivinf/docs/CollectionModel/
52 * <BR>
53 * Type figures are derived units with at least a figure object in media
54 *
55 * @author m.doering
56 * @created 08-Nov-2007 13:06:52
57 *
58 */
59 @XmlAccessorType(XmlAccessType.FIELD)
60 @XmlType(name = "DerivedUnit", propOrder = {
61 "collection",
62 "catalogNumber",
63 "storedUnder",
64 "derivedFrom",
65 "accessionNumber",
66 "collectorsNumber",
67 "barcode",
68 "preservation",
69 "exsiccatum",
70 "specimenTypeDesignations"
71 })
72 @XmlRootElement(name = "DerivedUnit")
73 @Entity
74 @Audited
75 // even if hibernate complains "Abstract classes can never insert index documents. Remove @Indexed."
76 // this is needed, otherwise the fields of the also abstract super class are missed during indexing
77 @Indexed(index = "eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase")
78 public class DerivedUnit extends SpecimenOrObservationBase<IIdentifiableEntityCacheStrategy> implements Cloneable{
79 private static final long serialVersionUID = -3525746216270843517L;
80
81 private static final Logger logger = Logger.getLogger(DnaSample.class);
82
83 @XmlElement(name = "Collection")
84 @XmlIDREF
85 @XmlSchemaType(name = "IDREF")
86 @ManyToOne(fetch = FetchType.LAZY)
87 @Cascade(CascadeType.SAVE_UPDATE)
88 @IndexedEmbedded
89 private Collection collection;
90
91 @XmlElement(name = "CatalogNumber")
92 @Field(analyze = Analyze.NO)
93 //TODO Val #3379
94 // @NullOrNotEmpty
95 @Length(max = 255)
96 private String catalogNumber;
97
98 @XmlElement(name = "AccessionNumber")
99 @Field(analyze = Analyze.NO)
100 //TODO Val #3379
101 // @NullOrNotEmpty
102 @Length(max = 255)
103 private String accessionNumber;
104
105 @XmlElement(name = "CollectorsNumber")
106 @Field(analyze = Analyze.NO)
107 //TODO Val #3379
108 // @NullOrNotEmpty
109 @Length(max = 255)
110 private String collectorsNumber;
111
112 @XmlElement(name = "Barcode")
113 @Field(analyze = Analyze.NO)
114 //TODO Val #3379
115 // @NullOrNotEmpty
116 @Length(max = 255)
117 private String barcode;
118
119 @XmlElement(name = "StoredUnder")
120 @XmlIDREF
121 @XmlSchemaType(name = "IDREF")
122 @ManyToOne(fetch = FetchType.LAZY)
123 @Cascade(CascadeType.SAVE_UPDATE)
124 @IndexedEmbedded
125 private TaxonNameBase storedUnder;
126
127 @XmlElement(name = "DerivedFrom")
128 @XmlIDREF
129 @XmlSchemaType(name = "IDREF")
130 @ManyToOne(fetch = FetchType.LAZY)
131 @Cascade(CascadeType.SAVE_UPDATE)
132 @IndexedEmbedded(depth = 4)
133 private DerivationEvent derivedFrom;
134
135 @XmlElementWrapper(name = "SpecimenTypeDesignations")
136 @XmlElement(name = "SpecimenTypeDesignation")
137 @OneToMany(fetch = FetchType.LAZY, mappedBy = "typeSpecimen")
138 @Cascade({ CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE })
139 private final Set<SpecimenTypeDesignation> specimenTypeDesignations = new HashSet<SpecimenTypeDesignation>();
140
141
142 //*** attributes valid only for preserved specimen (PreservedSpecimen, Fossil, DnaSample)
143
144 @XmlElement(name = "Preservation")
145 @XmlIDREF
146 @XmlSchemaType(name = "IDREF")
147 @ManyToOne(fetch = FetchType.LAZY)
148 @Cascade(CascadeType.SAVE_UPDATE)
149 private PreservationMethod preservation;
150
151
152 @XmlElement(name = "Exsiccatum")
153 //TODO Val #3379
154 // @NullOrNotEmpty
155 @Field
156 @Size(max = 255)
157 private String exsiccatum;
158
159 // ******************** FACTORY METHOD **********************************/
160
161
162 public static DerivedUnit NewInstance(SpecimenOrObservationType type) {
163 return new DerivedUnit(type);
164 }
165
166 /**
167 * Factory method
168 * @return
169 */
170 public static DerivedUnit NewPreservedSpecimenInstance(){
171 DerivedUnit result = new DerivedUnit(SpecimenOrObservationType.PreservedSpecimen);
172 return result;
173 }
174
175 //************************** CONSTRUCTOR *********************************/
176
177 //Constructor: For hibernate use only
178 protected DerivedUnit() {super();}
179
180
181 /**
182 * Constructor
183 * @param recordBasis
184 */
185 protected DerivedUnit(SpecimenOrObservationType recordBasis) {
186 super(recordBasis);
187 }
188
189
190 /**
191 * Create new unit derived from an existing field unit
192 * @param fieldUnit existing field unit from where this unit is derived
193 */
194 protected DerivedUnit(SpecimenOrObservationType recordBasis, FieldUnit fieldUnit) {
195 super(recordBasis);
196 DerivationEvent derivedFrom = new DerivationEvent();
197 // TODO: should be done in a more controlled way. Probably by making derivation event implement a general relationship interface (for bidirectional add/remove etc)
198 fieldUnit.addDerivationEvent(derivedFrom);
199 derivedFrom.getOriginals().add(fieldUnit);
200 derivedFrom.getDerivatives().add(this);
201 this.setDerivedFrom(derivedFrom);
202 }
203
204 /**
205 * create new unit derived from an existing gathering event,
206 * thereby creating a new empty field unit
207 * @param gatheringEvent the gathering event this unit was collected at
208 */
209 protected DerivedUnit(SpecimenOrObservationType recordBasis, GatheringEvent gatheringEvent) {
210 this(recordBasis, new FieldUnit());
211 FieldUnit field = (FieldUnit)this.getOriginalUnit();
212 field.setGatheringEvent(gatheringEvent);
213 }
214
215 // ******************** GETTER / SETTER *************************************/
216
217 public DerivationEvent getDerivedFrom() {
218 return derivedFrom;
219 }
220
221 public void setDerivedFrom(DerivationEvent derivedFrom){
222 if (getDerivedFrom() != null){
223 getDerivedFrom().getDerivatives().remove(derivedFrom);
224 }
225 this.derivedFrom = derivedFrom;
226 if (derivedFrom != null){
227 derivedFrom.addDerivative(this);
228 }
229 }
230
231 @Transient
232 public Set<SpecimenOrObservationBase> getOriginals(){
233 if(getDerivedFrom() != null){
234 return getDerivedFrom().getOriginals();
235 }
236 return null;
237 }
238
239 public Collection getCollection(){
240 return this.collection;
241 }
242
243 public void setCollection(Collection collection){
244 this.collection = collection;
245 }
246
247
248 public String getCatalogNumber() {
249 return catalogNumber;
250 }
251
252 public void setCatalogNumber(String catalogNumber) {
253 this.catalogNumber = catalogNumber;
254 }
255
256 public void setBarcode(String barcode) {
257 this.barcode = barcode;
258 }
259 public String getBarcode() {
260 return barcode;
261 }
262
263 public void setStoredUnder(TaxonNameBase storedUnder) {
264 this.storedUnder = storedUnder;
265 }
266
267 public String getAccessionNumber() {
268 return accessionNumber;
269 }
270
271
272 public void setAccessionNumber(String accessionNumber) {
273 this.accessionNumber = accessionNumber;
274 }
275
276 /**
277 * Will be removed in future versions as semantics is not clear.
278 * For accessing the collecting number use
279 * {@link FieldUnit#getFieldNumber()} instead.
280 * @return
281 */
282 @Deprecated
283 public String getCollectorsNumber() {
284 return collectorsNumber;
285 }
286
287 /**
288 * Will be removed in future versions as semantics is not clear.
289 * For editing the collecting number use
290 * {@link FieldUnit#getFieldNumber()} instead.
291 * @return
292 */
293 @Deprecated
294 public void setCollectorsNumber(String collectorsNumber) {
295 this.collectorsNumber = collectorsNumber;
296 }
297
298 public TaxonNameBase getStoredUnder() {
299 return storedUnder;
300 }
301
302 public void addSpecimenTypeDesignation(SpecimenTypeDesignation specimenTypeDesignation){
303 if (specimenTypeDesignation.getTypeSpecimen() == this){
304 return ;
305 }else if (specimenTypeDesignation.getTypeSpecimen() != null){
306 specimenTypeDesignation.getTypeSpecimen().removeSpecimenTypeDesignation(specimenTypeDesignation);
307
308 }
309 specimenTypeDesignations.add(specimenTypeDesignation);
310 specimenTypeDesignation.setTypeSpecimen(this);
311 }
312
313 public void removeSpecimenTypeDesignation(SpecimenTypeDesignation specimenTypeDesignation){
314 if (specimenTypeDesignation == null){
315 return;
316 }
317 if (specimenTypeDesignations.contains(specimenTypeDesignation)){
318 specimenTypeDesignations.remove(specimenTypeDesignation);
319 specimenTypeDesignation.setTypeSpecimen(null);
320 }
321 }
322
323 // ******* GETTER / SETTER for preserved specimen only ******************/
324
325 public Set<SpecimenTypeDesignation> getSpecimenTypeDesignations(){
326 return specimenTypeDesignations;
327 }
328
329 public PreservationMethod getPreservation(){
330 return this.preservation;
331 }
332
333 public void setPreservation(PreservationMethod preservation){
334 this.preservation = preservation;
335 }
336
337
338 public void setExsiccatum(String exsiccatum) {
339 this.exsiccatum = exsiccatum;
340 }
341
342 public String getExsiccatum() {
343 return exsiccatum;
344 }
345
346 //*********** CLONE **********************************/
347
348 /**
349 * Clones <i>this</i> derivedUnit. This is a shortcut that enables to
350 * create a new instance that differs only slightly from <i>this</i> specimen
351 * by modifying only some of the attributes.<BR>
352 * This method overrides the clone method from {@link SpecimenOrObservationBase SpecimenOrObservationBase}.
353 *
354 * @see SpecimenOrObservationBase#clone()
355 * @see eu.etaxonomy.cdm.model.media.IdentifiableMediaEntity#clone()
356 * @see java.lang.Object#clone()
357 */
358 @Override
359 public Object clone() {
360 try{
361 DerivedUnit result = (DerivedUnit)super.clone();
362 //collection
363 result.setCollection(this.collection);
364 //derivedFrom
365 result.setDerivedFrom(this.derivedFrom);
366 //storedUnder
367 result.setStoredUnder(this.storedUnder);
368 //preservation
369 result.setPreservation(this.preservation);
370 //no changes to: accessionNumber, catalogNumber, collectorsNumber
371 return result;
372 } catch (CloneNotSupportedException e) {
373 logger.warn("Object does not implement cloneable");
374 e.printStackTrace();
375 return null;
376 }
377 }
378
379
380 }