1
|
/**
|
2
|
* Copyright (C) 2015 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.api.service.dto;
|
10
|
|
11
|
import java.util.ArrayList;
|
12
|
import java.util.Collection;
|
13
|
import java.util.Collections;
|
14
|
import java.util.EnumSet;
|
15
|
import java.util.HashMap;
|
16
|
import java.util.HashSet;
|
17
|
import java.util.List;
|
18
|
import java.util.Map;
|
19
|
import java.util.Set;
|
20
|
import java.util.regex.Pattern;
|
21
|
|
22
|
import eu.etaxonomy.cdm.common.CdmUtils;
|
23
|
import eu.etaxonomy.cdm.common.URI;
|
24
|
import eu.etaxonomy.cdm.format.CdmFormatterFactory;
|
25
|
import eu.etaxonomy.cdm.format.ICdmFormatter.FormatKey;
|
26
|
import eu.etaxonomy.cdm.format.description.DefaultCategoricalDescriptionBuilder;
|
27
|
import eu.etaxonomy.cdm.format.description.DefaultQuantitativeDescriptionBuilder;
|
28
|
import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
|
29
|
import eu.etaxonomy.cdm.model.common.Language;
|
30
|
import eu.etaxonomy.cdm.model.description.CategoricalData;
|
31
|
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
|
32
|
import eu.etaxonomy.cdm.model.description.QuantitativeData;
|
33
|
import eu.etaxonomy.cdm.model.media.Media;
|
34
|
import eu.etaxonomy.cdm.model.name.SpecimenTypeDesignation;
|
35
|
import eu.etaxonomy.cdm.model.name.TaxonName;
|
36
|
import eu.etaxonomy.cdm.model.name.TypeDesignationStatusBase;
|
37
|
import eu.etaxonomy.cdm.model.occurrence.DerivedUnit;
|
38
|
import eu.etaxonomy.cdm.model.occurrence.MediaSpecimen;
|
39
|
import eu.etaxonomy.cdm.model.occurrence.OccurrenceStatus;
|
40
|
import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
|
41
|
import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationType;
|
42
|
import eu.etaxonomy.cdm.model.taxon.Taxon;
|
43
|
import eu.etaxonomy.cdm.ref.TypedEntityReference;
|
44
|
|
45
|
/**
|
46
|
* @author pplitzner
|
47
|
* @since Mar 26, 2015
|
48
|
*/
|
49
|
public class DerivedUnitDTO extends SpecimenOrObservationBaseDTO{
|
50
|
|
51
|
private static final long serialVersionUID = 2345864166579381295L;
|
52
|
|
53
|
private String accessionNumber;
|
54
|
private String specimenShortTitle;
|
55
|
private TypedEntityReference<TaxonName> storedUnder;
|
56
|
private URI preferredStableUri;
|
57
|
|
58
|
private List<TypedEntityReference<Taxon>> associatedTaxa;
|
59
|
private Map<String, List<String>> types;
|
60
|
|
61
|
private String originalLabelInfo;
|
62
|
private String exsiccatum;
|
63
|
private String mostSignificantIdentifier;
|
64
|
|
65
|
private CollectionDTO collection;
|
66
|
|
67
|
private String catalogNumber;
|
68
|
|
69
|
private String barcode;
|
70
|
|
71
|
private String preservationMethod;
|
72
|
private List<DerivedUnitStatusDto> status;
|
73
|
|
74
|
/**
|
75
|
* Constructs a new DerivedUnitDTO. All derivatives of the passed <code>DerivedUnit entity</code> will be collected and
|
76
|
* added as DerivedUnitDTO to the {@link SpecimenOrObservationBaseDTO#getDerivatives() derivative DTOs}.
|
77
|
*
|
78
|
* @param entity
|
79
|
* The entity to create the dto for
|
80
|
*
|
81
|
* @return <code>null</code> or the new DerivedUnitDTO
|
82
|
*/
|
83
|
public static DerivedUnitDTO fromEntity(DerivedUnit entity){
|
84
|
return fromEntity(entity, null, null);
|
85
|
}
|
86
|
|
87
|
/**
|
88
|
* Constructs a new DerivedUnitDTO. All derivatives of the passed <code>DerivedUnit entity</code> will be collected and
|
89
|
* added as DerivedUnitDTO to the {@link SpecimenOrObservationBaseDTO#getDerivatives() derivative DTOs}.
|
90
|
*
|
91
|
* @param entity
|
92
|
* The entity to create the dto for
|
93
|
* @param maxDepth
|
94
|
* The maximum number of derivation events levels up to which derivatives are to be collected.
|
95
|
* <code>NULL</code> means infinitely.
|
96
|
* @param specimenOrObservationTypeFilter
|
97
|
* Set of SpecimenOrObservationType to be included into the collection of {@link #getDerivatives() derivative DTOs}
|
98
|
* @return
|
99
|
* The DTO
|
100
|
*/
|
101
|
@SuppressWarnings("rawtypes")
|
102
|
public static DerivedUnitDTO fromEntity(DerivedUnit entity, Integer maxDepth,
|
103
|
EnumSet<SpecimenOrObservationType> specimenOrObservationTypeFilter){
|
104
|
|
105
|
if(entity == null) {
|
106
|
return null;
|
107
|
}
|
108
|
DerivedUnitDTO dto = new DerivedUnitDTO(entity);
|
109
|
|
110
|
// ---- assemble derivation tree summary
|
111
|
// this data should be sufficient in clients for showing the unit in a list view
|
112
|
dto.setDerivationTreeSummary(DerivationTreeSummaryDTO.fromEntity(entity, dto.getSpecimenShortTitle()));
|
113
|
|
114
|
// ---- assemble derivatives
|
115
|
// this data is is often only required for clients in order to show the details of the derivation tree
|
116
|
dto.addAllDerivatives(dto.assembleDerivatives(entity, maxDepth, specimenOrObservationTypeFilter));
|
117
|
|
118
|
// ---- annotations
|
119
|
dto.collectOriginals(entity, new HashSet<SpecimenOrObservationBase>())
|
120
|
.forEach(o -> o.getAnnotations()
|
121
|
.forEach(a -> dto.addAnnotation(AnnotationDTO.fromEntity(a))
|
122
|
)
|
123
|
);
|
124
|
|
125
|
return dto;
|
126
|
}
|
127
|
|
128
|
/**
|
129
|
* Collects all originals from the given <code>entity</code> to the root of the
|
130
|
* derivation graph including the <code>entity</code> itself.
|
131
|
*
|
132
|
* @param entity
|
133
|
* The DerivedUnit to start the collecting walk
|
134
|
*/
|
135
|
private Set<SpecimenOrObservationBase> collectOriginals(SpecimenOrObservationBase entity, Set<SpecimenOrObservationBase> originalsToRoot) {
|
136
|
originalsToRoot.add(entity);
|
137
|
SpecimenOrObservationBase entityDeproxied = HibernateProxyHelper.deproxy(entity);
|
138
|
if (entityDeproxied instanceof DerivedUnit) {
|
139
|
((DerivedUnit)entityDeproxied).getOriginals().forEach(o -> collectOriginals(o, originalsToRoot));
|
140
|
}
|
141
|
return originalsToRoot;
|
142
|
}
|
143
|
|
144
|
/**
|
145
|
* @param derivedUnit
|
146
|
*/
|
147
|
public DerivedUnitDTO(DerivedUnit derivedUnit) {
|
148
|
super(derivedUnit);
|
149
|
|
150
|
// experimental feature, not yet exposed in method signature
|
151
|
boolean cleanAccessionNumber = false;
|
152
|
accessionNumber = derivedUnit.getAccessionNumber();
|
153
|
preferredStableUri = derivedUnit.getPreferredStableUri();
|
154
|
if (derivedUnit.getCollection() != null){
|
155
|
setCollectioDTO(CollectionDTO.fromCollection(HibernateProxyHelper.deproxy(derivedUnit.getCollection())));
|
156
|
if(cleanAccessionNumber && getCollection().getCode() != null) {
|
157
|
accessionNumber = accessionNumber.replaceFirst("^" + Pattern.quote(getCollection().getCode()) + "-", "");
|
158
|
}
|
159
|
}
|
160
|
setBarcode(derivedUnit.getBarcode());
|
161
|
setCatalogNumber(derivedUnit.getCatalogNumber());
|
162
|
setDerivationEvent(DerivationEventDTO.fromEntity(derivedUnit.getDerivedFrom()));
|
163
|
if (derivedUnit.getPreservation()!= null){
|
164
|
setPreservationMethod(derivedUnit.getPreservation().getMaterialMethodText());
|
165
|
}
|
166
|
setRecordBase(derivedUnit.getRecordBasis());
|
167
|
setSources(derivedUnit.getSources());
|
168
|
setSpecimenTypeDesignations(derivedUnit.getSpecimenTypeDesignations());
|
169
|
|
170
|
// -------------------------------------------------------------
|
171
|
|
172
|
mostSignificantIdentifier = derivedUnit.getMostSignificantIdentifier();
|
173
|
|
174
|
//specimenShortTitle
|
175
|
setSpecimenShortTitle(composeSpecimenShortTitle(derivedUnit));
|
176
|
|
177
|
|
178
|
//preferred stable URI
|
179
|
setPreferredStableUri(derivedUnit.getPreferredStableUri());
|
180
|
|
181
|
// label
|
182
|
setSummaryLabel(derivedUnit.getTitleCache());
|
183
|
|
184
|
// character state data
|
185
|
if(derivedUnit.characterData() != null) {
|
186
|
Collection<DescriptionElementBase> characterDataForSpecimen = derivedUnit.characterData();
|
187
|
for (DescriptionElementBase descriptionElementBase : characterDataForSpecimen) {
|
188
|
String character = descriptionElementBase.getFeature().getLabel();
|
189
|
ArrayList<Language> languages = new ArrayList<>(Collections.singleton(Language.DEFAULT()));
|
190
|
if (descriptionElementBase instanceof QuantitativeData) {
|
191
|
QuantitativeData quantitativeData = (QuantitativeData) descriptionElementBase;
|
192
|
DefaultQuantitativeDescriptionBuilder builder = new DefaultQuantitativeDescriptionBuilder();
|
193
|
String state = builder.build(quantitativeData, languages).getText(Language.DEFAULT());
|
194
|
addCharacterData(character, state);
|
195
|
}
|
196
|
else if(descriptionElementBase instanceof CategoricalData){
|
197
|
CategoricalData categoricalData = (CategoricalData) descriptionElementBase;
|
198
|
DefaultCategoricalDescriptionBuilder builder = new DefaultCategoricalDescriptionBuilder();
|
199
|
String state = builder.build(categoricalData, languages).getText(Language.DEFAULT());
|
200
|
addCharacterData(character, state);
|
201
|
}
|
202
|
}
|
203
|
}
|
204
|
|
205
|
// check type designations
|
206
|
Collection<SpecimenTypeDesignation> specimenTypeDesignations = derivedUnit.getSpecimenTypeDesignations();
|
207
|
for (SpecimenTypeDesignation specimenTypeDesignation : specimenTypeDesignations) {
|
208
|
TypeDesignationStatusBase<?> typeStatus = specimenTypeDesignation.getTypeStatus();
|
209
|
Set<TaxonName> typifiedNames = specimenTypeDesignation.getTypifiedNames();
|
210
|
List<String> typedTaxaNames = new ArrayList<>();
|
211
|
for (TaxonName taxonName : typifiedNames) {
|
212
|
typedTaxaNames.add(taxonName.getTitleCache());
|
213
|
}
|
214
|
addTypes(typeStatus!=null?typeStatus.getLabel():"", typedTaxaNames);
|
215
|
}
|
216
|
Collection<OccurrenceStatus> occurrenceStatus = derivedUnit.getStatus();
|
217
|
|
218
|
if (occurrenceStatus != null && !occurrenceStatus.isEmpty()) {
|
219
|
this.status = new ArrayList<>();
|
220
|
|
221
|
for (OccurrenceStatus specimenStatus : occurrenceStatus) {
|
222
|
DerivedUnitStatusDto dto = new DerivedUnitStatusDto(specimenStatus.getType().getLabel());
|
223
|
dto.setStatusSource(SourceDTO.fromDescriptionElementSource(specimenStatus.getSource()) ) ;
|
224
|
this.status.add(dto);
|
225
|
}
|
226
|
}
|
227
|
this.setDerivationTreeSummary(DerivationTreeSummaryDTO.fromEntity(derivedUnit, this.getSpecimenShortTitle()));
|
228
|
|
229
|
|
230
|
if(derivedUnit.getStoredUnder() != null) {
|
231
|
storedUnder = TypedEntityReference.fromEntity(derivedUnit.getStoredUnder());
|
232
|
}
|
233
|
originalLabelInfo = derivedUnit.getOriginalLabelInfo();
|
234
|
exsiccatum = derivedUnit.getExsiccatum();
|
235
|
|
236
|
}
|
237
|
|
238
|
protected String composeSpecimenShortTitle(DerivedUnit derivedUnit) {
|
239
|
FormatKey collectionKey = FormatKey.COLLECTION_CODE;
|
240
|
String specimenShortTitle = CdmFormatterFactory.format(derivedUnit, collectionKey);
|
241
|
if (CdmUtils.isBlank(specimenShortTitle)) {
|
242
|
collectionKey = FormatKey.COLLECTION_NAME;
|
243
|
}
|
244
|
if(CdmUtils.isNotBlank(derivedUnit.getMostSignificantIdentifier())){
|
245
|
specimenShortTitle = CdmFormatterFactory.format(derivedUnit, new FormatKey[] {
|
246
|
collectionKey,
|
247
|
FormatKey.SPACE,
|
248
|
FormatKey.MOST_SIGNIFICANT_IDENTIFIER
|
249
|
});
|
250
|
if(!specimenShortTitle.isEmpty() && derivedUnit instanceof MediaSpecimen) {
|
251
|
Media media = ((MediaSpecimen)derivedUnit).getMediaSpecimen();
|
252
|
if(media != null && !CdmUtils.isBlank(media.getTitleCache()) ) {
|
253
|
if(media.getTitle() != null && !media.getTitle().getText().isEmpty()) {
|
254
|
specimenShortTitle += " (" + media.getTitle().getText() + ")";
|
255
|
}
|
256
|
}
|
257
|
}
|
258
|
}
|
259
|
if(CdmUtils.isBlank(specimenShortTitle)){
|
260
|
specimenShortTitle = derivedUnit.getTitleCache();
|
261
|
}
|
262
|
if(CdmUtils.isBlank(specimenShortTitle)){ //should not be necessary as titleCache should never be empty
|
263
|
specimenShortTitle = derivedUnit.getUuid().toString();
|
264
|
}
|
265
|
return specimenShortTitle;
|
266
|
}
|
267
|
|
268
|
@Override
|
269
|
protected Set<Media> collectMedia(SpecimenOrObservationBase<?> specimenOrObservation){
|
270
|
Set<Media> collectedMedia = super.collectMedia(specimenOrObservation);
|
271
|
if(specimenOrObservation instanceof MediaSpecimen) {
|
272
|
if(((MediaSpecimen)specimenOrObservation).getMediaSpecimen() != null) {
|
273
|
collectedMedia.add(((MediaSpecimen)specimenOrObservation).getMediaSpecimen());
|
274
|
}
|
275
|
}
|
276
|
return collectedMedia;
|
277
|
}
|
278
|
|
279
|
|
280
|
public String getAccessionNumber() {
|
281
|
return accessionNumber;
|
282
|
}
|
283
|
public void setAccessionNumber(String accessionNumber) {
|
284
|
this.accessionNumber = accessionNumber;
|
285
|
}
|
286
|
|
287
|
public Map<String, List<String>> getTypes() {
|
288
|
return types;
|
289
|
}
|
290
|
public void addTypes(String typeStatus, List<String> typedTaxa){
|
291
|
if(types==null){
|
292
|
types = new HashMap<>();
|
293
|
}
|
294
|
types.put(typeStatus, typedTaxa);
|
295
|
}
|
296
|
|
297
|
public List<TypedEntityReference<Taxon>> getAssociatedTaxa() {
|
298
|
return associatedTaxa;
|
299
|
}
|
300
|
public void addAssociatedTaxon(Taxon taxon){
|
301
|
if(associatedTaxa==null){
|
302
|
associatedTaxa = new ArrayList<>();
|
303
|
}
|
304
|
associatedTaxa.add(TypedEntityReference.fromEntity(taxon));
|
305
|
}
|
306
|
|
307
|
public void setPreferredStableUri(URI preferredStableUri) {
|
308
|
this.preferredStableUri = preferredStableUri;
|
309
|
}
|
310
|
public URI getPreferredStableUri() {
|
311
|
return preferredStableUri;
|
312
|
}
|
313
|
|
314
|
public String getSpecimenShortTitle() {
|
315
|
return specimenShortTitle;
|
316
|
}
|
317
|
public void setSpecimenShortTitle(String specimenIdentifier) {
|
318
|
this.specimenShortTitle = specimenIdentifier;
|
319
|
}
|
320
|
|
321
|
public String getMostSignificantIdentifier() {
|
322
|
return mostSignificantIdentifier;
|
323
|
}
|
324
|
public void setMostSignificantIdentifier(String mostSignificantIdentifier) {
|
325
|
this.mostSignificantIdentifier = mostSignificantIdentifier;
|
326
|
}
|
327
|
|
328
|
public TypedEntityReference<TaxonName> getStoredUnder() {
|
329
|
return storedUnder;
|
330
|
}
|
331
|
public void setStoredUnder(TypedEntityReference<TaxonName> storedUnder) {
|
332
|
this.storedUnder = storedUnder;
|
333
|
}
|
334
|
|
335
|
public String getOriginalLabelInfo() {
|
336
|
return originalLabelInfo;
|
337
|
}
|
338
|
public void setOriginalLabelInfo(String originalLabelInfo) {
|
339
|
this.originalLabelInfo = originalLabelInfo;
|
340
|
}
|
341
|
|
342
|
public String getExsiccatum() {
|
343
|
return exsiccatum;
|
344
|
}
|
345
|
public void setExsiccatum(String exsiccatum) {
|
346
|
this.exsiccatum = exsiccatum;
|
347
|
}
|
348
|
|
349
|
public String getCatalogNumber() {
|
350
|
return catalogNumber;
|
351
|
}
|
352
|
public void setCatalogNumber(String catalogNumber) {
|
353
|
this.catalogNumber = catalogNumber;
|
354
|
}
|
355
|
|
356
|
public String getBarcode() {
|
357
|
return barcode;
|
358
|
}
|
359
|
public void setBarcode(String barcode) {
|
360
|
this.barcode = barcode;
|
361
|
}
|
362
|
|
363
|
public String getPreservationMethod() {
|
364
|
return preservationMethod;
|
365
|
}
|
366
|
public void setPreservationMethod(String preservationMethod) {
|
367
|
this.preservationMethod = preservationMethod;
|
368
|
}
|
369
|
|
370
|
public CollectionDTO getCollection() {
|
371
|
return collection;
|
372
|
}
|
373
|
public void setCollectioDTO(CollectionDTO collection) {
|
374
|
this.collection = collection;
|
375
|
}
|
376
|
|
377
|
public List<DerivedUnitStatusDto> getStatus() {
|
378
|
return status;
|
379
|
}
|
380
|
|
381
|
public void setStatus(List<DerivedUnitStatusDto> status) {
|
382
|
this.status = status;
|
383
|
}
|
384
|
|
385
|
@Override
|
386
|
protected void updateTreeDependantData(Set<DerivedUnitDTO> derivatives) {
|
387
|
for (DerivedUnitDTO derivative: derivatives) {
|
388
|
this.setHasDna(this.isHasDna() || derivative.isHasDna() || !derivative.getDerivationTreeSummary().getMolecularDataList().isEmpty());
|
389
|
this.setHasDetailImage(this.isHasDetailImage() || derivative.isHasDetailImage() || !derivative.getDerivationTreeSummary().getDetailImages().isEmpty());
|
390
|
this.setHasSpecimenScan(isHasSpecimenScan()|| derivative.isHasSpecimenScan());
|
391
|
this.setHasCharacterData(isHasCharacterData()||derivative.isHasCharacterData());
|
392
|
}
|
393
|
|
394
|
// TODO DerivationTreeSummaryDTO should be updated here once it is refactored so that it can operate on dtos
|
395
|
}
|
396
|
}
|