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
;
67 private Set
<SpecimenTypeDesignationDTO
> specimenTypeDesignations
;
69 private EventDTO
<DerivationEvent
> derivationEvent
;
72 private Set
<IdentifiableSource
> sources
;
74 private List
<MediaDTO
> listOfMedia
= new ArrayList
<>();
76 private DefinedTerm sex
;
78 private DefinedTerm lifeStage
;
80 private List
<DeterminationEventDTO
>determinations
;
82 protected SpecimenOrObservationBaseDTO(SpecimenOrObservationBase
<?
> specimenOrObservation
) {
83 super(HibernateProxyHelper
.getClassWithoutInitializingProxy(specimenOrObservation
), specimenOrObservation
.getUuid(), specimenOrObservation
.getTitleCache());
84 this.id
= specimenOrObservation
.getId();
85 Set
<Media
> collectedMedia
= collectMedia(specimenOrObservation
);
86 addMediaAsDTO(collectedMedia
);
87 setKindOfUnit(specimenOrObservation
.getKindOfUnit());
88 setSex(specimenOrObservation
.getSex());
89 setIndividualCount(specimenOrObservation
.getIndividualCount());
90 lifeStage
= specimenOrObservation
.getLifeStage();
91 FieldUnit fieldUnit
= null;
92 if (specimenOrObservation
instanceof FieldUnit
){
93 fieldUnit
= (FieldUnit
)specimenOrObservation
;
95 fieldUnit
= getFieldUnit((DerivedUnit
)specimenOrObservation
);
97 if (fieldUnit
!= null){
98 AgentBase
<?
> collector
= null;
99 if (fieldUnit
.getGatheringEvent() != null){
100 collector
= fieldUnit
.getGatheringEvent().getCollector();
102 String fieldNumberString
= CdmUtils
.Nz(fieldUnit
.getFieldNumber());
103 if (collector
!= null){
104 if (collector
.isInstanceOf(TeamOrPersonBase
.class)){
105 collectorsString
= CdmBase
.deproxy(collector
, TeamOrPersonBase
.class).getCollectorTitleCache();
107 collectorsString
= collector
.getTitleCache(); //institutions
110 collectorsString
= CdmUtils
.concat(" - ", collectorsString
, fieldNumberString
);
112 setDeterminations(specimenOrObservation
.getDeterminations().stream()
113 .map(det
-> DeterminationEventDTO
.from(det
))
114 .collect(Collectors
.toList())
116 if (specimenOrObservation
instanceof DerivedUnit
){
117 DerivedUnit derivedUnit
= (DerivedUnit
)specimenOrObservation
;
118 if (derivedUnit
.getSpecimenTypeDesignations() != null){
119 setSpecimenTypeDesignations(derivedUnit
.getSpecimenTypeDesignations());
125 * finds the field unit of the derived unit or null if no field unit exist
126 * @param specimenOrObservation
129 private FieldUnit
getFieldUnit(DerivedUnit specimenOrObservation
) {
130 if (specimenOrObservation
.getDerivedFrom() != null && !specimenOrObservation
.getDerivedFrom().getOriginals().isEmpty()){
131 for (SpecimenOrObservationBase
<?
> specimen
: specimenOrObservation
.getDerivedFrom().getOriginals()){
132 if (specimen
instanceof FieldUnit
){
133 return (FieldUnit
)specimen
;
134 }else if (specimen
instanceof DerivedUnit
){
135 getFieldUnit(HibernateProxyHelper
.deproxy(specimen
,DerivedUnit
.class));
142 public String
getCollectorsString() {
143 return collectorsString
;
145 public void setCollectorsString(String collectorsString
) {
146 this.collectorsString
= collectorsString
;
149 public Set
<SpecimenTypeDesignationDTO
> getSpecimenTypeDesignations() {
150 return specimenTypeDesignations
;
153 public void setSpecimenTypeDesignations(Set
<SpecimenTypeDesignation
> specimenTypeDesignations
) {
154 this.specimenTypeDesignations
= new HashSet
<>();
155 for (SpecimenTypeDesignation typeDes
: specimenTypeDesignations
){
156 if (typeDes
!= null){
157 this.specimenTypeDesignations
.add(new SpecimenTypeDesignationDTO(typeDes
));
162 public Set
<IdentifiableSource
> getSources() {
166 public void setSources(Set
<IdentifiableSource
> sources
) {
167 this.sources
= sources
;
170 public DerivationTreeSummaryDTO
getDerivationTreeSummary() {
171 return derivationTreeSummary
;
173 public void setDerivationTreeSummary(DerivationTreeSummaryDTO derivationTreeSummary
) {
174 this.derivationTreeSummary
= derivationTreeSummary
;
175 if(derivationTreeSummary
!= null) {
176 setHasSpecimenScan(isHasSpecimenScan() || !derivationTreeSummary
.getSpecimenScans().isEmpty());
177 setHasDetailImage(isHasDetailImage() || !derivationTreeSummary
.getDetailImages().isEmpty());
178 setHasDna(isHasDna() || !derivationTreeSummary
.getMolecularDataList().isEmpty());
182 public TreeSet
<AbstractMap
.SimpleEntry
<String
, String
>> getCharacterData() {
183 return characterData
;
185 public void addCharacterData(String character
, String state
){
186 if(characterData
==null){
187 characterData
= new TreeSet
<>(new PairComparator());
189 characterData
.add(new AbstractMap
.SimpleEntry
<>(character
, state
));
192 private class PairComparator
implements Comparator
<AbstractMap
.SimpleEntry
<String
,String
>>, Serializable
{
194 private static final long serialVersionUID
= -8589392050761963540L;
197 public int compare(AbstractMap
.SimpleEntry
<String
, String
> o1
, AbstractMap
.SimpleEntry
<String
, String
> o2
) {
198 if(o1
==null && o2
!=null){
201 if(o1
!=null && o2
==null){
204 if(o1
!=null && o2
!=null){
205 return o1
.getKey().compareTo(o2
.getKey());
211 public boolean isHasCharacterData() {
212 return hasCharacterData
;
214 public void setHasCharacterData(boolean hasCharacterData
) {
215 this.hasCharacterData
= hasCharacterData
;
218 public boolean isHasDna() {
221 public void setHasDna(boolean hasDna
) {
222 this.hasDna
= hasDna
;
225 public boolean isHasDetailImage() {
226 return hasDetailImage
;
228 public void setHasDetailImage(boolean hasDetailImage
) {
229 this.hasDetailImage
= hasDetailImage
;
232 public boolean isHasSpecimenScan() {
233 return hasSpecimenScan
;
235 public void setHasSpecimenScan(boolean hasSpecimenScan
) {
236 this.hasSpecimenScan
= hasSpecimenScan
;
239 * @return The summary of all DerivedUnit identifiers with the label of
240 * this SpecimenOrObservationBase.
241 * This label is usually being user for citing the unit in publications.
243 public String
getSummaryLabel() {
248 * Summary of all DerivedUnit identifiers with the label of this SpecimenOrObservationBase.
249 * This label is usually being user for citing the unit in publications.
251 public void setSummaryLabel(String summaryLabel
) {
252 this.summaryLabel
= summaryLabel
;
255 public SpecimenOrObservationType
getRecordBase() {
258 public void setRecordBase(SpecimenOrObservationType specimenOrObservationType
) {
259 this.recordBase
= specimenOrObservationType
;
262 public Set
<DerivedUnitDTO
> getDerivatives() {
263 if (this.derivatives
== null){
264 this.derivatives
= new HashSet
<>();
269 public void setDerivatives(Set
<DerivedUnitDTO
> derivatives
) {
270 this.derivatives
= derivatives
;
271 updateTreeDependantData();
274 public void addDerivative(DerivedUnitDTO derivate
){
275 if (this.derivatives
== null){
276 this.derivatives
= new HashSet
<>();
278 this.derivatives
.add(derivate
);
279 updateTreeDependantData();
281 public void addAllDerivatives(Set
<DerivedUnitDTO
> derivatives
){
282 if (this.derivatives
== null){
283 this.derivatives
= new HashSet
<>();
285 this.derivatives
.addAll(derivatives
);
286 updateTreeDependantData();
290 * To be overwritten by implementing classes to
291 * update data which depends on the derivation tree
293 protected abstract void updateTreeDependantData();
296 * Recursively collects all derivatives from this.
298 public Collection
<DerivedUnitDTO
> collectDerivatives() {
299 return collectDerivatives(new HashSet
<>());
303 * private partner method to {@link #collectDerivatives()} for recursive calls.
307 private Collection
<DerivedUnitDTO
> collectDerivatives(Set
<DerivedUnitDTO
> dtos
) {
308 dtos
.addAll(getDerivatives());
309 if(derivatives
!= null) {
310 for(SpecimenOrObservationBaseDTO subDto
: derivatives
) {
311 dtos
.addAll(subDto
.collectDerivatives(dtos
));
317 public EventDTO
<DerivationEvent
> getDerivationEvent() {
318 return derivationEvent
;
320 public void setDerivationEvent(EventDTO
<DerivationEvent
> derivationEvent
) {
321 this.derivationEvent
= derivationEvent
;
324 public List
<MediaDTO
> getListOfMedia() {
327 public void setListOfMedia(List
<MediaDTO
> listOfMedia
) {
328 this.listOfMedia
= listOfMedia
;
331 protected Set
<Media
> collectMedia(SpecimenOrObservationBase
<?
> specimenOrObservation
){
332 Set
<Media
> collectedMedia
= new HashSet
<>();
333 Set
<SpecimenDescription
> descriptions
= specimenOrObservation
.getSpecimenDescriptionImageGallery();
334 for (DescriptionBase
<?
> desc
: descriptions
){
335 if (desc
instanceof SpecimenDescription
){
336 SpecimenDescription specimenDesc
= (SpecimenDescription
)desc
;
337 for (DescriptionElementBase element
: specimenDesc
.getElements()){
338 if (element
.isInstanceOf(TextData
.class)&& element
.getFeature().equals(Feature
.IMAGE())) {
339 for (Media media
:element
.getMedia()){
340 collectedMedia
.add(media
);
346 return collectedMedia
;
349 private void addMediaAsDTO(Set
<Media
> media
) {
350 for(Media m
: media
) {
351 List
<MediaDTO
> dtos
= MediaDTO
.fromEntity(m
);
352 getListOfMedia().addAll(dtos
);
358 * The Unit to assemble the derivatives information for
360 * The maximum number of derivation events levels up to which derivatives are to be assembled.
361 * <code>NULL</code> means infinitely.
362 * @param includeTypes
363 * Allows for positive filtering by {@link SpecimenOrObservationType}.
364 * Filter is disabled when <code>NULL</code>. This only affects the derivatives assembled in the
365 * {@link #derivatives} list. The <code>unitLabelsByCollection</code> are always collected for the
366 * whole bouquet of derivatives.
367 * @param unitLabelsByCollection
368 * A map to record the unit labels (most significant identifier + collection code) per collection.
369 * Optional parameter, may be <code>NULL</code>.
372 protected Set
<DerivedUnitDTO
> assembleDerivatives(SpecimenOrObservationBase
<?
> sob
,
373 Integer maxDepth
, EnumSet
<SpecimenOrObservationType
> includeTypes
) {
375 boolean doDescend
= maxDepth
== null || maxDepth
> 0;
376 Integer nextLevelMaxDepth
= maxDepth
!= null ? maxDepth
- 1 : null;
377 Set
<DerivedUnitDTO
> derivateDTOs
= new HashSet
<>();
378 // collectDerivedUnitsMaxdepth => 0 to avoid aggregation of sub ordinate
379 // derivatives at each level
380 Integer collectDerivedUnitsMaxdepth
= 0;
381 for (DerivedUnit derivedUnit
: sob
.collectDerivedUnits(collectDerivedUnitsMaxdepth
)) {
382 if(!derivedUnit
.isPublish()){
386 if (doDescend
&& (includeTypes
== null || includeTypes
.contains(derivedUnit
.getRecordBasis()))) {
387 DerivedUnitDTO derivedUnitDTO
= DerivedUnitDTO
.fromEntity(derivedUnit
, nextLevelMaxDepth
, includeTypes
);
388 derivateDTOs
.add(derivedUnitDTO
);
389 setHasCharacterData(isHasCharacterData() || derivedUnitDTO
.isHasCharacterData());
390 // NOTE! the flags setHasDetailImage, setHasDna, setHasSpecimenScan are also set in
391 // setDerivateDataDTO(), see below
392 setHasDetailImage(isHasDetailImage() || derivedUnitDTO
.isHasDetailImage());
393 setHasDna(isHasDna() || derivedUnitDTO
.isHasDna());
394 setHasSpecimenScan(isHasSpecimenScan() || derivedUnitDTO
.isHasSpecimenScan());
400 public TermBase
getKindOfUnit() {
403 public void setKindOfUnit(TermBase kindOfUnit
) {
404 this.kindOfUnit
= HibernateProxyHelper
.deproxy(kindOfUnit
);
407 public DefinedTerm
getSex() {
410 public void setSex(DefinedTerm sex
) {
414 public DefinedTerm
getLifeStage() {
417 public void setLifeStage(DefinedTerm lifeStage
) {
418 this.lifeStage
= lifeStage
;
425 public String
getIndividualCount() {
426 return individualCount
;
428 public void setIndividualCount(String individualCount
) {
429 this.individualCount
= individualCount
;
432 public List
<DeterminationEventDTO
> getDeterminations() {
433 return determinations
;
436 public void setDeterminations(List
<DeterminationEventDTO
> determinations
) {
437 this.determinations
= determinations
;