import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.Set;
import java.util.UUID;
+import java.util.stream.Collectors;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import eu.etaxonomy.cdm.api.service.dto.RowWrapperDTO;
+import eu.etaxonomy.cdm.api.service.dto.SpecimenRowWrapperDTO;
+import eu.etaxonomy.cdm.api.service.dto.TaxonRowWrapperDTO;
import eu.etaxonomy.cdm.common.monitor.IProgressMonitor;
import eu.etaxonomy.cdm.common.monitor.IRemotingProgressMonitor;
import eu.etaxonomy.cdm.common.monitor.RemotingProgressMonitorThread;
import eu.etaxonomy.cdm.filter.TaxonNodeFilter;
import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
import eu.etaxonomy.cdm.model.common.Language;
+import eu.etaxonomy.cdm.model.common.MarkerType;
import eu.etaxonomy.cdm.model.description.CategoricalData;
import eu.etaxonomy.cdm.model.description.DescriptionBase;
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
import eu.etaxonomy.cdm.model.description.Feature;
import eu.etaxonomy.cdm.model.description.QuantitativeData;
import eu.etaxonomy.cdm.model.description.SpecimenDescription;
+import eu.etaxonomy.cdm.model.description.StatisticalMeasure;
+import eu.etaxonomy.cdm.model.description.TaxonDescription;
import eu.etaxonomy.cdm.model.description.TextData;
import eu.etaxonomy.cdm.model.location.NamedArea;
import eu.etaxonomy.cdm.model.occurrence.DerivedUnit;
import eu.etaxonomy.cdm.model.occurrence.FieldUnit;
import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
+import eu.etaxonomy.cdm.model.taxon.Classification;
import eu.etaxonomy.cdm.model.taxon.Taxon;
-import eu.etaxonomy.cdm.model.taxon.TaxonBase;
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
import eu.etaxonomy.cdm.persistence.dao.description.IDescriptiveDataSetDao;
import eu.etaxonomy.cdm.persistence.dto.SpecimenNodeWrapper;
@Autowired
private IOccurrenceService occurrenceService;
+ @Autowired
+ private ITaxonService taxonService;
+
@Autowired
private IDescriptionService descriptionService;
if(monitor.isCanceled()){
return new ArrayList<>();
}
- wrappers.add(createRowWrapper(null, description, null, descriptiveDataSet));
+ RowWrapperDTO rowWrapper = null;
+ if(HibernateProxyHelper.isInstanceOf(description, TaxonDescription.class)){
+ rowWrapper = createTaxonRowWrapper(HibernateProxyHelper.deproxy(description, TaxonDescription.class), descriptiveDataSet);
+ }
+ else if (HibernateProxyHelper.isInstanceOf(description, SpecimenDescription.class)){
+ rowWrapper = createSpecimenRowWrapper(HibernateProxyHelper.deproxy(description, SpecimenDescription.class), descriptiveDataSet, false);
+ }
+ if(rowWrapper!=null){
+ wrappers.add(rowWrapper);
+ }
monitor.worked(1);
}
return wrappers;
@Override
public Collection<SpecimenNodeWrapper> loadSpecimens(DescriptiveDataSet descriptiveDataSet){
- //set filter parameters
+ List<UUID> filteredNodes = findFilteredTaxonNodes(descriptiveDataSet);
+ return occurrenceService.listUuidAndTitleCacheByAssociatedTaxon(filteredNodes, null, null);
+ }
+
+ @Override
+ public List<UUID> findFilteredTaxonNodes(DescriptiveDataSet descriptiveDataSet){
TaxonNodeFilter filter = TaxonNodeFilter.NewRankInstance(descriptiveDataSet.getMinRank(), descriptiveDataSet.getMaxRank());
descriptiveDataSet.getGeoFilter().forEach(area -> filter.orArea(area.getUuid()));
descriptiveDataSet.getTaxonSubtreeFilter().forEach(node -> filter.orSubtree(node));
filter.setIncludeUnpublished(true);
- List<UUID> filteredNodes = taxonNodeService.uuidList(filter);
- return occurrenceService.listUuidAndTitleCacheByAssociatedTaxon(filteredNodes, null, null);
+ return taxonNodeService.uuidList(filter);
}
@Override
- public RowWrapperDTO createRowWrapper(DescriptionBase description, DescriptiveDataSet descriptiveDataSet){
- return createRowWrapper(null, description, null, descriptiveDataSet);
+ public List<TaxonNode> loadFilteredTaxonNodes(DescriptiveDataSet descriptiveDataSet, List<String> propertyPaths){
+ return taxonNodeService.load(findFilteredTaxonNodes(descriptiveDataSet), propertyPaths);
+ }
+
+ private TaxonNode findTaxonNodeForDescription(TaxonNode taxonNode, SpecimenOrObservationBase specimen){
+ Collection<SpecimenNodeWrapper> nodeWrapper = occurrenceService.listUuidAndTitleCacheByAssociatedTaxon(Arrays.asList(taxonNode.getUuid()), null, null);
+ for (SpecimenNodeWrapper specimenNodeWrapper : nodeWrapper) {
+ if(specimenNodeWrapper.getUuidAndTitleCache().getId().equals(specimen.getId())){
+ return taxonNode;
+ }
+ }
+ return null;
}
@Override
- public RowWrapperDTO createRowWrapper(SpecimenOrObservationBase specimen, DescriptiveDataSet descriptiveDataSet){
- return createRowWrapper(specimen, null, null, descriptiveDataSet);
+ public TaxonRowWrapperDTO createTaxonRowWrapper(TaxonDescription description,
+ DescriptiveDataSet descriptiveDataSet) {
+ TaxonNode taxonNode = null;
+ Classification classification = null;
+ Optional<TaxonNode> first = descriptiveDataSet.getTaxonSubtreeFilter().stream()
+ .filter(node->node.getClassification()!=null).findFirst();
+ Optional<Classification> classificationOptional = first.map(node->node.getClassification());
+ if(classificationOptional.isPresent()){
+ classification = classificationOptional.get();
+ Taxon taxon = (Taxon) taxonService.load(description.getTaxon().getId(), Arrays.asList("taxonNodes", "taxonNodes.classification"));
+ taxonNode = taxon.getTaxonNode(classification);
+ }
+ return new TaxonRowWrapperDTO(description, taxonNode);
}
- private RowWrapperDTO createRowWrapper(SpecimenOrObservationBase specimen, DescriptionBase description, TaxonNode taxonNode, DescriptiveDataSet descriptiveDataSet){
- if(description!=null){
- specimen = description.getDescribedSpecimenOrObservation();
- }
+ @Override
+ public SpecimenRowWrapperDTO createSpecimenRowWrapper(SpecimenDescription description, DescriptiveDataSet descriptiveDataSet,
+ boolean createDefaultTaxonDescription){
+ SpecimenOrObservationBase specimen = description.getDescribedSpecimenOrObservation();
+ TaxonNode taxonNode = null;
FieldUnit fieldUnit = null;
String identifier = null;
NamedArea country = null;
//supplemental information
- if(specimen!=null){
- if(taxonNode==null){
- Collection<TaxonBase<?>> associatedTaxa = occurrenceService.listAssociatedTaxa(specimen, null, null, null,
- Arrays.asList(new String[]{
- "taxonNodes",
- "taxonNodes.classification",
- }));
- if(associatedTaxa!=null && !associatedTaxa.isEmpty()){
- //FIXME: what about multiple associated taxa
- Set<TaxonNode> taxonSubtreeFilter = descriptiveDataSet.getTaxonSubtreeFilter();
- if(taxonSubtreeFilter!=null && !taxonSubtreeFilter.isEmpty()){
- Taxon taxon = HibernateProxyHelper.deproxy(associatedTaxa.iterator().next(), Taxon.class);
- taxonNode = taxon.getTaxonNode(taxonSubtreeFilter.iterator().next().getClassification());
- }
- }
- }
- Collection<FieldUnit> fieldUnits = occurrenceService.findFieldUnits(specimen.getUuid(),
- Arrays.asList(new String[]{
- "gatheringEvent",
- "gatheringEvent.country"
- }));
- if(fieldUnits.size()!=1){
- logger.error("More than one or no field unit found for specimen"); //$NON-NLS-1$
+ //get taxon node
+ Set<TaxonNode> taxonSubtreeFilter = descriptiveDataSet.getTaxonSubtreeFilter();
+ for (TaxonNode node : taxonSubtreeFilter) {
+ //check for node
+ node = taxonNodeService.load(node.getId(), Arrays.asList("taxon"));
+ taxonNode = findTaxonNodeForDescription(node, specimen);
+ if(taxonNode!=null){
+ break;
}
else{
- fieldUnit = fieldUnits.iterator().next();
- }
- if(specimen instanceof DerivedUnit){
- identifier = occurrenceService.getMostSignificantIdentifier(HibernateProxyHelper.deproxy(specimen, DerivedUnit.class));
- }
- if(fieldUnit!=null && fieldUnit.getGatheringEvent()!=null){
- country = fieldUnit.getGatheringEvent().getCountry();
+ //check for child nodes
+ List<TaxonNode> allChildren = taxonNodeService.loadChildNodesOfTaxonNode(node, Arrays.asList("taxon"), true, true, null);
+ for (TaxonNode child : allChildren) {
+ taxonNode = findTaxonNodeForDescription(child, specimen);
+ if(taxonNode!=null){
+ break;
+ }
+ }
}
}
- return new RowWrapperDTO(description, specimen, taxonNode, fieldUnit, identifier, country);
+ if(taxonNode==null){
+ return null;
+ }
+ //taxon node was found
+
+ //get field unit
+ Collection<FieldUnit> fieldUnits = occurrenceService.findFieldUnits(specimen.getUuid(),
+ Arrays.asList(new String[]{
+ "gatheringEvent",
+ "gatheringEvent.country"
+ }));
+ if(fieldUnits.size()!=1){
+ logger.error("More than one or no field unit found for specimen"); //$NON-NLS-1$
+ return null;
+ }
+ else{
+ fieldUnit = fieldUnits.iterator().next();
+ }
+ //get identifier
+ if(specimen instanceof DerivedUnit){
+ identifier = occurrenceService.getMostSignificantIdentifier(HibernateProxyHelper.deproxy(specimen, DerivedUnit.class));
+ }
+ //get country
+ if(fieldUnit!=null && fieldUnit.getGatheringEvent()!=null){
+ country = fieldUnit.getGatheringEvent().getCountry();
+ }
+ //get default taxon description
+ TaxonDescription defaultTaxonDescription = findDefaultTaxonDescription(descriptiveDataSet.getUuid(),
+ taxonNode.getUuid(), createDefaultTaxonDescription);
+ TaxonRowWrapperDTO taxonRowWrapper = defaultTaxonDescription != null
+ ? createTaxonRowWrapper(defaultTaxonDescription, descriptiveDataSet) : null;
+ return new SpecimenRowWrapperDTO(description, taxonNode, fieldUnit, identifier, country, taxonRowWrapper);
}
@Override
}
@Override
- public SpecimenDescription findDescriptionForDescriptiveDataSet(UUID descriptiveDataSetUuid, UUID specimenUuid){
+ public TaxonDescription findDefaultTaxonDescription(UUID descriptiveDataSetUuid, UUID taxonNodeUuid, boolean create){
+ DescriptiveDataSet dataSet = load(descriptiveDataSetUuid);
+ TaxonNode taxonNode = taxonNodeService.load(taxonNodeUuid, Arrays.asList("taxon", "taxon.descriptions", "taxon.descriptions.markers"));
+ Set<DescriptionBase> dataSetDescriptions = dataSet.getDescriptions();
+ //filter out COMPUTED descriptions
+ List<TaxonDescription> nonComputedDescriptions = taxonNode.getTaxon().getDescriptions().stream()
+ .filter(desc -> desc.getMarkers().stream()
+ .anyMatch(marker -> marker.getMarkerType().equals(MarkerType.COMPUTED())))
+ .collect(Collectors.toList());
+ for (TaxonDescription taxonDescription : nonComputedDescriptions) {
+ for (DescriptionBase description : dataSetDescriptions) {
+ if(description.getUuid().equals(taxonDescription.getUuid())){
+ return taxonDescription;
+ }
+ }
+ }
+ if(!create){
+ return null;
+ }
+ //description not yet added to dataset -> create a new one
+ TaxonDescription newTaxonDescription = TaxonDescription.NewInstance(taxonNode.getTaxon());
+ newTaxonDescription.setTitleCache("Dataset "+dataSet.getLabel()+": "+newTaxonDescription.generateTitle(), true); //$NON-NLS-2$
+ dataSet.getDescriptiveSystem().getDistinctFeatures().forEach(wsFeature->{
+ if(wsFeature.isSupportsCategoricalData()){
+ newTaxonDescription.addElement(CategoricalData.NewInstance(wsFeature));
+ }
+ else if(wsFeature.isSupportsQuantitativeData()){
+ newTaxonDescription.addElement(QuantitativeData.NewInstance(wsFeature));
+ }
+ });
+ return newTaxonDescription;
+ }
+
+ @Override
+ public SpecimenDescription findSpecimenDescription(UUID descriptiveDataSetUuid, UUID specimenUuid){
DescriptiveDataSet dataSet = load(descriptiveDataSetUuid);
SpecimenOrObservationBase specimen = occurrenceService.load(specimenUuid);
}
+ //TODO: this should either be solved in the model class itself
+ //OR this should cover all possibilities including modifiers for example
private class DescriptionElementCompareWrapper {
private DescriptionElementBase element;
private Set<UUID> stateUuids = new HashSet<>();
- private Float min = null;
- private Float max = null;
+ private Set<Float> avgs = new HashSet<>();
+ private Set<Float> exacts = new HashSet<>();
+ private Set<Float> maxs = new HashSet<>();
+ private Set<Float> mins = new HashSet<>();
+ private Set<Float> sampleSizes = new HashSet<>();
+ private Set<Float> standardDevs = new HashSet<>();
+ private Set<Float> lowerBounds = new HashSet<>();
+ private Set<Float> upperBounds = new HashSet<>();
+ private Set<Float> variances = new HashSet<>();
public DescriptionElementCompareWrapper(DescriptionElementBase element) {
this.element = element;
}
else if(element.isInstanceOf(QuantitativeData.class)){
QuantitativeData elementData = (QuantitativeData)element;
- min = elementData.getMin();
- max = elementData.getMax();
- }
- }
+ elementData.getStatisticalValues().forEach(value->{
+ if(value.getType().equals(StatisticalMeasure.AVERAGE())){
+ avgs.add(value.getValue());
+ }
+ else if(value.getType().equals(StatisticalMeasure.EXACT_VALUE())){
+ exacts.add(value.getValue());
+
+ }
+ else if(value.getType().equals(StatisticalMeasure.MAX())){
+ maxs.add(value.getValue());
+ }
+ else if(value.getType().equals(StatisticalMeasure.MIN())){
+ mins.add(value.getValue());
+ }
+ else if(value.getType().equals(StatisticalMeasure.SAMPLE_SIZE())){
+ sampleSizes.add(value.getValue());
- public DescriptionElementBase unwrap() {
- return element;
+ }
+ else if(value.getType().equals(StatisticalMeasure.STANDARD_DEVIATION())){
+ standardDevs.add(value.getValue());
+ }
+ else if(value.getType().equals(StatisticalMeasure.TYPICAL_LOWER_BOUNDARY())){
+ lowerBounds.add(value.getValue());
+
+ }
+ else if(value.getType().equals(StatisticalMeasure.TYPICAL_UPPER_BOUNDARY())){
+ upperBounds.add(value.getValue());
+ }
+ else if(value.getType().equals(StatisticalMeasure.VARIANCE())){
+ variances.add(value.getValue());
+ }
+ });
+ }
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
- result = prime * result + ((max == null) ? 0 : max.hashCode());
- result = prime * result + ((min == null) ? 0 : min.hashCode());
+ result = prime * result + getOuterType().hashCode();
+ result = prime * result + ((avgs == null) ? 0 : avgs.hashCode());
+ result = prime * result + ((element == null) ? 0 : element.hashCode());
+ result = prime * result + ((exacts == null) ? 0 : exacts.hashCode());
+ result = prime * result + ((lowerBounds == null) ? 0 : lowerBounds.hashCode());
+ result = prime * result + ((maxs == null) ? 0 : maxs.hashCode());
+ result = prime * result + ((mins == null) ? 0 : mins.hashCode());
+ result = prime * result + ((sampleSizes == null) ? 0 : sampleSizes.hashCode());
+ result = prime * result + ((standardDevs == null) ? 0 : standardDevs.hashCode());
result = prime * result + ((stateUuids == null) ? 0 : stateUuids.hashCode());
+ result = prime * result + ((upperBounds == null) ? 0 : upperBounds.hashCode());
+ result = prime * result + ((variances == null) ? 0 : variances.hashCode());
return result;
}
return false;
}
DescriptionElementCompareWrapper other = (DescriptionElementCompareWrapper) obj;
- if (max == null) {
- if (other.max != null) {
+ if (!getOuterType().equals(other.getOuterType())) {
+ return false;
+ }
+ if (avgs == null) {
+ if (other.avgs != null) {
return false;
}
- } else if (!max.equals(other.max)) {
+ } else if (!avgs.equals(other.avgs)) {
return false;
}
- if (min == null) {
- if (other.min != null) {
+ if (element == null) {
+ if (other.element != null) {
return false;
}
- } else if (!min.equals(other.min)) {
+ } else if (!element.equals(other.element)) {
+ return false;
+ }
+ if (exacts == null) {
+ if (other.exacts != null) {
+ return false;
+ }
+ } else if (!exacts.equals(other.exacts)) {
+ return false;
+ }
+ if (lowerBounds == null) {
+ if (other.lowerBounds != null) {
+ return false;
+ }
+ } else if (!lowerBounds.equals(other.lowerBounds)) {
+ return false;
+ }
+ if (maxs == null) {
+ if (other.maxs != null) {
+ return false;
+ }
+ } else if (!maxs.equals(other.maxs)) {
+ return false;
+ }
+ if (mins == null) {
+ if (other.mins != null) {
+ return false;
+ }
+ } else if (!mins.equals(other.mins)) {
+ return false;
+ }
+ if (sampleSizes == null) {
+ if (other.sampleSizes != null) {
+ return false;
+ }
+ } else if (!sampleSizes.equals(other.sampleSizes)) {
+ return false;
+ }
+ if (standardDevs == null) {
+ if (other.standardDevs != null) {
+ return false;
+ }
+ } else if (!standardDevs.equals(other.standardDevs)) {
return false;
}
if (stateUuids == null) {
} else if (!stateUuids.equals(other.stateUuids)) {
return false;
}
+ if (upperBounds == null) {
+ if (other.upperBounds != null) {
+ return false;
+ }
+ } else if (!upperBounds.equals(other.upperBounds)) {
+ return false;
+ }
+ if (variances == null) {
+ if (other.variances != null) {
+ return false;
+ }
+ } else if (!variances.equals(other.variances)) {
+ return false;
+ }
return true;
}
+
+ private DescriptiveDataSetService getOuterType() {
+ return DescriptiveDataSetService.this;
+ }
+
}
}