2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
10 package eu
.etaxonomy
.cdm
.api
.service
;
12 import java
.util
.ArrayList
;
13 import java
.util
.Collection
;
14 import java
.util
.Collections
;
15 import java
.util
.HashSet
;
16 import java
.util
.List
;
19 import org
.apache
.log4j
.Logger
;
20 import org
.hibernate
.proxy
.HibernateProxy
;
21 import org
.hibernate
.proxy
.HibernateProxyHelper
;
23 import eu
.etaxonomy
.cdm
.common
.Tree
;
24 import eu
.etaxonomy
.cdm
.common
.TreeNode
;
25 import eu
.etaxonomy
.cdm
.model
.description
.Distribution
;
26 import eu
.etaxonomy
.cdm
.model
.location
.NamedArea
;
27 import eu
.etaxonomy
.cdm
.model
.location
.NamedAreaLevel
;
32 * There is a somehow similar implementation in {@link eu.etaxonomy.cdm.model.location.NamedArea}
34 public class DistributionTree
extends Tree
<Set
<Distribution
>, NamedArea
>{
36 public static final Logger logger
= Logger
.getLogger(DistributionTree
.class);
38 public DistributionTree(){
39 TreeNode
<Set
<Distribution
>, NamedArea
> rootElement
= new TreeNode
<Set
<Distribution
>, NamedArea
>();
40 List
<TreeNode
<Set
<Distribution
>, NamedArea
>> children
= new ArrayList
<TreeNode
<Set
<Distribution
>, NamedArea
>>();
41 rootElement
.setChildren(children
);
42 setRootElement(rootElement
);
48 * @return false if the node was not found
50 public boolean hasChildNode(TreeNode
<Set
<Distribution
>, NamedArea
> parentNode
, NamedArea nodeID
) {
51 return findChildNode(parentNode
, nodeID
) != null;
57 * @return the found node or null
59 public TreeNode
<Set
<Distribution
>, NamedArea
> findChildNode(TreeNode
<Set
<Distribution
>, NamedArea
> parentNode
, NamedArea nodeID
) {
60 if (parentNode
.getChildren() == null) {
64 for (TreeNode
<Set
<Distribution
>, NamedArea
> node
: parentNode
.getChildren()) {
65 if (node
.getNodeId().equals(nodeID
)) {
76 public void orderAsTree(Collection
<Distribution
> distList
, Set
<NamedAreaLevel
> omitLevels
){
78 for (Distribution distribution
: distList
) {
79 // get path through area hierarchy
80 List
<NamedArea
> namedAreaPath
= getAreaLevelPath(distribution
.getArea(), omitLevels
);
81 addDistributionToSubTree(distribution
, namedAreaPath
, this.getRootElement());
85 public void recursiveSortChildrenByLabel(){
86 _recursiveSortChildrenByLabel(this.getRootElement());
89 private void _recursiveSortChildrenByLabel(TreeNode
<Set
<Distribution
>, NamedArea
> treeNode
){
90 DistributionNodeByAreaLabelComparator comp
= new DistributionNodeByAreaLabelComparator();
91 if (treeNode
.children
== null) {
92 //nothing => stop condition
95 Collections
.sort(treeNode
.children
, comp
);
96 for (TreeNode
<Set
<Distribution
>, NamedArea
> child
: treeNode
.children
) {
97 _recursiveSortChildrenByLabel(child
);
103 * Adds the given <code>distributionElement</code> to the sub tree defined by
104 * the <code>root</code>.
106 * @param distribution
107 * the {@link Distribution} to add to the tree at the position
108 * according to the NamedArea hierarchy.
109 * @param namedAreaPath
110 * the path to the root of the NamedArea hierarchy starting the
111 * area used in the given <code>distributionElement</code>. The
112 * hierarchy is defined by the {@link NamedArea#getPartOf()}
115 * root element of the sub tree to which the
116 * <code>distributionElement</code> is to be added
118 private void addDistributionToSubTree(Distribution distribution
, List
<NamedArea
> namedAreaPath
, TreeNode
<Set
<Distribution
>, NamedArea
> root
){
121 //if the list to merge is empty finish the execution
122 if (namedAreaPath
.isEmpty()) {
126 //getting the highest area and inserting it into the tree
127 NamedArea highestArea
= namedAreaPath
.get(0);
130 TreeNode
<Set
<Distribution
>, NamedArea
> child
= findChildNode(root
, highestArea
);
132 // the highestDistNode is not yet in the set of children, so we add it
133 child
= new TreeNode
<Set
<Distribution
>, NamedArea
>(highestArea
);
134 child
.setData(new HashSet
<Distribution
>());
135 root
.addChild(child
);
138 // add another element to the list of data
139 if(namedAreaPath
.get(0).equals(distribution
.getArea())){
140 if(namedAreaPath
.size() > 1){
141 logger
.error("there seems to be something wrong with the area hierarchy");
143 child
.getData().add(distribution
);
147 // Recursively proceed into the namedAreaPath to merge the next node
148 List
<NamedArea
> newList
= namedAreaPath
.subList(1, namedAreaPath
.size());
149 addDistributionToSubTree(distribution
, newList
, child
);
156 * @return the path through area hierarchy from the <code>area</code> given as parameter to the root
158 private List
<NamedArea
> getAreaLevelPath(NamedArea area
, Set
<NamedAreaLevel
> omitLevels
){
159 List
<NamedArea
> result
= new ArrayList
<NamedArea
>();
160 if (omitLevels
== null || !omitLevels
.contains(area
.getLevel())){
163 // logging special case in order to help solving ticket #3891 (ordered distributions provided by portal/description/${uuid}/DistributionTree randomly broken)
165 if(area
.getPartOf() == null) {
166 StringBuilder hibernateInfo
= new StringBuilder();
167 hibernateInfo
.append(", area is of type: ").append(area
.getClass());
168 if(area
instanceof HibernateProxy
){
169 hibernateInfo
.append(" target object is ").append(HibernateProxyHelper
.getClassWithoutInitializingProxy(area
));
171 logger
.warn("area.partOf is NULL for " + area
.getLabel() + hibernateInfo
.toString());
173 while (area
.getPartOf() != null) {
174 area
= area
.getPartOf();
175 if (omitLevels
== null || !omitLevels
.contains(area
.getLevel())){