Merge branch 'develop' into taxonDecription
[cdmlib.git] / cdmlib-services / src / main / java / eu / etaxonomy / cdm / api / service / DescriptiveDataSetService.java
1 package eu.etaxonomy.cdm.api.service;
2
3 import java.io.Serializable;
4 import java.util.ArrayList;
5 import java.util.Arrays;
6 import java.util.Collection;
7 import java.util.HashMap;
8 import java.util.HashSet;
9 import java.util.List;
10 import java.util.Map;
11 import java.util.Optional;
12 import java.util.Set;
13 import java.util.UUID;
14 import java.util.stream.Collectors;
15
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;
20
21 import eu.etaxonomy.cdm.api.service.dto.RowWrapperDTO;
22 import eu.etaxonomy.cdm.api.service.dto.SpecimenRowWrapperDTO;
23 import eu.etaxonomy.cdm.api.service.dto.TaxonRowWrapperDTO;
24 import eu.etaxonomy.cdm.common.monitor.IProgressMonitor;
25 import eu.etaxonomy.cdm.common.monitor.IRemotingProgressMonitor;
26 import eu.etaxonomy.cdm.common.monitor.RemotingProgressMonitorThread;
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.common.Marker;
32 import eu.etaxonomy.cdm.model.common.MarkerType;
33 import eu.etaxonomy.cdm.model.common.OriginalSourceType;
34 import eu.etaxonomy.cdm.model.description.CategoricalData;
35 import eu.etaxonomy.cdm.model.description.Character;
36 import eu.etaxonomy.cdm.model.description.DescriptionBase;
37 import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
38 import eu.etaxonomy.cdm.model.description.DescriptiveDataSet;
39 import eu.etaxonomy.cdm.model.description.DescriptiveSystemRole;
40 import eu.etaxonomy.cdm.model.description.Feature;
41 import eu.etaxonomy.cdm.model.description.QuantitativeData;
42 import eu.etaxonomy.cdm.model.description.SpecimenDescription;
43 import eu.etaxonomy.cdm.model.description.StateData;
44 import eu.etaxonomy.cdm.model.description.StatisticalMeasure;
45 import eu.etaxonomy.cdm.model.description.StatisticalMeasurementValue;
46 import eu.etaxonomy.cdm.model.description.TaxonDescription;
47 import eu.etaxonomy.cdm.model.description.TextData;
48 import eu.etaxonomy.cdm.model.location.NamedArea;
49 import eu.etaxonomy.cdm.model.occurrence.DerivedUnit;
50 import eu.etaxonomy.cdm.model.occurrence.FieldUnit;
51 import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
52 import eu.etaxonomy.cdm.model.taxon.Classification;
53 import eu.etaxonomy.cdm.model.taxon.Taxon;
54 import eu.etaxonomy.cdm.model.taxon.TaxonBase;
55 import eu.etaxonomy.cdm.model.taxon.TaxonNode;
56 import eu.etaxonomy.cdm.persistence.dao.description.IDescriptiveDataSetDao;
57 import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonNodeDao;
58 import eu.etaxonomy.cdm.persistence.dto.SpecimenNodeWrapper;
59 import eu.etaxonomy.cdm.persistence.dto.UuidAndTitleCache;
60 import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
61
62 @Service
63 @Transactional(readOnly = false)
64 public class DescriptiveDataSetService
65 extends IdentifiableServiceBase<DescriptiveDataSet, IDescriptiveDataSetDao>
66 implements IDescriptiveDataSetService {
67
68 private static Logger logger = Logger.getLogger(DescriptiveDataSetService.class);
69
70 @Autowired
71 private IOccurrenceService occurrenceService;
72
73 @Autowired
74 private ITaxonService taxonService;
75
76 @Autowired
77 private IDescriptionService descriptionService;
78
79 @Autowired
80 private ITaxonNodeService taxonNodeService;
81
82 @Autowired
83 private ITaxonNodeDao taxonNodeDao;
84
85 @Autowired
86 private IProgressMonitorService progressMonitorService;
87
88 @Override
89 @Autowired
90 protected void setDao(IDescriptiveDataSetDao dao) {
91 this.dao = dao;
92 }
93
94 @Override
95 public Map<DescriptionBase, Set<DescriptionElementBase>> getDescriptionElements(DescriptiveDataSet descriptiveDataSet, Set<Feature> features, Integer pageSize, Integer pageNumber,
96 List<String> propertyPaths) {
97 return dao.getDescriptionElements(descriptiveDataSet, features, pageSize, pageNumber, propertyPaths);
98 }
99
100 @Override
101 public <T extends DescriptionElementBase> Map<UuidAndTitleCache, Map<UUID, Set<T>>> getTaxonFeatureDescriptionElementMap(
102 Class<T> clazz, UUID descriptiveDataSetUuid, DescriptiveSystemRole role) {
103 return dao.getTaxonFeatureDescriptionElementMap(clazz, descriptiveDataSetUuid, role);
104 }
105
106 @Override
107 public List<UuidAndTitleCache<DescriptiveDataSet>> getDescriptiveDataSetUuidAndTitleCache(Integer limitOfInitialElements, String pattern) {
108 return dao.getDescriptiveDataSetUuidAndTitleCache( limitOfInitialElements, pattern);
109 }
110
111
112 @Override
113 @Transactional
114 public UUID monitGetRowWrapper(DescriptiveDataSet descriptiveDataSet) {
115 RemotingProgressMonitorThread monitorThread = new RemotingProgressMonitorThread() {
116 @Override
117 public Serializable doRun(IRemotingProgressMonitor monitor) {
118 return getRowWrapper(descriptiveDataSet, monitor);
119 }
120 };
121 UUID uuid = progressMonitorService.registerNewRemotingMonitor(monitorThread);
122 monitorThread.setPriority(3);
123 monitorThread.start();
124 return uuid;
125 }
126
127 @Override
128 public ArrayList<RowWrapperDTO> getRowWrapper(DescriptiveDataSet descriptiveDataSet, IProgressMonitor monitor) {
129 monitor.beginTask("Load row wrapper", descriptiveDataSet.getDescriptions().size());
130 ArrayList<RowWrapperDTO> wrappers = new ArrayList<>();
131 Set<DescriptionBase> descriptions = descriptiveDataSet.getDescriptions();
132 for (DescriptionBase description : descriptions) {
133 if(monitor.isCanceled()){
134 return new ArrayList<>();
135 }
136 RowWrapperDTO rowWrapper = null;
137 if(HibernateProxyHelper.isInstanceOf(description, TaxonDescription.class)){
138 rowWrapper = createTaxonRowWrapper(HibernateProxyHelper.deproxy(description, TaxonDescription.class), descriptiveDataSet);
139 }
140 else if (HibernateProxyHelper.isInstanceOf(description, SpecimenDescription.class)){
141 rowWrapper = createSpecimenRowWrapper(HibernateProxyHelper.deproxy(description, SpecimenDescription.class), descriptiveDataSet, false);
142 }
143 if(rowWrapper!=null){
144 wrappers.add(rowWrapper);
145 }
146 monitor.worked(1);
147 }
148 return wrappers;
149 }
150
151 @Override
152 public Collection<SpecimenNodeWrapper> loadSpecimens(DescriptiveDataSet descriptiveDataSet){
153 List<UUID> filteredNodes = findFilteredTaxonNodes(descriptiveDataSet);
154 return occurrenceService.listUuidAndTitleCacheByAssociatedTaxon(filteredNodes, null, null);
155 }
156
157 @Override
158 public List<UUID> findFilteredTaxonNodes(DescriptiveDataSet descriptiveDataSet){
159 TaxonNodeFilter filter = TaxonNodeFilter.NewRankInstance(descriptiveDataSet.getMinRank(), descriptiveDataSet.getMaxRank());
160 descriptiveDataSet.getGeoFilter().forEach(area -> filter.orArea(area.getUuid()));
161 descriptiveDataSet.getTaxonSubtreeFilter().forEach(node -> filter.orSubtree(node));
162 filter.setIncludeUnpublished(true);
163
164 return taxonNodeService.uuidList(filter);
165 }
166
167 @Override
168 public List<TaxonNode> loadFilteredTaxonNodes(DescriptiveDataSet descriptiveDataSet, List<String> propertyPaths){
169 return taxonNodeService.load(findFilteredTaxonNodes(descriptiveDataSet), propertyPaths);
170 }
171
172 private TaxonNode findTaxonNodeForDescription(TaxonNode taxonNode, SpecimenOrObservationBase specimen){
173 Collection<SpecimenNodeWrapper> nodeWrapper = occurrenceService.listUuidAndTitleCacheByAssociatedTaxon(Arrays.asList(taxonNode.getUuid()), null, null);
174 for (SpecimenNodeWrapper specimenNodeWrapper : nodeWrapper) {
175 if(specimenNodeWrapper.getUuidAndTitleCache().getId().equals(specimen.getId())){
176 return taxonNode;
177 }
178 }
179 return null;
180 }
181
182 @Override
183 public TaxonRowWrapperDTO createTaxonRowWrapper(TaxonDescription description,
184 DescriptiveDataSet descriptiveDataSet) {
185 TaxonNode taxonNode = null;
186 Classification classification = null;
187 Optional<TaxonNode> first = descriptiveDataSet.getTaxonSubtreeFilter().stream()
188 .filter(node->node.getClassification()!=null).findFirst();
189 Optional<Classification> classificationOptional = first.map(node->node.getClassification());
190 if(classificationOptional.isPresent()){
191 classification = classificationOptional.get();
192 Taxon taxon = (Taxon) taxonService.load(description.getTaxon().getId(), Arrays.asList("taxonNodes", "taxonNodes.classification"));
193 taxonNode = taxon.getTaxonNode(classification);
194 }
195 return new TaxonRowWrapperDTO(description, taxonNode);
196 }
197
198 @Override
199 public SpecimenRowWrapperDTO createSpecimenRowWrapper(SpecimenDescription description, DescriptiveDataSet descriptiveDataSet,
200 boolean createDefaultTaxonDescription){
201 SpecimenOrObservationBase specimen = description.getDescribedSpecimenOrObservation();
202 TaxonNode taxonNode = null;
203 FieldUnit fieldUnit = null;
204 String identifier = null;
205 NamedArea country = null;
206 //supplemental information
207 //get taxon node
208 Set<TaxonNode> taxonSubtreeFilter = descriptiveDataSet.getTaxonSubtreeFilter();
209 for (TaxonNode node : taxonSubtreeFilter) {
210 //check for node
211 node = taxonNodeService.load(node.getId(), Arrays.asList("taxon"));
212 taxonNode = findTaxonNodeForDescription(node, specimen);
213 if(taxonNode!=null){
214 break;
215 }
216 else{
217 //check for child nodes
218 List<TaxonNode> allChildren = taxonNodeService.loadChildNodesOfTaxonNode(node, Arrays.asList("taxon"), true, true, null);
219 for (TaxonNode child : allChildren) {
220 taxonNode = findTaxonNodeForDescription(child, specimen);
221 if(taxonNode!=null){
222 break;
223 }
224 }
225 }
226 }
227 if(taxonNode==null){
228 return null;
229 }
230 //taxon node was found
231
232 //get field unit
233 Collection<FieldUnit> fieldUnits = occurrenceService.findFieldUnits(specimen.getUuid(),
234 Arrays.asList(new String[]{
235 "gatheringEvent",
236 "gatheringEvent.country"
237 }));
238 if(fieldUnits.size()!=1){
239 logger.error("More than one or no field unit found for specimen"); //$NON-NLS-1$
240 return null;
241 }
242 else{
243 fieldUnit = fieldUnits.iterator().next();
244 }
245 //get identifier
246 if(HibernateProxyHelper.isInstanceOf(specimen, DerivedUnit.class)){
247 identifier = occurrenceService.getMostSignificantIdentifier(HibernateProxyHelper.deproxy(specimen, DerivedUnit.class));
248 }
249 //get country
250 if(fieldUnit!=null && fieldUnit.getGatheringEvent()!=null){
251 country = fieldUnit.getGatheringEvent().getCountry();
252 }
253 //get default taxon description
254 TaxonDescription defaultTaxonDescription = findDefaultTaxonDescription(descriptiveDataSet.getUuid(),
255 taxonNode.getUuid(), createDefaultTaxonDescription);
256 TaxonRowWrapperDTO taxonRowWrapper = defaultTaxonDescription != null
257 ? createTaxonRowWrapper(defaultTaxonDescription, descriptiveDataSet) : null;
258 return new SpecimenRowWrapperDTO(description, taxonNode, fieldUnit, identifier, country, taxonRowWrapper);
259 }
260
261 @Override
262 @Transactional(readOnly = false)
263 public void updateTitleCache(Class<? extends DescriptiveDataSet> clazz, Integer stepSize,
264 IIdentifiableEntityCacheStrategy<DescriptiveDataSet> cacheStrategy, IProgressMonitor monitor) {
265 if (clazz == null) {
266 clazz = DescriptiveDataSet.class;
267 }
268 super.updateTitleCacheImpl(clazz, stepSize, cacheStrategy, monitor);
269 }
270
271 @Override
272 public TaxonDescription findDefaultTaxonDescription(UUID descriptiveDataSetUuid, UUID taxonNodeUuid, boolean create){
273 DescriptiveDataSet dataSet = load(descriptiveDataSetUuid);
274 TaxonNode taxonNode = taxonNodeService.load(taxonNodeUuid, Arrays.asList("taxon", "taxon.descriptions", "taxon.descriptions.markers"));
275 Set<DescriptionBase> dataSetDescriptions = dataSet.getDescriptions();
276 //filter out COMPUTED descriptions
277 List<TaxonDescription> nonComputedDescriptions = taxonNode.getTaxon().getDescriptions().stream()
278 .filter(desc -> desc.getMarkers().stream()
279 .noneMatch(marker -> marker.getMarkerType().equals(MarkerType.COMPUTED())))
280 .collect(Collectors.toList());
281 for (TaxonDescription taxonDescription : nonComputedDescriptions) {
282 for (DescriptionBase description : dataSetDescriptions) {
283 if(description.getUuid().equals(taxonDescription.getUuid())){
284 return HibernateProxyHelper.deproxy(descriptionService.load(taxonDescription.getUuid(),
285 Arrays.asList("taxon", "descriptionElements", "descriptionElements.feature")), TaxonDescription.class);
286 }
287 }
288 }
289 if(!create){
290 return null;
291 }
292 TaxonRowWrapperDTO taxonRowWrapperDTO = createTaxonDescription(descriptiveDataSetUuid, taxonNodeUuid, MarkerType.USE(), true);
293 TaxonDescription newTaxonDescription = taxonRowWrapperDTO.getDescription();
294 return newTaxonDescription;
295 }
296
297 @Override
298 @Transactional(readOnly=false)
299 public UpdateResult aggregateTaxonDescription(UUID taxonNodeUuid, UUID descriptiveDataSetUuid,
300 IRemotingProgressMonitor monitor){
301 UpdateResult result = new UpdateResult();
302
303 TaxonNode node = taxonNodeService.load(taxonNodeUuid);
304 Taxon taxon = HibernateProxyHelper.deproxy(taxonService.load(node.getTaxon().getUuid()), Taxon.class);
305 result.setCdmEntity(taxon);
306
307 //get all "computed" descriptions from all sub nodes
308 List<TaxonNode> childNodes = taxonNodeDao.listChildrenOf(node, null, null, true, false, null);
309 List<TaxonDescription> computedDescriptions = new ArrayList<>();
310
311 childNodes.stream().map(childNode -> childNode.getTaxon())
312 .forEach(childTaxon -> childTaxon.getDescriptions().stream()
313 // filter out non-computed descriptions
314 .filter(description -> description.getMarkers().stream()
315 .anyMatch(marker -> marker.getMarkerType().equals(MarkerType.COMPUTED())))
316 // add them to the list
317 .forEach(computedDescription -> computedDescriptions.add(computedDescription)));
318
319 UpdateResult aggregateDescription = aggregateDescription(taxon, computedDescriptions,
320 "[Taxon Descriptions]"+taxon.getTitleCache(), descriptiveDataSetUuid);
321 result.includeResult(aggregateDescription);
322 result.setCdmEntity(aggregateDescription.getCdmEntity());
323 aggregateDescription.setCdmEntity(null);
324 return result;
325 }
326
327 @Override
328 @Transactional(readOnly=false)
329 public UpdateResult aggregateDescription(UUID taxonUuid, List<UUID> descriptionUuids, String descriptionTitle
330 , UUID descriptiveDataSetUuid) {
331 UpdateResult result = new UpdateResult();
332
333 TaxonBase taxonBase = taxonService.load(taxonUuid);
334 if(!(taxonBase instanceof Taxon)){
335 result.addException(new ClassCastException("The given taxonUUID does not belong to a taxon"));
336 result.setError();
337 return result;
338 }
339 Taxon taxon = (Taxon)taxonBase;
340
341 List<DescriptionBase> descriptions = descriptionService.load(descriptionUuids, null);
342
343 UpdateResult aggregateDescriptionResult = aggregateDescription(taxon, descriptions, descriptionTitle, descriptiveDataSetUuid);
344 result.setCdmEntity(aggregateDescriptionResult.getCdmEntity());
345 aggregateDescriptionResult.setCdmEntity(null);
346 result.includeResult(aggregateDescriptionResult);
347 return result;
348 }
349
350 @SuppressWarnings("unchecked")
351 private UpdateResult aggregateDescription(Taxon taxon, List<? extends DescriptionBase> descriptions, String descriptionTitle
352 , UUID descriptiveDataSetUuid) {
353 UpdateResult result = new UpdateResult();
354 Map<Character, List<DescriptionElementBase>> featureToElementMap = new HashMap<>();
355
356 DescriptiveDataSet dataSet = load(descriptiveDataSetUuid);
357 if(dataSet==null){
358 result.addException(new IllegalArgumentException("Could not find data set for uuid "+descriptiveDataSetUuid));
359 result.setAbort();
360 return result;
361 }
362
363 //extract all character description elements
364 descriptions.forEach(description->{
365 description.getElements()
366 .stream()
367 //filter out elements that do not have a Characters as Feature
368 .filter(element->HibernateProxyHelper.isInstanceOf(((DescriptionElementBase)element).getFeature(), Character.class))
369 .forEach(ele->{
370 DescriptionElementBase descriptionElement = (DescriptionElementBase)ele;
371 List<DescriptionElementBase> list = featureToElementMap.get(descriptionElement.getFeature());
372 if(list==null){
373 list = new ArrayList<>();
374 }
375 list.add(descriptionElement);
376 featureToElementMap.put(HibernateProxyHelper.deproxy(descriptionElement.getFeature(), Character.class), list);
377 });
378 });
379
380 TaxonDescription description = TaxonDescription.NewInstance(taxon);
381 description.setTitleCache("[Aggregation] "+descriptionTitle, true);
382 description.addMarker(Marker.NewInstance(MarkerType.COMPUTED(), true));
383 IdentifiableSource source = IdentifiableSource.NewInstance(OriginalSourceType.Aggregation);
384 description.addSource(source);
385 description.addDescriptiveDataSet(dataSet);
386
387 featureToElementMap.forEach((feature, elements)->{
388 //aggregate categorical data
389 if(feature.isSupportsCategoricalData()){
390 CategoricalData aggregate = CategoricalData.NewInstance(feature);
391 elements.stream()
392 .filter(element->element instanceof CategoricalData)
393 .forEach(categoricalData->((CategoricalData)categoricalData).getStateData()
394 .forEach(stateData->aggregate.addStateData((StateData) stateData.clone())));
395 description.addElement(aggregate);
396 }
397 //aggregate quantitative data
398 else if(feature.isSupportsQuantitativeData()){
399 QuantitativeData aggregate = QuantitativeData.NewInstance(feature);
400 elements.stream()
401 .filter(element->element instanceof QuantitativeData)
402 .forEach(categoricalData->((QuantitativeData)categoricalData).getStatisticalValues()
403 .forEach(statisticalValue->aggregate.addStatisticalValue((StatisticalMeasurementValue) statisticalValue.clone())));
404 description.addElement(aggregate);
405 }
406 });
407 result.addUpdatedObject(taxon);
408 result.setCdmEntity(description);
409 return result;
410 }
411
412 @Override
413 public TaxonRowWrapperDTO createTaxonDescription(UUID dataSetUuid, UUID taxonNodeUuid, MarkerType markerType, boolean markerFlag){
414 DescriptiveDataSet dataSet = load(dataSetUuid);
415 TaxonNode taxonNode = taxonNodeService.load(taxonNodeUuid, Arrays.asList("taxon"));
416 TaxonDescription newTaxonDescription = TaxonDescription.NewInstance(taxonNode.getTaxon());
417 String tag = "";
418 if(markerFlag){
419 if(markerType.equals(MarkerType.USE())){
420 tag = "[Default]";
421 }
422 else if(markerType.equals(MarkerType.IN_BIBLIOGRAPHY())){
423 tag = "[Literature]";
424 }
425 }
426 newTaxonDescription.setTitleCache(tag+" "+dataSet.getLabel()+": "+newTaxonDescription.generateTitle(), true); //$NON-NLS-2$
427 if(markerType!=null){
428 newTaxonDescription.addMarker(Marker.NewInstance(markerType, markerFlag));
429 }
430 dataSet.getDescriptiveSystem().getDistinctFeatures().forEach(wsFeature->{
431 if(wsFeature.isSupportsCategoricalData()){
432 newTaxonDescription.addElement(CategoricalData.NewInstance(wsFeature));
433 }
434 else if(wsFeature.isSupportsQuantitativeData()){
435 newTaxonDescription.addElement(QuantitativeData.NewInstance(wsFeature));
436 }
437 });
438 dataSet.addDescription(newTaxonDescription);
439
440 return createTaxonRowWrapper(newTaxonDescription, dataSet);
441 }
442
443 @Override
444 public SpecimenDescription findSpecimenDescription(UUID descriptiveDataSetUuid, UUID specimenUuid){
445 DescriptiveDataSet dataSet = load(descriptiveDataSetUuid);
446 SpecimenOrObservationBase specimen = occurrenceService.load(specimenUuid);
447
448 Set<Feature> datasetFeatures = dataSet.getDescriptiveSystem().getDistinctFeatures();
449 List<DescriptionElementBase> matchingDescriptionElements = new ArrayList<>();
450
451 for (SpecimenDescription specimenDescription : (Set<SpecimenDescription>) specimen.getDescriptions()) {
452 specimenDescription = (SpecimenDescription) descriptionService.load(specimenDescription.getUuid());
453
454 //check if description is already added to data set
455 if(dataSet.getDescriptions().contains(specimenDescription)){
456 return specimenDescription;
457 }
458
459 //gather specimen description features and check for match with dataset features
460 Set<Feature> specimenDescriptionFeatures = new HashSet<>();
461 for (DescriptionElementBase specimenDescriptionElement : specimenDescription.getElements()) {
462 Feature feature = specimenDescriptionElement.getFeature();
463 specimenDescriptionFeatures.add(feature);
464 if(datasetFeatures.contains(feature)){
465 matchingDescriptionElements.add(specimenDescriptionElement);
466 }
467 }
468 }
469 //Create new specimen description if description has not already been added to the dataset
470 SpecimenDescription newDesription = SpecimenDescription.NewInstance(specimen);
471 newDesription.setTitleCache("Dataset "+dataSet.getLabel()+": "+newDesription.generateTitle(), true); //$NON-NLS-2$
472
473 //check for equals description element (same feature and same values)
474 Map<Feature, List<DescriptionElementBase>> featureToElementMap = new HashMap<>();
475 for(DescriptionElementBase element:matchingDescriptionElements){
476 List<DescriptionElementBase> list = featureToElementMap.get(element.getFeature());
477 if(list==null){
478 list = new ArrayList<>();
479 }
480 list.add(element);
481 featureToElementMap.put(element.getFeature(), list);
482 }
483 Set<DescriptionElementBase> descriptionElementsToClone = new HashSet<>();
484 for(Feature feature:featureToElementMap.keySet()){
485 List<DescriptionElementBase> elements = featureToElementMap.get(feature);
486 //no duplicate description elements found for this feature
487 if(elements.size()==1){
488 descriptionElementsToClone.add(elements.get(0));
489 }
490 //duplicates found -> check if all are equal
491 else{
492 DescriptionElementBase match = null;
493 for (DescriptionElementBase descriptionElementBase : elements) {
494 if(match==null){
495 match = descriptionElementBase;
496 }
497 else if(!new DescriptionElementCompareWrapper(match).equals(new DescriptionElementCompareWrapper(descriptionElementBase))){
498 match = null;
499 //TODO: propagate message
500 // MessagingUtils.informationDialog(Messages.CharacterMatrix_MULTIPLE_DATA,
501 // String.format(Messages.CharacterMatrix_MULTIPLE_DATA_MESSAGE, feature.getLabel()));
502 break;
503 }
504 }
505 if(match!=null){
506 descriptionElementsToClone.add(match);
507 }
508 }
509 }
510 //clone matching descriptionElements
511 for (DescriptionElementBase descriptionElementBase : descriptionElementsToClone) {
512 DescriptionElementBase clone;
513 try {
514 clone = descriptionElementBase.clone(newDesription);
515 clone.getSources().forEach(source -> {
516 if(descriptionElementBase instanceof CategoricalData){
517 TextData label = new DefaultCategoricalDescriptionBuilder().build((CategoricalData) descriptionElementBase, null);
518 source.setOriginalNameString(label.getText(Language.DEFAULT()));
519 }
520 else if(descriptionElementBase instanceof QuantitativeData){
521 TextData label = new DefaultQuantitativeDescriptionBuilder().build((QuantitativeData) descriptionElementBase, null);
522 source.setOriginalNameString(label.getText(Language.DEFAULT()));
523 }
524 });
525 } catch (CloneNotSupportedException e) {
526 // MessagingUtils.error(CharacterMatrix.class, e);
527 }
528 }
529
530 //add all remaining description elements to the new description
531 for(Feature wsFeature:datasetFeatures){
532 boolean featureFound = false;
533 for(DescriptionElementBase element:newDesription.getElements()){
534 if(element.getFeature().equals(wsFeature)){
535 featureFound = true;
536 break;
537 }
538 }
539 if(!featureFound){
540 if(wsFeature.isSupportsCategoricalData()){
541 newDesription.addElement(CategoricalData.NewInstance(wsFeature));
542 }
543 else if(wsFeature.isSupportsQuantitativeData()){
544 newDesription.addElement(QuantitativeData.NewInstance(wsFeature));
545 }
546 }
547 }
548 return newDesription;
549
550 }
551
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 {
555
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<>();
567
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()));
573 }
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());
579 }
580 else if(value.getType().equals(StatisticalMeasure.EXACT_VALUE())){
581 exacts.add(value.getValue());
582
583 }
584 else if(value.getType().equals(StatisticalMeasure.MAX())){
585 maxs.add(value.getValue());
586 }
587 else if(value.getType().equals(StatisticalMeasure.MIN())){
588 mins.add(value.getValue());
589 }
590 else if(value.getType().equals(StatisticalMeasure.SAMPLE_SIZE())){
591 sampleSizes.add(value.getValue());
592
593 }
594 else if(value.getType().equals(StatisticalMeasure.STANDARD_DEVIATION())){
595 standardDevs.add(value.getValue());
596 }
597 else if(value.getType().equals(StatisticalMeasure.TYPICAL_LOWER_BOUNDARY())){
598 lowerBounds.add(value.getValue());
599
600 }
601 else if(value.getType().equals(StatisticalMeasure.TYPICAL_UPPER_BOUNDARY())){
602 upperBounds.add(value.getValue());
603 }
604 else if(value.getType().equals(StatisticalMeasure.VARIANCE())){
605 variances.add(value.getValue());
606 }
607 });
608 }
609 }
610
611 @Override
612 public int hashCode() {
613 final int prime = 31;
614 int result = 1;
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());
627 return result;
628 }
629
630 @Override
631 public boolean equals(Object obj) {
632 if (this == obj) {
633 return true;
634 }
635 if (obj == null) {
636 return false;
637 }
638 if (getClass() != obj.getClass()) {
639 return false;
640 }
641 DescriptionElementCompareWrapper other = (DescriptionElementCompareWrapper) obj;
642 if (!getOuterType().equals(other.getOuterType())) {
643 return false;
644 }
645 if (avgs == null) {
646 if (other.avgs != null) {
647 return false;
648 }
649 } else if (!avgs.equals(other.avgs)) {
650 return false;
651 }
652 if (element == null) {
653 if (other.element != null) {
654 return false;
655 }
656 } else if (!element.equals(other.element)) {
657 return false;
658 }
659 if (exacts == null) {
660 if (other.exacts != null) {
661 return false;
662 }
663 } else if (!exacts.equals(other.exacts)) {
664 return false;
665 }
666 if (lowerBounds == null) {
667 if (other.lowerBounds != null) {
668 return false;
669 }
670 } else if (!lowerBounds.equals(other.lowerBounds)) {
671 return false;
672 }
673 if (maxs == null) {
674 if (other.maxs != null) {
675 return false;
676 }
677 } else if (!maxs.equals(other.maxs)) {
678 return false;
679 }
680 if (mins == null) {
681 if (other.mins != null) {
682 return false;
683 }
684 } else if (!mins.equals(other.mins)) {
685 return false;
686 }
687 if (sampleSizes == null) {
688 if (other.sampleSizes != null) {
689 return false;
690 }
691 } else if (!sampleSizes.equals(other.sampleSizes)) {
692 return false;
693 }
694 if (standardDevs == null) {
695 if (other.standardDevs != null) {
696 return false;
697 }
698 } else if (!standardDevs.equals(other.standardDevs)) {
699 return false;
700 }
701 if (stateUuids == null) {
702 if (other.stateUuids != null) {
703 return false;
704 }
705 } else if (!stateUuids.equals(other.stateUuids)) {
706 return false;
707 }
708 if (upperBounds == null) {
709 if (other.upperBounds != null) {
710 return false;
711 }
712 } else if (!upperBounds.equals(other.upperBounds)) {
713 return false;
714 }
715 if (variances == null) {
716 if (other.variances != null) {
717 return false;
718 }
719 } else if (!variances.equals(other.variances)) {
720 return false;
721 }
722 return true;
723 }
724
725 private DescriptiveDataSetService getOuterType() {
726 return DescriptiveDataSetService.this;
727 }
728
729 }
730
731 }