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
|
* @since 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<>();
|
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
|
}
|