Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/aendvari/common/osm/OsmNode.java


1   /*
2    * OsmNode.java
3    *
4    * Copyright (c) 2001, 2002 Aendvari, Ltd. All Rights Reserved.
5    *
6    * See the file LICENSE for terms of use.
7    *
8    */
9   
10  package com.aendvari.common.osm;
11  
12  import java.util.ArrayList;
13  import java.util.HashMap;
14  import java.util.Iterator;
15  import java.util.LinkedList;
16  import java.util.List;
17  import java.util.Map;
18  
19  import com.aendvari.common.osm.OsmException;
20  
21  /**
22   * <p>Represents a single node in the Object Space Model tree.
23   * An <code>OsmNode</code> has a parent and zero or more child nodes. A single <code>Object</code>
24   * value may be stored within an <code>OsmNode</code>.</p>
25   *
26   * @author  Trevor Milne
27   *
28   */
29  
30  public class OsmNode
31  {
32    /** The node name. */
33    protected String name;
34  
35    /** The node value. */
36    protected Object value;
37  
38    /** The parent node. */
39    protected OsmNode parent;
40  
41    /** Children nodes. */
42    protected ArrayList children;
43  
44    /** The child position in the parent. */
45    protected int position;
46  
47    /** The attributes of this node. */
48    protected HashMap attributes;
49  
50  
51    /* Constructors. */
52  
53  
54    /**
55     * Constructs an <code>OsmNode</code> instance.
56     *
57     */
58  
59    protected OsmNode()
60    {
61      name = null;
62      value = null;
63      parent = null;
64      children = new ArrayList();
65      position = -1;
66      attributes = new HashMap();
67    }
68  
69    /**
70     * Constructs an <code>OsmNode</code> instance as a copy of the supplied node.
71     * Only the value name, value, and attributes are copied.
72     *
73     * @param    setNode            The node to copy.
74     *
75     */
76  
77    protected OsmNode(OsmNode setNode)
78    {
79      this();
80  
81      name = setNode.name;
82      value = setNode.value;
83      attributes = new HashMap(setNode.attributes);
84    }
85  
86    /**
87     * Constructs an <code>OsmNode</code> instance using the supplied value.
88     *
89     * @param    setName            The name of the new node.
90     * @param    setValue          The value of the new node.
91     *
92     */
93  
94    protected OsmNode(String setName, Object setValue)
95    {
96      this();
97  
98      name = setName;
99      value = setValue;
100   }
101 
102 
103   /* Object value. */
104 
105 
106   /**
107    * Returns the value of this node.
108    *
109    * @return                  The <code>Object</code> held within this node.
110    *
111    */
112 
113   public Object getNodeValue()
114   {
115     return value;
116   }
117 
118   /**
119    * Returns the value of this node. If an object is not already assigned, then
120    * an instance of the specified class is created and stored.
121    *
122    * @param    type            <code>Class</code> of an object to created if one is not found.
123    *
124    * @return                  The <code>Object</code> held at the path.
125    *
126    * @exception  OsmException        The operation failed.
127    *
128    */
129 
130   public Object getNodeValue(Class type) throws OsmException
131   {
132     // create the object if one does not exist
133     if (value == null)
134     {
135       try
136       {
137         value = type.newInstance();
138       }
139       catch (java.lang.InstantiationException exception)
140       {
141         throw new OsmException(OsmException.Code.ValueNotCreated, exception);
142       }
143       catch (java.lang.IllegalAccessException exception)
144       {
145         throw new OsmException(OsmException.Code.ValueNotCreated, exception);
146       }
147     }
148 
149     return value;
150   }
151 
152   /**
153    * Sets the value of this node.
154    *
155    * @param    object            The <code>Object</code> to place in this node.
156    *
157    */
158 
159   public void setNodeValue(Object object)
160   {
161     value = object;
162   }
163 
164 
165   /* Attributes */
166 
167 
168   /**
169    * Returns the value of the specified attribute.
170    *
171    * @return                  The <code>Object</code> of the attibute.
172    *
173    */
174 
175   public Object getAttribute(String name)
176   {
177     return attributes.get(name);
178   }
179 
180   /**
181    * Returns the value of the specified attribute. If an object is not already set,
182    * then an instance of the specified class is created and stored.
183    *
184    * @param    type            <code>Class</code> of an object to created if one is not found.
185    *
186    * @return                  The <code>Object</code> held in the attribute specified.
187    *
188    * @exception  OsmException        The operation failed.
189    *
190    */
191 
192   public Object getAttribute(Class type) throws OsmException
193   {
194     // create the object if one does not exist
195     if (value == null)
196     {
197       try
198       {
199         value = type.newInstance();
200       }
201       catch (java.lang.InstantiationException exception)
202       {
203         throw new OsmException(OsmException.Code.ValueNotCreated, exception);
204       }
205       catch (java.lang.IllegalAccessException exception)
206       {
207         throw new OsmException(OsmException.Code.ValueNotCreated, exception);
208       }
209     }
210 
211     return value;
212   }
213 
214   /**
215    * Returns the attributes of this node. Modifications to this <code>Map</code>
216    * do not affect the node's attributes.
217    *
218    * @return                  A <code>Map</code> of all attibutes.
219    *
220    */
221 
222   public Map getAttributes()
223   {
224     return new HashMap(attributes);
225   }
226 
227   /**
228    * Sets the value of the specified attribute.
229    *
230    * @param    name            The name of the attibute.
231    * @param    value            The <code>Object</code> to set as the attribute value.
232    *
233    */
234 
235   public void setAttribute(String name, Object value)
236   {
237     attributes.put(name, value);
238   }
239 
240   /**
241    * Returns whether this node has any attributes.
242    *
243    * @return                  True if this node has attributes.
244    *
245    */
246 
247   public boolean hasAttributes()
248   {
249     return (attributes.size() > 0);
250   }
251 
252 
253   /* Accessors. */
254 
255 
256   /**
257    * Returns the name of this node.
258    *
259    * @return                  The name of this node.
260    *
261    */
262 
263   public String getNodeName()
264   {
265     return name;
266   }
267 
268   /**
269    * Returns a string representation of the node's position in the hierarchy.
270    *
271    * @return                  The position of this node in the hierarchy.
272    *
273    */
274 
275   public String getNodePath()
276   {
277     LinkedList nodes = new LinkedList();
278 
279     // traverse node tree upwards, and collect the nodes
280     OsmNode node = this;
281 
282     do
283     {
284       nodes.addFirst(node);
285       node = node.getParentNode();
286     }
287     while (node != null);
288 
289     // traverse back down tree, and create topic path
290     Iterator nodeIterator = nodes.iterator();
291     StringBuffer path = new StringBuffer();
292 
293     // skip the root node
294     nodeIterator.next();
295 
296     while (nodeIterator.hasNext())
297     {
298       // get the node at this level
299       node = (OsmNode)nodeIterator.next();
300 
301       path.append('/');
302       path.append(node.getNodeName());
303     }
304 
305     return path.toString();
306   }
307 
308   /**
309    * Returns the OSM to which this node belongs. This is the OSM object used to
310    * create new nodes.
311    *
312    * @return                  The {@link Osm} of which this node belongs.
313    *
314    */
315 
316   public Osm getOwnerOsm()
317   {
318     // traverse node tree upwards, and collect the nodes
319     OsmNode node = this;
320     OsmNode rootNode = this;
321 
322     while (node != null)
323     {
324       node = node.getParentNode();
325 
326       if (node != null)
327       {
328         rootNode = node;
329       }
330     }
331 
332     // the root OsmNode is an instance of Osm
333 
334     return (Osm)rootNode;
335   }
336 
337 
338   /* Node access. */
339 
340 
341   /**
342    * Returns a duplicate of this node. The duplicate node has no parent.
343    * If a shallow copy is performed, only the value name, value, and attributes are copied.
344    * If a deep copy is performed, a shallow copy of the node is made, then deep copies of
345    * each child of the node is made.
346    * Any objects stored as values or attributes are not copied, even if a deep copy is
347    * being performed.
348    *
349    * @param    deep            True to perform a deep copy, false to perform a shallow copy.
350    *
351    * @return                  The copied {@link OsmNode}.
352    *
353    */
354 
355   public OsmNode cloneNode(boolean deep)
356   {
357     // make a shallow copy of this node
358     OsmNode copy = new OsmNode(this);
359 
360     // perform a deep copy if requested
361     if (deep)
362     {
363       Iterator childIterator = children.iterator();
364 
365       while (childIterator.hasNext())
366       {
367         // get child
368         OsmNode child = (OsmNode)childIterator.next();
369 
370         // make deep copy of child
371         OsmNode childCopy = child.cloneNode(true);
372 
373         // add copy as child of clone
374         copy.appendChild(childCopy);
375       }
376     }
377 
378     return copy;
379   }
380 
381   /**
382    * The parent of this node. All nodes, exception the root ({@link Osm})
383    * node may have a parent. If a node has just been created and not yet added to the tree, or if
384    * it has been removed from the tree, this is null.
385    *
386    * @return                  The parent of this node.
387    *
388    */
389 
390   public OsmNode getParentNode()
391   {
392     return parent;
393   }
394 
395   /**
396    * Returns whether this node has any children.
397    *
398    * @return                  True if this node has children.
399    *
400    */
401 
402   public boolean hasChildNodes()
403   {
404     return (children.size() > 0);
405   }
406 
407   /**
408    * The first child of this node. If there is no such node, this returns null.
409    *
410    * @return                  The first child node.
411    *
412    */
413 
414   public OsmNode getFirstChild()
415   {
416     // make sure there are children
417     if (hasChildNodes())
418     {
419       return (OsmNode)children.get(0);
420     }
421 
422     return null;
423   }
424 
425   /**
426    * The last child of this node. If there is no such node, this returns null.
427    *
428    * @return                  The last child node.
429    *
430    */
431 
432   public OsmNode getLastChild()
433   {
434     // make sure there are children
435     if (hasChildNodes())
436     {
437       return (OsmNode)children.get(children.size() - 1);
438     }
439 
440     return null;
441   }
442 
443   /**
444    * The node immediately preceding this node. If there is no such node,
445    * this returns null.
446    *
447    * @return                  The preceding sibling node.
448    *                      <code>null</code> if nothing found.
449    *
450    */
451 
452   public OsmNode getPreviousSibling()
453   {
454     // check if first node
455     if (position == 0) return null;
456 
457     // return previous node in list
458     return (OsmNode)parent.children.get(position - 1);
459   }
460 
461   /**
462    * The node immediately following this node. If there is no such node,
463    * this returns null.
464    *
465    * @return                  The following sibling node.
466    *
467    */
468 
469   public OsmNode getNextSibling()
470   {
471     // get next index
472     int next = (position + 1);
473 
474     // check if last node
475     if (next == parent.children.size()) return null;
476 
477     // return next node in list
478     return (OsmNode)parent.children.get(next);
479   }
480 
481   /**
482    * Returns a <code>List</code> containing all the children of this node.
483    * Modifying this collection does not affect this node's children.
484    *
485    * @return                  A <code>List</code> of {@link OsmNode OsmNodes}.
486    *
487    */
488 
489   public List getChildNodes()
490   {
491     return new ArrayList(children);
492   }
493 
494   /**
495    * Removes all children of this node.
496    *
497    */
498 
499   public void removeChildNodes()
500   {
501     children.clear();
502   }
503 
504   /**
505    * Returns a <code>List</code> containing all the children of this node.
506    * This recursively collects all the children of each child node.
507    *
508    * @return                  A <code>List</code> of {@link OsmNode OsmNodes}.
509    *
510    */
511 
512   public List getAllChildNodes()
513   {
514     ArrayList nodes = new ArrayList();
515 
516     getAllChildNodes(children, nodes);
517 
518     return nodes;
519   }
520 
521   /**
522    * Helper method for #getAllChildNodes().
523    * This recursively collects all the children of each child node.
524    *
525    * @param    children          A <code>List</code> of children to examine.
526    * @param    collectedNodes        The collected children.
527    *
528    */
529 
530   protected void getAllChildNodes(List children, List collectedNodes)
531   {
532     // collect child nodes
533     Iterator childIterator = children.iterator();
534 
535     while (childIterator.hasNext())
536     {
537       OsmNode childNode = (OsmNode)childIterator.next();
538 
539       // add this child to the results
540       collectedNodes.add(childNode);
541 
542       // recursively examine this child
543       if (childNode.children.size() > 0)
544       {
545         getAllChildNodes(childNode.children, collectedNodes);
546       }
547     }
548   }
549 
550 
551   /* Node manipulation. */
552 
553 
554   /**
555    * Adds the node <code>newChild</code> to the end of the list of children of this node.
556    * If <code>newChild</code> is already in the tree, it is first removed.
557    *
558    * @param    newChild          The node to add.
559    *
560    * @return                  The node added.
561    *
562    */
563 
564   public OsmNode appendChild(OsmNode newChild)
565   {
566     // remove child node from current position (if there)
567     children.remove(newChild);
568 
569     // set parent
570     newChild.parent = this;
571 
572     // index of child is current collection size
573     newChild.position = children.size();
574 
575     // add child node
576     children.add(newChild);
577 
578     return newChild;
579   }
580 
581   /**
582    * Inserts the node <code>newChild</code> before the existing child node <code>refChild</code>.
583    * If <code>refChild</code> is null, <code>newChild</code> is inserted at the end of the list
584    * of children. If the <code>newChild</code> is already in the tree, it is first removed.
585    *
586    * @param    newChild          The node to insert.
587    * @param    refChild          The reference node.
588    *
589    * @return                  The node inserted.
590    *
591    */
592 
593   public OsmNode insertBefore(OsmNode newChild, OsmNode refChild)
594   {
595     // remove child node from current position (if there)
596     children.remove(newChild);
597 
598     // get position of reference node
599     int refPosition = refChild.position;
600 
601     // set parent
602     newChild.parent = this;
603 
604     // set position to that of refChild
605     newChild.position = refPosition;
606 
607     // insert new node into that position
608     children.add(refPosition, newChild);
609 
610     // resequence following siblings
611     int index;
612 
613     for (index = (refPosition + 1); index < children.size(); index++)
614     {
615       OsmNode node = (OsmNode)children.get(index);
616       node.position = index;
617     }
618 
619     return newChild;
620   }
621 
622   /**
623    * Replaces the child node <code>oldChild</code> with <code>newChild</code>, and returns
624    * the <code>oldChild</code> node. If the <code>newChild</code> is already in the tree,
625    * it is first removed.
626    *
627    * @param    newChild          The node to replace.
628    * @param    oldChild          The node being replaced.
629    *
630    * @return                  The node replaced.
631    *
632    */
633 
634   public OsmNode replaceChild(OsmNode newChild, OsmNode oldChild)
635   {
636     // remove new child node from current position (if there)
637     children.remove(newChild);
638 
639     // set parent
640     newChild.parent = this;
641 
642     // set the position to that of oldChild
643     newChild.position = oldChild.position;
644 
645     // erase parent
646     oldChild.parent = null;
647 
648     // replace the node at the position of oldChild
649     children.set(oldChild.position, newChild);
650 
651     return newChild;
652   }
653 
654   /**
655    * Removes the child node indicated by <code>oldChild</code> from the list of children,
656    * and returns it.
657    *
658    * @param    oldChild          The node to remove.
659    *
660    * @return                  The removed node.
661    *
662    */
663 
664   public OsmNode removeChild(OsmNode oldChild)
665   {
666     // erase parent
667     oldChild.parent = null;
668 
669     // remove the node at the position of oldChild
670     children.remove(oldChild.position);
671 
672     // resequence following siblings
673     int index;
674 
675     for (index = oldChild.position; index < children.size(); index++)
676     {
677       OsmNode node = (OsmNode)children.get(index);
678       node.position = index;
679     }
680 
681     return oldChild;
682   }
683 
684   /**
685    * Returns a string representation of the node.
686    *
687    */
688 
689   public String toString()
690   {
691     if (parent == null)
692       return (super.toString() + "; name=" + name + "; value=" + value + "; parent=null; children=" + children.size());
693     else
694       return (super.toString() + "; name=" + name + "; value=" + value + "; parent=" + parent.name + "; children=" + children.size());
695   }
696 }
697