Merge branch 'hotfix/3.12.4' into develop
[cdmlib.git] / cdmlib-model / src / main / java / eu / etaxonomy / cdm / model / molecular / AmplificationResult.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 package eu.etaxonomy.cdm.model.molecular;
10
11 import java.util.HashSet;
12 import java.util.Set;
13
14 import javax.persistence.Column;
15 import javax.persistence.Entity;
16 import javax.persistence.FetchType;
17 import javax.persistence.ManyToOne;
18 import javax.persistence.OneToMany;
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.XmlElementWrapper;
24 import javax.xml.bind.annotation.XmlIDREF;
25 import javax.xml.bind.annotation.XmlRootElement;
26 import javax.xml.bind.annotation.XmlSchemaType;
27 import javax.xml.bind.annotation.XmlType;
28
29 import org.apache.log4j.Logger;
30 import org.hibernate.annotations.Cascade;
31 import org.hibernate.annotations.CascadeType;
32 import org.hibernate.envers.Audited;
33 import org.hibernate.search.annotations.Field;
34 import org.hibernate.search.annotations.IndexedEmbedded;
35
36 import eu.etaxonomy.cdm.model.common.AnnotatableEntity;
37 import eu.etaxonomy.cdm.model.common.DefinedTerm;
38 import eu.etaxonomy.cdm.model.common.EventBase;
39 import eu.etaxonomy.cdm.model.common.TermType;
40 import eu.etaxonomy.cdm.model.media.Media;
41 import eu.etaxonomy.cdm.model.occurrence.DerivedUnit;
42
43 /**
44 * The physical process of amplification (also called PCR) extracts and replicates parts of the DNA of
45 * a given {@link #getDnaSample() DNA Sample} . The part of the DNA being replicated is defined by the
46 * {@link Amplification#getDnaMarker() marker} (also called locus) - implemented in CDM as a {@link DefinedTerm}
47 * of term type {@link TermType#DnaMarker}.
48 *
49 * <BR>
50 * To execute the replication {@link Primer primers} (short DNA fractions) are
51 * used. They may work in both directions of the DNA part therefore we do have a
52 * {@link #getForwardPrimer() forward primer} and a {@link #getReversePrimer() reverse primer}.
53 * Most (or all?) amplifications require a {@link #getPurification() purification process}. Additionally
54 * some use {@link #getCloning()} for replication.
55 *
56 * <H3>Quality control</H3>
57 * <BR>
58 * For quality control the resulting product (PCR) is tested using a chromatographic method called
59 * electrophoresis. The parameters (voltage, ladder used, running time, and gel concentration) used
60 * for this electrophoresis as well as the resulting
61 * {@link #getGelPhoto() photo} are also relevant for an amplification.
62 *
63 * We have 2 classes to store the core data for an amplification: {@link Amplification} and {@link AmplificationResult}.
64 * <BR>
65 * In {@link Amplification} we store all data that is equal for an amplification event which includes amplification
66 * of many {@link DnaSample dna samples}. Those data which are relevant only for a specific dna sample are
67 * stored in {@link AmplificationResult}. Theoretically this includes data on the resulting PCR. However, as the
68 * PCR itself is not persistent we do not store further information on it in the CDM and do not handle
69 * {@link AmplificationResult} as a {@link DerivedUnit}.
70 * <BR>
71 * This may change in future: http://dev.e-taxonomy.eu/trac/ticket/3717.
72 * <BR>
73 *
74 * @author a.mueller
75 * @created 2013-07-05
76 *
77 * @see Amplification
78 */
79 @XmlAccessorType(XmlAccessType.FIELD)
80 @XmlType(name = "AmplificationResult", propOrder = {
81 "dnaSample",
82 "amplification",
83 "cloning",
84 "successful",
85 "successText",
86 "gelPhoto",
87 "singleReads"
88 })
89 @XmlRootElement(name = "AmplificationResult")
90 @Entity
91 @Audited
92 public class AmplificationResult extends AnnotatableEntity implements Cloneable{
93 private static final long serialVersionUID = -8614860617229484621L;
94 private static final Logger logger = Logger.getLogger(AmplificationResult.class);
95
96
97 /** @see #getDnaSample() */
98 @XmlElement( name = "DnaSample")
99 @XmlIDREF
100 @XmlSchemaType(name = "IDREF")
101 @ManyToOne(fetch = FetchType.LAZY)
102 @IndexedEmbedded
103 private DnaSample dnaSample;
104
105 /** @see #getAmplification() */
106 @XmlElement( name = "Amplification")
107 @XmlIDREF
108 @XmlSchemaType(name = "IDREF")
109 @ManyToOne(fetch = FetchType.LAZY)
110 @Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE})
111 @IndexedEmbedded
112 private Amplification amplification;
113
114 @XmlElementWrapper(name = "SingleReads")
115 @XmlElement(name = "SingleRead")
116 @XmlIDREF
117 @XmlSchemaType(name = "IDREF")
118 @OneToMany(mappedBy="amplificationResult" , fetch = FetchType.LAZY)
119 @Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE})
120 private Set<SingleRead> singleReads = new HashSet<SingleRead>();
121
122 @XmlElement(name = "Cloning")
123 @XmlIDREF
124 @XmlSchemaType(name = "IDREF")
125 @ManyToOne(fetch=FetchType.LAZY)
126 @Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE})
127 private Cloning cloning;
128
129 /** @see #getSuccessful() */
130 @XmlAttribute(name = "successful")
131 private Boolean successful;
132
133 /** @see #getSuccessText() */
134 @XmlElement(name = "successText")
135 @Field
136 @Column(length=255)
137 private String successText;
138 //
139 // /** @see #getGelRunningTime() */
140 // @XmlElement(name = "gelRunningTime")
141 // @Field(analyze = Analyze.NO)
142 // @NumericField
143 // private Double gelRunningTime;
144
145 @XmlElement(name = "GelPhoto")
146 @XmlIDREF
147 @XmlSchemaType(name = "IDREF")
148 @ManyToOne(fetch=FetchType.LAZY)
149 @Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE})
150 private Media gelPhoto;
151
152
153 // ********************* FACTORY METHODS ************************/
154
155 public static AmplificationResult NewInstance(DnaSample dnaSample){
156 AmplificationResult result = new AmplificationResult();
157 dnaSample.addAmplificationResult(result);
158 return result;
159 }
160
161 public static AmplificationResult NewInstance(SingleRead singleRead){
162 AmplificationResult result = new AmplificationResult();
163 result.addSingleRead(singleRead);
164 return result;
165 }
166
167 public static AmplificationResult NewInstance(DnaSample dnaSample,
168 Amplification amplification) {
169 AmplificationResult result = new AmplificationResult();
170 dnaSample.addAmplificationResult(result);
171 result.setAmplification(amplification);
172 return result;
173 }
174
175 public static AmplificationResult NewInstance(){
176 return new AmplificationResult();
177 }
178
179
180 // ******************* CONSTRUCTOR *******************************/
181
182 protected AmplificationResult(){}
183
184
185 //********************* GETTER / SETTER ************/
186
187
188 /**
189 * The {@link DnaSample dna sample} which is the input for this {@link AmplificationResult amplification}.
190 */
191 public DnaSample getDnaSample() {
192 return dnaSample;
193 }
194
195 /**
196 * For use by DnaSample.addAmplification(ampl.) only. For now.
197 * @see #getDnaSample()
198 */
199 protected void setDnaSample(DnaSample dnaSample) {
200 this.dnaSample = dnaSample;
201 }
202
203 /**
204 * The {@link Amplification amplification event} this amplification result resulted from.
205 * @see #setAmplification(Amplification)
206 * @see Amplification
207 * @return the amplification event
208 */
209 public Amplification getAmplification() {
210 return amplification;
211 }
212 /**
213 * {@link #getAmplification()}
214 * @param amplification
215 */
216 public void setAmplification(Amplification amplification) {
217 this.amplification = amplification;
218 }
219
220 /**
221 * The {@link SingleRead single sequences} created by using this amplification's result (PCR).
222 */
223 public Set<SingleRead> getSingleReads() {
224 return singleReads;
225 }
226
227 public void addSingleRead(SingleRead singleRead){
228 if (singleRead.getAmplificationResult() != null){
229 singleRead.getAmplificationResult().singleReads.remove(singleRead);
230 }
231 this.singleReads.add(singleRead);
232 singleRead.setAmplificationResult(this);
233 }
234
235 public void removeSingleRead(SingleRead singleRead){
236 if(this.singleReads.contains(singleRead)){
237 this.singleReads.remove(singleRead);
238 singleRead.setAmplificationResult(null);
239 }
240 }
241
242 /**
243 * @see #getSingleReads()
244 */
245 //TODO private until it is clear how bidirectionality is handled
246 @SuppressWarnings("unused")
247 private void setSingleReads(Set<SingleRead> singleReads) {
248 this.singleReads = singleReads;
249 }
250
251 /**
252 * Information if this amplification was successful or not. Success may be defined
253 * by the results of the electrophoresis.
254 *
255 * @see #getSuccessText()
256 */
257 public Boolean getSuccessful() {
258 return successful;
259 }
260
261 /**
262 * @see #getSuccessful()
263 * @see #getSuccessText()
264 */
265 public void setSuccessful(Boolean successful) {
266 this.successful = successful;
267 }
268
269 /**
270 * Freetext about the success of this amplification explaining
271 * in detail why it is concidered to be successful/unsucessful
272 *
273 * @see #getSuccessful()
274 */
275 public String getSuccessText() {
276 return successText;
277 }
278
279 /**
280 * @see #getSuccessText()
281 * @see #getSuccessful()
282 */
283 public void setSuccessText(String successText) {
284 this.successText = successText;
285 }
286
287 /**
288 * The {@link Cloning cloning process} involved in this amplification.
289 */
290 public Cloning getCloning() {
291 return cloning;
292 }
293
294 /**
295 * @see #getCloning()
296 */
297 public void setCloning(Cloning cloning) {
298 this.cloning = cloning;
299 }
300 //
301 // /**
302 // * The time for running the electrophoresis quality check.
303 // * Base unit is minutes [min].
304 // */
305 // public Double getGelRunningTime() {
306 // return gelRunningTime;
307 // }
308 //
309 // /**
310 // * @see #getGelRunningTime()
311 // */
312 // public void setGelRunningTime(Double gelRunningTime) {
313 // this.gelRunningTime = gelRunningTime;
314 // }
315
316
317 /**
318 * The photo taken from the electrophoresis result showing the quality of the amplification.
319 * Gelphotos often do show multiple electrophoresis results. One may either cut or mark
320 * the part of the photo that displays <code>this</code> amplification. However, this may make
321 * the concrete media file unusable for other amplifications also represented by the same image.
322 * @see #getElectrophoresisVoltage()
323 * @see #getLadderUsed()
324 * @see #getGelConcentration()
325 * @see #getGelRunningTime()
326 */
327 public Media getGelPhoto() {
328 return gelPhoto;
329 }
330
331
332 /**
333 * @param gelPhoto the gelPhoto to set
334 */
335 public void setGelPhoto(Media gelPhoto) {
336 this.gelPhoto = gelPhoto;
337 }
338
339
340 // ********************** CLONE ***********************************/
341 /**
342 * Clones <i>this</i> amplification. This is a shortcut that enables to create
343 * a new instance that differs only slightly from <i>this</i> amplification by
344 * modifying only some of the attributes.<BR><BR>
345 *
346 *
347 * @see EventBase#clone()
348 * @see java.lang.Object#clone()
349 */
350 @Override
351 public Object clone() {
352 try{
353 AmplificationResult result = (AmplificationResult)super.clone();
354
355 result.singleReads = new HashSet<SingleRead>();
356 for (SingleRead seq: this.singleReads){
357 result.singleReads.add(seq);
358
359 }
360
361 //don't change dnaSample, marker, successful, successText, forwardPrimer,
362 //reversePrimer, purifiaction, cloning, ladderUsed, electrophoresisVoltage,
363 //gelRunningTime, gelPhoto, gelConcentration
364 return result;
365 }catch (CloneNotSupportedException e) {
366 logger.warn("Object does not implement cloneable");
367 e.printStackTrace();
368 return null;
369 }
370 }
371
372 }