2 * Copyright (C) 2015 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
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.
9 package eu
.etaxonomy
.cdm
.api
.service
.dto
;
11 import java
.io
.Serializable
;
12 import java
.util
.AbstractMap
;
13 import java
.util
.ArrayList
;
14 import java
.util
.Collection
;
15 import java
.util
.Comparator
;
16 import java
.util
.EnumSet
;
17 import java
.util
.HashSet
;
18 import java
.util
.List
;
20 import java
.util
.TreeSet
;
21 import java
.util
.stream
.Collectors
;
23 import eu
.etaxonomy
.cdm
.common
.CdmUtils
;
24 import eu
.etaxonomy
.cdm
.hibernate
.HibernateProxyHelper
;
25 import eu
.etaxonomy
.cdm
.model
.agent
.AgentBase
;
26 import eu
.etaxonomy
.cdm
.model
.agent
.TeamOrPersonBase
;
27 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
28 import eu
.etaxonomy
.cdm
.model
.common
.IdentifiableSource
;
29 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionBase
;
30 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionElementBase
;
31 import eu
.etaxonomy
.cdm
.model
.description
.Feature
;
32 import eu
.etaxonomy
.cdm
.model
.description
.SpecimenDescription
;
33 import eu
.etaxonomy
.cdm
.model
.description
.TextData
;
34 import eu
.etaxonomy
.cdm
.model
.media
.Media
;
35 import eu
.etaxonomy
.cdm
.model
.name
.SpecimenTypeDesignation
;
36 import eu
.etaxonomy
.cdm
.model
.occurrence
.DerivationEvent
;
37 import eu
.etaxonomy
.cdm
.model
.occurrence
.DerivedUnit
;
38 import eu
.etaxonomy
.cdm
.model
.occurrence
.FieldUnit
;
39 import eu
.etaxonomy
.cdm
.model
.occurrence
.SpecimenOrObservationBase
;
40 import eu
.etaxonomy
.cdm
.model
.occurrence
.SpecimenOrObservationType
;
41 import eu
.etaxonomy
.cdm
.model
.term
.DefinedTerm
;
42 import eu
.etaxonomy
.cdm
.model
.term
.TermBase
;
43 import eu
.etaxonomy
.cdm
.ref
.TypedEntityReference
;
46 public abstract class SpecimenOrObservationBaseDTO
extends TypedEntityReference
<SpecimenOrObservationBase
<?
>>{
48 private static final long serialVersionUID
= -7597690654462090732L;
51 private TreeSet
<AbstractMap
.SimpleEntry
<String
, String
>> characterData
;
52 private DerivationTreeSummaryDTO derivationTreeSummary
;
53 protected String taxonName
;
55 protected String summaryLabel
;
56 protected boolean hasDetailImage
;
57 private boolean hasCharacterData
;
58 private boolean hasDna
;
59 private boolean hasSpecimenScan
;
61 private SpecimenOrObservationType recordBase
;
62 private TermBase kindOfUnit
;
63 private String collectorsString
;
64 private String individualCount
;
65 private Set
<DerivedUnitDTO
> derivatives
;
66 private Set
<AnnotationDTO
> annotations
= new HashSet
<>();
68 private Set
<SpecimenTypeDesignationDTO
> specimenTypeDesignations
;
70 private EventDTO
<DerivationEvent
> derivationEvent
;
73 private Set
<IdentifiableSource
> sources
;
75 private List
<MediaDTO
> listOfMedia
= new ArrayList
<>();
77 private DefinedTerm sex
;
79 private DefinedTerm lifeStage
;
81 private List
<DeterminationEventDTO
>determinations
;
83 protected SpecimenOrObservationBaseDTO(SpecimenOrObservationBase
<?
> specimenOrObservation
) {
84 super(HibernateProxyHelper
.getClassWithoutInitializingProxy(specimenOrObservation
), specimenOrObservation
.getUuid(), specimenOrObservation
.getTitleCache());
85 this.id
= specimenOrObservation
.getId();
86 Set
<Media
> collectedMedia
= collectMedia(specimenOrObservation
);
87 addMediaAsDTO(collectedMedia
);
88 setKindOfUnit(specimenOrObservation
.getKindOfUnit());
89 setSex(specimenOrObservation
.getSex());
90 setIndividualCount(specimenOrObservation
.getIndividualCount());
91 lifeStage
= specimenOrObservation
.getLifeStage();
92 FieldUnit fieldUnit
= null;
93 if (specimenOrObservation
instanceof FieldUnit
){
94 fieldUnit
= (FieldUnit
)specimenOrObservation
;
96 fieldUnit
= getFieldUnit((DerivedUnit
)specimenOrObservation
);
98 if (fieldUnit
!= null){
99 AgentBase
<?
> collector
= null;
100 if (fieldUnit
.getGatheringEvent() != null){
101 collector
= fieldUnit
.getGatheringEvent().getCollector();
103 String fieldNumberString
= CdmUtils
.Nz(fieldUnit
.getFieldNumber());
104 if (collector
!= null){
105 if (collector
.isInstanceOf(TeamOrPersonBase
.class)){
106 collectorsString
= CdmBase
.deproxy(collector
, TeamOrPersonBase
.class).getCollectorTitleCache();
108 collectorsString
= collector
.getTitleCache(); //institutions
111 collectorsString
= CdmUtils
.concat(" - ", collectorsString
, fieldNumberString
);
113 setDeterminations(specimenOrObservation
.getDeterminations().stream()
114 .map(det
-> DeterminationEventDTO
.from(det
))
115 .collect(Collectors
.toList())
117 if (specimenOrObservation
instanceof DerivedUnit
){
118 DerivedUnit derivedUnit
= (DerivedUnit
)specimenOrObservation
;
119 if (derivedUnit
.getSpecimenTypeDesignations() != null){
120 setSpecimenTypeDesignations(derivedUnit
.getSpecimenTypeDesignations());
126 * finds the field unit of the derived unit or null if no field unit exist
127 * @param specimenOrObservation
130 private FieldUnit
getFieldUnit(DerivedUnit specimenOrObservation
) {
131 if (specimenOrObservation
.getDerivedFrom() != null && !specimenOrObservation
.getDerivedFrom().getOriginals().isEmpty()){
132 for (SpecimenOrObservationBase
<?
> specimen
: specimenOrObservation
.getDerivedFrom().getOriginals()){
133 if (specimen
instanceof FieldUnit
){
134 return (FieldUnit
)specimen
;
135 }else if (specimen
instanceof DerivedUnit
){
136 getFieldUnit(HibernateProxyHelper
.deproxy(specimen
,DerivedUnit
.class));
143 public String
getCollectorsString() {
144 return collectorsString
;
146 public void setCollectorsString(String collectorsString
) {
147 this.collectorsString
= collectorsString
;
150 public Set
<SpecimenTypeDesignationDTO
> getSpecimenTypeDesignations() {
151 return specimenTypeDesignations
;
154 public void setSpecimenTypeDesignations(Set
<SpecimenTypeDesignation
> specimenTypeDesignations
) {
155 this.specimenTypeDesignations
= new HashSet
<>();
156 for (SpecimenTypeDesignation typeDes
: specimenTypeDesignations
){
157 if (typeDes
!= null){
158 this.specimenTypeDesignations
.add(new SpecimenTypeDesignationDTO(typeDes
));
163 public Set
<IdentifiableSource
> getSources() {
167 public void setSources(Set
<IdentifiableSource
> sources
) {
168 this.sources
= sources
;
171 public DerivationTreeSummaryDTO
getDerivationTreeSummary() {
172 return derivationTreeSummary
;
174 public void setDerivationTreeSummary(DerivationTreeSummaryDTO derivationTreeSummary
) {
175 this.derivationTreeSummary
= derivationTreeSummary
;
176 if(derivationTreeSummary
!= null) {
177 setHasSpecimenScan(isHasSpecimenScan() || !derivationTreeSummary
.getSpecimenScans().isEmpty());
178 setHasDetailImage(isHasDetailImage() || !derivationTreeSummary
.getDetailImages().isEmpty());
179 setHasDna(isHasDna() || !derivationTreeSummary
.getMolecularDataList().isEmpty());
183 public TreeSet
<AbstractMap
.SimpleEntry
<String
, String
>> getCharacterData() {
184 return characterData
;
186 public void addCharacterData(String character
, String state
){
187 if(characterData
==null){
188 characterData
= new TreeSet
<>(new PairComparator());
190 characterData
.add(new AbstractMap
.SimpleEntry
<>(character
, state
));
191 this.setHasCharacterData(!this.characterData
.isEmpty());
194 private class PairComparator
implements Comparator
<AbstractMap
.SimpleEntry
<String
,String
>>, Serializable
{
196 private static final long serialVersionUID
= -8589392050761963540L;
199 public int compare(AbstractMap
.SimpleEntry
<String
, String
> o1
, AbstractMap
.SimpleEntry
<String
, String
> o2
) {
200 if(o1
==null && o2
!=null){
203 if(o1
!=null && o2
==null){
206 if(o1
!=null && o2
!=null){
207 return o1
.getKey().compareTo(o2
.getKey());
213 public boolean isHasCharacterData() {
214 return hasCharacterData
;
216 public void setHasCharacterData(boolean hasCharacterData
) {
217 this.hasCharacterData
= hasCharacterData
;
220 public boolean isHasDna() {
223 public void setHasDna(boolean hasDna
) {
224 this.hasDna
= hasDna
;
227 public boolean isHasDetailImage() {
228 return hasDetailImage
;
230 public void setHasDetailImage(boolean hasDetailImage
) {
231 this.hasDetailImage
= hasDetailImage
;
234 public boolean isHasSpecimenScan() {
235 return hasSpecimenScan
;
237 public void setHasSpecimenScan(boolean hasSpecimenScan
) {
238 this.hasSpecimenScan
= hasSpecimenScan
;
241 * @return The summary of all DerivedUnit identifiers with the label of
242 * this SpecimenOrObservationBase.
243 * This label is usually being user for citing the unit in publications.
245 public String
getSummaryLabel() {
250 * Summary of all DerivedUnit identifiers with the label of this SpecimenOrObservationBase.
251 * This label is usually being user for citing the unit in publications.
253 public void setSummaryLabel(String summaryLabel
) {
254 this.summaryLabel
= summaryLabel
;
257 public SpecimenOrObservationType
getRecordBase() {
260 public void setRecordBase(SpecimenOrObservationType specimenOrObservationType
) {
261 this.recordBase
= specimenOrObservationType
;
264 public Set
<DerivedUnitDTO
> getDerivatives() {
265 if (this.derivatives
== null){
266 this.derivatives
= new HashSet
<>();
271 public void setDerivatives(Set
<DerivedUnitDTO
> derivatives
) {
272 this.derivatives
= derivatives
;
273 updateTreeDependantData(derivatives
);
276 public void addDerivative(DerivedUnitDTO derivate
){
277 if (this.derivatives
== null){
278 this.derivatives
= new HashSet
<>();
280 this.derivatives
.add(derivate
);
281 Set
<DerivedUnitDTO
> derivatives
= new HashSet
<>();
282 derivatives
.add(derivate
);
283 updateTreeDependantData(derivatives
);
285 public void addAllDerivatives(Set
<DerivedUnitDTO
> derivatives
){
286 if (this.derivatives
== null){
287 this.derivatives
= new HashSet
<>();
289 this.derivatives
.addAll(derivatives
);
290 updateTreeDependantData(derivatives
);
294 * To be overwritten by implementing classes to
295 * update data which depends on the derivation tree
297 protected abstract void updateTreeDependantData(Set
<DerivedUnitDTO
> derivatives
) ;
300 * Recursively collects all derivatives from this.
302 public Collection
<DerivedUnitDTO
> collectDerivatives() {
303 return collectDerivatives(new HashSet
<>());
307 * private partner method to {@link #collectDerivatives()} for recursive calls.
311 private Collection
<DerivedUnitDTO
> collectDerivatives(Set
<DerivedUnitDTO
> dtos
) {
312 dtos
.addAll(getDerivatives());
313 if(derivatives
!= null) {
314 for(SpecimenOrObservationBaseDTO subDto
: derivatives
) {
315 dtos
.addAll(subDto
.collectDerivatives(dtos
));
321 public EventDTO
<DerivationEvent
> getDerivationEvent() {
322 return derivationEvent
;
324 public void setDerivationEvent(EventDTO
<DerivationEvent
> derivationEvent
) {
325 this.derivationEvent
= derivationEvent
;
328 public List
<MediaDTO
> getListOfMedia() {
331 public void setListOfMedia(List
<MediaDTO
> listOfMedia
) {
332 this.listOfMedia
= listOfMedia
;
335 protected Set
<Media
> collectMedia(SpecimenOrObservationBase
<?
> specimenOrObservation
){
336 Set
<Media
> collectedMedia
= new HashSet
<>();
337 Set
<SpecimenDescription
> descriptions
= specimenOrObservation
.getSpecimenDescriptionImageGallery();
338 for (DescriptionBase
<?
> desc
: descriptions
){
339 if (desc
instanceof SpecimenDescription
){
340 SpecimenDescription specimenDesc
= (SpecimenDescription
)desc
;
341 for (DescriptionElementBase element
: specimenDesc
.getElements()){
342 if (element
.isInstanceOf(TextData
.class)&& element
.getFeature().equals(Feature
.IMAGE())) {
343 for (Media media
:element
.getMedia()){
344 collectedMedia
.add(media
);
350 return collectedMedia
;
353 private void addMediaAsDTO(Set
<Media
> media
) {
354 for(Media m
: media
) {
355 List
<MediaDTO
> dtos
= MediaDTO
.fromEntity(m
);
356 getListOfMedia().addAll(dtos
);
362 * The Unit to assemble the derivatives information for
364 * The maximum number of derivation events levels up to which derivatives are to be assembled.
365 * <code>NULL</code> means infinitely.
366 * @param includeTypes
367 * Allows for positive filtering by {@link SpecimenOrObservationType}.
368 * Filter is disabled when <code>NULL</code>. This only affects the derivatives assembled in the
369 * {@link #derivatives} list. The <code>unitLabelsByCollection</code> are always collected for the
370 * whole bouquet of derivatives.
371 * @param unitLabelsByCollection
372 * A map to record the unit labels (most significant identifier + collection code) per collection.
373 * Optional parameter, may be <code>NULL</code>.
376 protected Set
<DerivedUnitDTO
> assembleDerivatives(SpecimenOrObservationBase
<?
> sob
,
377 Integer maxDepth
, EnumSet
<SpecimenOrObservationType
> includeTypes
) {
379 boolean doDescend
= maxDepth
== null || maxDepth
> 0;
380 Integer nextLevelMaxDepth
= maxDepth
!= null ? maxDepth
- 1 : null;
381 Set
<DerivedUnitDTO
> derivateDTOs
= new HashSet
<>();
382 // collectDerivedUnitsMaxdepth => 0 to avoid aggregation of sub ordinate
383 // derivatives at each level
384 Integer collectDerivedUnitsMaxdepth
= 0;
385 for (DerivedUnit derivedUnit
: sob
.collectDerivedUnits(collectDerivedUnitsMaxdepth
)) {
386 if(!derivedUnit
.isPublish()){
390 if (doDescend
&& (includeTypes
== null || includeTypes
.contains(derivedUnit
.getRecordBasis()))) {
391 SpecimenOrObservationBaseDTO derivedUnitDTO
= SpecimenOrObservationDTOFactory
.fromEntity(derivedUnit
, nextLevelMaxDepth
);
392 if (derivedUnitDTO
instanceof DerivedUnitDTO
) {
393 derivateDTOs
.add((DerivedUnitDTO
)derivedUnitDTO
);
395 setHasCharacterData(isHasCharacterData() || derivedUnitDTO
.isHasCharacterData());
396 // NOTE! the flags setHasDetailImage, setHasDna, setHasSpecimenScan are also set in
397 // setDerivateDataDTO(), see below
398 setHasDetailImage(isHasDetailImage() || derivedUnitDTO
.isHasDetailImage());
399 setHasDna(isHasDna() || derivedUnitDTO
.isHasDna());
400 setHasSpecimenScan(isHasSpecimenScan() || derivedUnitDTO
.isHasSpecimenScan());
401 setHasCharacterData(isHasCharacterData() || derivedUnitDTO
.isHasCharacterData());
407 public TermBase
getKindOfUnit() {
410 public void setKindOfUnit(TermBase kindOfUnit
) {
411 this.kindOfUnit
= HibernateProxyHelper
.deproxy(kindOfUnit
);
414 public DefinedTerm
getSex() {
417 public void setSex(DefinedTerm sex
) {
421 public DefinedTerm
getLifeStage() {
424 public void setLifeStage(DefinedTerm lifeStage
) {
425 this.lifeStage
= lifeStage
;
432 public String
getIndividualCount() {
433 return individualCount
;
435 public void setIndividualCount(String individualCount
) {
436 this.individualCount
= individualCount
;
439 public List
<DeterminationEventDTO
> getDeterminations() {
440 return determinations
;
443 public void setDeterminations(List
<DeterminationEventDTO
> determinations
) {
444 this.determinations
= determinations
;
447 public Set
<AnnotationDTO
> getAnnotations() {
451 protected void addAnnotation(AnnotationDTO annotation
) {
452 this.annotations
.add(annotation
);