remove deprecated method
[cdmlib.git] / cdmlib-services / src / main / java / eu / etaxonomy / cdm / api / service / DistributionTree.java
index 70174293eb5d8e8156d0b568f407cb65e454ccd4..070ee7f9c9a2f8cb2495821f2b3cae2e34c228ff 100644 (file)
 package eu.etaxonomy.cdm.api.service;\r
 \r
 import java.util.ArrayList;\r
+import java.util.Collection;\r
 import java.util.Collections;\r
-import java.util.Iterator;\r
+import java.util.HashSet;\r
 import java.util.List;\r
 import java.util.Set;\r
 \r
 import org.apache.log4j.Logger;\r
+import org.hibernate.proxy.HibernateProxy;\r
+import org.hibernate.proxy.HibernateProxyHelper;\r
 \r
 import eu.etaxonomy.cdm.common.Tree;\r
 import eu.etaxonomy.cdm.common.TreeNode;\r
-import eu.etaxonomy.cdm.model.common.Language;\r
 import eu.etaxonomy.cdm.model.description.Distribution;\r
 import eu.etaxonomy.cdm.model.location.NamedArea;\r
 import eu.etaxonomy.cdm.model.location.NamedAreaLevel;\r
 \r
 /**\r
  * TODO javadoc.\r
- * \r
- * There is a somehow similar implementation in {@link eu.etaxonomy.cdm.model.location.NamedArea} \r
+ *\r
+ * There is a somehow similar implementation in {@link eu.etaxonomy.cdm.model.location.NamedArea}\r
  */\r
-public class DistributionTree extends Tree<Distribution>{\r
+public class DistributionTree extends Tree<Set<Distribution>, NamedArea>{\r
 \r
     public static final Logger logger = Logger.getLogger(DistributionTree.class);\r
 \r
     public DistributionTree(){\r
-        NamedArea area = NamedArea.NewInstance();\r
-        Distribution data = Distribution.NewInstance();\r
-        data.setArea(area);\r
-        data.putModifyingText(Language.ENGLISH(), "test");\r
-        TreeNode<Distribution> rootElement = new TreeNode<Distribution>();\r
-        List<TreeNode<Distribution>> children = new ArrayList<TreeNode<Distribution>>();\r
-\r
-        rootElement.setData(data);\r
+        TreeNode<Set<Distribution>, NamedArea> rootElement = new TreeNode<Set<Distribution>, NamedArea>();\r
+        List<TreeNode<Set<Distribution>, NamedArea>> children = new ArrayList<TreeNode<Set<Distribution>, NamedArea>>();\r
         rootElement.setChildren(children);\r
         setRootElement(rootElement);\r
     }\r
 \r
-    public boolean containsChild(TreeNode<Distribution> root, TreeNode<Distribution> treeNode){\r
-         boolean result = false;\r
-         Iterator<TreeNode<Distribution>> it = root.getChildren().iterator();\r
-         while (it.hasNext() && !result) {\r
-             TreeNode<Distribution> node = it.next();\r
-             if (node.getData().equalsForTree(treeNode.getData())) {\r
-                 result = true;\r
-             }\r
-         }\r
-         /*\r
-         while (!result && it.hasNext()) {\r
-              if (it.next().data.equalsForTree(treeNode.data)){\r
-                  result = true;\r
-              }\r
-         }\r
-         */\r
-         return result;\r
-     }\r
-\r
-    public TreeNode<Distribution> getChild(TreeNode<Distribution> root, TreeNode<Distribution> TreeNode) {\r
-        boolean found = false;\r
-        TreeNode<Distribution> result = null;\r
-        Iterator<TreeNode<Distribution>> it = root.children.iterator();\r
-        while (!found && it.hasNext()) {\r
-            result = it.next();\r
-            if (result.data.equalsForTree(TreeNode.data)){\r
-                found = true;\r
-            }\r
-        }\r
-        if (!found){\r
-            try {\r
-                throw new Exception("The node was not found in among children and that is a precondition of getChild(node) method");\r
-            } catch (Exception e) {\r
-                e.printStackTrace();\r
-            }\r
-        }\r
-        return result;\r
+    /**\r
+     * @param parentNode\r
+     * @param nodeToFind\r
+     * @return false if the node was not found\r
+     */\r
+    public boolean hasChildNode(TreeNode<Set<Distribution>, NamedArea> parentNode, NamedArea nodeID) {\r
+        return findChildNode(parentNode, nodeID) != null;\r
     }\r
 \r
-    private List<Distribution> orderDistributionsByLevel(List<Distribution> distList){\r
-\r
-        if(distList == null){\r
-            distList = new ArrayList<Distribution>();\r
-        }\r
-        if(distList.size() == 0){\r
-            return distList;\r
+    /**\r
+     * @param parentNode\r
+     * @param nodeToFind\r
+     * @return the found node or null\r
+     */\r
+    public TreeNode<Set<Distribution>, NamedArea> findChildNode(TreeNode<Set<Distribution>, NamedArea> parentNode, NamedArea  nodeID) {\r
+        if (parentNode.getChildren() == null) {\r
+            return null;\r
         }\r
 \r
-        Distribution dist;\r
-        List<Distribution> orderedList = new ArrayList<Distribution>(distList.size());\r
-        orderedList.addAll(distList);\r
-\r
-        int length = -1;\r
-        boolean flag = true;\r
-        for (int i = 0; i < length && flag; i++) {\r
-            flag = false;\r
-            for (int j = 0; j < length-1; j++) {\r
-                String level1 = orderedList.get(j).getArea().getLevel().toString();\r
-                String level2 = orderedList.get(j+1).getArea().getLevel().toString();\r
-                //if level from j+1 is greater than level from j\r
-                if (level2.compareTo(\r
-                        level1) < 0) {\r
-                    dist = orderedList.get(j);\r
-                    orderedList.set(j, orderedList.get(j+1));\r
-                    orderedList.set(j+1, dist);\r
-                    flag = true;\r
-                }\r
+        for (TreeNode<Set<Distribution>, NamedArea> node : parentNode.getChildren()) {\r
+            if (node.getNodeId().equals(nodeID)) {\r
+                return node;\r
             }\r
         }\r
-        return orderedList;\r
+        return null;\r
     }\r
 \r
     /**\r
      * @param distList\r
      * @param omitLevels\r
      */\r
-    public void orderAsTree(List<Distribution> distList, Set<NamedAreaLevel> omitLevels){\r
-\r
-        List<Distribution> orderedDistList = orderDistributionsByLevel(distList);\r
+    public void orderAsTree(Collection<Distribution> distList, Set<NamedAreaLevel> omitLevels){\r
 \r
-        for (Distribution distributionElement : orderedDistList) {\r
+        for (Distribution distribution : distList) {\r
             // get path through area hierarchy\r
-            List<NamedArea> namedAreaPath = getAreaLevelPath(distributionElement.getArea(), omitLevels);\r
-            // order by merging\r
-            mergeAux(distributionElement, namedAreaPath, this.getRootElement());\r
+            List<NamedArea> namedAreaPath = getAreaLevelPath(distribution.getArea(), omitLevels);\r
+            addDistributionToSubTree(distribution, namedAreaPath, this.getRootElement());\r
         }\r
     }\r
 \r
-    public void sortChildren(){\r
-        sortChildrenAux(this.getRootElement());\r
+    public void recursiveSortChildrenByLabel(){\r
+        _recursiveSortChildrenByLabel(this.getRootElement());\r
     }\r
 \r
-    private void sortChildrenAux(TreeNode<Distribution> treeNode){\r
-        DistributionNodeComparator comp = new DistributionNodeComparator();\r
+    private void _recursiveSortChildrenByLabel(TreeNode<Set<Distribution>, NamedArea> treeNode){\r
+        DistributionNodeByAreaLabelComparator comp = new DistributionNodeByAreaLabelComparator();\r
         if (treeNode.children == null) {\r
             //nothing => stop condition\r
             return;\r
         }else {\r
             Collections.sort(treeNode.children, comp);\r
-            for (TreeNode<Distribution> child : treeNode.children) {\r
-                sortChildrenAux(child);\r
+            for (TreeNode<Set<Distribution>, NamedArea> child : treeNode.children) {\r
+                _recursiveSortChildrenByLabel(child);\r
             }\r
         }\r
     }\r
 \r
-    private void mergeAux(Distribution distributionElement, List<NamedArea> namedAreaPath, TreeNode<Distribution> root){\r
+    /**\r
+     * Adds the given <code>distributionElement</code> to the sub tree defined by\r
+     * the <code>root</code>.\r
+     *\r
+     * @param distribution\r
+     *            the {@link Distribution} to add to the tree at the position\r
+     *            according to the NamedArea hierarchy.\r
+     * @param namedAreaPath\r
+     *            the path to the root of the NamedArea hierarchy starting the\r
+     *            area used in the given <code>distributionElement</code>. The\r
+     *            hierarchy is defined by the {@link NamedArea#getPartOf()}\r
+     *            relationships\r
+     * @param root\r
+     *            root element of the sub tree to which the\r
+     *            <code>distributionElement</code> is to be added\r
+     */\r
+    private void addDistributionToSubTree(Distribution distribution, List<NamedArea> namedAreaPath, TreeNode<Set<Distribution>, NamedArea> root){\r
 \r
-        TreeNode<Distribution> highestDistNode;\r
-        TreeNode<Distribution> child;// the new child to add or the child to follow through the tree\r
 \r
-         //if the list to merge is empty finish the execution\r
+        //if the list to merge is empty finish the execution\r
         if (namedAreaPath.isEmpty()) {\r
             return;\r
         }\r
@@ -164,39 +126,30 @@ public class DistributionTree extends Tree<Distribution>{
         //getting the highest area and inserting it into the tree\r
         NamedArea highestArea = namedAreaPath.get(0);\r
 \r
-        boolean isOnTop = false;\r
-        if(distributionElement.getArea().getLevel() == null) {\r
-            // is level is null compare by area only\r
-//            isOnTop = distributionElement.getArea().getUuid().equals(highestArea.getUuid());\r
-            isOnTop = false;\r
-        } else {\r
-            // otherwise compare by level\r
-            isOnTop = highestArea.getLevel().getUuid().equals((distributionElement.getArea().getLevel().getUuid()));\r
-        }\r
 \r
-        if (isOnTop) {\r
-            highestDistNode = new TreeNode<Distribution>(distributionElement); //distribution.area comes from proxy!!!!\r
-        }else{\r
-            //if distribution.status is not relevant\r
-            Distribution dummyDistributionElement = Distribution.NewInstance(highestArea, null);\r
-            highestDistNode = new TreeNode<Distribution>(dummyDistributionElement);\r
+        TreeNode<Set<Distribution>, NamedArea> child = findChildNode(root, highestArea);\r
+        if (child == null) {\r
+            // the highestDistNode is not yet in the set of children, so we add it\r
+            child = new TreeNode<Set<Distribution>, NamedArea>(highestArea);\r
+            child.setData(new HashSet<Distribution>());\r
+            root.addChild(child);\r
         }\r
 \r
-        if (root.getChildren().isEmpty() || !containsChild(root, highestDistNode)) {\r
-            //if the highest level is not on the depth-1 of the tree we add it.\r
-            //child = highestDistNode;\r
-            child = new TreeNode<Distribution>(highestDistNode.data);\r
-            root.addChild(child);//child.getData().getArea().getUuid().toString().equals("8cfc1722-e1e8-49d3-95a7-9879de6de490");\r
-        }else {\r
-            //if the depth-1 of the tree contains the highest area level\r
-            //get the subtree or create it in order to continuing merging\r
-            child = getChild(root,highestDistNode);\r
+        // add another element to the list of data\r
+        if(namedAreaPath.get(0).equals(distribution.getArea())){\r
+            if(namedAreaPath.size() > 1){\r
+                logger.error("there seems to be something wrong with the area hierarchy");\r
+            }\r
+            child.getData().add(distribution);\r
+            return; // done!\r
         }\r
-        //continue merging with the next highest area of the list.\r
+\r
+        // Recursively proceed into the namedAreaPath to merge the next node\r
         List<NamedArea> newList = namedAreaPath.subList(1, namedAreaPath.size());\r
-        mergeAux(distributionElement, newList, child);\r
+        addDistributionToSubTree(distribution, newList, child);\r
     }\r
 \r
+\r
     /**\r
      * @param area\r
      * @param omitLevels\r
@@ -207,12 +160,24 @@ public class DistributionTree extends Tree<Distribution>{
         if (omitLevels == null || !omitLevels.contains(area.getLevel())){\r
             result.add(area);\r
         }\r
+        // logging special case in order to help solving ticket #3891 (ordered distributions provided by portal/description/${uuid}/DistributionTree randomly broken)\r
+\r
+        if(area.getPartOf() == null) {\r
+            StringBuilder hibernateInfo = new StringBuilder();\r
+            hibernateInfo.append(", area is of type: ").append(area.getClass());\r
+            if(area instanceof HibernateProxy){\r
+                hibernateInfo.append(" target object is ").append(HibernateProxyHelper.getClassWithoutInitializingProxy(area));\r
+            }\r
+            logger.warn("area.partOf is NULL for " + area.getLabel() + hibernateInfo.toString());\r
+        }\r
         while (area.getPartOf() != null) {\r
             area = area.getPartOf();\r
             if (omitLevels == null || !omitLevels.contains(area.getLevel())){\r
                 result.add(0, area);\r
             }\r
         }\r
+\r
+\r
         return result;\r
     }\r
 }\r