1 package eu
.etaxonomy
.cdm
.api
.service
;
3 import java
.util
.ArrayList
;
4 import java
.util
.Arrays
;
5 import java
.util
.Collection
;
6 import java
.util
.Collections
;
7 import java
.util
.HashMap
;
8 import java
.util
.HashSet
;
11 import java
.util
.Optional
;
13 import java
.util
.UUID
;
14 import java
.util
.stream
.Collectors
;
16 import org
.apache
.log4j
.Logger
;
17 import org
.springframework
.beans
.factory
.annotation
.Autowired
;
18 import org
.springframework
.stereotype
.Service
;
19 import org
.springframework
.transaction
.annotation
.Transactional
;
21 import eu
.etaxonomy
.cdm
.api
.service
.UpdateResult
.Status
;
22 import eu
.etaxonomy
.cdm
.api
.service
.config
.IdentifiableServiceConfiguratorImpl
;
23 import eu
.etaxonomy
.cdm
.api
.service
.dto
.RowWrapperDTO
;
24 import eu
.etaxonomy
.cdm
.api
.service
.dto
.SpecimenRowWrapperDTO
;
25 import eu
.etaxonomy
.cdm
.api
.service
.dto
.TaxonRowWrapperDTO
;
26 import eu
.etaxonomy
.cdm
.common
.monitor
.IProgressMonitor
;
27 import eu
.etaxonomy
.cdm
.filter
.TaxonNodeFilter
;
28 import eu
.etaxonomy
.cdm
.hibernate
.HibernateProxyHelper
;
29 import eu
.etaxonomy
.cdm
.model
.common
.IdentifiableSource
;
30 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
31 import eu
.etaxonomy
.cdm
.model
.description
.CategoricalData
;
32 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionBase
;
33 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionElementBase
;
34 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionType
;
35 import eu
.etaxonomy
.cdm
.model
.description
.DescriptiveDataSet
;
36 import eu
.etaxonomy
.cdm
.model
.description
.DescriptiveSystemRole
;
37 import eu
.etaxonomy
.cdm
.model
.description
.Feature
;
38 import eu
.etaxonomy
.cdm
.model
.description
.IndividualsAssociation
;
39 import eu
.etaxonomy
.cdm
.model
.description
.PolytomousKey
;
40 import eu
.etaxonomy
.cdm
.model
.description
.QuantitativeData
;
41 import eu
.etaxonomy
.cdm
.model
.description
.SpecimenDescription
;
42 import eu
.etaxonomy
.cdm
.model
.description
.StatisticalMeasure
;
43 import eu
.etaxonomy
.cdm
.model
.description
.TaxonDescription
;
44 import eu
.etaxonomy
.cdm
.model
.description
.TextData
;
45 import eu
.etaxonomy
.cdm
.model
.location
.NamedArea
;
46 import eu
.etaxonomy
.cdm
.model
.occurrence
.DerivedUnit
;
47 import eu
.etaxonomy
.cdm
.model
.occurrence
.FieldUnit
;
48 import eu
.etaxonomy
.cdm
.model
.occurrence
.SpecimenOrObservationBase
;
49 import eu
.etaxonomy
.cdm
.model
.taxon
.Classification
;
50 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
51 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonBase
;
52 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonNode
;
53 import eu
.etaxonomy
.cdm
.persistence
.dao
.description
.IDescriptiveDataSetDao
;
54 import eu
.etaxonomy
.cdm
.persistence
.dao
.term
.IDefinedTermDao
;
55 import eu
.etaxonomy
.cdm
.persistence
.dto
.SpecimenNodeWrapper
;
56 import eu
.etaxonomy
.cdm
.persistence
.dto
.TaxonNodeDto
;
57 import eu
.etaxonomy
.cdm
.persistence
.dto
.TermDto
;
58 import eu
.etaxonomy
.cdm
.persistence
.dto
.UuidAndTitleCache
;
59 import eu
.etaxonomy
.cdm
.strategy
.cache
.common
.IIdentifiableEntityCacheStrategy
;
60 import eu
.etaxonomy
.cdm
.strategy
.generate
.PolytomousKeyGenerator
;
61 import eu
.etaxonomy
.cdm
.strategy
.generate
.PolytomousKeyGeneratorConfigurator
;
64 @Transactional(readOnly
=true)
65 public class DescriptiveDataSetService
66 extends IdentifiableServiceBase
<DescriptiveDataSet
, IDescriptiveDataSetDao
>
67 implements IDescriptiveDataSetService
{
69 private static Logger logger
= Logger
.getLogger(DescriptiveDataSetService
.class);
72 private IOccurrenceService occurrenceService
;
75 private ITaxonService taxonService
;
78 private IPolytomousKeyService polytomousKeyService
;
81 private IDefinedTermDao termDao
;
84 private IDescriptionService descriptionService
;
87 private ITaxonNodeService taxonNodeService
;
91 protected void setDao(IDescriptiveDataSetDao dao
) {
96 public Map
<DescriptionBase
, Set
<DescriptionElementBase
>> getDescriptionElements(DescriptiveDataSet descriptiveDataSet
, Set
<Feature
> features
, Integer pageSize
, Integer pageNumber
,
97 List
<String
> propertyPaths
) {
98 return dao
.getDescriptionElements(descriptiveDataSet
, features
, pageSize
, pageNumber
, propertyPaths
);
102 public <T
extends DescriptionElementBase
> Map
<UuidAndTitleCache
, Map
<UUID
, Set
<T
>>> getTaxonFeatureDescriptionElementMap(
103 Class
<T
> clazz
, UUID descriptiveDataSetUuid
, DescriptiveSystemRole role
) {
104 return dao
.getTaxonFeatureDescriptionElementMap(clazz
, descriptiveDataSetUuid
, role
);
108 public List
<UuidAndTitleCache
<DescriptiveDataSet
>> getDescriptiveDataSetUuidAndTitleCache(Integer limitOfInitialElements
, String pattern
) {
109 return dao
.getDescriptiveDataSetUuidAndTitleCache( limitOfInitialElements
, pattern
);
113 public ArrayList
<RowWrapperDTO
> getRowWrapper(UUID descriptiveDataSetUuid
, IProgressMonitor monitor
) {
114 DescriptiveDataSet descriptiveDataSet
= load(descriptiveDataSetUuid
);
115 monitor
.beginTask("Load row wrapper", descriptiveDataSet
.getDescriptions().size());
116 ArrayList
<RowWrapperDTO
> wrappers
= new ArrayList
<>();
117 Set
<DescriptionBase
> descriptions
= descriptiveDataSet
.getDescriptions();
118 for (DescriptionBase description
: descriptions
) {
119 if(monitor
.isCanceled()){
120 return new ArrayList
<>();
122 RowWrapperDTO rowWrapper
= null;
123 // only viable descriptions are aggregated, literature or default descriptions
124 if(HibernateProxyHelper
.isInstanceOf(description
, TaxonDescription
.class) &&
125 (description
.isAggregatedStructuredDescription()
126 || description
.getTypes().contains(DescriptionType
.DEFAULT_VALUES_FOR_AGGREGATION
)
127 || description
.getTypes().contains(DescriptionType
.SECONDARY_DATA
)
129 rowWrapper
= createTaxonRowWrapper(description
.getUuid(), descriptiveDataSet
.getUuid());
131 else if (HibernateProxyHelper
.isInstanceOf(description
, SpecimenDescription
.class)&&
132 !description
.getTypes().contains(DescriptionType
.CLONE_FOR_SOURCE
)){
133 rowWrapper
= createSpecimenRowWrapper(HibernateProxyHelper
.deproxy(description
, SpecimenDescription
.class), descriptiveDataSetUuid
);
135 if(rowWrapper
!=null){
136 wrappers
.add(rowWrapper
);
144 public Collection
<SpecimenNodeWrapper
> loadSpecimens(DescriptiveDataSet descriptiveDataSet
){
145 List
<UUID
> filteredNodes
= findFilteredTaxonNodes(descriptiveDataSet
);
146 if(filteredNodes
.isEmpty()){
147 return Collections
.EMPTY_SET
;
149 return occurrenceService
.listUuidAndTitleCacheByAssociatedTaxon(filteredNodes
, null, null);
153 public List
<UUID
> findFilteredTaxonNodes(DescriptiveDataSet descriptiveDataSet
){
154 TaxonNodeFilter filter
= TaxonNodeFilter
.NewRankInstance(descriptiveDataSet
.getMinRank(), descriptiveDataSet
.getMaxRank());
155 descriptiveDataSet
.getGeoFilter().forEach(area
-> filter
.orArea(area
.getUuid()));
156 descriptiveDataSet
.getTaxonSubtreeFilter().forEach(node
-> filter
.orSubtree(node
));
157 filter
.setIncludeUnpublished(true);
159 return taxonNodeService
.uuidList(filter
);
163 public List
<TaxonNode
> loadFilteredTaxonNodes(DescriptiveDataSet descriptiveDataSet
, List
<String
> propertyPaths
){
164 return taxonNodeService
.load(findFilteredTaxonNodes(descriptiveDataSet
), propertyPaths
);
168 public TaxonDescription
findDefaultDescription(UUID specimenDescriptionUuid
, UUID dataSetUuid
){
169 SpecimenDescription specimenDescription
= (SpecimenDescription
) descriptionService
.load(specimenDescriptionUuid
);
170 DescriptiveDataSet dataSet
= load(dataSetUuid
);
171 TaxonNode node
= findTaxonNodeForDescription(specimenDescription
, dataSet
);
172 return recurseDefaultDescription(node
, dataSet
);
175 private TaxonDescription
recurseDefaultDescription(TaxonNode node
, DescriptiveDataSet dataSet
){
176 TaxonDescription defaultDescription
= null;
177 if(node
!=null && node
.getTaxon()!=null){
178 defaultDescription
= findTaxonDescriptionByDescriptionType(dataSet
, node
.getTaxon(), DescriptionType
.DEFAULT_VALUES_FOR_AGGREGATION
);
179 if(defaultDescription
==null && node
.getParent()!=null){
180 defaultDescription
= recurseDefaultDescription(node
.getParent(), dataSet
);
183 return defaultDescription
;
186 private TaxonNode
findTaxonNodeForDescription(SpecimenDescription description
, DescriptiveDataSet descriptiveDataSet
){
187 SpecimenOrObservationBase specimen
= description
.getDescribedSpecimenOrObservation();
190 Set
<IndividualsAssociation
> associations
= (Set
<IndividualsAssociation
>)descriptiveDataSet
.getDescriptions()
192 .flatMap(desc
->desc
.getElements().stream())// put all description element in one stream
193 .filter(element
->element
instanceof IndividualsAssociation
)
194 .map(ia
->(IndividualsAssociation
)ia
)
195 .collect(Collectors
.toSet());
196 Classification classification
= descriptiveDataSet
.getTaxonSubtreeFilter().iterator().next().getClassification();
197 for (IndividualsAssociation individualsAssociation
: associations
) {
198 if(individualsAssociation
.getAssociatedSpecimenOrObservation().equals(specimen
)){
199 return ((TaxonDescription
) individualsAssociation
.getInDescription()).getTaxon().getTaxonNode(classification
);
206 public TaxonRowWrapperDTO
createTaxonRowWrapper(UUID taxonDescriptionUuid
, UUID descriptiveDataSetUuid
) {
207 TaxonNode taxonNode
= null;
208 Classification classification
= null;
209 TaxonDescription description
= (TaxonDescription
) descriptionService
.load(taxonDescriptionUuid
,
210 Arrays
.asList("taxon", "descriptionElements", "descriptionElements.feature"));
211 DescriptiveDataSet descriptiveDataSet
= dao
.load(descriptiveDataSetUuid
, null);
212 Optional
<TaxonNode
> first
= descriptiveDataSet
.getTaxonSubtreeFilter().stream()
213 .filter(node
->node
.getClassification()!=null).findFirst();
214 Optional
<Classification
> classificationOptional
= first
.map(node
->node
.getClassification());
215 if(classificationOptional
.isPresent()){
216 classification
= classificationOptional
.get();
217 Taxon taxon
= (Taxon
) taxonService
.load(description
.getTaxon().getId(), Arrays
.asList("taxonNodes", "taxonNodes.classification"));
218 taxonNode
= taxon
.getTaxonNode(classification
);
220 return new TaxonRowWrapperDTO(description
, new TaxonNodeDto(taxonNode
));
224 @Transactional(readOnly
=false)
225 public UpdateResult
addRowWrapperToDataset(Collection
<SpecimenNodeWrapper
> wrappers
, UUID datasetUuid
){
226 UpdateResult result
= new UpdateResult();
227 DescriptiveDataSet dataSet
= load(datasetUuid
);
228 result
.setCdmEntity(dataSet
);
230 List
<UUID
> taxonUuids
= wrappers
.stream().map(wrapper
->wrapper
.getTaxonNode().getTaxon().getUuid()).collect(Collectors
.toList());
231 List
<TaxonBase
> taxa
= taxonService
.load(taxonUuids
, Arrays
.asList(new String
[]{"descriptions"}));
233 for (SpecimenNodeWrapper wrapper
: wrappers
) {
234 Optional
<TaxonBase
> findAny
= taxa
.stream().filter(taxon
->taxon
.getUuid().equals(wrapper
.getTaxonNode().getTaxon().getUuid())).findAny();
235 if(!findAny
.isPresent()){
236 result
.addException(new IllegalArgumentException("Could not create wrapper for "+wrapper
.getUuidAndTitleCache().getTitleCache()));
239 Taxon taxon
= (Taxon
) findAny
.get();
240 UUID taxonDescriptionUuid
= wrapper
.getTaxonDescriptionUuid();
241 TaxonDescription taxonDescription
= null;
242 if(taxonDescriptionUuid
!=null){
243 taxonDescription
= (TaxonDescription
) descriptionService
.load(taxonDescriptionUuid
);
245 if(taxonDescription
==null){
246 Optional
<TaxonDescription
> associationDescriptionOptional
= taxon
.getDescriptions().stream()
247 .filter(desc
->desc
.getTypes().contains(DescriptionType
.INDIVIDUALS_ASSOCIATION
))
249 if(!associationDescriptionOptional
.isPresent()){
250 taxonDescription
= TaxonDescription
.NewInstance(taxon
);
253 taxonDescription
= associationDescriptionOptional
.get();
256 SpecimenOrObservationBase specimen
= occurrenceService
.load(wrapper
.getUuidAndTitleCache().getUuid());
257 IndividualsAssociation association
= IndividualsAssociation
.NewInstance(specimen
);
258 taxonDescription
.addElement(association
);
259 taxonService
.saveOrUpdate(taxon
);
260 result
.addUpdatedObject(taxon
);
262 SpecimenDescription specimenDescription
= findSpecimenDescription(datasetUuid
, wrapper
.getUuidAndTitleCache().getUuid(), true);
263 SpecimenRowWrapperDTO rowWrapper
= createSpecimenRowWrapper(specimenDescription
, wrapper
.getTaxonNode().getUuid(), datasetUuid
);
264 if(rowWrapper
==null){
265 result
.addException(new IllegalArgumentException("Could not create wrapper for "+specimenDescription
));
268 //add specimen description to data set
269 rowWrapper
.getDescription().addDescriptiveDataSet(dataSet
);
270 //add taxon description with IndividualsAssociation to the specimen to data set
271 taxonDescription
.addDescriptiveDataSet(dataSet
);
273 result
.addUpdatedObject(rowWrapper
.getDescription());
274 result
.addUpdatedObject(taxonDescription
);
276 saveOrUpdate(dataSet
);
280 private SpecimenRowWrapperDTO
createSpecimenRowWrapper(SpecimenDescription description
, UUID taxonNodeUuid
,
282 TaxonNode taxonNode
= taxonNodeService
.load(taxonNodeUuid
);
283 DescriptiveDataSet descriptiveDataSet
= load(datasetUuid
);
284 SpecimenOrObservationBase specimen
= description
.getDescribedSpecimenOrObservation();
285 //supplemental information
287 taxonNode
= findTaxonNodeForDescription(description
, descriptiveDataSet
);
289 FieldUnit fieldUnit
= null;
290 String identifier
= null;
291 NamedArea country
= null;
295 //taxon node was found
298 Collection
<FieldUnit
> fieldUnits
= occurrenceService
.findFieldUnits(specimen
.getUuid(),
299 Arrays
.asList(new String
[]{
301 "gatheringEvent.country"
303 if(fieldUnits
.size()!=1){
304 logger
.error("More than one or no field unit found for specimen"); //$NON-NLS-1$
308 fieldUnit
= fieldUnits
.iterator().next();
311 if(HibernateProxyHelper
.isInstanceOf(specimen
, DerivedUnit
.class)){
312 identifier
= occurrenceService
.getMostSignificantIdentifier(HibernateProxyHelper
.deproxy(specimen
, DerivedUnit
.class));
315 if(fieldUnit
!=null && fieldUnit
.getGatheringEvent()!=null){
316 country
= fieldUnit
.getGatheringEvent().getCountry();
318 //get default taxon description
319 TaxonDescription defaultTaxonDescription
= findDefaultDescription(description
.getUuid(), descriptiveDataSet
.getUuid());
320 TaxonRowWrapperDTO taxonRowWrapper
= defaultTaxonDescription
!= null
321 ?
createTaxonRowWrapper(defaultTaxonDescription
.getUuid(), descriptiveDataSet
.getUuid()) : null;
322 SpecimenRowWrapperDTO specimenRowWrapperDTO
= new SpecimenRowWrapperDTO(description
, new TaxonNodeDto(taxonNode
), fieldUnit
, identifier
, country
);
323 specimenRowWrapperDTO
.setDefaultDescription(taxonRowWrapper
);
324 return specimenRowWrapperDTO
;
328 public SpecimenRowWrapperDTO
createSpecimenRowWrapper(SpecimenDescription description
, UUID descriptiveDataSetUuid
){
329 return createSpecimenRowWrapper(description
, null, descriptiveDataSetUuid
);
333 @Transactional(readOnly
= false)
334 public UpdateResult
updateCaches(Class
<?
extends DescriptiveDataSet
> clazz
, Integer stepSize
,
335 IIdentifiableEntityCacheStrategy
<DescriptiveDataSet
> cacheStrategy
, IProgressMonitor monitor
) {
337 clazz
= DescriptiveDataSet
.class;
339 return super.updateCachesImpl(clazz
, stepSize
, cacheStrategy
, monitor
);
342 private TaxonDescription
findTaxonDescriptionByDescriptionType(DescriptiveDataSet dataSet
, Taxon taxon
, DescriptionType descriptionType
){
343 Optional
<TaxonDescription
> first
= taxon
.getDescriptions().stream()
344 .filter(desc
-> desc
.getTypes().stream().anyMatch(type
-> type
.equals(descriptionType
)))
345 .filter(desc
-> dataSet
.getDescriptions().contains(desc
))
347 if(first
.isPresent()){
348 return HibernateProxyHelper
.deproxy(descriptionService
.load(first
.get().getUuid(),
349 Arrays
.asList("taxon", "descriptionElements", "descriptionElements.feature")), TaxonDescription
.class);
355 public TaxonDescription
findTaxonDescriptionByDescriptionType(UUID dataSetUuid
, UUID taxonNodeUuid
, DescriptionType descriptionType
){
356 DescriptiveDataSet dataSet
= load(dataSetUuid
);
357 TaxonNode taxonNode
= taxonNodeService
.load(taxonNodeUuid
);
358 return findTaxonDescriptionByDescriptionType(dataSet
, taxonNode
.getTaxon(), descriptionType
);
362 @Transactional(readOnly
=false)
363 public UpdateResult
generatePolytomousKey(UUID descriptiveDataSetUuid
, UUID taxonUuid
) {
364 UpdateResult result
= new UpdateResult();
366 PolytomousKeyGeneratorConfigurator keyConfig
= new PolytomousKeyGeneratorConfigurator();
367 DescriptiveDataSet descriptiveDataSet
= load(descriptiveDataSetUuid
);
368 keyConfig
.setDataSet(descriptiveDataSet
);
369 PolytomousKey key
= new PolytomousKeyGenerator().invoke(keyConfig
);
370 IdentifiableServiceConfiguratorImpl
<PolytomousKey
> serviceConfig
= new IdentifiableServiceConfiguratorImpl
<>();
371 serviceConfig
.setTitleSearchString(descriptiveDataSet
.getTitleCache());
372 List
<PolytomousKey
> list
= polytomousKeyService
.findByTitle(serviceConfig
).getRecords();
374 list
.forEach(polytomousKey
->polytomousKeyService
.delete(polytomousKey
));
376 key
.setTitleCache(descriptiveDataSet
.getTitleCache(), true);
378 Taxon taxon
= (Taxon
) taxonService
.load(taxonUuid
);
379 key
.addTaxonomicScope(taxon
);
381 polytomousKeyService
.saveOrUpdate(key
);
383 result
.setCdmEntity(key
);
384 result
.addUpdatedObject(taxon
);
389 @Transactional(readOnly
=false)
390 public DeleteResult
removeDescription(UUID descriptionUuid
, UUID descriptiveDataSetUuid
) {
391 DeleteResult result
= new DeleteResult();
392 DescriptiveDataSet dataSet
= load(descriptiveDataSetUuid
);
393 DescriptionBase descriptionBase
= descriptionService
.load(descriptionUuid
);
394 if(dataSet
==null || descriptionBase
==null){
398 boolean success
= dataSet
.removeDescription(descriptionBase
);
399 result
.addDeletedObject(descriptionBase
);
400 // remove taxon description with IndividualsAssociation from data set
401 if(descriptionBase
instanceof SpecimenDescription
){
402 @SuppressWarnings("cast")
403 Set
<IndividualsAssociation
> associations
= (Set
<IndividualsAssociation
>)dataSet
.getDescriptions()
405 .flatMap(desc
->desc
.getElements().stream())// put all description element in one stream
406 .filter(element
->element
instanceof IndividualsAssociation
)
407 .map(ia
->(IndividualsAssociation
)ia
)
408 .collect(Collectors
.toSet());
409 Classification classification
= dataSet
.getTaxonSubtreeFilter().iterator().next().getClassification();
410 for (IndividualsAssociation individualsAssociation
: associations
) {
411 if(individualsAssociation
.getAssociatedSpecimenOrObservation().equals(descriptionBase
.getDescribedSpecimenOrObservation())){
412 dataSet
.removeDescription(individualsAssociation
.getInDescription());
413 result
.addDeletedObject(individualsAssociation
.getInDescription());
417 result
.addUpdatedObject(dataSet
);
418 result
.setStatus(success?Status
.OK
:Status
.ERROR
);
424 @Transactional(readOnly
=false)
425 public TaxonRowWrapperDTO
createTaxonDescription(UUID dataSetUuid
, UUID taxonNodeUuid
, DescriptionType descriptionType
){
426 DescriptiveDataSet dataSet
= load(dataSetUuid
);
427 TaxonNode taxonNode
= taxonNodeService
.load(taxonNodeUuid
, Arrays
.asList("taxon"));
428 TaxonDescription newTaxonDescription
= TaxonDescription
.NewInstance(taxonNode
.getTaxon());
429 newTaxonDescription
.setTitleCache(dataSet
.getLabel()+": "+newTaxonDescription
.generateTitle(), true); //$NON-NLS-2$
430 newTaxonDescription
.getTypes().add(descriptionType
);
432 dataSet
.getDescriptiveSystem().getDistinctTerms().forEach(wsFeature
->{
433 if(wsFeature
.isSupportsCategoricalData()){
434 newTaxonDescription
.addElement(CategoricalData
.NewInstance(wsFeature
));
436 else if(wsFeature
.isSupportsQuantitativeData()){
437 newTaxonDescription
.addElement(QuantitativeData
.NewInstance(wsFeature
));
440 dataSet
.addDescription(newTaxonDescription
);
442 return createTaxonRowWrapper(newTaxonDescription
.getUuid(), dataSet
.getUuid());
446 public List
<TermDto
> getSupportedStatesForFeature(UUID featureUuid
){
447 return termDao
.getSupportedStatesForFeature(featureUuid
);
451 @Transactional(readOnly
=false)
452 public SpecimenDescription
findSpecimenDescription(UUID descriptiveDataSetUuid
, UUID specimenUuid
, boolean addDatasetSource
){
453 DescriptiveDataSet dataSet
= load(descriptiveDataSetUuid
);
454 SpecimenOrObservationBase specimen
= occurrenceService
.load(specimenUuid
);
456 Set
<?
extends Feature
> datasetFeatures
= dataSet
.getDescriptiveSystem().getDistinctTerms();
457 List
<DescriptionElementBase
> matchingDescriptionElements
= new ArrayList
<>();
459 for (SpecimenDescription specimenDescription
: (Set
<SpecimenDescription
>) specimen
.getDescriptions()) {
460 specimenDescription
= (SpecimenDescription
) descriptionService
.load(specimenDescription
.getUuid());
462 //check if description is already added to data set
463 if(dataSet
.getDescriptions().contains(specimenDescription
)){
464 return specimenDescription
;
467 //gather specimen description features and check for match with dataset features
468 Set
<Feature
> specimenDescriptionFeatures
= new HashSet
<>();
469 for (DescriptionElementBase specimenDescriptionElement
: specimenDescription
.getElements()) {
470 Feature feature
= specimenDescriptionElement
.getFeature();
471 specimenDescriptionFeatures
.add(feature
);
472 if(datasetFeatures
.contains(feature
) && RowWrapperDTO
.hasData(specimenDescriptionElement
)){
473 matchingDescriptionElements
.add(specimenDescriptionElement
);
477 //Create new specimen description if description has not already been added to the dataset
478 SpecimenDescription newDesription
= SpecimenDescription
.NewInstance(specimen
);
479 newDesription
.setTitleCache("Dataset "+dataSet
.getLabel()+": "+newDesription
.generateTitle(), true); //$NON-NLS-2$
481 //check for equals description element (same feature and same values)
482 Map
<Feature
, List
<DescriptionElementBase
>> featureToElementMap
= new HashMap
<>();
483 for(DescriptionElementBase element
:matchingDescriptionElements
){
484 List
<DescriptionElementBase
> list
= featureToElementMap
.get(element
.getFeature());
486 list
= new ArrayList
<>();
489 featureToElementMap
.put(element
.getFeature(), list
);
491 Set
<DescriptionElementBase
> descriptionElementsToClone
= new HashSet
<>();
492 for(Feature feature
:featureToElementMap
.keySet()){
493 List
<DescriptionElementBase
> elements
= featureToElementMap
.get(feature
);
494 //no duplicate description elements found for this feature
495 if(elements
.size()==1){
496 descriptionElementsToClone
.add(elements
.get(0));
498 //duplicates found -> check if all are equal
500 DescriptionElementBase match
= null;
501 for (DescriptionElementBase descriptionElementBase
: elements
) {
503 match
= descriptionElementBase
;
505 else if(!new DescriptionElementCompareWrapper(match
).equals(new DescriptionElementCompareWrapper(descriptionElementBase
))){
507 //TODO: propagate message
508 // MessagingUtils.informationDialog(Messages.CharacterMatrix_MULTIPLE_DATA,
509 // String.format(Messages.CharacterMatrix_MULTIPLE_DATA_MESSAGE, feature.getLabel()));
514 descriptionElementsToClone
.add(match
);
518 //clone matching descriptionElements
519 for (DescriptionElementBase descriptionElementBase
: descriptionElementsToClone
) {
520 DescriptionElementBase clone
;
522 clone
= descriptionElementBase
.clone(newDesription
);
523 clone
.getSources().forEach(source
-> {
524 if(descriptionElementBase
instanceof CategoricalData
){
525 TextData label
= new DefaultCategoricalDescriptionBuilder().build((CategoricalData
) descriptionElementBase
, null);
526 source
.setOriginalNameString(label
.getText(Language
.DEFAULT()));
528 else if(descriptionElementBase
instanceof QuantitativeData
){
529 TextData label
= new DefaultQuantitativeDescriptionBuilder().build((QuantitativeData
) descriptionElementBase
, null);
530 source
.setOriginalNameString(label
.getText(Language
.DEFAULT()));
533 } catch (CloneNotSupportedException e
) {
538 //add sources of data set
539 if(addDatasetSource
){
540 dataSet
.getSources().forEach(source
->{
542 newDesription
.addSource((IdentifiableSource
) source
.clone());
543 } catch (CloneNotSupportedException e
) {
548 return newDesription
;
552 //TODO: this should either be solved in the model class itself
553 //OR this should cover all possibilities including modifiers for example
554 private class DescriptionElementCompareWrapper
{
556 private DescriptionElementBase element
;
557 private Set
<UUID
> stateUuids
= new HashSet
<>();
558 private Set
<Float
> avgs
= new HashSet
<>();
559 private Set
<Float
> exacts
= new HashSet
<>();
560 private Set
<Float
> maxs
= new HashSet
<>();
561 private Set
<Float
> mins
= new HashSet
<>();
562 private Set
<Float
> sampleSizes
= new HashSet
<>();
563 private Set
<Float
> standardDevs
= new HashSet
<>();
564 private Set
<Float
> lowerBounds
= new HashSet
<>();
565 private Set
<Float
> upperBounds
= new HashSet
<>();
566 private Set
<Float
> variances
= new HashSet
<>();
568 public DescriptionElementCompareWrapper(DescriptionElementBase element
) {
569 this.element
= element
;
570 if(element
.isInstanceOf(CategoricalData
.class)){
571 CategoricalData elementData
= (CategoricalData
)element
;
572 elementData
.getStatesOnly().forEach(state
->stateUuids
.add(state
.getUuid()));
574 else if(element
.isInstanceOf(QuantitativeData
.class)){
575 QuantitativeData elementData
= (QuantitativeData
)element
;
576 elementData
.getStatisticalValues().forEach(value
->{
577 if(value
.getType().equals(StatisticalMeasure
.AVERAGE())){
578 avgs
.add(value
.getValue());
580 else if(value
.getType().equals(StatisticalMeasure
.EXACT_VALUE())){
581 exacts
.add(value
.getValue());
584 else if(value
.getType().equals(StatisticalMeasure
.MAX())){
585 maxs
.add(value
.getValue());
587 else if(value
.getType().equals(StatisticalMeasure
.MIN())){
588 mins
.add(value
.getValue());
590 else if(value
.getType().equals(StatisticalMeasure
.SAMPLE_SIZE())){
591 sampleSizes
.add(value
.getValue());
594 else if(value
.getType().equals(StatisticalMeasure
.STANDARD_DEVIATION())){
595 standardDevs
.add(value
.getValue());
597 else if(value
.getType().equals(StatisticalMeasure
.TYPICAL_LOWER_BOUNDARY())){
598 lowerBounds
.add(value
.getValue());
601 else if(value
.getType().equals(StatisticalMeasure
.TYPICAL_UPPER_BOUNDARY())){
602 upperBounds
.add(value
.getValue());
604 else if(value
.getType().equals(StatisticalMeasure
.VARIANCE())){
605 variances
.add(value
.getValue());
612 public int hashCode() {
613 final int prime
= 31;
615 result
= prime
* result
+ getOuterType().hashCode();
616 result
= prime
* result
+ ((avgs
== null) ?
0 : avgs
.hashCode());
617 result
= prime
* result
+ ((element
== null) ?
0 : element
.hashCode());
618 result
= prime
* result
+ ((exacts
== null) ?
0 : exacts
.hashCode());
619 result
= prime
* result
+ ((lowerBounds
== null) ?
0 : lowerBounds
.hashCode());
620 result
= prime
* result
+ ((maxs
== null) ?
0 : maxs
.hashCode());
621 result
= prime
* result
+ ((mins
== null) ?
0 : mins
.hashCode());
622 result
= prime
* result
+ ((sampleSizes
== null) ?
0 : sampleSizes
.hashCode());
623 result
= prime
* result
+ ((standardDevs
== null) ?
0 : standardDevs
.hashCode());
624 result
= prime
* result
+ ((stateUuids
== null) ?
0 : stateUuids
.hashCode());
625 result
= prime
* result
+ ((upperBounds
== null) ?
0 : upperBounds
.hashCode());
626 result
= prime
* result
+ ((variances
== null) ?
0 : variances
.hashCode());
631 public boolean equals(Object obj
) {
638 if (getClass() != obj
.getClass()) {
641 DescriptionElementCompareWrapper other
= (DescriptionElementCompareWrapper
) obj
;
642 if (!getOuterType().equals(other
.getOuterType())) {
646 if (other
.avgs
!= null) {
649 } else if (!avgs
.equals(other
.avgs
)) {
652 if (element
== null) {
653 if (other
.element
!= null) {
656 } else if (!element
.equals(other
.element
)) {
659 if (exacts
== null) {
660 if (other
.exacts
!= null) {
663 } else if (!exacts
.equals(other
.exacts
)) {
666 if (lowerBounds
== null) {
667 if (other
.lowerBounds
!= null) {
670 } else if (!lowerBounds
.equals(other
.lowerBounds
)) {
674 if (other
.maxs
!= null) {
677 } else if (!maxs
.equals(other
.maxs
)) {
681 if (other
.mins
!= null) {
684 } else if (!mins
.equals(other
.mins
)) {
687 if (sampleSizes
== null) {
688 if (other
.sampleSizes
!= null) {
691 } else if (!sampleSizes
.equals(other
.sampleSizes
)) {
694 if (standardDevs
== null) {
695 if (other
.standardDevs
!= null) {
698 } else if (!standardDevs
.equals(other
.standardDevs
)) {
701 if (stateUuids
== null) {
702 if (other
.stateUuids
!= null) {
705 } else if (!stateUuids
.equals(other
.stateUuids
)) {
708 if (upperBounds
== null) {
709 if (other
.upperBounds
!= null) {
712 } else if (!upperBounds
.equals(other
.upperBounds
)) {
715 if (variances
== null) {
716 if (other
.variances
!= null) {
719 } else if (!variances
.equals(other
.variances
)) {
725 private DescriptiveDataSetService
getOuterType() {
726 return DescriptiveDataSetService
.this;