src/core/net/sf/basedb/util/overview/Node.java

Code
Comments
Other
Rev Date Author Line
3033 15 Dec 06 nicklas 1 /**
3033 15 Dec 06 nicklas 2   $Id$
3033 15 Dec 06 nicklas 3
3675 16 Aug 07 jari 4   Copyright (C) 2006 Nicklas Nordborg
3033 15 Dec 06 nicklas 5
3033 15 Dec 06 nicklas 6   This file is part of BASE - BioArray Software Environment.
3033 15 Dec 06 nicklas 7   Available at http://base.thep.lu.se/
3033 15 Dec 06 nicklas 8
3033 15 Dec 06 nicklas 9   BASE is free software; you can redistribute it and/or
3033 15 Dec 06 nicklas 10   modify it under the terms of the GNU General Public License
4479 05 Sep 08 jari 11   as published by the Free Software Foundation; either version 3
3033 15 Dec 06 nicklas 12   of the License, or (at your option) any later version.
3033 15 Dec 06 nicklas 13
3033 15 Dec 06 nicklas 14   BASE is distributed in the hope that it will be useful,
3033 15 Dec 06 nicklas 15   but WITHOUT ANY WARRANTY; without even the implied warranty of
3033 15 Dec 06 nicklas 16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
3033 15 Dec 06 nicklas 17   GNU General Public License for more details.
3033 15 Dec 06 nicklas 18
3033 15 Dec 06 nicklas 19   You should have received a copy of the GNU General Public License
4515 11 Sep 08 jari 20   along with BASE. If not, see <http://www.gnu.org/licenses/>.
3033 15 Dec 06 nicklas 21 */
3033 15 Dec 06 nicklas 22 package net.sf.basedb.util.overview;
3033 15 Dec 06 nicklas 23
5132 14 Oct 09 nicklas 24 import java.util.Collections;
5132 14 Oct 09 nicklas 25 import java.util.Comparator;
5748 19 Sep 11 nicklas 26 import java.util.IdentityHashMap;
3033 15 Dec 06 nicklas 27 import java.util.LinkedList;
3033 15 Dec 06 nicklas 28 import java.util.List;
5748 19 Sep 11 nicklas 29 import java.util.Map;
3033 15 Dec 06 nicklas 30
3033 15 Dec 06 nicklas 31 import net.sf.basedb.core.BasicItem;
4740 05 Feb 09 nicklas 32 import net.sf.basedb.core.DbControl;
4740 05 Feb 09 nicklas 33 import net.sf.basedb.core.Item;
4740 05 Feb 09 nicklas 34 import net.sf.basedb.core.PermissionDeniedException;
4740 05 Feb 09 nicklas 35 import net.sf.basedb.util.filter.Filter;
4740 05 Feb 09 nicklas 36 import net.sf.basedb.util.filter.IdentityFilter;
4740 05 Feb 09 nicklas 37 import net.sf.basedb.util.overview.node.ChildNodeDirection;
3033 15 Dec 06 nicklas 38
3033 15 Dec 06 nicklas 39 /**
3033 15 Dec 06 nicklas 40    A node in an overview. There are two types of nodes: folder nodes
3033 15 Dec 06 nicklas 41    and item nodes. The only difference is that an item node has a link
3033 15 Dec 06 nicklas 42    to a {@link BasicItem} (see {@link #getItem()} but a folder node does not.
3033 15 Dec 06 nicklas 43    Both node types can have child nodes.
3033 15 Dec 06 nicklas 44    <p>
3033 15 Dec 06 nicklas 45    Each node has a unique ID ({@link #getId()}) which is based on the system 
3033 15 Dec 06 nicklas 46    hashcode. Each node also has a name which should be unique among the
3033 15 Dec 06 nicklas 47    child nodes. If the name isn't unique the {@link #getChild(String)} returns the
3033 15 Dec 06 nicklas 48    first matching node.
3033 15 Dec 06 nicklas 49    <p>
3033 15 Dec 06 nicklas 50    
3033 15 Dec 06 nicklas 51
3033 15 Dec 06 nicklas 52   @author Nicklas
3033 15 Dec 06 nicklas 53   @version 2.2
3033 15 Dec 06 nicklas 54   @base.modified $Date$
3033 15 Dec 06 nicklas 55 */
3033 15 Dec 06 nicklas 56 public class Node
5132 14 Oct 09 nicklas 57   implements Comparable<Node>
3033 15 Dec 06 nicklas 58 {
4740 05 Feb 09 nicklas 59   private final String name;
4740 05 Feb 09 nicklas 60   private final String title;
6041 02 Apr 12 nicklas 61   private BasicItem item;
4740 05 Feb 09 nicklas 62   private final Node parent;
4740 05 Feb 09 nicklas 63   private final Type type;
4740 05 Feb 09 nicklas 64   private final String nodeId;
4740 05 Feb 09 nicklas 65   private final ChildNodeDirection direction;
3033 15 Dec 06 nicklas 66   private List<Node> children;
3033 15 Dec 06 nicklas 67   private int numWarnings;
3033 15 Dec 06 nicklas 68   private int numErrors;
3033 15 Dec 06 nicklas 69   private int childWarnings;
3033 15 Dec 06 nicklas 70   private int childErrors;
4740 05 Feb 09 nicklas 71   private boolean childrenLoaded;
6875 20 Apr 15 nicklas 72   private Map<NodeAttribute<?>, Object> attributes;
6043 03 Apr 12 nicklas 73   private List<Node> newChildren;
3033 15 Dec 06 nicklas 74   
3033 15 Dec 06 nicklas 75   /**
3033 15 Dec 06 nicklas 76     Create an item-type root node.
3033 15 Dec 06 nicklas 77
3033 15 Dec 06 nicklas 78     @param name The name of the node
3033 15 Dec 06 nicklas 79     @param title The display title of the node
3033 15 Dec 06 nicklas 80     @param item The item the node references
4789 24 Feb 09 nicklas 81     @see GenericOverview#getRootNode()
3033 15 Dec 06 nicklas 82   */
3033 15 Dec 06 nicklas 83   public Node(String name, String title, BasicItem item)
3033 15 Dec 06 nicklas 84   {
4740 05 Feb 09 nicklas 85     this(name, title, null, item, Type.ITEM, ChildNodeDirection.ALL);
3033 15 Dec 06 nicklas 86   }
3033 15 Dec 06 nicklas 87   
3033 15 Dec 06 nicklas 88   /**
3033 15 Dec 06 nicklas 89     Create a folder-type child node.
3033 15 Dec 06 nicklas 90     @param name The name of the child node
3033 15 Dec 06 nicklas 91     @param title The display title of the node
3033 15 Dec 06 nicklas 92     @param parent The parent node
3033 15 Dec 06 nicklas 93   */
3033 15 Dec 06 nicklas 94   public Node(String name, String title, Node parent)
3033 15 Dec 06 nicklas 95   {
4740 05 Feb 09 nicklas 96     this(name, title, parent, null, Type.FOLDER, ChildNodeDirection.NONE);
3033 15 Dec 06 nicklas 97   }
3033 15 Dec 06 nicklas 98   
3033 15 Dec 06 nicklas 99   /**
4740 05 Feb 09 nicklas 100     Create a folder-type child node.
4740 05 Feb 09 nicklas 101     @param name The name of the child node
4740 05 Feb 09 nicklas 102     @param title The display title of the node
4740 05 Feb 09 nicklas 103     @param parent The parent node
4740 05 Feb 09 nicklas 104     @param direction The direction to use when continuing to
4740 05 Feb 09 nicklas 105       load child nodes
4740 05 Feb 09 nicklas 106     @since 2.10
4740 05 Feb 09 nicklas 107   */
4740 05 Feb 09 nicklas 108   public Node(String name, String title, Node parent, ChildNodeDirection direction)
4740 05 Feb 09 nicklas 109   {
4740 05 Feb 09 nicklas 110     this(name, title, parent, null, Type.FOLDER, direction);
4740 05 Feb 09 nicklas 111   }
4740 05 Feb 09 nicklas 112   
4740 05 Feb 09 nicklas 113   /**
3033 15 Dec 06 nicklas 114     Create an item-type child node
3033 15 Dec 06 nicklas 115     @param name The name of the child node
3033 15 Dec 06 nicklas 116     @param title The display title of the node
3033 15 Dec 06 nicklas 117     @param parent The parent node
3033 15 Dec 06 nicklas 118     @param item The item this node references
3033 15 Dec 06 nicklas 119    */
3033 15 Dec 06 nicklas 120   public Node(String name, String title, Node parent, BasicItem item)
3033 15 Dec 06 nicklas 121   {
4740 05 Feb 09 nicklas 122     this(name, title, parent, item, Type.ITEM, ChildNodeDirection.NONE);
3033 15 Dec 06 nicklas 123   }
3033 15 Dec 06 nicklas 124   
4740 05 Feb 09 nicklas 125   /**
4740 05 Feb 09 nicklas 126     Create an item-type child node
4740 05 Feb 09 nicklas 127     @param name The name of the child node
4740 05 Feb 09 nicklas 128     @param title The display title of the node
4740 05 Feb 09 nicklas 129     @param parent The parent node
4740 05 Feb 09 nicklas 130     @param item The item this node references
4740 05 Feb 09 nicklas 131     @param direction The direction to use when continuing to
4740 05 Feb 09 nicklas 132       load child nodes
4740 05 Feb 09 nicklas 133     @since 2.10
4740 05 Feb 09 nicklas 134   */
4740 05 Feb 09 nicklas 135   public Node(String name, String title, Node parent, BasicItem item, ChildNodeDirection direction)
3033 15 Dec 06 nicklas 136   {
4740 05 Feb 09 nicklas 137     this(name, title, parent, item, Type.ITEM, direction);
4740 05 Feb 09 nicklas 138   }
4740 05 Feb 09 nicklas 139   
4740 05 Feb 09 nicklas 140   private Node(String name, String title, Node parent, BasicItem item, Type type, ChildNodeDirection direction)
4740 05 Feb 09 nicklas 141   {
3033 15 Dec 06 nicklas 142     this.name = name;
3033 15 Dec 06 nicklas 143     this.title = title;
3033 15 Dec 06 nicklas 144     this.parent = parent;
3033 15 Dec 06 nicklas 145     this.item = item;
3033 15 Dec 06 nicklas 146     this.type = type;
4740 05 Feb 09 nicklas 147     this.direction = direction == null ? ChildNodeDirection.NONE : direction;
4740 05 Feb 09 nicklas 148     this.childrenLoaded = this.direction == ChildNodeDirection.NONE;
4740 05 Feb 09 nicklas 149     this.nodeId = "N" + hashCode();
3033 15 Dec 06 nicklas 150     if (parent != null)
3033 15 Dec 06 nicklas 151     {
3033 15 Dec 06 nicklas 152       parent.addChild(this);
3033 15 Dec 06 nicklas 153     }
3033 15 Dec 06 nicklas 154   }
3033 15 Dec 06 nicklas 155
3033 15 Dec 06 nicklas 156   /**
4740 05 Feb 09 nicklas 157     Make a copy of a node
4740 05 Feb 09 nicklas 158     @since 2.10
4740 05 Feb 09 nicklas 159   */
4740 05 Feb 09 nicklas 160   private Node(Node copyFrom, Node parent)
4740 05 Feb 09 nicklas 161   {
4740 05 Feb 09 nicklas 162     this(copyFrom.name, copyFrom.title, parent, copyFrom.item, copyFrom.type, copyFrom.direction);
4740 05 Feb 09 nicklas 163   }
4740 05 Feb 09 nicklas 164   
4740 05 Feb 09 nicklas 165   
4740 05 Feb 09 nicklas 166   /**
3033 15 Dec 06 nicklas 167     Get a unique ID for this node. The ID is based on the hashcode and should be unique
3033 15 Dec 06 nicklas 168     for a given virtual machine.
3033 15 Dec 06 nicklas 169   */
3033 15 Dec 06 nicklas 170   public String getId()
3033 15 Dec 06 nicklas 171   {
4740 05 Feb 09 nicklas 172     return nodeId;
3033 15 Dec 06 nicklas 173   }
3033 15 Dec 06 nicklas 174   
3033 15 Dec 06 nicklas 175   /**
3033 15 Dec 06 nicklas 176     Get the node type of this node. Note that for folder-type nodes
3033 15 Dec 06 nicklas 177     the {@link #getItem()} always return null. It it returns null for 
3033 15 Dec 06 nicklas 178     an item-type node it usually means that access was denied to that
3033 15 Dec 06 nicklas 179     particular item. 
3033 15 Dec 06 nicklas 180   */
3033 15 Dec 06 nicklas 181   public Type getNodeType()
3033 15 Dec 06 nicklas 182   {
3033 15 Dec 06 nicklas 183     return type;
3033 15 Dec 06 nicklas 184   }
3033 15 Dec 06 nicklas 185   
3033 15 Dec 06 nicklas 186   /**
3033 15 Dec 06 nicklas 187     Get the name of this node. If the name is unique among the child
3033 15 Dec 06 nicklas 188     nodes for a parent the call <code>getParent().getChild(this.getName())</code>
3033 15 Dec 06 nicklas 189     should return this node.
3033 15 Dec 06 nicklas 190   */
3033 15 Dec 06 nicklas 191   public String getName()
3033 15 Dec 06 nicklas 192   {
3033 15 Dec 06 nicklas 193     return name;
3033 15 Dec 06 nicklas 194   }
3033 15 Dec 06 nicklas 195   
3033 15 Dec 06 nicklas 196   /**
3033 15 Dec 06 nicklas 197     Get the display title of this node.
3033 15 Dec 06 nicklas 198   */
3033 15 Dec 06 nicklas 199   public String getTitle()
3033 15 Dec 06 nicklas 200   {
3033 15 Dec 06 nicklas 201     return title;
3033 15 Dec 06 nicklas 202   }
3033 15 Dec 06 nicklas 203   
3033 15 Dec 06 nicklas 204   /**
3033 15 Dec 06 nicklas 205     Get the item that is related to this node. Folder-type nodes always
3033 15 Dec 06 nicklas 206     return null. If an item-type node returns null it usually means that
3033 15 Dec 06 nicklas 207     access was denied to the item.
3033 15 Dec 06 nicklas 208   */
3033 15 Dec 06 nicklas 209   public BasicItem getItem()
3033 15 Dec 06 nicklas 210   {
3033 15 Dec 06 nicklas 211     return item;
3033 15 Dec 06 nicklas 212   }
3033 15 Dec 06 nicklas 213   
3033 15 Dec 06 nicklas 214   /**
4740 05 Feb 09 nicklas 215     Get the item that is related to this node and make sure that it is
4740 05 Feb 09 nicklas 216     loaded with the current DbControl. Folder-type nodes always
4740 05 Feb 09 nicklas 217     return null. If an item-type node returns null it usually means that
4740 05 Feb 09 nicklas 218     access was denied to the item.
4740 05 Feb 09 nicklas 219     @since 2.10
4740 05 Feb 09 nicklas 220   */
4740 05 Feb 09 nicklas 221   public BasicItem getItem(DbControl dc)
4740 05 Feb 09 nicklas 222   {
6041 02 Apr 12 nicklas 223     if (item != null)
6041 02 Apr 12 nicklas 224     {
6041 02 Apr 12 nicklas 225       item = item.getType().getById(dc, item.getId());
6041 02 Apr 12 nicklas 226     }
6041 02 Apr 12 nicklas 227     return item;
4740 05 Feb 09 nicklas 228   }
4740 05 Feb 09 nicklas 229   
4740 05 Feb 09 nicklas 230   /**
4740 05 Feb 09 nicklas 231     Get the item type of the item that this node related to this node.
4740 05 Feb 09 nicklas 232     This method is a shortcut for <code>getItem().getType()</code>.
4740 05 Feb 09 nicklas 233     @return The item type, or null if no item is attached to this
4740 05 Feb 09 nicklas 234       node
4740 05 Feb 09 nicklas 235     @since 2.10
4740 05 Feb 09 nicklas 236   */
4740 05 Feb 09 nicklas 237   public Item getItemType()
4740 05 Feb 09 nicklas 238   {
4740 05 Feb 09 nicklas 239     return item == null ? null : item.getType();
4740 05 Feb 09 nicklas 240   }
4740 05 Feb 09 nicklas 241   
4740 05 Feb 09 nicklas 242   /**
3033 15 Dec 06 nicklas 243     Get the parent of this node. Returns null if this is the root node.
3033 15 Dec 06 nicklas 244   */
3033 15 Dec 06 nicklas 245   public Node getParent()
3033 15 Dec 06 nicklas 246   {
3033 15 Dec 06 nicklas 247     return parent;
3033 15 Dec 06 nicklas 248   }
3033 15 Dec 06 nicklas 249   
3033 15 Dec 06 nicklas 250   /**
4740 05 Feb 09 nicklas 251     Find the first parent node that matches a filter. Eg.
4740 05 Feb 09 nicklas 252     The first parent were {@link Filter#evaluate(Object)}
4740 05 Feb 09 nicklas 253     returns true is the node that is returned.
4740 05 Feb 09 nicklas 254     
4740 05 Feb 09 nicklas 255     @param filter The filter to use for matching parent
4740 05 Feb 09 nicklas 256     @return The node, or null if no node was found
4740 05 Feb 09 nicklas 257     @since 2.10
4740 05 Feb 09 nicklas 258   */
4740 05 Feb 09 nicklas 259   public Node getFirstParent(Filter<? super Node> filter)
4740 05 Feb 09 nicklas 260   {
4740 05 Feb 09 nicklas 261     Node parent = getParent();
4740 05 Feb 09 nicklas 262     while (parent != null)
4740 05 Feb 09 nicklas 263     {
4740 05 Feb 09 nicklas 264       if (filter.evaluate(parent)) return parent;
4740 05 Feb 09 nicklas 265       parent = parent.getParent();
4740 05 Feb 09 nicklas 266     }
4740 05 Feb 09 nicklas 267     return null;
4740 05 Feb 09 nicklas 268   }
4740 05 Feb 09 nicklas 269   
4740 05 Feb 09 nicklas 270   /**
5748 19 Sep 11 nicklas 271     Find the first node (including this) that matches
5748 19 Sep 11 nicklas 272     a filter. Eg. the first node were {@link Filter#evaluate(Object)}
5748 19 Sep 11 nicklas 273     returns true is the node that is returned. Calling
5748 19 Sep 11 nicklas 274     this method is equivalent to first evaluating the
5748 19 Sep 11 nicklas 275     filter on this node, and then calling
5748 19 Sep 11 nicklas 276     {@link #getFirstParent(Filter)} if it didn't match.
5748 19 Sep 11 nicklas 277     
5748 19 Sep 11 nicklas 278     @param filter The filter to use for matching nodes
5748 19 Sep 11 nicklas 279     @return The node, or null if no node was found
5748 19 Sep 11 nicklas 280     @since 3.0
5748 19 Sep 11 nicklas 281   */
5748 19 Sep 11 nicklas 282   public Node getFirstNode(Filter<? super Node> filter)
5748 19 Sep 11 nicklas 283   {
5748 19 Sep 11 nicklas 284     return filter.evaluate(this) ? this : getFirstParent(filter);
5748 19 Sep 11 nicklas 285   }
5748 19 Sep 11 nicklas 286   
5748 19 Sep 11 nicklas 287   /**
6090 22 Aug 12 nicklas 288     Find all nodes in the parent chain that matches the given
6090 22 Aug 12 nicklas 289     filter.
6090 22 Aug 12 nicklas 290     @param filter The filter to use for matching nodes
6090 22 Aug 12 nicklas 291     @return A list with the matched nodes in the order they matched
6090 22 Aug 12 nicklas 292     @since 3.2
6090 22 Aug 12 nicklas 293   */
6090 22 Aug 12 nicklas 294   public List<Node> findAll(Filter<? super Node> filter)
6090 22 Aug 12 nicklas 295   {
6090 22 Aug 12 nicklas 296     List<Node> result = new LinkedList<Node>();
6090 22 Aug 12 nicklas 297     Node current = this;
6090 22 Aug 12 nicklas 298     while (current != null)
6090 22 Aug 12 nicklas 299     {
6090 22 Aug 12 nicklas 300       if (filter.evaluate(current)) result.add(current);
6090 22 Aug 12 nicklas 301       current = current.getParent();
6090 22 Aug 12 nicklas 302     }
6090 22 Aug 12 nicklas 303     return result;
6090 22 Aug 12 nicklas 304   }
6090 22 Aug 12 nicklas 305   
6090 22 Aug 12 nicklas 306   /**
3033 15 Dec 06 nicklas 307     Get all child nodes of this node. May return null or an empty
3033 15 Dec 06 nicklas 308     list if this node has no children.
3033 15 Dec 06 nicklas 309   */
3033 15 Dec 06 nicklas 310   public List<Node> getChildren()
3033 15 Dec 06 nicklas 311   {
3033 15 Dec 06 nicklas 312     return children;
3033 15 Dec 06 nicklas 313   }
3033 15 Dec 06 nicklas 314   
3033 15 Dec 06 nicklas 315   /**
4740 05 Feb 09 nicklas 316     Get the number of child nodes in this node.
4740 05 Feb 09 nicklas 317     @return The number of child nodes, or -1 if the child nodes
4740 05 Feb 09 nicklas 318       has not been loaded yet
4740 05 Feb 09 nicklas 319     @since 2.10
4740 05 Feb 09 nicklas 320   */
4740 05 Feb 09 nicklas 321   public int numChildren()
4740 05 Feb 09 nicklas 322   {
4740 05 Feb 09 nicklas 323     if (!childrenLoaded) return -1;
4740 05 Feb 09 nicklas 324     return children == null ? 0 : children.size();
4740 05 Feb 09 nicklas 325   }
4740 05 Feb 09 nicklas 326   
4740 05 Feb 09 nicklas 327   /**
3033 15 Dec 06 nicklas 328     Get the child node with a specific name. If more than one
3033 15 Dec 06 nicklas 329     node has the same name only the first one found is returned.
3033 15 Dec 06 nicklas 330     @param name The name of the child node.
4740 05 Feb 09 nicklas 331     @return The child node with the given name, or null if no node is found
3033 15 Dec 06 nicklas 332   */
3033 15 Dec 06 nicklas 333   public Node getChild(String name)
3033 15 Dec 06 nicklas 334   {
3033 15 Dec 06 nicklas 335     if (children != null)
3033 15 Dec 06 nicklas 336     {
3033 15 Dec 06 nicklas 337       for (Node child : children)
3033 15 Dec 06 nicklas 338       {
3033 15 Dec 06 nicklas 339         if (name.equals(child.getName()))
3033 15 Dec 06 nicklas 340         {
3033 15 Dec 06 nicklas 341           return child;
3033 15 Dec 06 nicklas 342         }
3033 15 Dec 06 nicklas 343       }
3033 15 Dec 06 nicklas 344     }
3033 15 Dec 06 nicklas 345     return null;
3033 15 Dec 06 nicklas 346   }
3033 15 Dec 06 nicklas 347   
3033 15 Dec 06 nicklas 348   /**
6043 03 Apr 12 nicklas 349     Get the number of new children added to this node
6043 03 Apr 12 nicklas 350     since the last call to {@link #getNewChildren()}.
6043 03 Apr 12 nicklas 351     @return The number of child nodes, or -1 if the child nodes
6043 03 Apr 12 nicklas 352       has not been loaded yet
6043 03 Apr 12 nicklas 353     @since 3.2
6043 03 Apr 12 nicklas 354   */
6043 03 Apr 12 nicklas 355   public int numNewChildren()
6043 03 Apr 12 nicklas 356   {
6043 03 Apr 12 nicklas 357     if (!childrenLoaded) return -1;
6043 03 Apr 12 nicklas 358     return newChildren == null ? 0 : newChildren.size();
6043 03 Apr 12 nicklas 359   }
6043 03 Apr 12 nicklas 360   
6043 03 Apr 12 nicklas 361   /**
6043 03 Apr 12 nicklas 362     Get all new children to this node. May return null or an empty
6043 03 Apr 12 nicklas 363     list if this node has no children. Calling this method clears
6043 03 Apr 12 nicklas 364     the new children information and the next call will return null
6043 03 Apr 12 nicklas 365     unless more children is added inbetween.
6043 03 Apr 12 nicklas 366     @since 3.2
6043 03 Apr 12 nicklas 367   */
6043 03 Apr 12 nicklas 368   public List<Node> getNewChildren()
6043 03 Apr 12 nicklas 369   {
6043 03 Apr 12 nicklas 370     List<Node> result = newChildren;
6043 03 Apr 12 nicklas 371     newChildren = null;
6043 03 Apr 12 nicklas 372     return result;
6043 03 Apr 12 nicklas 373   }
6043 03 Apr 12 nicklas 374   
6043 03 Apr 12 nicklas 375   /**
3033 15 Dec 06 nicklas 376     Add a child node to this one.
3033 15 Dec 06 nicklas 377   */
3033 15 Dec 06 nicklas 378   protected void addChild(Node child)
3033 15 Dec 06 nicklas 379   {
3033 15 Dec 06 nicklas 380     if (children == null) children = new LinkedList<Node>();
6043 03 Apr 12 nicklas 381     if (newChildren == null) newChildren = new LinkedList<Node>();
3033 15 Dec 06 nicklas 382     children.add(child);
6043 03 Apr 12 nicklas 383     newChildren.add(child);
4740 05 Feb 09 nicklas 384     this.childrenLoaded = true;
3033 15 Dec 06 nicklas 385   }
3033 15 Dec 06 nicklas 386   
3033 15 Dec 06 nicklas 387   /**
5132 14 Oct 09 nicklas 388     Sorts the list of child nodes.
5132 14 Oct 09 nicklas 389     @param comparator A comparator that determines the sort order, 
5132 14 Oct 09 nicklas 390       if not specifed, they children are sorted according to their
5132 14 Oct 09 nicklas 391       title
5132 14 Oct 09 nicklas 392     @since 2.14
5132 14 Oct 09 nicklas 393    */
5132 14 Oct 09 nicklas 394   public void sortChildren(Comparator<? super Node> comparator)
5132 14 Oct 09 nicklas 395   {
5132 14 Oct 09 nicklas 396     if (children == null) return;
5132 14 Oct 09 nicklas 397     Collections.sort(children, comparator);
5132 14 Oct 09 nicklas 398   }
5132 14 Oct 09 nicklas 399   
5132 14 Oct 09 nicklas 400   /**
4740 05 Feb 09 nicklas 401     Sets a flag to indicate that all children has been loaded.
4740 05 Feb 09 nicklas 402     @since 2.10
4740 05 Feb 09 nicklas 403   */
4740 05 Feb 09 nicklas 404   public void setChildrenLoaded()
4740 05 Feb 09 nicklas 405   {
4740 05 Feb 09 nicklas 406     this.childrenLoaded = true;
4740 05 Feb 09 nicklas 407   }
4740 05 Feb 09 nicklas 408   
4740 05 Feb 09 nicklas 409   /**
4740 05 Feb 09 nicklas 410     @return TRUE if the children to this node has been loaded, FALSE otherwise
4740 05 Feb 09 nicklas 411     @since 2.10
4740 05 Feb 09 nicklas 412   */
4740 05 Feb 09 nicklas 413   public boolean isChildrenLoaded()
4740 05 Feb 09 nicklas 414   {
4740 05 Feb 09 nicklas 415     return childrenLoaded;
4740 05 Feb 09 nicklas 416   }
4740 05 Feb 09 nicklas 417
4740 05 Feb 09 nicklas 418   /**
4740 05 Feb 09 nicklas 419     Get the direction to use when loading children of this node.
4740 05 Feb 09 nicklas 420     @return A ChildNodeDirection object
4740 05 Feb 09 nicklas 421     @since 2.10
4740 05 Feb 09 nicklas 422   */
4740 05 Feb 09 nicklas 423   public ChildNodeDirection getChildNodeDirection()
4740 05 Feb 09 nicklas 424   {
4740 05 Feb 09 nicklas 425     return direction;
4740 05 Feb 09 nicklas 426   }
4740 05 Feb 09 nicklas 427   
4740 05 Feb 09 nicklas 428   /**
3033 15 Dec 06 nicklas 429     Set the number of warnings that was found while validating this
3033 15 Dec 06 nicklas 430     node. This method automatically updates the number of child
3033 15 Dec 06 nicklas 431     warnings reported by parent nodes.
3033 15 Dec 06 nicklas 432     @param numWarnings The number of warnings
3033 15 Dec 06 nicklas 433     @see #addWarnings(int)
3033 15 Dec 06 nicklas 434   */
3033 15 Dec 06 nicklas 435   public void setWarnings(int numWarnings)
3033 15 Dec 06 nicklas 436   {
3033 15 Dec 06 nicklas 437     if (parent != null) parent.addChildWarnings(numWarnings-this.numWarnings);
3033 15 Dec 06 nicklas 438     this.numWarnings = numWarnings;
3033 15 Dec 06 nicklas 439   }
3033 15 Dec 06 nicklas 440   
3033 15 Dec 06 nicklas 441   /**
3033 15 Dec 06 nicklas 442     Add more warnings to this node. This method automatically updates the 
3033 15 Dec 06 nicklas 443     number of child warnings reported by parent nodes.
3033 15 Dec 06 nicklas 444     @param numWarnings The numer of warnings to add
3033 15 Dec 06 nicklas 445     @see #setWarnings(int)
3033 15 Dec 06 nicklas 446   */
3033 15 Dec 06 nicklas 447   public void addWarnings(int numWarnings)
3033 15 Dec 06 nicklas 448   {
3033 15 Dec 06 nicklas 449     this.numWarnings += numWarnings;
3033 15 Dec 06 nicklas 450     if (parent != null) parent.addChildWarnings(numWarnings);
3033 15 Dec 06 nicklas 451   }
3033 15 Dec 06 nicklas 452   
3033 15 Dec 06 nicklas 453   /**
3033 15 Dec 06 nicklas 454     Add child warnings to this node. This method is called by child 
3033 15 Dec 06 nicklas 455     nodes when the warnings are updated on them.
3033 15 Dec 06 nicklas 456   */
3033 15 Dec 06 nicklas 457   protected void addChildWarnings(int numWarnings)
3033 15 Dec 06 nicklas 458   {
3033 15 Dec 06 nicklas 459     this.childWarnings += numWarnings;
3033 15 Dec 06 nicklas 460     if (parent != null) parent.addChildWarnings(numWarnings);
3033 15 Dec 06 nicklas 461   }
3033 15 Dec 06 nicklas 462   
3033 15 Dec 06 nicklas 463   /**
3033 15 Dec 06 nicklas 464     Set the number of errors that was found while validating this
3033 15 Dec 06 nicklas 465     node. This method automatically updates the number of child
3033 15 Dec 06 nicklas 466     errors reported by parent nodes.
3033 15 Dec 06 nicklas 467     @param numErrors The number of errors
3033 15 Dec 06 nicklas 468     @see #addErrors(int)
3033 15 Dec 06 nicklas 469   */
3033 15 Dec 06 nicklas 470   public void setErrors(int numErrors)
3033 15 Dec 06 nicklas 471   {
3033 15 Dec 06 nicklas 472     if (parent != null) parent.addChildErrors(numErrors-this.numErrors);
3033 15 Dec 06 nicklas 473     this.numErrors = numErrors;
3033 15 Dec 06 nicklas 474   }
3033 15 Dec 06 nicklas 475   
3033 15 Dec 06 nicklas 476   /**
3033 15 Dec 06 nicklas 477     Add more errors to this node. This method automatically updates the 
3033 15 Dec 06 nicklas 478     number of child errors reported by parent nodes.
3033 15 Dec 06 nicklas 479     @param numErrors The numer of errors to add
3033 15 Dec 06 nicklas 480     @see #setErrors(int)
3033 15 Dec 06 nicklas 481   */
3033 15 Dec 06 nicklas 482   public void addErrors(int numErrors)
3033 15 Dec 06 nicklas 483   {
3033 15 Dec 06 nicklas 484     this.numErrors += numErrors;
3033 15 Dec 06 nicklas 485     if (parent != null) parent.addChildErrors(numErrors);
3033 15 Dec 06 nicklas 486   }
3033 15 Dec 06 nicklas 487   
3033 15 Dec 06 nicklas 488   /**
3033 15 Dec 06 nicklas 489     Add child errors to this node. This method is called by child 
3033 15 Dec 06 nicklas 490     nodes when the errors are updated on them.
3033 15 Dec 06 nicklas 491   */
3033 15 Dec 06 nicklas 492   protected void addChildErrors(int numErrors)
3033 15 Dec 06 nicklas 493   {
3033 15 Dec 06 nicklas 494     this.childErrors += numErrors;
3033 15 Dec 06 nicklas 495     if (parent != null) parent.addChildErrors(numErrors);
3033 15 Dec 06 nicklas 496   }
3033 15 Dec 06 nicklas 497   
3033 15 Dec 06 nicklas 498   /**
3033 15 Dec 06 nicklas 499     Get the number of warnings on this node.
3033 15 Dec 06 nicklas 500     @see #getChildWarnings()
3033 15 Dec 06 nicklas 501   */
3033 15 Dec 06 nicklas 502   public int getNumWarnings()
3033 15 Dec 06 nicklas 503   {
3033 15 Dec 06 nicklas 504     return numWarnings;
3033 15 Dec 06 nicklas 505   }
3033 15 Dec 06 nicklas 506   
3033 15 Dec 06 nicklas 507   /**
3033 15 Dec 06 nicklas 508     Get the number of errors on this node.
3033 15 Dec 06 nicklas 509     @see #getChildErrors()
3033 15 Dec 06 nicklas 510   */
3033 15 Dec 06 nicklas 511   public int getNumErrors()
3033 15 Dec 06 nicklas 512   {
3033 15 Dec 06 nicklas 513     return numErrors;
3033 15 Dec 06 nicklas 514   }
3033 15 Dec 06 nicklas 515   
3033 15 Dec 06 nicklas 516   /**
3033 15 Dec 06 nicklas 517     Get the number of warnings to children of this node.
3033 15 Dec 06 nicklas 518     @see #getNumWarnings()
3033 15 Dec 06 nicklas 519   */
3033 15 Dec 06 nicklas 520   public int getChildWarnings()
3033 15 Dec 06 nicklas 521   {
3033 15 Dec 06 nicklas 522     return childWarnings;
3033 15 Dec 06 nicklas 523   }
3033 15 Dec 06 nicklas 524   
3033 15 Dec 06 nicklas 525   /**
3033 15 Dec 06 nicklas 526     Get the number of errors to children of this node.
3033 15 Dec 06 nicklas 527     @see #getNumErrors()
3033 15 Dec 06 nicklas 528   */
3033 15 Dec 06 nicklas 529   public int getChildErrors()
3033 15 Dec 06 nicklas 530   {
3033 15 Dec 06 nicklas 531     return childErrors;
3033 15 Dec 06 nicklas 532   }
3033 15 Dec 06 nicklas 533   
3033 15 Dec 06 nicklas 534   /**
3033 15 Dec 06 nicklas 535     Clear all warnings, errors on this node and on all child nodes.
3033 15 Dec 06 nicklas 536   */
3033 15 Dec 06 nicklas 537   public void clearFailures()
3033 15 Dec 06 nicklas 538   {
3033 15 Dec 06 nicklas 539     numErrors = 0;
3033 15 Dec 06 nicklas 540     numWarnings = 0;
3033 15 Dec 06 nicklas 541     childWarnings = 0;
3033 15 Dec 06 nicklas 542     childErrors = 0;
3033 15 Dec 06 nicklas 543     if (getChildren() != null)
3033 15 Dec 06 nicklas 544     {
3033 15 Dec 06 nicklas 545       for (Node child : getChildren())
3033 15 Dec 06 nicklas 546       {
3033 15 Dec 06 nicklas 547         child.clearFailures();
3033 15 Dec 06 nicklas 548       }
3033 15 Dec 06 nicklas 549     }
3033 15 Dec 06 nicklas 550   }
3033 15 Dec 06 nicklas 551
3033 15 Dec 06 nicklas 552   /**
5748 19 Sep 11 nicklas 553     Set a node attribute.
5748 19 Sep 11 nicklas 554     @param attribute The attribute to set
5748 19 Sep 11 nicklas 555     @param value The value to set for the attribute or null to remove the
5748 19 Sep 11 nicklas 556       current value
5748 19 Sep 11 nicklas 557     @since 3.0
5748 19 Sep 11 nicklas 558   */
5748 19 Sep 11 nicklas 559   public <T> void setAttribute(NodeAttribute<T> attribute, T value)
5748 19 Sep 11 nicklas 560   {
5748 19 Sep 11 nicklas 561     if (value == null)
5748 19 Sep 11 nicklas 562     {
5748 19 Sep 11 nicklas 563       if (attributes != null)  attributes.remove(attribute);
5748 19 Sep 11 nicklas 564     }
5748 19 Sep 11 nicklas 565     else
5748 19 Sep 11 nicklas 566     {
6875 20 Apr 15 nicklas 567       if (attributes == null) attributes = new IdentityHashMap<NodeAttribute<?>, Object>();
5748 19 Sep 11 nicklas 568       attributes.put(attribute, value);
5748 19 Sep 11 nicklas 569     }
5748 19 Sep 11 nicklas 570   }
5748 19 Sep 11 nicklas 571   
5748 19 Sep 11 nicklas 572   /**
5748 19 Sep 11 nicklas 573     Get the value for a node attribute.
5748 19 Sep 11 nicklas 574     @param attribute The attribute to get
5748 19 Sep 11 nicklas 575     @return The value or null if there is no value
5748 19 Sep 11 nicklas 576     @since 3.0
5748 19 Sep 11 nicklas 577   */
5748 19 Sep 11 nicklas 578   @SuppressWarnings("unchecked")
5748 19 Sep 11 nicklas 579   public <T> T getAttribute(NodeAttribute<T> attribute)
5748 19 Sep 11 nicklas 580   {
5748 19 Sep 11 nicklas 581     T value = null;
5748 19 Sep 11 nicklas 582     if (attributes != null) value = (T)attributes.get(attribute);
5748 19 Sep 11 nicklas 583     return value;
5748 19 Sep 11 nicklas 584   }
5748 19 Sep 11 nicklas 585   
5748 19 Sep 11 nicklas 586   /**
5748 19 Sep 11 nicklas 587     Check if the node has a value for the given attribute.
5748 19 Sep 11 nicklas 588     @param attribute The attribute to check
5748 19 Sep 11 nicklas 589     @return TRUE if a value exists, FALSE otherwise
5748 19 Sep 11 nicklas 590     @since 3.0
5748 19 Sep 11 nicklas 591   */
5748 19 Sep 11 nicklas 592   public boolean hasAttribute(NodeAttribute<?> attribute)
5748 19 Sep 11 nicklas 593   {
5748 19 Sep 11 nicklas 594     return attributes != null && attributes.containsKey(attribute);
5748 19 Sep 11 nicklas 595   }
5748 19 Sep 11 nicklas 596   
5748 19 Sep 11 nicklas 597   /**
4740 05 Feb 09 nicklas 598     Create a deep copy of this node and all it's children. The copy
4740 05 Feb 09 nicklas 599     will be attached to the given parent.
4740 05 Feb 09 nicklas 600     @param parentOfCopy The node that should be the parent of the
4740 05 Feb 09 nicklas 601       copy or null to make the copy a root node
4740 05 Feb 09 nicklas 602     @return The copy
4740 05 Feb 09 nicklas 603     @throws PermissionDeniedException If the given parent node is a
4740 05 Feb 09 nicklas 604       descendant of this node (it would lead to an infinite loop)
4740 05 Feb 09 nicklas 605     @since 2.10
4740 05 Feb 09 nicklas 606   */
4740 05 Feb 09 nicklas 607   public Node deepCopy(Node parentOfCopy)
4740 05 Feb 09 nicklas 608   {
4740 05 Feb 09 nicklas 609     if (parentOfCopy.getFirstParent(new IdentityFilter<Node>(this)) != null)
4740 05 Feb 09 nicklas 610     {
4740 05 Feb 09 nicklas 611       throw new PermissionDeniedException("The parent node '" + parentOfCopy.getName() + 
4740 05 Feb 09 nicklas 612         "' is a descendant of this node: " + getName());
4740 05 Feb 09 nicklas 613     }
4740 05 Feb 09 nicklas 614     return deepCopyInternal(parentOfCopy);
4740 05 Feb 09 nicklas 615   }
4740 05 Feb 09 nicklas 616   
4740 05 Feb 09 nicklas 617   private Node deepCopyInternal(Node parentOfCopy)
4740 05 Feb 09 nicklas 618   {
4740 05 Feb 09 nicklas 619     Node copy = new Node(this, parentOfCopy);
6046 17 Apr 12 nicklas 620     copy.childrenLoaded = this.childrenLoaded;
4740 05 Feb 09 nicklas 621     List<Node> children = getChildren();
4740 05 Feb 09 nicklas 622     if (children != null)
4740 05 Feb 09 nicklas 623     {
4740 05 Feb 09 nicklas 624       for (Node child : children)
4740 05 Feb 09 nicklas 625       {
4740 05 Feb 09 nicklas 626         Node childCopy = child.deepCopyInternal(copy);
4740 05 Feb 09 nicklas 627       }
4740 05 Feb 09 nicklas 628     }
4740 05 Feb 09 nicklas 629     return copy;
4740 05 Feb 09 nicklas 630   }
4740 05 Feb 09 nicklas 631   
5132 14 Oct 09 nicklas 632   @Override
5132 14 Oct 09 nicklas 633   public int compareTo(Node o)
5132 14 Oct 09 nicklas 634   {
5384 13 Aug 10 nicklas 635     int tmp = title.compareTo(o.title);
5384 13 Aug 10 nicklas 636     return tmp != 0 ? tmp : nodeId.compareTo(o.nodeId);
5132 14 Oct 09 nicklas 637   }
5132 14 Oct 09 nicklas 638
5132 14 Oct 09 nicklas 639   
6127 14 Sep 12 nicklas 640   @Override
4740 05 Feb 09 nicklas 641   public String toString()
4740 05 Feb 09 nicklas 642   {
4740 05 Feb 09 nicklas 643     return "Node[" + type + "; id=" + nodeId + "; name=" + name + "; title=" + title + "]";
4740 05 Feb 09 nicklas 644   }
4740 05 Feb 09 nicklas 645   
4740 05 Feb 09 nicklas 646   /**
3033 15 Dec 06 nicklas 647     The type of node.
3033 15 Dec 06 nicklas 648   */
3033 15 Dec 06 nicklas 649   public enum Type
3033 15 Dec 06 nicklas 650   {
3033 15 Dec 06 nicklas 651     FOLDER, ITEM;
3033 15 Dec 06 nicklas 652   }
3033 15 Dec 06 nicklas 653
3033 15 Dec 06 nicklas 654 }