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
//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
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