ref #9502, ref #9503, ref #10308 use areaTree in distributionInfo
authorAndreas Müller <a.mueller@bgbm.org>
Fri, 28 Apr 2023 21:26:10 +0000 (23:26 +0200)
committerAndreas Müller <a.mueller@bgbm.org>
Fri, 28 Apr 2023 22:45:32 +0000 (00:45 +0200)
22 files changed:
cdmlib-api/src/main/java/eu/etaxonomy/cdm/api/dto/portal/DistributionDto.java
cdmlib-api/src/main/java/eu/etaxonomy/cdm/api/dto/portal/NamedAreaDto.java
cdmlib-api/src/main/java/eu/etaxonomy/cdm/api/dto/portal/config/DistributionInfoConfiguration.java
cdmlib-commons/src/main/java/eu/etaxonomy/cdm/common/SetMap.java
cdmlib-io/src/main/java/eu/etaxonomy/cdm/io/cdmLight/CdmLightClassificationExport.java
cdmlib-io/src/main/java/eu/etaxonomy/cdm/io/cdmLightWord/WordClassificationExport.java
cdmlib-io/src/main/java/eu/etaxonomy/cdm/io/csv/caryophyllales/out/CsvNameExport.java
cdmlib-model/src/main/java/eu/etaxonomy/cdm/format/description/distribution/CondensedDistributionComposer.java
cdmlib-model/src/main/java/eu/etaxonomy/cdm/model/term/TermNode.java
cdmlib-model/src/main/java/eu/etaxonomy/cdm/model/term/TermTree.java
cdmlib-model/src/test/java/eu/etaxonomy/cdm/format/description/distribution/CondensedDistributionComposerEuroMedTest.java
cdmlib-model/src/test/java/eu/etaxonomy/cdm/format/description/distribution/CondensedDistributionComposerFloraCubaTest.java
cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/persistence/dao/hibernate/term/DefinedTermDaoImpl.java
cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/persistence/dao/term/IDefinedTermDao.java
cdmlib-remote/src/main/java/eu/etaxonomy/cdm/remote/controller/DescriptionListController.java
cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/geo/DistributionServiceImpl.java
cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/geo/DistributionServiceUtilities.java
cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/geo/DistributionTree.java
cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/geo/IDistributionService.java
cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/portal/DistributionTreeDtoLoader.java
cdmlib-services/src/test/java/eu/etaxonomy/cdm/api/service/geo/DistributionServiceImplTest.java
cdmlib-services/src/test/java/eu/etaxonomy/cdm/api/service/geo/DistributionServiceUtilitiesTest.java

index 42c675f547bdc1d5b3d4e8297415de3c340d2d7c..974a8634ff5d6acd2c10662ce154a60f927d0c39 100644 (file)
@@ -35,7 +35,7 @@ public class DistributionDto extends FactDtoBase {
         this.setId(distribution.getId());
         this.setLastUpdated(null);   //TODO
         if (distribution.getArea() != null) {
-            this.area = new NamedAreaDto(distribution.getArea(), false);
+            this.area = new NamedAreaDto(distribution.getArea(), null);
         }
         if (distribution.getStatus() != null) {
             PresenceAbsenceTerm distStatus = distribution.getStatus();
index e1bf59ae2e91c09fe8a2e01acf2c1c876376be1c..82abe4378b01ad1610e7e8b5dbc252e8774488d2 100644 (file)
@@ -12,6 +12,7 @@ package eu.etaxonomy.cdm.api.dto.portal;
 import java.util.Set;
 import java.util.UUID;
 
+import eu.etaxonomy.cdm.common.SetMap;
 import eu.etaxonomy.cdm.model.common.Marker;
 import eu.etaxonomy.cdm.model.common.MarkerType;
 import eu.etaxonomy.cdm.model.location.NamedArea;
@@ -26,7 +27,7 @@ public class NamedAreaDto extends CdmBaseDto {
 
     private String label;
     private LabeledEntityDto level;
-    private NamedAreaDto partOf;
+    private NamedAreaDto parent;
     private Set<Marker> markers;
 
 //    public class NamedAreaLevelDTO extends CdmBaseDto {
@@ -40,19 +41,19 @@ public class NamedAreaDto extends CdmBaseDto {
 //        }
 //    }
 
-    public NamedAreaDto(UUID uuid, int id, String label, NamedAreaLevel level, NamedAreaDto partOf, Set<Marker> markers) {
+    public NamedAreaDto(UUID uuid, int id, String label, NamedAreaLevel level, NamedAreaDto parent, Set<Marker> markers) {
         super(uuid, id, null);
         setUuid(uuid);
         this.label = label;
         if (level != null) {
             this.level = new LabeledEntityDto(level.getUuid(), level.getId(), level.getLabel());
         }
-        this.partOf = partOf;
+        this.parent = parent;
         this.markers = markers;
     }
 
     //TODO should not exist
-    public NamedAreaDto(NamedArea area, boolean withPartOf) {
+    public NamedAreaDto(NamedArea area, SetMap<NamedArea, NamedArea> parentAreaMap) {
         super(area.getUuid(), area.getId(), null);
         this.label = area.getLabel();   //TODO i18n
         if (area.getLevel() != null) {
@@ -60,8 +61,11 @@ public class NamedAreaDto extends CdmBaseDto {
             //TODO i18n
             level = new LabeledEntityDto(aLevel.getUuid(), aLevel.getId(), aLevel.getLabel());
         }
-        if (withPartOf && area.getPartOf() != null) {
-            this.partOf = new NamedAreaDto(area.getPartOf(), withPartOf);
+        if (parentAreaMap != null) {
+            NamedArea parent = parentAreaMap.getFirstValue(area);  //TODO handle >1 parents
+            if (parent != null) {
+                this.parent = new NamedAreaDto(parent, parentAreaMap);
+            }
         }
         this.markers = area.getMarkers();
     }
@@ -77,8 +81,8 @@ public class NamedAreaDto extends CdmBaseDto {
     }
 
 //    @Override
-    public NamedAreaDto getPartOf() {
-        return partOf;
+    public NamedAreaDto getParent() {
+        return parent;
     }
 
     public boolean hasMarker(MarkerType markerType, boolean value) {
index 9b6607e72ed1c233530f20e5a6678e85da1c0aaa..4adeb31e42436f12cfed34c515b364a1b961d7cb 100644 (file)
@@ -38,6 +38,8 @@ public class DistributionInfoConfiguration {
 
     private Set<UUID> features = new HashSet<>();
 
+    private UUID areaTree = null;
+
     private CondensedDistributionConfiguration condensedDistrConfig = CondensedDistributionConfiguration.NewDefaultInstance();
 
     private EnumSet<InfoPart> infoParts = EnumSet.of(
@@ -125,4 +127,11 @@ public class DistributionInfoConfiguration {
     public void setFeatures(Set<UUID> features) {
         this.features = features;
     }
+
+    public UUID getAreaTree() {
+        return areaTree;
+    }
+    public void setAreaTree(UUID areaTree) {
+        this.areaTree = areaTree;
+    }
 }
\ No newline at end of file
index 7693c47d6b0024810f10b0f8740e103b8c5c7af0..aa1635a2e0bbb043cc9896f43811bac42e424332 100644 (file)
@@ -125,6 +125,18 @@ public class SetMap<K,V> implements Map<K, Set<V>>{
         return set.add(value);
     }
 
+    /**
+     * Returns any of the values for the given key if there are any values.
+     */
+    public V getFirstValue(K key) {
+        Set<V> set = map.get(key);
+        if (CdmUtils.isNullSafeEmpty(set)) {
+            return null;
+        }else {
+            return set.iterator().next();
+        }
+    }
+
     @Override
     public Set<V> remove(Object key) {
         return map.remove(key);
index 28c5907c5dfc8005263ee28911e70f38fe80b62c..54c254cf9604fafd43aa65a858218034ee2f600e 100755 (executable)
@@ -103,6 +103,7 @@ import eu.etaxonomy.cdm.model.taxon.TaxonBase;
 import eu.etaxonomy.cdm.model.taxon.TaxonNode;
 import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
 import eu.etaxonomy.cdm.model.term.IdentifierType;
+import eu.etaxonomy.cdm.model.term.TermTree;
 import eu.etaxonomy.cdm.persistence.dto.TaxonNodeDto;
 import eu.etaxonomy.cdm.persistence.dto.TaxonNodeDtoByRankAndNameComparator;
 import eu.etaxonomy.cdm.strategy.cache.HTMLTagRules;
@@ -874,10 +875,11 @@ public class CdmLightClassificationExport
          if(state.getConfig().isCreateCondensedDistributionString()){
              List<Language> langs = new ArrayList<>();
              langs.add(Language.ENGLISH());
+             TermTree<NamedArea> areaTree = null; //TODO
 
              CondensedDistribution conDis = distributionService.getCondensedDistribution(
                      //TODO add CondensedDistributionConfiguration to export configuration
-                     distributions, true, null, state.getConfig().getCondensedDistributionConfiguration(), langs);
+                     distributions, areaTree, true, null, state.getConfig().getCondensedDistributionConfiguration(), langs);
              CdmLightExportTable tableCondensed =
                      CdmLightExportTable.SIMPLE_FACT;
              String[] csvLine = new String[tableCondensed.getSize()];
index 8fdd83921700ed9e83dfe0f65b9fca513a8fc6b2..0a8036b92960edee6a247e45176ba9169c8735b2 100644 (file)
@@ -100,6 +100,7 @@ import eu.etaxonomy.cdm.model.taxon.TaxonBase;
 import eu.etaxonomy.cdm.model.taxon.TaxonNode;
 import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
 import eu.etaxonomy.cdm.model.term.IdentifierType;
+import eu.etaxonomy.cdm.model.term.TermTree;
 import eu.etaxonomy.cdm.persistence.dto.TaxonNodeDto;
 import eu.etaxonomy.cdm.persistence.dto.TaxonNodeDtoByRankAndNameComparator;
 import eu.etaxonomy.cdm.strategy.cache.HTMLTagRules;
@@ -770,9 +771,10 @@ public class WordClassificationExport
              List<Language> langs = new ArrayList<>();
              langs.add(Language.ENGLISH());
 
+             TermTree<NamedArea> areaTree = null; //TODO
              CondensedDistribution conDis = geoService.getCondensedDistribution(
                      //TODO add CondensedDistributionConfiguration to export configuration
-                     distributions, true, null, state.getConfig().getCondensedDistributionConfiguration(), langs);
+                     distributions, areaTree, true, null, state.getConfig().getCondensedDistributionConfiguration(), langs);
              WordClassificationExportTable tableCondensed =
                      WordClassificationExportTable.SIMPLE_FACT;
              String[] csvLine = new String[tableCondensed.getSize()];
index c1d8c33829dd761b1fd4738f283b5b1baa14e0a6..f1d2c4eaf0e3f074f67c9e0f5b7a1f5fd20b0b04 100644 (file)
@@ -55,6 +55,7 @@ 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.model.taxon.TaxonRelationship;
+import eu.etaxonomy.cdm.model.term.TermTree;
 import eu.etaxonomy.cdm.persistence.query.MatchMode;
 
 /**
@@ -461,10 +462,11 @@ public class CsvNameExport extends CsvNameExportBase {
         if (state.getConfig().isCondensedDistribution()){
             List<Language> langs = new ArrayList<>();
             langs.add(Language.ENGLISH());
+            TermTree<NamedArea> areaTree = null;  //TODO
 
             //TODO add condensed distribution configuration to export configuration
             CondensedDistribution conDis = distributionService.getCondensedDistribution(
-                    distributions, true, null, CondensedDistributionConfiguration.NewCubaInstance(), langs );
+                    distributions, areaTree, true, null, CondensedDistributionConfiguration.NewCubaInstance(), langs );
 
             nameRecord.put(columnName, conDis.toString());
 
index d7cca72e019b21f70d73759f3da0e756f5da5560..270ceaa794a3f1fcc39a4bb36bc9baf27a9a9153 100644 (file)
@@ -24,6 +24,7 @@ import org.codehaus.plexus.util.StringUtils;
 
 import eu.etaxonomy.cdm.common.CdmUtils;
 import eu.etaxonomy.cdm.common.DoubleResult;
+import eu.etaxonomy.cdm.common.SetMap;
 import eu.etaxonomy.cdm.common.TripleResult;
 import eu.etaxonomy.cdm.common.UTF8;
 import eu.etaxonomy.cdm.compare.common.OrderType;
@@ -87,13 +88,14 @@ public class CondensedDistributionComposer {
     }
 
     public CondensedDistribution createCondensedDistribution(Collection<Distribution> filteredDistributions,
-            List<Language> languages, CondensedDistributionConfiguration config) {
+            SetMap<NamedArea, NamedArea> parentAreaMap, List<Language> languages, CondensedDistributionConfiguration config) {
 
         CondensedDistribution result = new CondensedDistribution();
 
         Map<NamedArea, PresenceAbsenceTerm> areaToStatusMap = new HashMap<>();
 
-        DoubleResult<List<AreaNode>, List<AreaNode>> step1_3 = createAreaTreesAndStatusMap(filteredDistributions, areaToStatusMap, config);
+        DoubleResult<List<AreaNode>, List<AreaNode>> step1_3 = createAreaTreesAndStatusMap(
+                filteredDistributions, parentAreaMap, areaToStatusMap, config);
         List<AreaNode> topLevelNodes = step1_3.getFirstResult();
         List<AreaNode> introducedTopLevelNodes = step1_3.getSecondResult();
 
@@ -154,7 +156,7 @@ public class CondensedDistributionComposer {
     }
 
     protected Map<NamedArea, AreaNode>[] buildAreaHierarchie(Map<NamedArea, PresenceAbsenceTerm> areaToStatusMap,
-            CondensedDistributionConfiguration config) {
+            SetMap<NamedArea, NamedArea> parentAreaMap, CondensedDistributionConfiguration config) {
 
         Map<NamedArea, AreaNode> areaNodeMap = new HashMap<>();
         Map<NamedArea, AreaNode> introducedAreaNodeMap = new HashMap<>();
@@ -164,7 +166,7 @@ public class CondensedDistributionComposer {
             if (config.splitNativeAndIntroduced && isIntroduced(areaToStatusMap.get(area))){
                 map = introducedAreaNodeMap;
             }
-            mergeIntoHierarchy(areaToStatusMap.keySet(), map, area, config);
+            mergeIntoHierarchy(areaToStatusMap.keySet(), map, area, parentAreaMap, config);
         }
 
         //TODO move this filter further up where native and introduced is still combined,
@@ -223,7 +225,7 @@ public class CondensedDistributionComposer {
     }
 
     private void mergeIntoHierarchy(Collection<NamedArea> areas,  //areas not really needed anymore if we don't use findParentIn
-            Map<NamedArea, AreaNode> areaNodeMap, NamedArea area, CondensedDistributionConfiguration config) {
+            Map<NamedArea, AreaNode> areaNodeMap, NamedArea area, SetMap<NamedArea, NamedArea> parentAreaMap, CondensedDistributionConfiguration config) {
 
         AreaNode node = areaNodeMap.get(area);
         if(node == null) {
@@ -232,7 +234,7 @@ public class CondensedDistributionComposer {
             areaNodeMap.put(area, node);
         }
 
-        NamedArea parent = getNonFallbackParent(area, config);   // findParentIn(area, areas);
+        NamedArea parent = getNonFallbackParent(area, parentAreaMap, config);   // findParentIn(area, areas);
 
         if(parent != null) {
             AreaNode parentNode = areaNodeMap.get(parent);
@@ -241,12 +243,13 @@ public class CondensedDistributionComposer {
                 areaNodeMap.put(parent, parentNode);
             }
             parentNode.addSubArea(node);
-            mergeIntoHierarchy(areas, areaNodeMap, parentNode.area, config);  //recursive to top
+            mergeIntoHierarchy(areas, areaNodeMap, parentNode.area, parentAreaMap, config);  //recursive to top
         }
     }
 
-    private NamedArea getNonFallbackParent(NamedArea area, CondensedDistributionConfiguration config) {
-        NamedArea parent = area.getPartOf();
+    private NamedArea getNonFallbackParent(NamedArea area, SetMap<NamedArea, NamedArea> parentAreaMap, CondensedDistributionConfiguration config) {
+        NamedArea parent = parentAreaMap.getFirstValue(area);  //TODO handle >1 parents
+
         //if done here the fallback test does not work anymore
 //        while(parent != null && isHiddenOrFallback(parent, config)){
 //            parent = parent.getPartOf();
@@ -466,7 +469,7 @@ public class CondensedDistributionComposer {
     }
 
     protected DoubleResult<List<AreaNode>, List<AreaNode>> createAreaTreesAndStatusMap(Collection<Distribution> filteredDistributions,
-            Map<NamedArea, PresenceAbsenceTerm> areaToStatusMap, CondensedDistributionConfiguration config){
+            SetMap<NamedArea, NamedArea> parentAreaMap, Map<NamedArea, PresenceAbsenceTerm> areaToStatusMap, CondensedDistributionConfiguration config){
 
         //we expect every area only to have 1 status  (multiple status should have been filtered beforehand)
 
@@ -484,7 +487,7 @@ public class CondensedDistributionComposer {
         }
 
         //2. build the area hierarchy
-        Map<NamedArea, AreaNode>[] areaNodeMaps = buildAreaHierarchie(areaToStatusMap, config);
+        Map<NamedArea, AreaNode>[] areaNodeMaps = buildAreaHierarchie(areaToStatusMap, parentAreaMap, config);
 
         //3. find root nodes
         @SuppressWarnings("unchecked")
index a0b2bd7ba363fe6dd4586b81d0204e1f9aa99097..a031780f40360793343e9dfd1abb17832150f50b 100644 (file)
@@ -40,6 +40,8 @@ import org.hibernate.annotations.Cascade;
 import org.hibernate.annotations.CascadeType;
 import org.hibernate.envers.Audited;
 
+import eu.etaxonomy.cdm.common.CdmUtils;
+import eu.etaxonomy.cdm.common.SetMap;
 import eu.etaxonomy.cdm.model.common.ITreeNode;
 import eu.etaxonomy.cdm.model.description.CategoricalData;
 import eu.etaxonomy.cdm.model.description.Feature;
@@ -538,6 +540,72 @@ public class TermNode <T extends DefinedTermBase>
                return terms;
        }
 
+       /**
+        * Returns the first node having <code>term</code>
+     * as term. Searches in the subtree defined by this term node.
+     * Using depth search.
+        */
+       @Transient
+    public TermNode<T> getNodeForTerm(T term){
+        if (CdmUtils.nullSafeEqual(getTerm(), term)){
+            return this;
+        }
+        for (TermNode<T> child : getChildNodes()){
+            TermNode<T> result = child.getNodeForTerm(term);
+            if (result != null) {
+                return result;
+            }
+        }
+        return null;
+    }
+
+       /**
+     * Returns all nodes having <code>term</code>
+     * as term. Searches in the subtree defined by this term node.
+     * Using depth search.
+     */
+    @Transient
+    public Set<TermNode<T>> getNodesForTerm(T term){
+        Set<TermNode<T>> result = new HashSet<>();
+        if (CdmUtils.nullSafeEqual(getTerm(), term)){
+            result.add(this);
+        }
+        for (TermNode<T> child : getChildNodes()){
+            result.addAll(child.getNodesForTerm(term));
+        }
+        return result;
+    }
+
+    /**
+     * Returns the parent term for the given
+     * as defined in this subtree (and its direct parent).
+     * If more than 1 node use the
+     * given term an arbitrary first node is used.
+     * If the node has only the invisible root node as parent
+     * <code>null</code> is returned.
+     */
+    @Transient
+    public T getParentTerm(){
+        if (getParent() != null) {
+            return getParent().getTerm();
+        }else {
+            return null;
+        }
+    }
+
+    /**
+     * Fills the given map with areas mapping to their parents.
+     */
+    public void fillParentMap(SetMap<T, T> map) {
+        if (getTerm() != null) {
+            map.putItem(getTerm(), getParentTerm());
+        }
+        for (TermNode<T> node : getChildNodes()){
+            node.fillParentMap(map);
+        }
+        return;
+    }
+
     @Transient
        public String getPath(){
            String result = "";
@@ -668,4 +736,4 @@ public class TermNode <T extends DefinedTermBase>
                        return this.getGraph().getId();
                }
        }
-}
+}
\ No newline at end of file
index 1d463330646504f3a1239d407a17840be62ef84c..3e21f7082b81bd37238195bbf6b8b48c69ac8a60 100644 (file)
@@ -31,6 +31,7 @@ import org.hibernate.annotations.Cascade;
 import org.hibernate.annotations.CascadeType;
 import org.hibernate.envers.Audited;
 
+import eu.etaxonomy.cdm.common.SetMap;
 import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
 import eu.etaxonomy.cdm.model.description.Feature;
 
@@ -224,6 +225,46 @@ public class TermTree <T extends DefinedTermBase>
         return terms;
     }
 
+    /**
+     * Returns the first node having <code>term</code>
+     * as term. Using depth search.
+     */
+    @Transient
+    public TermNode<T> getNodeForTerm(T term){
+        return getRoot().getNodeForTerm(term);
+    }
+
+    /**
+     * Returns all nodes having <code>term</code>
+     * as term. Using depth search.
+     */
+    @Transient
+    public Set<TermNode<T>> getNodesForTerm(T term){
+        return getRoot().getNodesForTerm(term);
+    }
+
+    /**
+     * Returns the parent term for the given
+     * as defined by this tree. If more than 1 node use the
+     * given term an arbitrary first node is used.
+     * If the node has only the invisible root node as parent
+     * <code>null</code> is returned.
+     */
+    @Transient
+    public T getParentTerm(T term){
+        TermNode<T> node = getNodeForTerm(term);
+        return node == null? null : node.getParentTerm();
+    }
+
+    /**
+     * Returns a map for an area and its parents.
+     */
+    public SetMap<T, T> getParentMap() {
+        SetMap<T, T> result = new SetMap<>();
+        getRoot().fillParentMap(result);
+        return result;
+    }
+
 //*********************** CLONE ********************************************************/
 
        /**
index c1a8401764c8c317e03cb7af9e806a87e98fd6cf..98705cdacb03b3a9c3ad08a17f790c156afc9ddc 100644 (file)
@@ -17,6 +17,7 @@ import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 
+import eu.etaxonomy.cdm.common.SetMap;
 import eu.etaxonomy.cdm.common.UTF8;
 import eu.etaxonomy.cdm.format.description.distribution.CondensedDistributionComposer.SymbolUsage;
 import eu.etaxonomy.cdm.model.common.Language;
@@ -25,6 +26,8 @@ import eu.etaxonomy.cdm.model.description.Distribution;
 import eu.etaxonomy.cdm.model.description.PresenceAbsenceTerm;
 import eu.etaxonomy.cdm.model.location.NamedArea;
 import eu.etaxonomy.cdm.model.term.OrderedTermVocabulary;
+import eu.etaxonomy.cdm.model.term.TermNode;
+import eu.etaxonomy.cdm.model.term.TermTree;
 import eu.etaxonomy.cdm.model.term.TermType;
 import eu.etaxonomy.cdm.test.TermTestBase;
 
@@ -45,6 +48,7 @@ public class CondensedDistributionComposerEuroMedTest extends TermTestBase {
     private NamedArea spain;
 
     private Set<Distribution> distributions;
+    private SetMap<NamedArea,NamedArea> parentAreaMap;
     private List<Language> languages;
 
     private CondensedDistributionComposer composer;
@@ -57,45 +61,50 @@ public class CondensedDistributionComposerEuroMedTest extends TermTestBase {
     @Before
     public void setUp(){
 
+        TermTree<NamedArea> areaTree = TermTree.NewInstance(TermType.NamedArea, NamedArea.class);
+
         @SuppressWarnings("unchecked")
         OrderedTermVocabulary<NamedArea>  voc = OrderedTermVocabulary.NewInstance(TermType.NamedArea);
         europe = NamedArea.NewInstance("", "Europe", "EU");
         voc.addTerm(europe);
+        TermNode<NamedArea> europeNode = areaTree.getRoot().addChild(europe);
 
         westEurope = NamedArea.NewInstance("", "West Europe", "WE");
-        westEurope.setPartOf(europe);
+        TermNode<NamedArea> westEuropeNode = europeNode.addChild(westEurope);
         voc.addTerm(westEurope);
         setAsFallback(westEurope);
 
         //Germany
         germany = NamedArea.NewInstance("", "Germany", "GER");
-        germany.setPartOf(europe);
+        TermNode<NamedArea> germanyNode = europeNode.addChild(germany);
         berlin = NamedArea.NewInstance("", "Berlin", "GER(B)");
-        berlin.setPartOf(germany);
+        germanyNode.addChild(berlin);
         bawue = NamedArea.NewInstance("", "Baden Württemberg", "GER(BW)");
-        bawue.setPartOf(germany);
+        germanyNode.addChild(bawue);
         voc.addTerm(germany);
         voc.addTerm(berlin);
         voc.addTerm(bawue);
 
         //France
         france = NamedArea.NewInstance("", "France", "FR");
-        france.setPartOf(westEurope);
+        TermNode<NamedArea> franceNode = westEuropeNode.addChild(france);
         ileDeFrance = NamedArea.NewInstance("", "Ile-de-France", "FR(J)");
-        ileDeFrance.setPartOf(france);
+        franceNode.addChild(ileDeFrance);
         voc.addTerm(france);
         voc.addTerm(ileDeFrance);
 
         //Italy
         italy = NamedArea.NewInstance("", "Italy", "IT");
-        italy.setPartOf(europe);
+        europeNode.addChild(italy);
         voc.addTerm(italy);
 
         //Spain
         spain = NamedArea.NewInstance("", "Spain", "S");
-        spain.setPartOf(europe);
+        europeNode.addChild(spain);
         voc.addTerm(spain);
 
+        parentAreaMap = areaTree.getParentMap();
+
         distributions = new HashSet<>();
 
         languages = new ArrayList<>();
@@ -132,7 +141,7 @@ public class CondensedDistributionComposerEuroMedTest extends TermTestBase {
         createDefaultDistributions();
 
         CondensedDistribution condensedDistribution = composer.createCondensedDistribution(
-                distributions, languages, config);
+                distributions, parentAreaMap, languages, config);
 
         Assert.assertEquals(endemic + " <b>GER(B BW)</b> ?IT [cFR(J) nS]", condensedDistribution.toString());
     }
@@ -142,16 +151,19 @@ public class CondensedDistributionComposerEuroMedTest extends TermTestBase {
         createDefaultDistributions();
 
         bawueDistribution.setStatus(PresenceAbsenceTerm.NATIVE_DOUBTFULLY_NATIVE());
-        Assert.assertEquals(endemic + " <b>GER(B</b> dBW<b>)</b> ?IT [cFR(J) nS]", composer.createCondensedDistribution(distributions, languages, config).toString());
+        Assert.assertEquals(endemic + " <b>GER(B</b> dBW<b>)</b> ?IT [cFR(J) nS]",
+                composer.createCondensedDistribution(distributions, parentAreaMap, languages, config).toString());
 
         bawueDistribution.setStatus(PresenceAbsenceTerm.CASUAL());
-        Assert.assertEquals(endemic +" <b>GER(B)</b> ?IT [cFR(J) aGER(BW) nS]", composer.createCondensedDistribution(distributions, languages, config).toString());
+        Assert.assertEquals(endemic +" <b>GER(B)</b> ?IT [cFR(J) aGER(BW) nS]",
+                composer.createCondensedDistribution(distributions, parentAreaMap, languages, config).toString());
 
         //#9583
         distributions = new HashSet<>();
         distributions.add(Distribution.NewInstance(berlin, PresenceAbsenceTerm.PRESENT_DOUBTFULLY()));
         distributions.add(Distribution.NewInstance(bawue, PresenceAbsenceTerm.NATIVE()));
-        Assert.assertEquals("<b>GER(</b>?B <b>BW)</b>", composer.createCondensedDistribution(distributions, languages, config).toString());
+        Assert.assertEquals("<b>GER(</b>?B <b>BW)</b>",
+                composer.createCondensedDistribution(distributions, parentAreaMap, languages, config).toString());
 
     }
 
@@ -162,7 +174,7 @@ public class CondensedDistributionComposerEuroMedTest extends TermTestBase {
         distributions.add(Distribution.NewInstance(france, PresenceAbsenceTerm.CASUAL()));
 
         CondensedDistribution condensedDistribution = composer.createCondensedDistribution(
-                distributions, languages, config);
+                distributions, parentAreaMap, languages, config);
 
         Assert.assertEquals(endemic + " <b>GER(B BW)</b> ?IT [aFR(cJ) nS]", condensedDistribution.toString());
     }
@@ -178,11 +190,11 @@ public class CondensedDistributionComposerEuroMedTest extends TermTestBase {
         distributions.add(nativeDist);
         distributions.add(Distribution.NewInstance(westEurope, PresenceAbsenceTerm.NATIVE_DOUBTFULLY_NATIVE()));
 
-        Assert.assertEquals("dFR(J)", composer.createCondensedDistribution(distributions, languages, config).getHtmlString());
+        Assert.assertEquals("dFR(J)", composer.createCondensedDistribution(distributions, parentAreaMap, languages, config).getHtmlString());
 
         distributions.remove(nativeDist);
         distributions.add(introducedDist);
-        Assert.assertEquals("[iFR(J)]", composer.createCondensedDistribution(distributions, languages, config).getHtmlString());
+        Assert.assertEquals("[iFR(J)]", composer.createCondensedDistribution(distributions, parentAreaMap, languages, config).getHtmlString());
     }
 
     @Test
@@ -190,16 +202,16 @@ public class CondensedDistributionComposerEuroMedTest extends TermTestBase {
 
         distributions.add(Distribution.NewInstance(germany, PresenceAbsenceTerm.NATIVE()));
         Assert.assertEquals("<b>GER</b>", composer.createCondensedDistribution(
-                distributions, languages, config).toString());
+                distributions, parentAreaMap, languages, config).toString());
 
         distributions.add(Distribution.NewInstance(europe, PresenceAbsenceTerm.ENDEMISM_UNKNOWN()));
         Assert.assertEquals("<b>GER</b>", composer.createCondensedDistribution(
-                distributions, languages, config).toString());
+                distributions, parentAreaMap, languages, config).toString());
 
         distributions.clear();
         distributions.add(Distribution.NewInstance(germany, PresenceAbsenceTerm.CASUAL()));
         Assert.assertEquals("[aGER]", composer.createCondensedDistribution(
-                distributions, languages, config).toString());
+                distributions, parentAreaMap, languages, config).toString());
     }
 
     @Test
@@ -211,7 +223,7 @@ public class CondensedDistributionComposerEuroMedTest extends TermTestBase {
         CondensedDistributionConfiguration config = CondensedDistributionConfiguration.NewCubaInstance();
         config.areaSymbolField = SymbolUsage.AbbrevLabel;
         CondensedDistribution condensedDistribution = composer.createCondensedDistribution(
-                distributions, languages, config);
+                distributions, parentAreaMap, languages, config);
 
         Assert.assertEquals(endemic + "<b>EU</b>(<b>GER</b>(<b>GER(B) GER(BW)</b>) a<b>FR</b>(c<b>FR(J)</b>) ?<b>IT</b> n<b>S</b>)", condensedDistribution.toString());
     }
index 372405cacdd4be1addcb36866c630f8b41651e09..7d0dd990ae19709bfc2c124a97fca16f02e28ecd 100644 (file)
@@ -17,14 +17,14 @@ import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
 
-import eu.etaxonomy.cdm.format.description.distribution.CondensedDistribution;
-import eu.etaxonomy.cdm.format.description.distribution.CondensedDistributionComposer;
-import eu.etaxonomy.cdm.format.description.distribution.CondensedDistributionConfiguration;
+import eu.etaxonomy.cdm.common.SetMap;
 import eu.etaxonomy.cdm.format.description.distribution.CondensedDistributionComposer.SymbolUsage;
 import eu.etaxonomy.cdm.model.description.Distribution;
 import eu.etaxonomy.cdm.model.description.PresenceAbsenceTerm;
 import eu.etaxonomy.cdm.model.location.NamedArea;
 import eu.etaxonomy.cdm.model.term.OrderedTermVocabulary;
+import eu.etaxonomy.cdm.model.term.TermNode;
+import eu.etaxonomy.cdm.model.term.TermTree;
 import eu.etaxonomy.cdm.model.term.TermType;
 import eu.etaxonomy.cdm.model.term.TermVocabulary;
 import eu.etaxonomy.cdm.test.TermTestBase;
@@ -40,6 +40,7 @@ public class CondensedDistributionComposerFloraCubaTest extends TermTestBase {
 
     private static OrderedTermVocabulary<PresenceAbsenceTerm> statusVoc;
     private static OrderedTermVocabulary<NamedArea> cubaAreasVocabualary;
+    private static SetMap<NamedArea,NamedArea> parentAreaMap;
 
     private static NamedArea cuba;
     private static NamedArea westernCuba;
@@ -133,7 +134,8 @@ public class CondensedDistributionComposerFloraCubaTest extends TermTestBase {
         filteredDistributions.add(Distribution.NewInstance(bahamas, PresenceAbsenceTerm.NATIVE()));
         filteredDistributions.add(Distribution.NewInstance(oldWorld, PresenceAbsenceTerm.NATIVE_PRESENCE_QUESTIONABLE()));
 
-        CondensedDistribution condensedDistribution = composer.createCondensedDistribution(filteredDistributions, null, config);
+        CondensedDistribution condensedDistribution = composer.createCondensedDistribution(
+                filteredDistributions, parentAreaMap, null, config);
         String condensedString = condensedDistribution.toString();
 
         Assert.assertEquals("Condensed string for Cuba differs",
@@ -167,7 +169,8 @@ public class CondensedDistributionComposerFloraCubaTest extends TermTestBase {
         filteredDistributions.add(Distribution.NewInstance(oldWorld, PresenceAbsenceTerm.NATIVE_PRESENCE_QUESTIONABLE()));
 
         config.areasBold = false;
-        CondensedDistribution condensedDistribution = composer.createCondensedDistribution(filteredDistributions, null, config);
+        CondensedDistribution condensedDistribution = composer.createCondensedDistribution(
+                filteredDistributions, parentAreaMap, null, config);
 
         Assert.assertEquals("Condensed string for Cuba differs",
                 "nCu(-dCuW(PR* Art Hab* May Mat IJ) (c)CuE(nHo -cGu))" + config.outOfScopeAreasSeperator + "Bah ?VM",
@@ -179,7 +182,7 @@ public class CondensedDistributionComposerFloraCubaTest extends TermTestBase {
         //this should better be done CondensedDistributionComposerEuroMedTest but we have the test data here, therefore we keep the test here
         config = CondensedDistributionConfiguration.NewDefaultInstance();
         config.statusSymbolField = SymbolUsage.Symbol1;
-        condensedDistribution = composer.createCondensedDistribution(filteredDistributions, null, config);
+        condensedDistribution = composer.createCondensedDistribution(filteredDistributions, parentAreaMap, null, config);
         Assert.assertEquals("Condensed string for Cuba differs",
                 "n (c)CuE -dCuW(<b>Art Hab* IJ Mat May PR*</b>) [(c)CuE(-cGu nHo)]" + config.outOfScopeAreasSeperator + "<b>Bah</b> ?VM",
                 condensedDistribution.toString());
@@ -189,6 +192,8 @@ public class CondensedDistributionComposerFloraCubaTest extends TermTestBase {
 
     private static boolean makeAreas(){
 
+        TermTree<NamedArea> areaTree = TermTree.NewInstance(TermType.NamedArea, NamedArea.class);
+
         //vocabulary
         UUID cubaAreasVocabularyUuid = UUID.fromString("c81e3c7b-3c01-47d1-87cf-388de4b1908c");
         String label = "Cuba Areas";
@@ -203,71 +208,71 @@ public class CondensedDistributionComposerFloraCubaTest extends TermTestBase {
         abbrev = "Cu";
         UUID uuid = UUID.fromString("d0144a6e-0e17-4a1d-bce5-d464a2aa7229");
         cuba = getNamedArea(uuid, label, abbrev, cubaAreasVocabualary);
+        TermNode<NamedArea> cubaNode = areaTree.getRoot().addChild(cuba);
 
         //Western Cuba
         label = "Western Cuba";
         abbrev = "CuW";
         uuid = UUID.randomUUID();
         westernCuba = getNamedArea(uuid, label, abbrev, cubaAreasVocabualary);
-//        cuba.addIncludes(westernCuba);
 
         //Central Cuba
         label = "Central Cuba";
         abbrev = "CuC";
         uuid = UUID.randomUUID();
         centralCuba = getNamedArea(uuid, label, abbrev, cubaAreasVocabualary);
-        cuba.addIncludes(centralCuba);
+        TermNode<NamedArea> centralCubaNode = cubaNode.addChild(centralCuba);
 
         //East Cuba
         label = "East Cuba";
         abbrev = "CuE";
         uuid = UUID.randomUUID();
         eastCuba = getNamedArea(uuid, label, abbrev, cubaAreasVocabualary);
-        cuba.addIncludes(eastCuba);
+        TermNode<NamedArea> eastCubaNode = cubaNode.addChild(eastCuba);
 
-        cuba.addIncludes(westernCuba);
+        TermNode<NamedArea> westernCubaNode = cubaNode.addChild(westernCuba);
 
         //Pinar del Río PR
         label = "Pinar del Río";
         abbrev = "PR*";
         uuid = UUID.randomUUID();
         pinarDelRio = getNamedArea(uuid, label, abbrev, cubaAreasVocabualary);
-        westernCuba.addIncludes(pinarDelRio);
+        westernCubaNode.addChild(pinarDelRio);
 
         //Artemisa
         label = "Artemisa";
         abbrev = "Art";
         uuid = UUID.randomUUID();
         artemisa = getNamedArea(uuid, label, abbrev, cubaAreasVocabualary);
-        westernCuba.addIncludes(artemisa);
+        westernCubaNode.addChild(artemisa);
 
         //Ciudad de la Habana
         label = "Ciudad de la Habana";
         abbrev = "Hab*";
         uuid = UUID.randomUUID();
         habana = getNamedArea(uuid, label, abbrev, cubaAreasVocabualary);
-        westernCuba.addIncludes(habana);
+        westernCubaNode.addChild(habana);
 
         //Ciudad de la Habana
         label = "Mayabeque";
         abbrev = "May";
         uuid = UUID.randomUUID();
         mayabeque = getNamedArea(uuid, label, abbrev, cubaAreasVocabualary);
-        westernCuba.addIncludes(mayabeque);
+        westernCubaNode.addChild(mayabeque);
 
         //Matanzas Mat
         label = "Matanzas";
         abbrev = "Mat";
         uuid = UUID.randomUUID();
         matanzas = getNamedArea(uuid, label, abbrev, cubaAreasVocabualary);
-        westernCuba.addIncludes(matanzas);
+        westernCubaNode.addChild(matanzas);
 
         //Isla de la Juventud IJ
         label = "Isla de la Juventud";
         abbrev = "IJ";
         uuid = UUID.randomUUID();
         isla_juventud = getNamedArea(uuid, label, abbrev, cubaAreasVocabualary);
-        westernCuba.addIncludes(isla_juventud);
+        westernCubaNode.addChild(isla_juventud);
 
         //Provinces - Central
         //Villa Clara VC
@@ -275,42 +280,42 @@ public class CondensedDistributionComposerFloraCubaTest extends TermTestBase {
         abbrev = "VC";
         uuid = UUID.randomUUID();
         NamedArea area = getNamedArea(uuid, label, abbrev, cubaAreasVocabualary);
-        centralCuba.addIncludes(area);
+        centralCubaNode.addChild(area);
 
         //Cienfuegos Ci VC
         label = "Cienfuegos";
         abbrev = "Ci";
         uuid = UUID.randomUUID();
         area = getNamedArea(uuid, label, abbrev, cubaAreasVocabualary);
-        centralCuba.addIncludes(area);
+        centralCubaNode.addChild(area);
 
         //Sancti Spiritus SS
         label = "Sancti Spíritus";
         abbrev = "SS";
         uuid = UUID.randomUUID();
         area = getNamedArea(uuid, label, abbrev, cubaAreasVocabualary);
-        centralCuba.addIncludes(area);
+        centralCubaNode.addChild(area);
 
         //Ciego de Ávila CA
         label = "Ciego de Ávila";
         abbrev = "CA";
         uuid = UUID.randomUUID();
         area = getNamedArea(uuid, label, abbrev, cubaAreasVocabualary);
-        centralCuba.addIncludes(area);
+        centralCubaNode.addChild(area);
 
         //Camagüey Cam
         label = "Camagüey";
         abbrev = "Cam";
         uuid = UUID.randomUUID();
         area = getNamedArea(uuid, label, abbrev, cubaAreasVocabualary);
-        centralCuba.addIncludes(area);
+        centralCubaNode.addChild(area);
 
         //Las Tunas LT
         label = "Las Tunas";
         abbrev = "LT";
         uuid = UUID.randomUUID();
         area = getNamedArea(uuid, label, abbrev, cubaAreasVocabualary);
-        centralCuba.addIncludes(area);
+        centralCubaNode.addChild(area);
 
         //Provinces - East
         //Granma Gr
@@ -318,28 +323,28 @@ public class CondensedDistributionComposerFloraCubaTest extends TermTestBase {
         abbrev = "Gr";
         uuid = UUID.randomUUID();
         area = getNamedArea(uuid, label, abbrev, cubaAreasVocabualary);
-        eastCuba.addIncludes(area);
+        eastCubaNode.addChild(area);
 
         //Holguín Ho
         label = "Holguín";
         abbrev = "Ho";
         uuid = UUID.randomUUID();
         holguin = getNamedArea(uuid, label, abbrev, cubaAreasVocabualary);
-        eastCuba.addIncludes(holguin);
+        eastCubaNode.addChild(holguin);
 
         //Santiago de Cuba SC
         label = "Santiago de Cuba";
         abbrev = "SC";
         uuid = UUID.randomUUID();
         area = getNamedArea(uuid, label, abbrev, cubaAreasVocabualary);
-        eastCuba.addIncludes(area);
+        eastCubaNode.addChild(area);
 
         //Guantánamo Gu
         label = "Guantánamo";
         abbrev = "Gu";
         uuid = UUID.randomUUID();
         guantanamo = getNamedArea(uuid, label, abbrev, cubaAreasVocabualary);
-        eastCuba.addIncludes(guantanamo);
+        eastCubaNode.addChild(guantanamo);
 
         //other Greater Antilles (Cuba, Española, Jamaica, Puerto Rico)
         //Española Esp (=Haiti + Dominican Republic)
@@ -347,36 +352,42 @@ public class CondensedDistributionComposerFloraCubaTest extends TermTestBase {
         abbrev = "Esp";
         uuid = UUID.randomUUID();
         area = getNamedArea(uuid, label, abbrev, cubaAreasVocabualary);
+        areaTree.getRoot().addChild(area);
 
         //Jamaica Ja
         label = "Jamaica";
         abbrev = "Ja";
         uuid = UUID.randomUUID();
         area = getNamedArea(uuid, label, abbrev, cubaAreasVocabualary);
+        areaTree.getRoot().addChild(area);
 
         //Puerto Rico PR
         label = "Puerto Rico";
         abbrev = "PRc";
         uuid = UUID.randomUUID();
         area = getNamedArea(uuid, label, abbrev, cubaAreasVocabualary);
+        areaTree.getRoot().addChild(area);
 
         //Lesser Antilles Men
         label = "Lesser Antilles";
         abbrev = "Men";
         uuid = UUID.randomUUID();
         area = getNamedArea(uuid, label, abbrev, cubaAreasVocabualary);
+        areaTree.getRoot().addChild(area);
 
         //Bahamas
         label = "Bahamas";
         abbrev = "Bah";
         uuid = UUID.randomUUID();
         bahamas = getNamedArea(uuid, label, abbrev, cubaAreasVocabualary);
+        areaTree.getRoot().addChild(bahamas);
 
         //Cayman Islands
         label = "Cayman Islands"; //[Trinidad, Tobago, Curaçao, Margarita, ABC Isl. => S. America];
         abbrev = "Cay";
         uuid = UUID.randomUUID();
         area = getNamedArea(uuid, label, abbrev, cubaAreasVocabualary);
+        areaTree.getRoot().addChild(area);
 
         //World
         //N America
@@ -384,25 +395,30 @@ public class CondensedDistributionComposerFloraCubaTest extends TermTestBase {
         abbrev = "AmN";
         uuid = UUID.randomUUID();
         area = getNamedArea(uuid, label, abbrev, cubaAreasVocabualary);
+        areaTree.getRoot().addChild(area);
 
         //Central America
         label = "Central America";
         abbrev = "AmC";
         uuid = UUID.randomUUID();
         area = getNamedArea(uuid, label, abbrev, cubaAreasVocabualary);
-
+        areaTree.getRoot().addChild(area);
 
         //S America
         label = "S America";
         abbrev = "AmS";
         uuid = UUID.randomUUID();
         area = getNamedArea(uuid, label, abbrev, cubaAreasVocabualary);
+        areaTree.getRoot().addChild(area);
 
         //Old World
         label = "Old World ";
         abbrev = "VM";
         uuid = UUID.randomUUID();
         oldWorld = getNamedArea(uuid, label, abbrev, cubaAreasVocabualary);
+        areaTree.getRoot().addChild(oldWorld);
+
+        parentAreaMap = areaTree.getParentMap();
 
         return true;
     }
index 1b01ec3d78c09ebf75bb078d5a37f330149e4bb7..00fb117a8810b500a5e01a752c88b2e47b810ba5 100644 (file)
@@ -35,6 +35,7 @@ import org.springframework.dao.DataAccessException;
 import org.springframework.stereotype.Repository;
 
 import eu.etaxonomy.cdm.api.dto.portal.NamedAreaDto;
+import eu.etaxonomy.cdm.common.SetMap;
 import eu.etaxonomy.cdm.common.URI;
 import eu.etaxonomy.cdm.model.common.AnnotationType;
 import eu.etaxonomy.cdm.model.common.CdmBase;
@@ -550,8 +551,9 @@ public class DefinedTermDaoImpl
        }
 
        //preliminary until term structure has been finalized
+       //areaTree already added by not in use yet
     @Override
-    public List<NamedAreaDto> getPartOfNamedAreas(Set<UUID> areaUuids) {
+    public List<NamedAreaDto> getPartOfNamedAreas(Set<UUID> areaUuids, SetMap<NamedArea,NamedArea> parentAreaMap) {
         Query<NamedArea> query = getSession().createQuery("SELECT DISTINCT definedTerm "
                 + " FROM NamedArea definedTerm "
                 + " JOIN definedTerm.includes included "
@@ -561,7 +563,7 @@ public class DefinedTermDaoImpl
 
         List<NamedAreaDto> list = new ArrayList<>();
         for (NamedArea area : terms) {
-            NamedAreaDto partOf = area.getPartOf() != null ? new NamedAreaDto(area.getPartOf(), true) : null;
+            NamedAreaDto partOf = area.getPartOf() != null ? new NamedAreaDto(area.getPartOf(), parentAreaMap) : null;
             NamedAreaDto dto = new NamedAreaDto(area.getUuid(), area.getId(), area.getLabel(), area.getLevel(), partOf, area.getMarkers());
             dto.setUuid(area.getUuid());
             list.add(dto);
index e3e559557a3ca9b009d23abdf5f571a77f76d6f2..97d6eb4a7f9dafb3c1c27e6c22d47efa76f01335 100644 (file)
@@ -17,6 +17,7 @@ import java.util.Set;
 import java.util.UUID;
 
 import eu.etaxonomy.cdm.api.dto.portal.NamedAreaDto;
+import eu.etaxonomy.cdm.common.SetMap;
 import eu.etaxonomy.cdm.common.URI;
 import eu.etaxonomy.cdm.model.common.CdmBase;
 import eu.etaxonomy.cdm.model.common.Language;
@@ -149,7 +150,7 @@ public interface IDefinedTermDao
        public <T extends DefinedTermBase> List<T> getPartOf(Set<T> definedTerms, Integer pageSize, Integer pageNumber, List<String> propertyPaths);
 
        //see getPartOf above
-       public List<NamedAreaDto> getPartOfNamedAreas(Set<UUID> areaUuids);
+       public List<NamedAreaDto> getPartOfNamedAreas(Set<UUID> areaUuids, SetMap<NamedArea, NamedArea> parentAreaMap);
 
        /**
         * Return a count of distinct terms which include the terms supplied
index 3399f8f51687d0555f6da671765cbdc983a738ab..b4f4a9f0cd3ba6891dc70361d978e668296ddd75 100644 (file)
@@ -316,6 +316,7 @@ public class DescriptionListController
                 config.setDistributionOrder(distributionOrder);
                 config.setIgnoreDistributionStatusUndefined(ignoreDistributionStatusUndefined);
                 config.setFeatures(featureUuids);
+                config.setAreaTree(areaTreeUuid);
                 config.setCondensedDistrConfig(condensedConfig);
                 //TODO needed?
                 config.setStatusColorsString(statusColorsString);
index 9e330ee7713506f067f098f78167ae376c40d5e4..bb650e98e3e0fc334db9346950cec2a440918e53 100644 (file)
@@ -38,6 +38,7 @@ import eu.etaxonomy.cdm.api.dto.portal.IDistributionTree;
 import eu.etaxonomy.cdm.api.dto.portal.config.DistributionInfoConfiguration;
 import eu.etaxonomy.cdm.api.dto.portal.config.DistributionOrder;
 import eu.etaxonomy.cdm.common.CdmUtils;
+import eu.etaxonomy.cdm.common.SetMap;
 import eu.etaxonomy.cdm.format.description.distribution.CondensedDistribution;
 import eu.etaxonomy.cdm.format.description.distribution.CondensedDistributionConfiguration;
 import eu.etaxonomy.cdm.model.common.CdmBase;
@@ -51,9 +52,11 @@ import eu.etaxonomy.cdm.model.description.TaxonDescription;
 import eu.etaxonomy.cdm.model.location.NamedArea;
 import eu.etaxonomy.cdm.model.location.NamedAreaLevel;
 import eu.etaxonomy.cdm.model.term.DefinedTermBase;
+import eu.etaxonomy.cdm.model.term.TermTree;
 import eu.etaxonomy.cdm.model.term.TermVocabulary;
 import eu.etaxonomy.cdm.persistence.dao.description.IDescriptionDao;
 import eu.etaxonomy.cdm.persistence.dao.term.IDefinedTermDao;
+import eu.etaxonomy.cdm.persistence.dao.term.ITermTreeDao;
 import eu.etaxonomy.cdm.persistence.dao.term.ITermVocabularyDao;
 
 /**
@@ -73,6 +76,9 @@ public class DistributionServiceImpl implements IDistributionService {
     @Autowired
     private IDefinedTermDao termDao;
 
+    @Autowired
+    private ITermTreeDao termTreeDao;
+
     @Autowired
     private ITermVocabularyDao vocabDao;
 
@@ -143,10 +149,19 @@ public class DistributionServiceImpl implements IDistributionService {
             omitLevels = emptySet;
         }
 
+        TermTree<NamedArea> areaTree = getPersistentAreaTree(distributions, config);
+        if (areaTree == null) {
+            //TODO better use areaTree created within filterDistributions(...) but how to get it easily?
+            areaTree = DistributionServiceUtilities.getAreaTree(distributions, hiddenAreaMarkerTypes);
+        }
+        SetMap<NamedArea, NamedArea> parentAreaMap = areaTree.getParentMap();
+
+
         // for all later applications apply the rules statusOrderPreference, hideHiddenArea and ignoreUndefinedStatus
         // to all distributions, but KEEP fallback area distributions
-        Set<Distribution> filteredDistributions = DistributionServiceUtilities.filterDistributions(distributions, hiddenAreaMarkerTypes,
-                !PREFER_AGGREGATED, statusOrderPreference, !PREFER_SUBAREA, false, config.isIgnoreDistributionStatusUndefined());
+        Set<Distribution> filteredDistributions = DistributionServiceUtilities.filterDistributions(distributions,
+                areaTree, hiddenAreaMarkerTypes, !PREFER_AGGREGATED, statusOrderPreference, !PREFER_SUBAREA, false,
+                config.isIgnoreDistributionStatusUndefined());
 
         if(parts.contains(InfoPart.elements)) {
             dto.setElements(filteredDistributions);
@@ -162,11 +177,12 @@ public class DistributionServiceImpl implements IDistributionService {
                 }
 
                 tree = DistributionServiceUtilities.buildOrderedTreeDto(omitLevels,
-                        filteredDtoDistributions, hiddenAreaMarkerTypes, neverUseFallbackAreaAsParent,
+                        filteredDtoDistributions, parentAreaMap, hiddenAreaMarkerTypes, neverUseFallbackAreaAsParent,
                         distributionOrder, termDao);
             }else {
+                //version with model entities as used in direct webservice (not taxon page DTO)
                 tree = DistributionServiceUtilities.buildOrderedTree(omitLevels,
-                        filteredDistributions, hiddenAreaMarkerTypes, neverUseFallbackAreaAsParent,
+                        filteredDistributions, parentAreaMap, hiddenAreaMarkerTypes, neverUseFallbackAreaAsParent,
                         distributionOrder, termDao);
             }
             dto.setTree(tree);
@@ -174,17 +190,19 @@ public class DistributionServiceImpl implements IDistributionService {
 
         if(parts.contains(InfoPart.condensedDistribution)) {
             CondensedDistribution condensedDistribution = DistributionServiceUtilities.getCondensedDistribution(
-                    filteredDistributions, condensedDistConfig, languages);
+                    filteredDistributions, parentAreaMap, condensedDistConfig, languages);
             dto.setCondensedDistribution(condensedDistribution);
         }
 
         if (parts.contains(InfoPart.mapUriParams)) {
-            boolean IGNORE_STATUS_ORDER_PREF_ = false;
+            boolean IGNORE_STATUS_ORDER_PREF = false;
             Set<MarkerType> hiddenAreaMarkerType = null;
             // only apply the subAreaPreference rule for the maps
+            boolean keepFallBackOnlyIfNoSubareaDataExists = true;
             Set<Distribution> filteredMapDistributions = DistributionServiceUtilities.filterDistributions(
-                    filteredDistributions, hiddenAreaMarkerType, !PREFER_AGGREGATED,
-                    IGNORE_STATUS_ORDER_PREF_, subAreaPreference, true, config.isIgnoreDistributionStatusUndefined());
+                    filteredDistributions, areaTree, hiddenAreaMarkerType, !PREFER_AGGREGATED,
+                    IGNORE_STATUS_ORDER_PREF, subAreaPreference, keepFallBackOnlyIfNoSubareaDataExists,
+                    config.isIgnoreDistributionStatusUndefined());
 
             dto.setMapUriParams(DistributionServiceUtilities.getDistributionServiceRequestParameterString(filteredMapDistributions,
                     areaMapping,
@@ -195,17 +213,30 @@ public class DistributionServiceImpl implements IDistributionService {
         return dto;
     }
 
+    private TermTree<NamedArea> getPersistentAreaTree(List<Distribution> distributions, DistributionInfoConfiguration config) {
+        UUID areaTreeUuid = config.getAreaTree();
+        //TODO property path
+        String[] propertyPath = new String[] {};
+        @SuppressWarnings("unchecked")
+        TermTree<NamedArea> areaTree = termTreeDao.load(areaTreeUuid, Arrays.asList(propertyPath));
+        return areaTree;
+    }
+
     @Override
     public CondensedDistribution getCondensedDistribution(Set<Distribution> distributions,
+            TermTree<NamedArea> areaTree,
             boolean statusOrderPreference,
             Set<MarkerType> hiddenAreaMarkerTypes,
             CondensedDistributionConfiguration config,
             List<Language> langs) {
 
+        areaTree = areaTree == null ? DistributionServiceUtilities.getAreaTree(distributions, hiddenAreaMarkerTypes) : areaTree;
+        SetMap<NamedArea, NamedArea> parentMap = areaTree.getParentMap();
         Collection<Distribution> filteredDistributions = DistributionServiceUtilities.filterDistributions(
-                distributions, hiddenAreaMarkerTypes, false, statusOrderPreference, false, false, true);
+                distributions, null, hiddenAreaMarkerTypes, false, statusOrderPreference, false, false, true);
         CondensedDistribution condensedDistribution = DistributionServiceUtilities.getCondensedDistribution(
                 filteredDistributions,
+                parentMap,
                 config,
                 langs);
         return condensedDistribution;
@@ -225,7 +256,8 @@ public class DistributionServiceImpl implements IDistributionService {
             Map<PresenceAbsenceTerm, Color> presenceAbsenceTermColors,
             List<Language> langs) {
 
-        Collection<Distribution> filteredDistributions = DistributionServiceUtilities.filterDistributions(distributions,
+        Collection<Distribution> filteredDistributions = DistributionServiceUtilities.filterDistributions(
+                distributions, null,
                 hideMarkedAreas, false, statusOrderPreference, subAreaPreference, true, false);
 
         String uriParams = DistributionServiceUtilities.getDistributionServiceRequestParameterString(
index f938d2bde8ebf6238b1e20fb45183a09936886de..1a07288fdebd7d9c9bd07d8242b9c00fb0809545 100644 (file)
@@ -59,6 +59,8 @@ import eu.etaxonomy.cdm.model.location.NamedAreaLevel;
 import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationType;
 import eu.etaxonomy.cdm.model.term.DefinedTermBase;
 import eu.etaxonomy.cdm.model.term.Representation;
+import eu.etaxonomy.cdm.model.term.TermNode;
+import eu.etaxonomy.cdm.model.term.TermTree;
 import eu.etaxonomy.cdm.model.term.TermType;
 import eu.etaxonomy.cdm.model.term.TermVocabulary;
 import eu.etaxonomy.cdm.persistence.dao.term.IDefinedTermDao;
@@ -127,6 +129,8 @@ public class DistributionServiceUtilities {
      *            1 status exists, otherwise the behavior is not deterministic.
      *            For filtering see {@link DescriptionUtility#filterDistributions(
      *            Collection, Set, boolean, boolean, boolean, boolean, boolean)}
+     * @param parentAreaMap TODO should we have a separate tree for the condensed distribution string?
+     *            Add the tree to the CondensedDistributionConfiguration?
      * @param config
      *            The configuration for the condensed distribution string creation.
      * @param languages
@@ -138,12 +142,12 @@ public class DistributionServiceUtilities {
      *            and a {@link TaggedText} representation of the condensed distribution string.
      */
     public static CondensedDistribution getCondensedDistribution(Collection<Distribution> filteredDistributions,
-            CondensedDistributionConfiguration config, List<Language> languages) {
+            SetMap<NamedArea, NamedArea> parentAreaMap, CondensedDistributionConfiguration config, List<Language> languages) {
 
         CondensedDistributionComposer composer = new CondensedDistributionComposer();
 
         CondensedDistribution condensedDistribution = composer.createCondensedDistribution(
-                filteredDistributions, languages, config);
+                filteredDistributions, parentAreaMap, languages, config);
         return condensedDistribution;
     }
 
@@ -696,6 +700,7 @@ public class DistributionServiceUtilities {
      * @return the filtered collection of distribution elements.
      */
     public static Set<Distribution> filterDistributions(Collection<Distribution> distributions,
+            TermTree<NamedArea> areaTree,
             Set<MarkerType> hiddenAreaMarkerTypes, boolean preferAggregated, boolean statusOrderPreference,
             boolean subAreaPreference, boolean keepFallBackOnlyIfNoSubareaDataExists, boolean ignoreDistributionStatusUndefined) {
 
@@ -713,14 +718,19 @@ public class DistributionServiceUtilities {
             if (!filterUndefined){
                 filteredDistributions.putItem(area, distribution);
             }
+        }
 
+        if (areaTree == null) {
+            areaTree = getAreaTree(distributions, hiddenAreaMarkerTypes);
         }
 
         // -------------------------------------------------------------------
         // 1) skip distributions having an area with markers matching hiddenAreaMarkerTypes
         //    but keep distributions for fallback areas (areas with hidden marker, but with visible sub-areas)
-        if( hiddenAreaMarkerTypes != null && !hiddenAreaMarkerTypes.isEmpty()) {
-            removeHiddenAndKeepFallbackAreas(hiddenAreaMarkerTypes, filteredDistributions, keepFallBackOnlyIfNoSubareaDataExists);
+        //TODO since using area tree this is only relevant if keepFallBackOnlyIfNoSubareaDataExists = true
+        //     as the area tree should also exclude real hidden areas
+        if(!CdmUtils.isNullSafeEmpty(hiddenAreaMarkerTypes)) {
+            removeHiddenAndKeepFallbackAreas(areaTree, hiddenAreaMarkerTypes, filteredDistributions, keepFallBackOnlyIfNoSubareaDataExists);
         }
 
         // -------------------------------------------------------------------
@@ -743,20 +753,132 @@ public class DistributionServiceUtilities {
         // -------------------------------------------------------------------
         // 4) Sub area preference rule
         if(subAreaPreference){
-            handleSubAreaPreferenceRule(filteredDistributions);
-         }
+            handleSubAreaPreferenceRule(filteredDistributions, areaTree);
+        }
 
         return valuesOfAllInnerSets(filteredDistributions.values());
     }
 
-    private static void handleSubAreaPreferenceRule(SetMap<NamedArea, Distribution> filteredDistributions) {
+    static TermTree<NamedArea> getAreaTree(Collection<Distribution> distributions,
+            Set<MarkerType> hiddenAreaMarkerTypes) {
+
+        //TODO see comment in below method
+//        List<TermVocabulary<NamedArea>> vocs = getVocabualries(distributions);
+        TermTree<NamedArea> areaTree = createAreaTreeByDistributions(distributions, hiddenAreaMarkerTypes);
+        return areaTree;
+    }
+
+    /**
+     * Returns a list of all named area vocabularies for named areas used in the given
+     */
+    //TODO maybe needed by above call once vocabularies are term trees
+    private static List<TermVocabulary<NamedArea>> getVocabualries(Collection<Distribution> distributions) {
+        List<TermVocabulary<NamedArea>> result = new ArrayList<>();
+        distributions.stream()
+            .map(d->d.getArea())
+            .filter(a->a != null)
+            .map(a->a.getVocabulary())
+            .filter(v->!result.contains(v))
+            .forEach(v->result.add(v));
+        return result;
+    }
+
+    /**
+     * Creates a term tree from the part-of information of the distribution areas.
+     * Removes hidden areas marked as such if they have no children.
+     */
+    private static TermTree<NamedArea> createAreaTreeByDistributions(Collection<Distribution> distributions,
+            Set<MarkerType> hiddenAreaMarkerTypes) {
+
+        hiddenAreaMarkerTypes = hiddenAreaMarkerTypes == null ? new HashSet<>() : hiddenAreaMarkerTypes;
+        TermTree<NamedArea> result = TermTree.NewInstance(TermType.NamedArea, NamedArea.class);
+
+        //create area list
+        Set<NamedArea> relevantAreas = new HashSet<>();
+        for (Distribution distribution : distributions) {
+            NamedArea area = distribution.getArea();
+            if (area != null && !relevantAreas.contains(area)) {
+                boolean isHidden = isMarkedHidden(area, hiddenAreaMarkerTypes);
+                if (isHidden) {
+                    //if is hidden area either ignore (hidden area) or add unhidden children (fallback area)
+                    Set<NamedArea> unhiddenChildren = getUnhiddenChildren(area, hiddenAreaMarkerTypes);
+                    if (!unhiddenChildren.isEmpty()) {
+                        relevantAreas.addAll(unhiddenChildren);
+                    }
+                }else {
+                    relevantAreas.add(area);
+                }
+            }
+        }
+
+        //create area tree from area list using part-of info
+        Map<NamedArea, TermNode<NamedArea>> map = new HashMap<>();
+
+        for (NamedArea area : relevantAreas) {
+            NamedArea parent = area.getPartOf();
+            TermNode<NamedArea> parentNode;
+
+            if (parent == null) {
+                parentNode = result.getRoot();
+            }else {
+                parentNode = getNodeRecursive(parent, map, result.getRoot());
+            }
+
+            TermNode<NamedArea> node = parentNode.addChild(area);
+            map.put(area, node);
+        }
+        return result;
+    }
+
+    private static TermNode<NamedArea> getNodeRecursive(NamedArea area, Map<NamedArea, TermNode<NamedArea>> map,
+            TermNode<NamedArea> root) {
+
+            TermNode<NamedArea> areaNode = map.get(area);
+            if (areaNode != null) {
+                return areaNode;
+            }
+            //this usage is only needed as long as vocabularies are not term trees yet
+            NamedArea parentArea = area.getPartOf();
+            TermNode<NamedArea> parentNode;
+
+            if (parentArea == null) {
+                parentNode = root;
+            }else {
+                parentNode = map.get(parentArea);
+                if (parentNode == null) {
+                    parentNode = getNodeRecursive(parentArea, map, root);
+                }
+            }
+            areaNode = parentNode.addChild(area);
+            map.put(area, areaNode);
+            return areaNode;
+    }
+
+    private static Set<NamedArea> getUnhiddenChildren(NamedArea area, Set<MarkerType> hiddenAreaMarkerTypes) {
+        Set<NamedArea> result = new HashSet<>();
+        for (NamedArea child : area.getIncludes()) {
+            if (!isMarkedHidden(child, hiddenAreaMarkerTypes)) {
+                result.add(child);
+            }
+            result.addAll(getUnhiddenChildren(child, hiddenAreaMarkerTypes));
+        }
+        return result;
+    }
+
+
+    private static void handleSubAreaPreferenceRule(SetMap<NamedArea, Distribution> filteredDistributions,
+            TermTree<NamedArea> areaTree) {
+
+        SetMap<NamedArea, NamedArea> parentMap = areaTree.getParentMap();
         Set<NamedArea> removeCandidatesArea = new HashSet<>();
-        for(NamedArea key : filteredDistributions.keySet()){
-            if(removeCandidatesArea.contains(key)){
+        for(NamedArea area : filteredDistributions.keySet()){
+            if(removeCandidatesArea.contains(area)){
                 continue;
             }
-            if(key.getPartOf() != null && filteredDistributions.containsKey(key.getPartOf())){
-                removeCandidatesArea.add(key.getPartOf());
+            //xx;
+            NamedArea parent = parentMap.getFirstValue(area);
+            if(parent != null && filteredDistributions.containsKey(parent)){
+                removeCandidatesArea.add(parent);
             }
         }
         for(NamedArea removeKey : removeCandidatesArea){
@@ -765,18 +887,24 @@ public class DistributionServiceUtilities {
     }
 
     /**
-     * Remove hidden areas but keep fallback areas.
+     * Remove areas not in area tree but keep fallback areas.
      */
-    private static void removeHiddenAndKeepFallbackAreas(Set<MarkerType> hiddenAreaMarkerTypes,
+    private static void removeHiddenAndKeepFallbackAreas(TermTree<NamedArea> areaTree, Set<MarkerType> hiddenAreaMarkerTypes,
             SetMap<NamedArea, Distribution> filteredDistributions, boolean keepFallBackOnlyIfNoSubareaDataExists) {
 
         Set<NamedArea> areasHiddenByMarker = new HashSet<>();
+        Set<NamedArea> availableAreas = areaTree.getDistinctTerms();
+
         for(NamedArea area : filteredDistributions.keySet()) {
-            if(isMarkedHidden(area, hiddenAreaMarkerTypes)) {
+            if (! availableAreas.contains(area)) {
+                areasHiddenByMarker.add(area);
+            }else if(isMarkedHidden(area, hiddenAreaMarkerTypes)) {
+                Set<TermNode<NamedArea>> nodes = areaTree.getNodesForTerm(area);
+
                 // if at least one sub area is not hidden by a marker
                 // the given area is a fall-back area for this sub area
-                SetMap<NamedArea, Distribution>  distributionsForSubareaCheck = keepFallBackOnlyIfNoSubareaDataExists ? filteredDistributions : null;
-                boolean isFallBackArea = isRemainingFallBackArea(area, hiddenAreaMarkerTypes, distributionsForSubareaCheck);
+                SetMap<NamedArea, Distribution> distributionsForSubareaCheck = keepFallBackOnlyIfNoSubareaDataExists ? filteredDistributions : null;
+                boolean isFallBackArea = isRemainingFallBackArea(nodes, hiddenAreaMarkerTypes, distributionsForSubareaCheck);
                 if (!isFallBackArea) {
                     // this area does not need to be shown as
                     // fall-back for another area so it will be hidden.
@@ -790,17 +918,20 @@ public class DistributionServiceUtilities {
     }
 
     //if filteredDistributions == null it can be ignored if data exists or not
-    private static boolean isRemainingFallBackArea(NamedArea area, Set<MarkerType> hiddenAreaMarkerTypes,
+    private static boolean isRemainingFallBackArea(Set<TermNode<NamedArea>> areaNode, Set<MarkerType> hiddenAreaMarkerTypes,
             SetMap<NamedArea, Distribution> filteredDistributions) {
 
-        boolean result = false;
-        for(DefinedTermBase<NamedArea> included : area.getIncludes()) {
-            NamedArea subArea = CdmBase.deproxy(included,NamedArea.class);
+        Set<TermNode<NamedArea>> childNodes = new HashSet<>();
+        areaNode.stream().forEach(an->childNodes.addAll(an.getChildNodes()));
+        for(TermNode<NamedArea> included : childNodes) {
+            NamedArea subArea = included.getTerm();
             boolean noOrIgnoreData = filteredDistributions == null || !filteredDistributions.containsKey(subArea);
 
+            Set<TermNode<NamedArea>> childNodeAsSet = new HashSet<>();
+            childNodeAsSet.add(included);
             //if subarea is not hidden and data exists return true
             if (isMarkedHidden(subArea, hiddenAreaMarkerTypes)){
-                boolean subAreaIsFallback = isRemainingFallBackArea(subArea, hiddenAreaMarkerTypes, filteredDistributions);
+                boolean subAreaIsFallback = isRemainingFallBackArea(childNodeAsSet, hiddenAreaMarkerTypes, filteredDistributions);
                 if (subAreaIsFallback && noOrIgnoreData){
                     return true;
                 }else{
@@ -899,6 +1030,7 @@ public class DistributionServiceUtilities {
      */
     public static DistributionTree buildOrderedTree(Set<NamedAreaLevel> omitLevels,
             Collection<Distribution> distributions,
+            SetMap<NamedArea, NamedArea> parentAreaMap,
             Set<MarkerType> fallbackAreaMarkerTypes,
             boolean neverUseFallbackAreaAsParent,
             DistributionOrder distributionOrder,
@@ -908,7 +1040,7 @@ public class DistributionServiceUtilities {
 
         if (logger.isDebugEnabled()){logger.debug("order tree ...");}
         //order by areas
-        tree.orderAsTree(distributions, omitLevels, fallbackAreaMarkerTypes, neverUseFallbackAreaAsParent);
+        tree.orderAsTree(distributions, parentAreaMap, omitLevels, fallbackAreaMarkerTypes, neverUseFallbackAreaAsParent);
         tree.recursiveSortChildren(distributionOrder); // TODO respect current locale for sorting
         if (logger.isDebugEnabled()){logger.debug("create tree - DONE");}
         return tree;
@@ -916,6 +1048,7 @@ public class DistributionServiceUtilities {
 
     public static DistributionTreeDto buildOrderedTreeDto(Set<NamedAreaLevel> omitLevels,
             Collection<DistributionDto> distributions,
+            SetMap<NamedArea, NamedArea> parentAreaMap,
             Set<MarkerType> fallbackAreaMarkerTypes,
             boolean neverUseFallbackAreaAsParent,
             DistributionOrder distributionOrder,
@@ -927,7 +1060,7 @@ public class DistributionServiceUtilities {
 
         if (logger.isDebugEnabled()){logger.debug("order tree ...");}
         //order by areas
-        loader.orderAsTree(dto, distributions, omitLevels, fallbackAreaMarkerTypes, neverUseFallbackAreaAsParent);
+        loader.orderAsTree(dto, distributions, parentAreaMap, omitLevels, fallbackAreaMarkerTypes, neverUseFallbackAreaAsParent);
         loader.recursiveSortChildren(dto, distributionOrder); // TODO respect current locale for sorting
         if (logger.isDebugEnabled()){logger.debug("create tree - DONE");}
         return dto;
index ceb0b3d5b570364b08f508b5ad351ad79751bd0f..71dba127d15568b854924a7980a7a89eef313725 100644 (file)
@@ -23,6 +23,7 @@ import org.hibernate.proxy.HibernateProxy;
 
 import eu.etaxonomy.cdm.api.dto.portal.IDistributionTree;
 import eu.etaxonomy.cdm.api.dto.portal.config.DistributionOrder;
+import eu.etaxonomy.cdm.common.SetMap;
 import eu.etaxonomy.cdm.common.Tree;
 import eu.etaxonomy.cdm.common.TreeNode;
 import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
@@ -54,9 +55,8 @@ public class DistributionTree
         this.termDao = termDao;
     }
 
-
-
     /**
+     * @param parentAreaMap
      * @param fallbackAreaMarkerTypes
      *      Areas are fallback areas if they have a {@link Marker} with one of the specified
      *      {@link MarkerType marker types}.
@@ -69,7 +69,7 @@ public class DistributionTree
      *      if <code>true</code> a fallback area never has children even if a record exists for the area
      */
     public void orderAsTree(Collection<Distribution> distributions,
-            Set<NamedAreaLevel> omitLevels,
+            SetMap<NamedArea, NamedArea> parentAreaMap, Set<NamedAreaLevel> omitLevels,
             Set<MarkerType> fallbackAreaMarkerTypes,
             boolean neverUseFallbackAreasAsParents){
 
@@ -79,7 +79,7 @@ public class DistributionTree
             areas.add(distribution.getArea());
         }
         // preload all areas which are a parent of another one, this is a performance improvement
-        loadAllParentAreas(areas);
+        loadAllParentAreasIntoSession(areas);
 
         Set<Integer> omitLevelIds = new HashSet<>(omitLevels.size());
         for(NamedAreaLevel level : omitLevels) {
@@ -88,7 +88,7 @@ public class DistributionTree
 
         for (Distribution distribution : distributions) {
             // get path through area hierarchy
-            List<NamedArea> namedAreaPath = getAreaLevelPath(distribution.getArea(), omitLevelIds,
+            List<NamedArea> namedAreaPath = getAreaLevelPath(distribution.getArea(), parentAreaMap, omitLevelIds,
                     areas, fallbackAreaMarkerTypes, neverUseFallbackAreasAsParents);
             addDistributionToSubTree(distribution, namedAreaPath, this.getRootElement());
         }
@@ -99,7 +99,7 @@ public class DistributionTree
      * all initialization of the NamedArea term instances is ready. This improves the
      * performance of the tree building
      */
-    private void loadAllParentAreas(Set<NamedArea> areas) {
+    private void loadAllParentAreasIntoSession(Set<NamedArea> areas) {
 
         List<NamedArea> parentAreas = null;
         Set<NamedArea> childAreas = new HashSet<>(areas.size());
@@ -192,7 +192,7 @@ public class DistributionTree
      *
      * Areas for which no distribution data is available and which are marked as hidden are omitted, see #5112
      *
-     * @param area
+     * @param area the area to get the path for
      * @param distributionAreas the areas for which distribution data exists (after filtering by
      *  {@link eu.etaxonomy.cdm.api.service.geo.DescriptionUtility#filterDistributions()} )
      * @param fallbackAreaMarkerTypes
@@ -203,7 +203,7 @@ public class DistributionTree
      * @param omitLevels
      * @return the path through the area hierarchy
      */
-    private List<NamedArea> getAreaLevelPath(NamedArea area, Set<Integer> omitLevelIds,
+    private List<NamedArea> getAreaLevelPath(NamedArea area, SetMap<NamedArea, NamedArea> parentAreaMap, Set<Integer> omitLevelIds,
             Set<NamedArea> distributionAreas, Set<MarkerType> fallbackAreaMarkerTypes,
             boolean neverUseFallbackAreasAsParents){
 
@@ -212,8 +212,8 @@ public class DistributionTree
             result.add(area);
         }
 
-        while (area.getPartOf() != null) {
-            area = area.getPartOf();
+        while (parentAreaMap.getFirstValue(area) != null) {  //handle >1 parents
+            area = parentAreaMap.getFirstValue(area);
             if (!matchesLevels(area, omitLevelIds)){
                 if(!isFallback(fallbackAreaMarkerTypes, area) ||
                         (distributionAreas.contains(area) && !neverUseFallbackAreasAsParents ) ) {
index 72a091a35a415d848a3704cfad50ffce9445c778..48523f27a6f4ce1b6aa3eb97f9a266f1ebd3e105 100644 (file)
@@ -32,6 +32,7 @@ import eu.etaxonomy.cdm.model.description.Distribution;
 import eu.etaxonomy.cdm.model.description.PresenceAbsenceTerm;
 import eu.etaxonomy.cdm.model.description.TaxonDescription;
 import eu.etaxonomy.cdm.model.location.NamedArea;
+import eu.etaxonomy.cdm.model.term.TermTree;
 
 /**
  * This service has been extracted from cdmlib-ext IEditGeoService
@@ -57,7 +58,7 @@ public interface IDistributionService {
      * @return
      */
     public DistributionInfoDto composeDistributionInfoFor(DistributionInfoConfiguration config, UUID taxonUUID,
-            Set<UUID> features, boolean neverUseFallbackAreaAsParent,
+            boolean neverUseFallbackAreaAsParent,
             Map<PresenceAbsenceTerm, Color> presenceAbsenceTermColors, List<Language> languages, List<String> propertyPaths);
 
     public DistributionInfoDto composeDistributionInfoFor(DistributionInfoConfiguration config, List<Distribution> distributions,
@@ -73,6 +74,7 @@ public interface IDistributionService {
     * @return
     */
     public CondensedDistribution getCondensedDistribution(Set<Distribution> distributions,
+            TermTree<NamedArea> areaTree,
             boolean statusOrderPreference,
             Set<MarkerType> hiddenAreaMarkerTypes,
             CondensedDistributionConfiguration config,
index 9a15ad5dba90b4cc1b2ab2f350dc052d8c6c8940..83ae94d36384b07c547390d06e887790f6841891 100644 (file)
@@ -27,6 +27,7 @@ import eu.etaxonomy.cdm.api.dto.portal.DistributionTreeDto;
 import eu.etaxonomy.cdm.api.dto.portal.LabeledEntityDto;
 import eu.etaxonomy.cdm.api.dto.portal.NamedAreaDto;
 import eu.etaxonomy.cdm.api.dto.portal.config.DistributionOrder;
+import eu.etaxonomy.cdm.common.SetMap;
 import eu.etaxonomy.cdm.common.TreeNode;
 import eu.etaxonomy.cdm.model.common.Marker;
 import eu.etaxonomy.cdm.model.common.MarkerType;
@@ -76,7 +77,8 @@ public class DistributionTreeDtoLoader {
     }
 
   /**
-   * @param fallbackAreaMarkerTypes
+   * @param parentAreaMap
+ * @param fallbackAreaMarkerTypes
    *      Areas are fallback areas if they have a {@link Marker} with one of the specified
    *      {@link MarkerType marker types}.
    *      Areas identified as such are omitted from the hierarchy and the sub areas are moving one level up.
@@ -88,17 +90,17 @@ public class DistributionTreeDtoLoader {
    *      if <code>true</code> a fallback area never has children even if a record exists for the area
    */
   public void orderAsTree(DistributionTreeDto dto, Collection<DistributionDto> distributions,
-          Set<NamedAreaLevel> omitLevels,
+          SetMap<NamedArea, NamedArea> parentAreaMap, Set<NamedAreaLevel> omitLevels,
           Set<MarkerType> fallbackAreaMarkerTypes,
           boolean neverUseFallbackAreasAsParents){
 
       //compute all areas
-      Set<NamedAreaDto> areas = new HashSet<>(distributions.size());
+      Set<NamedAreaDto> relevantAreas = new HashSet<>(distributions.size());
       for (DistributionDto distribution : distributions) {
-          areas.add(distribution.getArea());
+          relevantAreas.add(distribution.getArea());
       }
       // preload all areas which are a parent of another one, this is a performance improvement
-      loadAllParentAreas(areas);
+      loadAllParentAreasIntoSession(relevantAreas, parentAreaMap);
 
       Set<Integer> omitLevelIds = new HashSet<>(omitLevels.size());
       for(NamedAreaLevel level : omitLevels) {
@@ -107,8 +109,8 @@ public class DistributionTreeDtoLoader {
 
       for (DistributionDto distribution : distributions) {
           // get path through area hierarchy
-          List<NamedAreaDto> namedAreaPath = getAreaLevelPath(distribution.getArea(), omitLevelIds,
-                  areas, fallbackAreaMarkerTypes, neverUseFallbackAreasAsParents);
+          List<NamedAreaDto> namedAreaPath = getAreaLevelPath(distribution.getArea(), parentAreaMap,
+                  omitLevelIds, relevantAreas, fallbackAreaMarkerTypes, neverUseFallbackAreasAsParents);
           addDistributionToSubTree(distribution, namedAreaPath, dto.getRootElement());
       }
   }
@@ -118,17 +120,16 @@ public class DistributionTreeDtoLoader {
    * all initialization of the NamedArea term instances is ready. This improves the
    * performance of the tree building
    */
-  private void loadAllParentAreas(Set<NamedAreaDto> areas) {
+  private void loadAllParentAreasIntoSession(Set<NamedAreaDto> areas, SetMap<NamedArea, NamedArea> parentAreaMap) {
 
       List<NamedAreaDto> parentAreas = null;
       Set<UUID> childAreas = new HashSet<>(areas.size());
       for(NamedAreaDto area : areas) {
-//          NamedAreaDto deproxied = HibernateProxyHelper.deproxy(areaProxy);
           childAreas.add(area.getUuid());
       }
 
       if(!childAreas.isEmpty()) {
-          parentAreas = termDao.getPartOfNamedAreas(childAreas);
+          parentAreas = termDao.getPartOfNamedAreas(childAreas, parentAreaMap);
           childAreas.clear();
 //          cdhildAreas.addAll(parentAreas);
       }
@@ -212,6 +213,7 @@ public class DistributionTreeDtoLoader {
    * Areas for which no distribution data is available and which are marked as hidden are omitted, see #5112
    *
    * @param area
+ * @param parentAreaMap
    * @param distributionAreas the areas for which distribution data exists (after filtering by
    *  {@link eu.etaxonomy.cdm.api.service.geo.DescriptionUtility#filterDistributions()} )
    * @param fallbackAreaMarkerTypes
@@ -222,7 +224,8 @@ public class DistributionTreeDtoLoader {
    * @param omitLevels
    * @return the path through the area hierarchy
    */
-  private List<NamedAreaDto> getAreaLevelPath(NamedAreaDto area, Set<Integer> omitLevelIds,
+  private List<NamedAreaDto> getAreaLevelPath(NamedAreaDto area, SetMap<NamedArea, NamedArea> parentAreaMap,
+          Set<Integer> omitLevelIds,
           Set<NamedAreaDto> distributionAreas, Set<MarkerType> fallbackAreaMarkerTypes,
           boolean neverUseFallbackAreasAsParents){
 
@@ -231,18 +234,34 @@ public class DistributionTreeDtoLoader {
           result.add(area);
       }
 
-      while (area.getPartOf() != null) {
-          area = area.getPartOf();
-          if (!matchesLevels(area, omitLevelIds)){
-              if(!isFallback(fallbackAreaMarkerTypes, area) ||
-                      (distributionAreas.contains(area) && !neverUseFallbackAreasAsParents ) ) {
-                  result.add(0, area);
-              } else {
-                  if(logger.isDebugEnabled()) {logger.debug("positive fallback area detection, skipping " + area );}
+      if (parentAreaMap == null) { //TODO should this happen?
+          while (area.getParent() != null) {
+              area = area.getParent();
+              if (!matchesLevels(area, omitLevelIds)){
+                  if(!isFallback(fallbackAreaMarkerTypes, area) ||
+                          (distributionAreas.contains(area) && !neverUseFallbackAreasAsParents ) ) {
+                      result.add(0, area);
+                  } else {
+                      if(logger.isDebugEnabled()) {logger.debug("positive fallback area detection, skipping " + area );}
+                  }
+              }
+          }
+      } else {
+          //FIXME same as above case, maybe we do not need to distinguish as parent handling is done
+          // in NamedAreaDTO constructor
+          while (area.getParent() != null) {
+              area = area.getParent();
+              if (!matchesLevels(area, omitLevelIds)){
+                  if(!isFallback(fallbackAreaMarkerTypes, area) ||
+                          (distributionAreas.contains(area) && !neverUseFallbackAreasAsParents ) ) {
+                      result.add(0, area);
+                  } else {
+                      if(logger.isDebugEnabled()) {logger.debug("positive fallback area detection, skipping " + area );}
+                  }
               }
           }
-      }
 
+      }
       return result;
   }
 
index 30c0c18c9c46445e4c0e1501d11f421f7856176e..e8656eeb65206968aa069a7358c4b8c9fc6b496b 100644 (file)
@@ -57,6 +57,7 @@ import eu.etaxonomy.cdm.model.location.NamedAreaLevel;
 import eu.etaxonomy.cdm.model.location.NamedAreaType;
 import eu.etaxonomy.cdm.model.taxon.Taxon;
 import eu.etaxonomy.cdm.model.term.DefinedTermBase;
+import eu.etaxonomy.cdm.model.term.TermTree;
 import eu.etaxonomy.cdm.model.term.TermType;
 import eu.etaxonomy.cdm.model.term.TermVocabulary;
 import eu.etaxonomy.cdm.test.integration.CdmTransactionalIntegrationTest;
@@ -109,9 +110,12 @@ public class DistributionServiceImplTest extends CdmTransactionalIntegrationTest
 
         boolean subAreaPreference = false;
         boolean statusOrderPreference = false;
+        TermTree<NamedArea> areaTree = null;
+        Set<MarkerType> hiddenAreaMarkerTypes = null;
 
         Collection<Distribution> filteredDistributions = DistributionServiceUtilities.filterDistributions(
-                distributions, null, false, statusOrderPreference, subAreaPreference, true, false);
+                distributions, areaTree, hiddenAreaMarkerTypes, false,
+                statusOrderPreference, subAreaPreference, true, false);
 
         String result = DistributionServiceUtilities.getDistributionServiceRequestParameterString(filteredDistributions,
                 mapping, null, null, languages );
index ce5d6ea001e2255db45e233f4e2b1ec5e1b3aa1b..c9abd15d3bdebd6e394068a474b9b8f413287d62 100644 (file)
@@ -20,7 +20,6 @@ import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 
-import eu.etaxonomy.cdm.api.service.geo.DistributionServiceUtilities;
 import eu.etaxonomy.cdm.model.common.Marker;
 import eu.etaxonomy.cdm.model.common.MarkerType;
 import eu.etaxonomy.cdm.model.description.DescriptionType;
@@ -29,6 +28,7 @@ import eu.etaxonomy.cdm.model.description.PresenceAbsenceTerm;
 import eu.etaxonomy.cdm.model.description.TaxonDescription;
 import eu.etaxonomy.cdm.model.location.Country;
 import eu.etaxonomy.cdm.model.location.NamedArea;
+import eu.etaxonomy.cdm.model.term.TermTree;
 import eu.etaxonomy.cdm.test.TermTestBase;
 
 /**
@@ -83,7 +83,9 @@ public class DistributionServiceUtilitiesTest extends TermTestBase {
 
         statusOrderPreference= true;
         boolean preferAggregated = true;
-        filteredDistributions = DistributionServiceUtilities.filterDistributions(distributions, hideMarkedAreas, preferAggregated, statusOrderPreference, subAreaPreference, false, false);
+        TermTree<NamedArea> areaTree = null;
+        filteredDistributions = DistributionServiceUtilities.filterDistributions(distributions,
+                areaTree, hideMarkedAreas, preferAggregated, statusOrderPreference, subAreaPreference, false, false);
         Assert.assertEquals(1, filteredDistributions.size());
         Assert.assertEquals("expecting to see computed status INTRODUCED even it has lower preference than NATIVE", PresenceAbsenceTerm.INTRODUCED(), filteredDistributions.iterator().next().getStatus());
 
@@ -98,13 +100,15 @@ public class DistributionServiceUtilitiesTest extends TermTestBase {
         distributions.add(parentComputedDistribution);
 
         filteredDistributions = DistributionServiceUtilities.filterDistributions(
-                distributions, hideMarkedAreas, preferAggregated, statusOrderPreference, subAreaPreference, true, false);
+                distributions, areaTree, hideMarkedAreas, preferAggregated,
+                statusOrderPreference, subAreaPreference, true, false);
         Assert.assertEquals(2, filteredDistributions.size());
     }
 
     @Test
     public void testFilterDistributions_statusOrderPreference(){
         statusOrderPreference = true;
+        TermTree<NamedArea> areaTree = null;
 
         /*
          * Status order preference rule: In case of multiple distribution status
@@ -115,7 +119,7 @@ public class DistributionServiceUtilitiesTest extends TermTestBase {
         distributions.add(Distribution.NewInstance(Country.GERMANY(), PresenceAbsenceTerm.NATIVE()));
         distributions.add(Distribution.NewInstance(Country.GERMANY(), PresenceAbsenceTerm.INTRODUCED()));
         filteredDistributions = DistributionServiceUtilities.filterDistributions(
-                distributions, hideMarkedAreas, false, statusOrderPreference, subAreaPreference, true, false);
+                distributions, areaTree, hideMarkedAreas, false, statusOrderPreference, subAreaPreference, true, false);
         Assert.assertEquals(1, filteredDistributions.size());
         Assert.assertEquals(PresenceAbsenceTerm.NATIVE(), filteredDistributions.iterator().next().getStatus());
     }
@@ -123,6 +127,7 @@ public class DistributionServiceUtilitiesTest extends TermTestBase {
     @Test
     public void testFilterDistributions_subAreaPreference(){
         subAreaPreference = true;
+        TermTree<NamedArea> areaTree = null;
 
         /*
          * Sub area preference rule: If there is an area with a direct sub area
@@ -144,7 +149,7 @@ public class DistributionServiceUtilitiesTest extends TermTestBase {
         // no computed data
         distributions.add(distGermany);
         distributions.add(distBerlin);
-        filteredDistributions = DistributionServiceUtilities.filterDistributions(distributions,
+        filteredDistributions = DistributionServiceUtilities.filterDistributions(distributions, areaTree,
                 hideMarkedAreas, NO_PREFER_AGGREGATED, statusOrderPreference, subAreaPreference, true, false);
         Assert.assertEquals(1, filteredDistributions.size());
         Assert.assertEquals(berlin, filteredDistributions.iterator().next().getArea());
@@ -152,14 +157,14 @@ public class DistributionServiceUtilitiesTest extends TermTestBase {
         // mixed situation
         distGermany.addMarker(Marker.NewInstance(MarkerType.COMPUTED(), true));
         filteredDistributions = DistributionServiceUtilities.filterDistributions(distributions,
-                hideMarkedAreas, NO_PREFER_AGGREGATED, statusOrderPreference, subAreaPreference, true, false);
+                areaTree, hideMarkedAreas, NO_PREFER_AGGREGATED, statusOrderPreference, subAreaPreference, true, false);
         Assert.assertEquals(1, filteredDistributions.size());
         Assert.assertEquals(berlin, filteredDistributions.iterator().next().getArea());
 
         // all computed
         distBerlin.addMarker(Marker.NewInstance(MarkerType.COMPUTED(), true));
         filteredDistributions = DistributionServiceUtilities.filterDistributions(distributions,
-                hideMarkedAreas, NO_PREFER_AGGREGATED, statusOrderPreference, subAreaPreference, true, false);
+                areaTree, hideMarkedAreas, NO_PREFER_AGGREGATED, statusOrderPreference, subAreaPreference, true, false);
         Assert.assertEquals(1, filteredDistributions.size());
         Assert.assertEquals(berlin, filteredDistributions.iterator().next().getArea());
     }
@@ -187,8 +192,10 @@ public class DistributionServiceUtilitiesTest extends TermTestBase {
         hideMarkedAreas = new HashSet<>();
         hideMarkedAreas.add(MarkerType.TO_BE_CHECKED());
         hideMarkedAreas.add(MarkerType.IMPORTED());
+        TermTree<NamedArea> areaTree = null;
 
-        filteredDistributions = DistributionServiceUtilities.filterDistributions(distributions, hideMarkedAreas, false,
+        filteredDistributions = DistributionServiceUtilities.filterDistributions(distributions,
+                areaTree, hideMarkedAreas, false,
                 statusOrderPreference, subAreaPreference, true, false);
         Assert.assertEquals(1, filteredDistributions.size());
         Assert.assertEquals(germany, filteredDistributions.iterator().next().getArea());
@@ -213,10 +220,11 @@ public class DistributionServiceUtilitiesTest extends TermTestBase {
 
         hideMarkedAreas = new HashSet<>();
         hideMarkedAreas.add(MarkerType.TO_BE_CHECKED());
+        TermTree<NamedArea> areaTree = null;
 
         boolean keepFallBackOnlyIfNoSubareaDataExists = true;
         filteredDistributions = DistributionServiceUtilities.filterDistributions(
-                distributions,
+                distributions, areaTree,
                 hideMarkedAreas,
                 NO_PREFER_AGGREGATED,
                 statusOrderPreference,
@@ -228,7 +236,7 @@ public class DistributionServiceUtilitiesTest extends TermTestBase {
 
         keepFallBackOnlyIfNoSubareaDataExists = false;
         filteredDistributions = DistributionServiceUtilities.filterDistributions(
-                distributions,
+                distributions, areaTree,
                 hideMarkedAreas,
                 NO_PREFER_AGGREGATED,
                 statusOrderPreference,
@@ -261,10 +269,11 @@ public class DistributionServiceUtilitiesTest extends TermTestBase {
 
         hideMarkedAreas = new HashSet<>();
         hideMarkedAreas.add(MarkerType.TO_BE_CHECKED());
+        TermTree<NamedArea> areaTree = null;
 
         boolean keepFallBackOnlyIfNoSubareaDataExists = true;
         filteredDistributions = DistributionServiceUtilities.filterDistributions(
-                distributions, hideMarkedAreas, NO_PREFER_AGGREGATED,
+                distributions, areaTree, hideMarkedAreas, NO_PREFER_AGGREGATED,
                 statusOrderPreference, subAreaPreference,
                 keepFallBackOnlyIfNoSubareaDataExists, false);
 
@@ -273,7 +282,7 @@ public class DistributionServiceUtilitiesTest extends TermTestBase {
 
         keepFallBackOnlyIfNoSubareaDataExists = false;
         filteredDistributions = DistributionServiceUtilities.filterDistributions(
-                distributions, hideMarkedAreas, NO_PREFER_AGGREGATED,
+                distributions, areaTree, hideMarkedAreas, NO_PREFER_AGGREGATED,
                 statusOrderPreference, subAreaPreference,
                 keepFallBackOnlyIfNoSubareaDataExists, false);
 
@@ -283,7 +292,7 @@ public class DistributionServiceUtilitiesTest extends TermTestBase {
         keepFallBackOnlyIfNoSubareaDataExists = true;
         distributions.add(distSerbia);
         filteredDistributions = DistributionServiceUtilities.filterDistributions(
-                distributions, hideMarkedAreas, NO_PREFER_AGGREGATED,
+                distributions, areaTree, hideMarkedAreas, NO_PREFER_AGGREGATED,
                 statusOrderPreference, subAreaPreference,
                 keepFallBackOnlyIfNoSubareaDataExists, false);
 
@@ -292,7 +301,7 @@ public class DistributionServiceUtilitiesTest extends TermTestBase {
 
         keepFallBackOnlyIfNoSubareaDataExists = false;
         filteredDistributions = DistributionServiceUtilities.filterDistributions(
-                distributions, hideMarkedAreas, NO_PREFER_AGGREGATED,
+                distributions, areaTree, hideMarkedAreas, NO_PREFER_AGGREGATED,
                 statusOrderPreference, subAreaPreference,
                 keepFallBackOnlyIfNoSubareaDataExists, false);
         Assert.assertEquals(2, filteredDistributions.size());
@@ -302,7 +311,7 @@ public class DistributionServiceUtilitiesTest extends TermTestBase {
         distributions.add(distPartOfSerbia);
         keepFallBackOnlyIfNoSubareaDataExists = true;
         filteredDistributions = DistributionServiceUtilities.filterDistributions(
-                distributions, hideMarkedAreas, NO_PREFER_AGGREGATED,
+                distributions, areaTree, hideMarkedAreas, NO_PREFER_AGGREGATED,
                 statusOrderPreference, subAreaPreference,
                 keepFallBackOnlyIfNoSubareaDataExists, false);
 
@@ -311,7 +320,7 @@ public class DistributionServiceUtilitiesTest extends TermTestBase {
 
         keepFallBackOnlyIfNoSubareaDataExists = false;
         filteredDistributions = DistributionServiceUtilities.filterDistributions(
-                distributions, hideMarkedAreas, NO_PREFER_AGGREGATED,
+                distributions, areaTree, hideMarkedAreas, NO_PREFER_AGGREGATED,
                 statusOrderPreference, subAreaPreference,
                 keepFallBackOnlyIfNoSubareaDataExists, false);
         Assert.assertEquals(3, filteredDistributions.size());
@@ -345,9 +354,10 @@ public class DistributionServiceUtilitiesTest extends TermTestBase {
 
         hideMarkedAreas = new HashSet<>();
         hideMarkedAreas.add(MarkerType.TO_BE_CHECKED());
+        TermTree<NamedArea> areaTree = null;
 
         filteredDistributions = DistributionServiceUtilities.filterDistributions(
-                distributions,
+                distributions, areaTree,
                 hideMarkedAreas,
                 preferAggregated,
                 statusOrderPreference,
@@ -371,14 +381,15 @@ public class DistributionServiceUtilitiesTest extends TermTestBase {
         distributions.add(distJugoslavia);
         // no Distribution for any of the sub areas of jugoslavia, so it should be shown
 
-        // using TO_BE_CHECKED to mark Ju as fallback area
+        // using TO_BE_CHECKED as hidden area marker to mark Ju as fallback area
         jugoslavia.addMarker(Marker.NewInstance(MarkerType.TO_BE_CHECKED(), true));
 
         hideMarkedAreas = new HashSet<>();
         hideMarkedAreas.add(MarkerType.TO_BE_CHECKED());
+        TermTree<NamedArea> areaTree = null;
 
         filteredDistributions = DistributionServiceUtilities.filterDistributions(
-                distributions,
+                distributions, areaTree,
                 hideMarkedAreas,
                 false,
                 statusOrderPreference,
@@ -388,4 +399,4 @@ public class DistributionServiceUtilitiesTest extends TermTestBase {
         Assert.assertEquals(1, filteredDistributions.size());
         Assert.assertEquals(jugoslavia, filteredDistributions.iterator().next().getArea());
     }
-}
+}
\ No newline at end of file