KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openharmonise > rm > resources > AbstractParentObject


1 /*
2  * The contents of this file are subject to the
3  * Mozilla Public License Version 1.1 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at http://www.mozilla.org/MPL/
6  *
7  * Software distributed under the License is distributed on an "AS IS"
8  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
9  * See the License for the specific language governing rights and
10  * limitations under the License.
11  *
12  * The Initial Developer of the Original Code is Simulacra Media Ltd.
13  * Portions created by Simulacra Media Ltd are Copyright (C) Simulacra Media Ltd, 2004.
14  *
15  * All Rights Reserved.
16  *
17  * Contributor(s):
18  */

19 package org.openharmonise.rm.resources;
20
21 import java.sql.*;
22 import java.util.*;
23 import java.util.logging.*;
24
25 import org.openharmonise.commons.cache.*;
26 import org.openharmonise.commons.dsi.*;
27 import org.openharmonise.commons.dsi.dml.*;
28 import org.openharmonise.rm.*;
29 import org.openharmonise.rm.dsi.*;
30 import org.openharmonise.rm.factory.*;
31 import org.openharmonise.rm.publishing.*;
32 import org.openharmonise.rm.resources.lifecycle.*;
33 import org.openharmonise.rm.resources.publishing.*;
34 import org.openharmonise.rm.search.Search;
35 import org.w3c.dom.*;
36
37
38 /**
39  * Abstract class that provides the necessary functionality for objects
40  * which can be parents in a parent-child relationship within Harmonise.
41  * Children are indexed so that the order of children can be managed.
42  *
43  * @author Michael Bell
44  * @version $Revision: 1.6 $
45  */

46 public abstract class AbstractParentObject
47     extends AbstractChildObject
48     implements Editable, Publishable, DataStoreObject, Cloneable JavaDoc, EditEventListener {
49
50     //DB constant
51
/**
52      * Relationship table position column name
53      */

54     private static final String JavaDoc CLMN_POSITION = "pos";
55
56     //Constants used for accessing children by type
57
/**
58      * Constant for branch node type
59      */

60     public static final int BRANCH_NODES = 1;
61     
62     /**
63      * Constant for all node types
64      */

65     public static final int LEAF_NODES = 2;
66     
67     /**
68      * Constant for leaf node types
69      */

70     public static final int ALL_NODES = 3;
71
72     //XML constants
73
/**
74      * Children tag name
75      */

76     public static final String JavaDoc TAG_CHILDREN = "Children";
77     
78     /**
79      * Contents tag name
80      */

81     public static final String JavaDoc TAG_CONTENTS = "Contents";
82     
83     /**
84      * Sub-groups tag name
85      */

86     public static final String JavaDoc TAG_SUBGROUPS = "SubGroups";
87     
88     /**
89      * Attach tag name
90      */

91     public static final String JavaDoc TAG_ATTACH = "Attach";
92     
93     /**
94      * Detach tag name
95      */

96     public final String JavaDoc TAG_DETACH = "Detach";
97
98     //Member variables
99
/**
100      * List of <code>OrderableCachePointer</code> objects
101      * referencing the children of this object
102      */

103     protected List m_children = null;
104     
105     /**
106      * The maximum value of index for children of this object
107      */

108     protected int m_nMaxIndex = -1;
109     
110     /**
111      * List of <code>OrderableCachePointer</code> objects
112      * referencing the children to be added on the
113      * next <code>save()</code> operation
114      */

115     protected List m_add_children = null;
116     
117     /**
118      * List of <code>OrderableCachePointer</code> objects
119      * referencing the children to be removed on the next
120      * <code>save()</code> operation
121      */

122     protected List m_remove_children = null;
123     
124     /**
125      * List of ids of children of those to be added for which this object is the 'real' parent
126      */

127     protected List m_add_real_children = null;
128     
129     /**
130      * List of ids of children of this object for which this object is the 'real' parent
131      */

132     protected List m_real_children = null;
133     
134     /**
135      * <code>boolean</code> flag which indicates whether the list of
136      * children of this object has been populated
137      */

138     protected boolean m_bIsChildrenPopulated = false;
139     
140     /**
141      * List of archived children
142      */

143     protected List m_archivedChildren = null;
144     
145     /**
146      * List of archived descendants
147      */

148     protected List m_allArchivedChildren = null;
149
150     /**
151      * <code>boolean</code> flag which indicates whether the list of
152      * children of this object is to be changed on the next
153      * <code>save()</code> operation
154      */

155     protected boolean m_bIsContentsChanged = false;
156     
157     /**
158      * <code>boolean</code> flag which indicates whether the list of
159      * archived children has been populated
160      */

161     protected boolean m_bIsArchivedChildrenPopulated = false;
162     
163     /**
164      * <code>boolean</code> flag which indicates whether the list
165      * of all archived descendants has been populated
166      */

167     protected boolean m_bIsAllArchivedChildrenPopulated = false;
168     
169     /**
170      * Logger for this class
171      */

172     private static Logger m_logger = Logger.getLogger(AbstractParentObject.class.getName());
173
174     //initialiser block
175
{
176         m_children = new Vector();
177         m_add_children = new Vector();
178         m_remove_children = new Vector();
179         m_add_real_children = new Vector();
180         m_real_children = new Vector();
181         m_archivedChildren = new Vector();
182         m_allArchivedChildren = new Vector();
183     }
184     /**
185      * Constructs a new or anonymous instance without an interface
186      * to the database.
187      */

188     public AbstractParentObject() {
189         super();
190     }
191
192     /**
193      * Constructor for a new or anonymous instance.
194      *
195      * @param dbintrf the data store interface
196      */

197     public AbstractParentObject(AbstractDataStoreInterface dbintrf) {
198         super(dbintrf);
199     }
200
201     /**
202      * Constructs an existing resource which may be historical.
203      *
204      * @param dbintrf the interface to the database
205      * @param nId the id of the resource
206      * @param nKey the unique key of the resource
207      * @param bIsHist <code>true</code> if the resource is historical
208      */

209     public AbstractParentObject(
210         AbstractDataStoreInterface dbintrf,
211         int nId,
212         int nKey,
213         boolean bIsHist) {
214         super(dbintrf, nId, nKey, bIsHist);
215     }
216
217     /**
218      * Standard constructor for an existing resource,
219      * registering an <code>AbstractDataStoreInterface</code> to use
220      * with all database communications.
221      *
222      * @param dbintrf the interface to the database
223      * @param nId the id of the resource
224      */

225     public AbstractParentObject(AbstractDataStoreInterface dbintrf, int nId) {
226         super(dbintrf, nId);
227     }
228
229     /* (non-Javadoc)
230      * @see org.openharmonise.rm.resources.AbstractChildObject#getPath()
231      */

232     public String JavaDoc getPath() throws DataAccessException {
233         String JavaDoc sPath = null;
234
235         AbstractParentObject parent = getRealParent();
236
237         //if it has no real parent return the root slash
238
if (parent == null) {
239             sPath = separator;
240         } else {
241             sPath = super.getPath();
242         }
243
244         return sPath;
245     }
246
247     /* (non-Javadoc)
248      * @see org.openharmonise.rm.resources.AbstractObject#markAsNew()
249      */

250     public void markAsNew() throws PopulateException {
251         super.markAsNew();
252         m_bIsContentsChanged = false;
253         
254         clearChildren();
255         clearArchivedChildren();
256     }
257
258     /* (non-Javadoc)
259      * @see java.lang.Object#clone()
260      */

261     public Object JavaDoc clone() {
262         AbstractParentObject other = null;
263
264         try {
265             if (m_bIsChildrenPopulated == false) {
266                 populateChildrenFromDatabase();
267             }
268
269             other = (AbstractParentObject) super.clone();
270
271             //the Lists below are cloned in the 'set' methods
272
if (m_children != null) {
273                 other.setChildren(m_children);
274             }
275
276         } catch (InvalidChildException e) {
277             throw new IllegalStateException JavaDoc(
278                 "Problem occured adding child to clone:"
279                     + e.getLocalizedMessage());
280         } catch (PopulateException e) {
281             throw new IllegalStateException JavaDoc(
282                 "Problem occured populating:" + e.getLocalizedMessage());
283         }
284
285         return other;
286     }
287
288     /**
289      * Clears all stored lists of children.
290      *
291      */

292     public void clearChildren() {
293         m_bIsChildrenPopulated = false;
294         m_children = null;
295         m_real_children = null;
296     }
297
298     /* (non-Javadoc)
299      * @see org.openharmonise.rm.resources.AbstractObject#clear()
300      */

301     public void clear() {
302         super.clear();
303         m_bIsContentsChanged = false;
304
305         clearChildren();
306         clearArchivedChildren();
307     }
308
309     /* (non-Javadoc)
310      * @see org.openharmonise.rm.publishing.Publishable#publish(org.w3c.dom.Element, org.openharmonise.rm.publishing.HarmoniseOutput, org.openharmonise.rm.publishing.State)
311      */

312     public org.w3c.dom.Element JavaDoc publish(
313         Element topEl,
314         HarmoniseOutput xmlDoc,
315         State state)
316         throws PublishException {
317         Element docEl = null;
318         NodeList nodes = null;
319         Text txt = null;
320         String JavaDoc sTagName = topEl.getTagName();
321
322         if (sTagName.equals(TAG_CONTENTS)) {
323             docEl = xmlDoc.createElement(TAG_CONTENTS);
324             nodes = topEl.getChildNodes();
325         } else if (sTagName.equals(TAG_SUBGROUPS)) {
326             docEl = xmlDoc.createElement(TAG_SUBGROUPS);
327
328             NodeList nlChildren = topEl.getChildNodes();
329             Node nTemp = null;
330
331             for (int j = 0; j < nlChildren.getLength(); j++) {
332                 nTemp = nlChildren.item(j);
333
334                 if (nTemp.getNodeType() != Node.ELEMENT_NODE) {
335                     continue;
336                 } else if (nTemp.getNodeName().equals(Template.TAG_TEMPLATE)) {
337                     List subGroups = null;
338                     try {
339                         subGroups = this.getChildrenByType(BRANCH_NODES);
340                     } catch (DataAccessException e) {
341                         throw new PublishException(
342                             "Error occured getting branch children", e);
343                     }
344
345                     int nPageId = -1;
346
347                     NodeList pageNodes =
348                         ((Element) nTemp).getElementsByTagName(
349                             WebPage.TAG_PAGE);
350
351                     if (pageNodes.getLength() > 0) {
352                         nPageId =
353                             Integer.parseInt(
354                                 ((Element) pageNodes.item(0)).getAttribute(
355                                     AbstractObject.ATTRIB_ID));
356                     }
357
358                     if (subGroups.size() > 0) {
359                         Template grpTemplate = null;
360                         try {
361                             grpTemplate = (Template) HarmoniseObjectFactory.instantiateHarmoniseObject(m_dsi, Template.class.getName(), Integer.parseInt(
362                                     ((Element) nTemp).getAttribute(
363                                             AbstractObject.ATTRIB_ID)));
364                         } catch (NumberFormatException JavaDoc e) {
365                             throw new PublishException(e);
366                         } catch (HarmoniseFactoryException e) {
367                             throw new PublishException(e);
368                         }
369                         
370
371                         if (grpTemplate == null) {
372                             throw new PublishException("No template supplied.");
373                         }
374
375                         String JavaDoc sSubClassName = null;
376
377                         NodeList tmpNL = nTemp.getChildNodes();
378
379                         if (tmpNL.getLength() > 0) {
380                             boolean bFound = false;
381                             int k = 0;
382
383                             while ((bFound == false)
384                                 && (k < tmpNL.getLength())) {
385                                 if (tmpNL.item(k).getNodeType()
386                                     == Node.ELEMENT_NODE) {
387                                     Element tmpEl = (Element) tmpNL.item(k);
388
389                                     if (tmpEl
390                                         .getTagName()
391                                         .equals(WebPage.TAG_PAGE)
392                                         == false) {
393                                         bFound = true;
394                                         try {
395                                             sSubClassName =
396                                                 HarmoniseObjectFactory.getClassName(
397                                                     this.m_dsi,
398                                                     tmpEl);
399                                         } catch (HarmoniseFactoryException e) {
400                                             throw new PublishException(
401                                                 "Error occured getting data from factory",e);
402                                         }
403                                     }
404                                 }
405
406                                 k++;
407                             }
408                         }
409
410                         if (sSubClassName == null) {
411                             try {
412                                 sSubClassName =
413                                     HarmoniseObjectFactory.getClassName(
414                                         this.m_dsi,
415                                         grpTemplate.getTemplateRootElement());
416                             } catch (HarmoniseFactoryException e) {
417                                 throw new PublishException(
418                                     "Error occured getting data from factory",e);
419                             } catch (DataAccessException e) {
420                                 throw new PublishException(
421                                     "Error occured getting data from Template",e);
422                             }
423                         }
424
425                         try {
426                             Class JavaDoc objClass = Class.forName(sSubClassName);
427
428                             List matchedSubs = getChildrenByClass(objClass);
429
430                             Iterator iter = matchedSubs.iterator();
431
432                             while (iter.hasNext()) {
433                                 Publishable pObj = (Publishable) iter.next();
434
435                                 boolean bPublishable = true;
436
437                                 PublishFilter filter = state.getPublishFilter();
438                                 if (filter != null) {
439
440                                     bPublishable =
441                                         filter.allowPublish(this, pObj);
442                                 }
443
444                                 if (bPublishable == true) {
445
446                                     Element grpEl =
447                                         pObj.publish(
448                                             grpTemplate,
449                                             xmlDoc,
450                                             state);
451
452                                     if (nPageId > 0) {
453                                         xmlDoc.addPageIdToLinkNode(
454                                             state.getLoggedInUser(),
455                                             grpEl,
456                                             nPageId);
457                                     }
458
459                                     docEl.appendChild(grpEl);
460                                 }
461                             }
462                         } catch (DataAccessException e) {
463                             throw new PublishException(
464                                 "Error occured getting data from Template",e);
465                         } catch (DOMException e) {
466                             throw new PublishException(
467                                 "DOMException occured",e);
468                         } catch (ClassNotFoundException JavaDoc e) {
469                             throw new PublishException(
470                                 "Class not found",e);
471                         }
472                     }
473                 }
474             }
475         } else if (sTagName.equals(TAG_CHILDREN)) {
476             docEl = xmlDoc.createElement(TAG_CHILDREN);
477
478             NodeList nlChildren = topEl.getChildNodes();
479             Node nTemp = null;
480             boolean bHistorical = false;
481             String JavaDoc sHistorical = topEl.getAttribute(ATTRIB_HISTORICAL);
482
483             if (sHistorical != null) {
484                 if (sHistorical.equals("1")) {
485                     bHistorical = true;
486                 }
487             }
488
489             for (int j = 0; j < nlChildren.getLength(); j++) {
490                 nTemp = nlChildren.item(j);
491
492                 if (nTemp.getNodeType() != Node.ELEMENT_NODE) {
493                     continue;
494                 } else if (nTemp.getNodeName().equals(Template.TAG_TEMPLATE)) {
495                     List children = null;
496
497                     try {
498                         if (bHistorical) {
499                             children =
500                                 this.getArchivedChildrenByType(LEAF_NODES);
501                         } else {
502                             children = this.getChildrenByType(LEAF_NODES);
503                         }
504                     } catch (DataAccessException e) {
505                         throw new PublishException(
506                             "Error occured accessing children", e);
507                     }
508
509                     if (children.size() > 0) {
510                         Template template = null;
511                         try {
512                             template = (Template) HarmoniseObjectFactory.instantiateHarmoniseObject(m_dsi, Template.class.getName(), Integer.parseInt(
513                                     ((Element) nTemp).getAttribute(
514                                             AbstractObject.ATTRIB_ID)));
515                         } catch (NumberFormatException JavaDoc e) {
516                             throw new PublishException(e);
517                         } catch (HarmoniseFactoryException e) {
518                             throw new PublishException(e);
519                         }
520
521                         int nPageId = -1;
522
523                         NodeList pageNodes =
524                             ((Element) nTemp).getElementsByTagName(
525                                 WebPage.TAG_PAGE);
526
527                         if (pageNodes.getLength() > 0) {
528                             nPageId =
529                                 Integer.parseInt(
530                                     ((Element) pageNodes.item(0)).getAttribute(
531                                         AbstractObject.ATTRIB_ID));
532                         }
533
534                         if (template == null) {
535                             throw new PublishException("No template supplied.");
536                         }
537
538                         Iterator iter = children.iterator();
539                         while (iter.hasNext()) {
540                             Publishable pObj = (Publishable) iter.next();
541                             Element chldEl =
542                                 pObj.publish(template, xmlDoc, state);
543
544                             if (nPageId > 0) {
545                                 xmlDoc.addPageIdToLinkNode(
546                                     state.getLoggedInUser(),
547                                     chldEl,
548                                     nPageId);
549                             }
550
551                             docEl.appendChild(chldEl);
552                         }
553                     }
554                 }
555             }
556         } else if (sTagName.equals(Search.TAG_LIST)) {
557             Search searchObj;
558             try {
559                 searchObj =
560                     (Search) HarmoniseObjectFactory.instantiatePublishableObject(
561                         m_dsi,
562                         topEl,
563                         state);
564                 searchObj.addConditionGroup(this);
565
566                 docEl = searchObj.publish(topEl, xmlDoc, state);
567             } catch (HarmoniseFactoryException e) {
568                 throw new PublishException(
569                     "Error occured processing List element",e);
570             }
571
572         } else {
573             // if we don't know about the tag, pass it up
574
docEl = super.publish(topEl, xmlDoc, state);
575         }
576
577         // recurse through the children if there are any
578
Element formEl;
579         Element el;
580
581         if (nodes != null) {
582             for (int i = 0; i < nodes.getLength(); i++) {
583                 if (nodes.item(i).getNodeType() != Node.ELEMENT_NODE) {
584                     continue;
585                 }
586
587                 formEl = (Element) nodes.item(i);
588                 el = publish(formEl, xmlDoc, state);
589
590                 if (el != null) {
591                     try {
592                         docEl.appendChild(el);
593                     } catch (org.w3c.dom.DOMException JavaDoc e) {
594                         throw new PublishException(
595                             el.getTagName() + ":" + e.getMessage());
596                     }
597                 }
598             }
599         }
600
601         return docEl;
602     }
603
604     /* (non-Javadoc)
605      * @see org.openharmonise.rm.publishing.Publishable#populate(org.w3c.dom.Element, org.openharmonise.rm.publishing.State)
606      */

607     public void populate(Element xmlElement, State state)
608         throws PopulateException {
609         Element formEl = xmlElement;
610         String JavaDoc sTagName = formEl.getTagName();
611         int nId = -1;
612
613         if (sTagName.equals(TAG_CHILDREN)) {
614             String JavaDoc sIdTemp = "";
615             String JavaDoc sDefault = "";
616             boolean bDefault = false;
617
618             NodeList nlAttach = formEl.getElementsByTagName(TAG_ATTACH);
619
620             if (nlAttach.getLength() > 0) {
621                 NodeList nlAttachObjects =
622                     ((Element) nlAttach.item(0)).getChildNodes();
623
624                 for (int j = 0; j < nlAttachObjects.getLength(); j++) {
625                     if (nlAttachObjects.item(j).getNodeType()
626                         != Node.ELEMENT_NODE) {
627                         continue;
628                     }
629
630                     sIdTemp =
631                         ((Element) nlAttachObjects.item(j)).getAttribute(
632                             ATTRIB_ID);
633                     sDefault =
634                         ((Element) nlAttachObjects.item(j)).getAttribute(
635                             ATTRIB_DEFAULT);
636
637                     if (!sIdTemp.equals("XXXX")) {
638
639                         if ((sDefault != null) && sDefault.equals("1")) {
640                             bDefault = true;
641                         } else {
642                             bDefault = false;
643                         }
644
645                         try {
646                             addChild(
647                                 (
648                                     AbstractChildObject) this
649                                         .getObjectFromFactory(
650                                     (Element) nlAttachObjects.item(j)),
651                                 bDefault);
652                         } catch (InvalidChildException e) {
653                             throw new PopulateException(
654                                 "Invalid child:" + e.getLocalizedMessage());
655                         } catch (HarmoniseFactoryException e) {
656                             throw new PopulateException(
657                                 "Invalid child:" + e.getLocalizedMessage());
658                         }
659                     }
660                 }
661             }
662
663             NodeList nlDetach = formEl.getElementsByTagName(TAG_DETACH);
664
665             if (nlDetach.getLength() > 0) {
666                 NodeList nlDetachObjects =
667                     ((Element) nlDetach.item(0)).getChildNodes();
668
669                 for (int j = 0; j < nlDetachObjects.getLength(); j++) {
670                     if (nlDetachObjects.item(j).getNodeType()
671                         != Node.ELEMENT_NODE) {
672                         continue;
673                     }
674
675                     sIdTemp =
676                         ((Element) nlDetachObjects.item(j)).getAttribute(
677                             ATTRIB_ID);
678
679                     if (!sIdTemp.equals("XXXX")) {
680
681                         try {
682                             removeChild(
683                                 (
684                                     AbstractChildObject) this
685                                         .getObjectFromFactory(
686                                     (Element) nlDetachObjects.item(j)));
687                         } catch (HarmoniseFactoryException e) {
688                             throw new PopulateException(
689                                 "Error occured removing child from parent",e);
690                         }
691                     }
692                 }
693             }
694         } else {
695             super.populate(formEl, state);
696         }
697     }
698
699     /**
700      * Adds the specified object as a child to this parent.
701      *
702      * @param obj the child to be added
703      * @throws InvalidChildException if the child is an invalid child for this parent
704      * @throws PopulateException if there is an error populating the children of this object
705      */

706     public void addChild(AbstractChildObject obj)
707         throws InvalidChildException, PopulateException {
708         addChild(-1, obj, false);
709     }
710
711     /**
712      * Inserts the specified child object at the specified position
713      * in the list of children. Shifts the object currently at that
714      * position (if any) and any subsequent objects to the
715      * right (adds one to their indices).
716      *
717      * @param nIndex the desired index for the specified child
718      * @param obj the child to be added
719      * @throws InvalidChildException if the child is an invalid child for this parent
720      * @throws PopulateException if there is an error populating the children of this object
721      */

722     public void addChild(int nIndex, AbstractChildObject obj)
723         throws InvalidChildException, PopulateException {
724         addChild(nIndex, obj, false);
725     }
726
727     /**
728      * Adds the specified object as a child to this parent. If
729      * <code>bIsSoftLink</code> is true then the relationship is
730      * weak, meaning this group is not the main group of the
731      * child.
732      *
733      * @param obj the new child
734      * @param bIsSoftLink <code>true</code> if the relationship is weak
735      * @throws InvalidChildException if the new child is invalid
736      * @throws PopulateException if there is an error populating the children of this object
737      */

738     public void addChild(AbstractChildObject obj, boolean bIsSoftLink)
739         throws InvalidChildException, PopulateException {
740         addChild(-1, obj, bIsSoftLink);
741     }
742
743     /**
744      * Inserts the specified child object at the specified position
745      * in the list of children. Shifts the object currently at that
746      * position (if any) and any subsequent objects to the
747      * right (adds one to their indices). The <code>boolean</code>
748      * value <code>bIsSoftLink</code> determines whether this parent
749      * is the default parent of the child, i.e. a value of <code>true</code>
750      * specifies a weak relationship and therefore the parent
751      * is not the default parent of the child.
752      *
753      * @param nIndex the index of the new child
754      * @param obj the new child
755      * @param bIsSoftLink <code>true</code> if the relationship is weak
756      * @throws InvalidChildException if the new child is invalid
757      * @throws PopulateException if there is an error populating the children of this object
758      */

759     public void addChild(
760         int nIndex,
761         AbstractChildObject obj,
762         boolean bIsSoftLink)
763         throws InvalidChildException, PopulateException {
764
765         try {
766             if(isLiveVersion() == false) {
767                 throw new InvalidChildException("Can't add child to non-live parent");
768             }
769         } catch (DataAccessException e) {
770             throw new PopulateException(e);
771         }
772         
773         if(m_logger.isLoggable(Level.INFO)) {
774             try {
775                 m_logger.logp(Level.INFO, this.getClass().getName(), "addChild", "Adding child (id - " + obj.getId() + ",key - " + obj.getKey() + ") to parent (id - " + m_nId + ",key - " + m_nObjectKey + ")");
776             } catch (DataAccessException e) {
777                 m_logger.log(Level.WARNING, "Trouble logging addChild", e);
778             }
779         }
780         
781         //initialise lists
782
if (m_add_children == null) {
783             m_add_children = new Vector();
784             m_add_real_children = new Vector();
785         }
786
787         //check for validity
788
if (obj == null) {
789             if(m_logger.isLoggable(Level.INFO)) {
790                 m_logger.logp(Level.INFO, this.getClass().getName(), "addChild", "attempt to add null child");
791             }
792             throw new InvalidChildException("Null object");
793         }
794
795         if (isValidChild(obj) == false) {
796             
797             throw new InvalidChildException(
798                 this.getClass().getName()
799                     + " can't have "
800                     + obj.getClass().getName()
801                     + " descendent");
802
803             
804         }
805
806         if (obj.getId() <= 0) {
807             if(m_logger.isLoggable(Level.INFO)) {
808                 m_logger.logp(Level.INFO, this.getClass().getName(), "addChild", "Object has invalid id");
809             }
810             throw new InvalidChildException("Object has invalid id");
811         }
812
813         //populate lists if necessary
814
if (m_bIsChildrenPopulated == false) {
815             populateChildrenFromDatabase();
816         }
817
818         try {
819             //if object isn't already a child register it for addition
820
if (isChild(obj) == false) {
821                 
822                 if(isNameAllowed(obj) == false) {
823                     throw new InvalidChildException("Duplicate name - " + obj.getName());
824                 }
825                 
826                 if (obj instanceof AbstractParentObject
827                     && obj.getParents().size() > 0) {
828                     try {
829                         List objpaths = obj.getAllFullPaths();
830
831                         Iterator iter = objpaths.iterator();
832
833                         while (iter.hasNext()) {
834                             String JavaDoc sPath = (String JavaDoc) iter.next();
835                             if (getPath().startsWith(sPath) == true) {
836                                 throw new InvalidChildException("Child is not allowed, it's an ancestor of this parent");
837                             }
838                         }
839
840                     } catch (DataAccessException e) {
841                         throw new PopulateException(
842                             "Problem occured validating child's path",e);
843                     }
844                 }
845
846                 OrderableCachePointer ptr =
847                     new OrderableCachePointer(
848                         CacheHandler.getInstance(m_dsi).getCachePointer(obj));
849                 
850                 obj.addEditEventListener(this);
851
852                 if (nIndex < 0) {
853                     nIndex = getMaxIndex() + 1;
854                     setMaxIndex(nIndex);
855                 }
856
857                 ptr.setPosition(nIndex);
858
859                 //ensure a unique position
860
if (nIndex < getMaxIndex() && getChild(nIndex) != null) {
861                     Set sortedSet = getOrderedChildPointers();
862                     Object JavaDoc[] array = sortedSet.toArray();
863
864                     //loop through those object with a higher index and reset
865
//ensuring that they'll be saved
866
for (int i = nIndex; i < array.length; i++) {
867                         OrderableCachePointer tmpPtr =
868                             (OrderableCachePointer) array[i];
869                         OrderableCachePointer newPtr =
870                             new OrderableCachePointer(tmpPtr);
871                         newPtr.setPosition(tmpPtr.getPosition() + 1);
872                         if (m_remove_children.contains(tmpPtr) == false) {
873                             m_remove_children.add(tmpPtr);
874                         }
875                         if (m_add_children.contains(newPtr) == false) {
876                             m_add_children.add(newPtr);
877
878                             //ensure we keep default markers
879
Integer JavaDoc intId =
880                                 new Integer JavaDoc(
881                                     ((AbstractChildObject) newPtr.getObject())
882                                         .getId());
883                             if (m_real_children.contains(intId)) {
884                                 m_add_real_children.add(intId);
885                             }
886                         }
887                     }
888                 }
889
890                 m_add_children.add(ptr);
891
892                 if (bIsSoftLink == false) {
893                     m_add_real_children.add(new Integer JavaDoc(obj.getId()));
894                 }
895
896                 m_bIsContentsChanged = true;
897             }
898         } catch (DataAccessException e) {
899             throw new PopulateException(
900                 "Error occured accessing current children",e);
901         } catch (CacheException e) {
902             throw new PopulateException(
903                 "Error occured getting cache pointer",e);
904         }
905     }
906
907     /**
908      * Returns <code>true</code> if the child name is allowed.
909      *
910      * @param string the name of the new child
911      * @return <code>true</code> if the child name is allowed
912      * @throws DataAccessException if there is an error populating this object
913      * or obtaining the existing children from the appropriate cache
914      */

915     private boolean isNameAllowed(AbstractChildObject obj) throws DataAccessException {
916         boolean bIsAllowed = true;
917         String JavaDoc sName = obj.getName();
918         
919         if(sName != null) {
920             try {
921                 if(m_bIsChildrenPopulated == false) {
922                     populateChildrenFromDatabase();
923                 }
924     
925                 Iterator iter = m_children.iterator();
926     
927                 while (iter.hasNext() && bIsAllowed == true) {
928                     CachePointer ptr = (CachePointer) iter.next();
929         
930                     AbstractChildObject child = (AbstractChildObject) ptr.getObject();
931         
932                     if(sName.equals(child.getName()) == true) {
933                         if(obj.getLiveVersion() != null && obj.getLiveVersion().equals(child) == true) {
934                             bIsAllowed = true;
935                         } else {
936                             bIsAllowed = false;
937                         }
938                         
939                     }
940                 }
941             } catch (CacheException e) {
942                 throw new DataAccessException(e.getLocalizedMessage(),e);
943             } catch (PopulateException e) {
944                 throw new DataAccessException(e.getLocalizedMessage(),e);
945             }
946         } else {
947             bIsAllowed = false;
948         }
949         
950         
951         return bIsAllowed;
952     }
953
954     /**
955      * Returns <code>true</code> if the given object is a child of this object.
956      *
957      * @param child the potential child object
958      * @return <code>true</code> if the given object is a child of this object.
959      *
960      * @throws DataAccessException if there is an error populating the children of this object
961      */

962     public boolean isChild(AbstractChildObject child)
963         throws DataAccessException {
964         if (m_bIsChildrenPopulated == false) {
965             try {
966                 populateChildrenFromDatabase();
967             } catch (PopulateException e) {
968                 throw new DataAccessException(
969                     "Error occured populating children",e);
970             }
971         }
972
973         boolean bRtn = false;
974
975         //construct cache pointer so we can do a simple contains on m_children
976
CachePointer ptr = null;
977         try {
978             ptr = CacheHandler.getInstance(m_dsi).getCachePointer(child);
979         } catch (CacheException e) {
980             throw new DataAccessException(
981                 "Error occured getting cache pointer:", e);
982         }
983
984         bRtn = m_children.contains(ptr);
985
986         return bRtn;
987     }
988
989     /**
990      * Returns the index of the given child object in the list
991      * of children.
992      *
993      * @param child the child object
994      * @return the index of the given child object
995      * @throws DataAccessException if there is an error populating the children of this object
996      */

997     public int indexOf(AbstractChildObject child) throws DataAccessException {
998         if (m_bIsChildrenPopulated == false) {
999             try {
1000                populateChildrenFromDatabase();
1001            } catch (PopulateException e) {
1002                throw new DataAccessException(
1003                    "Error occured populating kids:" + e.getLocalizedMessage());
1004            }
1005        }
1006
1007        //construct cache pointer so we can search through m_children
1008
OrderableCachePointer ptr = null;
1009        try {
1010            ptr = getCachePointer(child);
1011        } catch (CacheException e) {
1012            throw new DataAccessException(
1013                "Error occured getting cache pointer",e);
1014        } catch (PopulateException e) {
1015            throw new DataAccessException(
1016                "Error occured getting cache pointer",e);
1017        }
1018        
1019        int nIndex = -1;
1020        
1021        if(m_children.contains(ptr)) {
1022            nIndex = new ArrayList(getOrderedChildPointers()).indexOf(ptr);
1023        }
1024
1025        return nIndex;
1026    }
1027
1028    /**
1029     * Sets the complete list of children of this object, children will be
1030     * saved with their order position taken from their index in the list.
1031     *
1032     * @param children the list of <code>AbstractChildObject</code>
1033     * @throws InvalidChildException if any of the new children is invalid
1034     * @throws PopulateException if there is an error populating the children of this object
1035     */

1036    public void setChildren(List children)
1037        throws InvalidChildException, PopulateException {
1038
1039        if (m_bIsChildrenPopulated == false) {
1040            populateChildrenFromDatabase();
1041        }
1042
1043        if (children.equals(m_children) == false) {
1044            m_add_children = new Vector();
1045            m_remove_children = new Vector();
1046            
1047            try {
1048                List curr_children = getChildren();
1049                
1050                //schedule any current children for deletion if not in the list
1051
Iterator iter = curr_children.iterator();
1052                
1053                while (iter.hasNext()) {
1054                    AbstractChildObject tmpChild = (AbstractChildObject) iter.next();
1055                    if(children.contains(tmpChild) == false) {
1056                        OrderableCachePointer ptr = getCachePointer(tmpChild);
1057                
1058                        m_remove_children.add(ptr);
1059                    }
1060                }
1061            } catch (DataAccessException e) {
1062                throw new PopulateException(
1063                        "Error occured getting cache pointer",e);
1064            } catch (CacheException e) {
1065                throw new PopulateException(
1066                        "Error occured getting cache pointer",e);
1067            }
1068
1069            for (int i = 0; i < children.size(); i++) {
1070
1071                AbstractChildObject child;
1072                try {
1073                    child = (AbstractChildObject) children.get(i);
1074                } catch (ClassCastException JavaDoc e) {
1075                    throw new InvalidChildException();
1076                }
1077
1078                if (isValidChild(child) == false) {
1079                    throw new InvalidChildException();
1080                }
1081                
1082                try {
1083                    //if this child is a child already we have to see whether it has
1084
//changed position
1085
if(isChild(child) == true) {
1086                        int nIndex = indexOf(child);
1087                        OrderableCachePointer ptr = getCachePointer(child);
1088                        
1089                        if(nIndex != i && ptr.getPosition() != i) {
1090                            m_remove_children.add(ptr);
1091                        } else {
1092                            //break out of loop cause there's nothing to change for this child
1093
continue;
1094                        }
1095                    }
1096                } catch (DataAccessException e) {
1097                    throw new PopulateException(
1098                        "Error occured getting cache pointer",e);
1099                } catch (CacheException e) {
1100                    throw new PopulateException(
1101                        "Error occured getting cache pointer",e);
1102                }
1103
1104                // construct cache pointer so we can search through m_children
1105
OrderableCachePointer ptr = null;
1106                try {
1107                    ptr =
1108                        new OrderableCachePointer(
1109                            CacheHandler.getInstance(m_dsi).getCachePointer(
1110                                child));
1111                } catch (CacheException e) {
1112                    throw new PopulateException(
1113                        "Error occured getting cache pointer",e);
1114                }
1115                ptr.setPosition(i);
1116                m_add_children.add(ptr);
1117
1118                Integer JavaDoc intId = new Integer JavaDoc(child.getId());
1119
1120                if (m_real_children.contains(intId) == true) {
1121                    m_add_real_children.add(intId);
1122                }
1123            }
1124        }
1125
1126        m_bIsContentsChanged = true;
1127    }
1128
1129    /**
1130     * Removes the scpecified child from this object's list of children.
1131     *
1132     * @param obj the child to remove
1133     * @throws PopulateException if an error occurs populating the children of this object
1134     */

1135    public void removeChild(AbstractChildObject obj) throws PopulateException {
1136        
1137        if(m_logger.isLoggable(Level.INFO)) {
1138            try {
1139                m_logger.logp(Level.INFO,this.getClass().getName(), "removeChild", "Removing child " + obj.getClass().getName() + ", key - " + obj.getKey() + " from parent, key - " + this.getKey());
1140            } catch (DataAccessException e) {
1141                m_logger.log(Level.WARNING, "Problem logging child removal", e);
1142            }
1143        }
1144        
1145        if (m_remove_children == null) {
1146            m_remove_children = new Vector();
1147        }
1148
1149        String JavaDoc sClassName = obj.getClass().getName();
1150
1151        //if it's a valid child register it for removal
1152
if (isValidChild(obj) == true) {
1153            if (m_bIsChildrenPopulated == false) {
1154                populateChildrenFromDatabase();
1155            }
1156
1157            // construct cache pointer so we can do a simple remove on m_children
1158
CachePointer ptr = null;
1159            try {
1160                ptr = CacheHandler.getInstance(m_dsi).getCachePointer(obj);
1161            } catch (CacheException e) {
1162                throw new PopulateException(
1163                    "Error occured getting cache pointer",e);
1164            }
1165
1166            int nPtrIndex = m_children.indexOf(ptr);
1167
1168            if (nPtrIndex >= 0) {
1169                OrderableCachePointer ordPtr =
1170                    (OrderableCachePointer) m_children.get(nPtrIndex);
1171
1172                if (m_remove_children.contains(ordPtr) == false) {
1173                    m_remove_children.add(ordPtr);
1174                }
1175
1176                Set sortedSet = getOrderedChildPointers();
1177
1178                Object JavaDoc[] array = sortedSet.toArray();
1179
1180                //loop through those object with a higher index and reset
1181
//ensuring that they'll be saved
1182

1183                int nIndex = ordPtr.getPosition();
1184                if (nIndex >= 0) {
1185                    for (int i = nIndex; i < array.length; i++) {
1186                        OrderableCachePointer tmpPtr =
1187                            (OrderableCachePointer) array[i];
1188                        if (tmpPtr.equals(ordPtr) == false) {
1189                            OrderableCachePointer newPtr =
1190                                new OrderableCachePointer(tmpPtr);
1191                            newPtr.setPosition(tmpPtr.getPosition() - 1);
1192
1193                            if (m_remove_children.contains(tmpPtr) == false) {
1194                                m_remove_children.add(tmpPtr);
1195                            }
1196
1197                            if (m_add_children.contains(newPtr) == false) {
1198                                m_add_children.add(newPtr);
1199                                // ensure we keep default markers
1200
try {
1201                                    Integer JavaDoc intId =
1202                                        new Integer JavaDoc(
1203                                            ((AbstractChildObject) newPtr
1204                                                .getObject())
1205                                                .getId());
1206                                    if (m_real_children.contains(intId)) {
1207                                        m_add_real_children.add(intId);
1208                                    }
1209                                } catch (CacheException e) {
1210                                    throw new PopulateException(e.getLocalizedMessage(),e);
1211                                }
1212                            }
1213                        }
1214                    }
1215                    setMaxIndex(m_nMaxIndex - 1);
1216                }
1217                m_bIsContentsChanged = true;
1218            }
1219        }
1220    }
1221
1222    /**
1223     * Returns <code>true</code> if the given object is of a valid
1224     * type to become a child of this object.
1225     *
1226     * @param childObj the child object to test
1227     * @return <code>true</code> if the given object is of a valid
1228     * type to become a child of this object.
1229     */

1230    public boolean isValidChild(AbstractChildObject childObj) {
1231        
1232        if(m_logger.isLoggable(Level.FINER)) {
1233            try {
1234                m_logger.logp(Level.FINER, this.getClass().getName(), "isValidChild", "Validating child - " + childObj.getClass().getName() + " key - " + childObj.getKey());
1235            } catch (DataAccessException e) {
1236                m_logger.log(Level.WARNING, "Error logging child validation", e);
1237            }
1238        }
1239        
1240        List classes = new ArrayList();
1241        List classNames = getChildClassNames();
1242        
1243        Iterator iter = classNames.iterator();
1244        boolean bIsValid = false;
1245        while (iter.hasNext() && bIsValid == false) {
1246            String JavaDoc sClassname = (String JavaDoc) iter.next();
1247            Class JavaDoc clss;
1248            try {
1249                clss = Class.forName(sClassname);
1250                if(clss.isAssignableFrom(childObj.getClass())) {
1251                    bIsValid = true;
1252                }
1253            } catch (ClassNotFoundException JavaDoc e) {
1254                bIsValid = false;
1255            }
1256            
1257        }
1258        
1259        return bIsValid;
1260    }
1261
1262    /**
1263     * Returns all children that match the class specified.
1264     *
1265     * @param clss the class to match children against
1266     * @return a list of children that match the specified class
1267     * @throws DataAccessException if there is an error accessing
1268     * the children of this parent
1269     */

1270    public List getChildrenByClass(Class JavaDoc clss) throws DataAccessException {
1271        List rtn = new Vector();
1272
1273        Iterator iter = getChildren().iterator();
1274
1275        while (iter.hasNext()) {
1276            Object JavaDoc obj = iter.next();
1277            if (clss.isInstance(obj) == true) {
1278                rtn.add(obj);
1279            }
1280        }
1281
1282        return rtn;
1283    }
1284
1285    /**
1286     * Returns a list of all children of the given type,
1287     * i.e. branch or leaf children.
1288     *
1289     * @param nType the type code which determines which children
1290     * are returned
1291     * @return a list of all children of the given type
1292     * @throws DataAccessException if there is an error accessing
1293     * the children of this parent
1294     */

1295    public List getChildrenByType(int nType) throws DataAccessException {
1296        List rtn = new Vector();
1297
1298        //if this is not a live version then get the kids from the live version
1299
if (isLiveVersion() == false) {
1300            AbstractParentObject parent =
1301                (AbstractParentObject) getLiveVersion();
1302
1303            if (parent != null) {
1304                rtn = parent.getChildrenByType(nType);
1305            }
1306        } else {
1307            //populate kids if necessary
1308
if (m_bIsChildrenPopulated == false) {
1309                try {
1310                    populateChildrenFromDatabase();
1311                } catch (PopulateException e) {
1312                    throw new DataAccessException(
1313                        "Error occured populating kids:",e);
1314                }
1315            }
1316
1317            rtn = new Vector();
1318
1319            Iterator iter = m_children.iterator();
1320
1321            //loop through getting object from cache pointers and adding to
1322
//list as appropriate
1323
while (iter.hasNext()) {
1324                CachePointer ptr = (CachePointer) iter.next();
1325
1326                AbstractChildObject child = null;
1327
1328                try {
1329                    child = (AbstractChildObject) ptr.getObject();
1330                } catch (CacheException e) {
1331                    throw new DataAccessException(
1332                        "Error occured getting object from cache:"
1333                            + e.getLocalizedMessage());
1334                }
1335
1336                if (nType == ALL_NODES) {
1337                    rtn.add(child);
1338                } else {
1339
1340                    if (nType == BRANCH_NODES
1341                        && child instanceof AbstractParentObject) {
1342                        rtn.add(child);
1343                    } else if (
1344                        nType == LEAF_NODES
1345                            && (child instanceof AbstractParentObject) == false) {
1346                        rtn.add(child);
1347                    }
1348                }
1349            }
1350        }
1351
1352        return rtn;
1353    }
1354
1355    /**
1356     * Returns a list of all children of this object.
1357     *
1358     * @return a list of all children of this object
1359     * @throws DataAccessException if there is an error accessing the children of this object
1360     */

1361    public List getChildren() throws DataAccessException {
1362
1363        if(m_logger.isLoggable(Level.FINE)) {
1364            m_logger.logp(Level.FINE, this.getClass().getName(), "getChildren", "Getting children for object, id - " + m_nId + ", key - " + m_nObjectKey);
1365        }
1366        
1367        List rtn = getChildrenByType(ALL_NODES);
1368
1369        return rtn;
1370    }
1371
1372    /**
1373     * Returns the child with the specified name, otherwise returns a null.
1374     *
1375     * @param string the name of the desired child object
1376     * @returnthe child with the specified name, otherwise returns a <code>null</code>
1377     */

1378    public AbstractChildObject getChildByName(String JavaDoc sName)
1379        throws DataAccessException {
1380        AbstractChildObject child = null;
1381        
1382        if (isLiveVersion() == false) {
1383            AbstractParentObject parent =
1384                (AbstractParentObject) getLiveVersion();
1385
1386            if (parent != null) {
1387                child = parent.getChildByName(sName);
1388            }
1389        } else {
1390            //populate kids if necessary
1391
if (m_bIsChildrenPopulated == false) {
1392                try {
1393                    populateChildrenFromDatabase();
1394                } catch (PopulateException e) {
1395                    throw new DataAccessException(
1396                        "Error occured populating kids:",e);
1397                }
1398            }
1399            
1400            Iterator iter = m_children.iterator();
1401
1402            try {
1403                while (iter.hasNext() == true && child == null) {
1404                    CachePointer tmpPtr = (CachePointer) iter.next();
1405                    AbstractChildObject tmpChild = (AbstractChildObject) tmpPtr.getObject();
1406                    
1407                    if (tmpChild.getName().equals(sName)) {
1408                        child = tmpChild;
1409                    }
1410                }
1411            } catch (CacheException e) {
1412                throw new DataAccessException(e.getLocalizedMessage(),e);
1413            }
1414
1415        }
1416
1417        return child;
1418    }
1419
1420    /**
1421     * Returns the child of this parent object at the specified
1422     * index.
1423     *
1424     * @param nIndex the index of the desired child object
1425     * @return the index of the desired child object
1426     * @throws DataAccessException if there is an error populating the children of this object
1427     */

1428    public AbstractChildObject getChild(int nIndex)
1429        throws DataAccessException {
1430        AbstractChildObject child = null;
1431
1432        if (nIndex >= 0) {
1433            try {
1434                if (m_bIsChildrenPopulated == false) {
1435                    populateChildrenFromDatabase();
1436                }
1437
1438                Iterator iter = m_children.iterator();
1439                boolean bFound = false;
1440                while (iter.hasNext() && bFound == false) {
1441                    OrderableCachePointer ptr =
1442                        (OrderableCachePointer) iter.next();
1443                    if (ptr.getPosition() == nIndex) {
1444                        child = (AbstractChildObject) ptr.getObject();
1445                        bFound = true;
1446                    }
1447                }
1448            } catch (PopulateException e) {
1449                throw new DataAccessException("Error populating parent", e);
1450            } catch (CacheException e) {
1451                throw new DataAccessException(
1452                    "Error getting object from cache",
1453                    e);
1454            }
1455        }
1456
1457        return child;
1458    }
1459
1460    /**
1461     * Returns the current maximum child index position.
1462     *
1463     * Note: this isn't the same as size as there is no enforcement rules on
1464     * index values being contiguous.
1465     *
1466     * @return the current maximum child index position
1467     * @throws DataAccessException if an error occurs populating the children of this object
1468     */

1469    public int getMaxIndex() throws DataAccessException {
1470        if (m_nMaxIndex < 0 && m_bIsChildrenPopulated == false) {
1471            try {
1472                populateChildrenFromDatabase();
1473            } catch (PopulateException e) {
1474                throw new DataAccessException("Error populating children", e);
1475            }
1476        }
1477
1478        return m_nMaxIndex;
1479    }
1480
1481    /**
1482     * Sets the value of the field containing the maximum child index position.
1483     *
1484     * @param nMax the maximum child index position
1485     */

1486    private void setMaxIndex(int nMax) {
1487        m_nMaxIndex = nMax;
1488    }
1489
1490    /**
1491     * Returns the archived child with the specified name,
1492     * otherwise returns a <code>null</code>.
1493     *
1494     * @param sName the name of the archived child to return
1495     * @return the archived child with the specified name
1496     * @throws DataAccessException if there is an error populating the list of archived children
1497     */

1498    public AbstractChildObject getArchivedChildByName(String JavaDoc sName)
1499        throws DataAccessException {
1500        AbstractChildObject child = null;
1501        List children = getArchivedChildren();
1502
1503        Iterator iter = children.iterator();
1504
1505        while (iter.hasNext() == true && child == null) {
1506            AbstractChildObject tmpChild = (AbstractChildObject) iter.next();
1507
1508            if (tmpChild.getName().equals(sName)) {
1509                child = tmpChild;
1510            }
1511        }
1512
1513        return child;
1514    }
1515
1516    /**
1517     * Returns a list of archived children which match the specified
1518     * <code>Class</code>.
1519     *
1520     * @param clss the <code>Class</code> to match children by
1521     * @return the list of archived children
1522     * @throws DataAccessException if there is an error populating the
1523     * list of archived children
1524     */

1525    public List getArchivedChildrenByClass(Class JavaDoc clss)
1526        throws DataAccessException {
1527        List rtn = new Vector();
1528
1529        Iterator iter = getArchivedChildren().iterator();
1530
1531        while (iter.hasNext()) {
1532            Object JavaDoc obj = iter.next();
1533
1534            if (clss.isInstance(obj) == true) {
1535                rtn.add(obj);
1536            }
1537        }
1538
1539        return rtn;
1540    }
1541
1542    /**
1543     * Returns a list of archived children matching the type specified,
1544     * i.e. leaf, branch or all children.
1545     *
1546     * @param nType the type code of children to return
1547     * @return a list of archived children matching the type specified
1548     * @throws DataAccessException if there is an error populating the
1549     * list of archived children
1550     */

1551    public List getArchivedChildrenByType(int nType)
1552        throws DataAccessException {
1553        List rtn = null;
1554
1555        if (nType == ALL_NODES) {
1556            rtn = getArchivedChildren();
1557        } else {
1558            rtn = new Vector();
1559
1560            List archive = getArchivedChildren();
1561
1562            Iterator iter = archive.iterator();
1563
1564            //loop through adding kids as appropriate
1565
while (iter.hasNext()) {
1566                AbstractChildObject child = (AbstractChildObject) iter.next();
1567
1568                if (nType == BRANCH_NODES
1569                    && child instanceof AbstractParentObject) {
1570                    rtn.add(child);
1571                } else if (
1572                    nType == LEAF_NODES
1573                        && (child instanceof AbstractParentObject) == false) {
1574                    rtn.add(child);
1575                }
1576            }
1577        }
1578
1579        return rtn;
1580    }
1581
1582    /**
1583     * Returns a list of archived descendants matching the specified
1584     * <code>Class</code>.
1585     *
1586     * @param clss the <code>Class</code> to match by
1587     * @return the list of archived descendants matching the specified
1588     * <code>Class</code>
1589     * @throws DataAccessException if there is an error populating the
1590     * list of archived children
1591     */

1592    public List getAllArchivedChildrenByClass(Class JavaDoc clss)
1593        throws DataAccessException {
1594        List rtn = new Vector();
1595
1596        Iterator iter = getAllArchivedChildren().iterator();
1597
1598        while (iter.hasNext()) {
1599            Object JavaDoc obj = iter.next();
1600
1601            if (clss.isInstance(obj) == true) {
1602                rtn.add(obj);
1603            }
1604        }
1605
1606        return rtn;
1607    }
1608
1609    /**
1610     * Returns a list of all archived descendants, i.e. of this object and
1611     * its branch children, of the specified type, i.e. leaf, branch or all
1612     * children
1613     *
1614     * @param nType the type code of children to return
1615     * @return a list of all archived descendants of the specified type
1616     * @throws DataAccessException if there is an error populating the
1617     * list of archived children
1618     */

1619    public List getAllArchivedChildrenByType(int nType)
1620        throws DataAccessException {
1621        List rtn = null;
1622
1623        if (nType == ALL_NODES) {
1624            rtn = this.getAllArchivedChildren();
1625        } else {
1626            rtn = new Vector();
1627
1628            List archive = this.getAllArchivedChildren();
1629
1630            Iterator iter = archive.iterator();
1631
1632            //loop though adding kids as appropriate
1633
while (iter.hasNext()) {
1634                AbstractChildObject child = (AbstractChildObject) iter.next();
1635
1636                if (nType == BRANCH_NODES
1637                    && child instanceof AbstractParentObject) {
1638                    rtn.add(child);
1639                } else if (
1640                    nType == LEAF_NODES
1641                        && (child instanceof AbstractParentObject) == false) {
1642                    rtn.add(child);
1643                }
1644            }
1645        }
1646
1647        return rtn;
1648    }
1649
1650    /**
1651     * Returns <code>true</code> if this parent is a top level parent
1652     * in the hierarchy of relationships,
1653     * i.e. if it is not a child of another parent
1654     *
1655     * @return <code>true</code> if this parent is a top level parent
1656     */

1657    public boolean isTopLevel() {
1658        boolean bIsTopLevel = false;
1659
1660        try {
1661            bIsTopLevel = (this.getParents().size() == 0);
1662        } catch (Exception JavaDoc e) {
1663            m_logger.log(Level.WARNING, e.getMessage(), e);
1664        }
1665
1666        return bIsTopLevel;
1667    }
1668
1669    /* (non-Javadoc)
1670     * @see org.openharmonise.rm.resources.lifecycle.Editable#changeStatus(org.openharmonise.rm.resources.lifecycle.Status)
1671     */

1672    public Editable changeStatus(Status status) throws EditException {
1673        boolean bIsUnApproved = false;
1674
1675        try {
1676            if (getStatus() == Status.UNAPPROVED) {
1677                bIsUnApproved = true;
1678            }
1679        } catch (DataAccessException e) {
1680            throw new EditException(
1681                "Error occured getting status:" + e.getLocalizedMessage());
1682        }
1683
1684        if ((bIsUnApproved == true) && (status == Status.APPROVED)) {
1685            // if there is a live version copy the child group links
1686
AbstractParentObject live = null;
1687            try {
1688                live = (AbstractParentObject) getLiveVersion();
1689            } catch (DataAccessException e) {
1690                throw new EditException("Error occured finding live version",e);
1691            }
1692
1693            if (live != null) {
1694                try {
1695                    List childClassNames = getChildClassNames();
1696                    Iterator iter = childClassNames.iterator();
1697                    UpdateStatement update = new UpdateStatement();
1698                    int nParentKey = live.getKey();
1699
1700                    while (iter.hasNext()) {
1701                        String JavaDoc sClassname = (String JavaDoc) iter.next();
1702                        String JavaDoc sTable =
1703                            DatabaseInfo.getInstance().getTableName(sClassname);
1704
1705                        ColumnRef colGroup =
1706                            getGroupChildJoinColumnRef(sTable, TAG_GROUP);
1707
1708                        update.addColumnValue(colGroup, this.m_nObjectKey);
1709                        update.addWhereCondition(colGroup, "=", nParentKey);
1710
1711                        m_dsi.execute(update);
1712
1713                        update.clear();
1714                    }
1715
1716                    live.clearChildren();
1717
1718                } catch (DataStoreException dse) {
1719                    throw new EditException(
1720                        "Error occured updating DB",dse);
1721                } catch (DataAccessException dae) {
1722                    throw new EditException(
1723                        "Error accessing data for update",dae);
1724                }
1725            }
1726        }
1727
1728        return super.changeStatus(status);
1729    }
1730
1731    /**
1732     * Returns a list of top level parent objects of a specified object type.
1733     *
1734     * @param dbinterf the data store interface
1735     * @param grpObj an instance of the type of object to be returned
1736     * @return a list of top level parent objects
1737     * @throws DataAccessException if there is any errors building the
1738     * list of objects
1739     */

1740    public static List getTopLevelGroups(
1741        AbstractDataStoreInterface dbinterf,
1742        AbstractParentObject grpObj)
1743        throws DataAccessException {
1744        Vector vTopLevelGroups = new Vector(16);
1745        ResultSet rs = null;
1746
1747        try {
1748            String JavaDoc sTable = null;
1749            try {
1750                sTable =
1751                    DatabaseInfo.getInstance().getTableName(
1752                        grpObj.getClass().getName());
1753            } catch (DataStoreException e) {
1754                throw new DataAccessException("Error getting table name", e);
1755            }
1756
1757            SelectStatement nestedSelect = new SelectStatement();
1758
1759            nestedSelect.addSelectColumn(
1760                grpObj.getGroupChildJoinColumnRef(sTable, TAG_CHILDREN));
1761
1762            SelectStatement select = new SelectStatement();
1763
1764            select.addSelectColumn(
1765                grpObj.getInstanceColumnRef(ATTRIB_ID, false));
1766
1767            select.addWhereCondition(
1768                grpObj.getInstanceColumnRef(ATTRIB_KEY, false),
1769                "NOT IN",
1770                nestedSelect);
1771            
1772      select.addWhereCondition(
1773         grpObj.getInstanceColumnRef(ATTRIB_TYPE, false),
1774         "=",
1775         grpObj.getClass().getName());
1776      
1777            rs = dbinterf.execute(select);
1778
1779            while (rs.next()) {
1780                Publishable topObj =
1781                    HarmoniseObjectFactory.instantiatePublishableObject(
1782                        dbinterf,
1783                        grpObj.getClass().getName(),
1784                        rs.getInt(1));
1785                vTopLevelGroups.addElement(topObj);
1786            }
1787        } catch (DataStoreException e) {
1788            throw new DataAccessException(
1789                "Error occured building query",e);
1790        } catch (HarmoniseFactoryException e) {
1791            throw new DataAccessException(
1792                "Error occured instantiating object from factory",e);
1793        } catch (SQLException e) {
1794            throw new DataAccessException(
1795                "SQL error",e);
1796        } finally {
1797            if (rs != null) {
1798                try {
1799                    rs.close();
1800                } catch (SQLException e) {
1801                    throw new DataAccessException(
1802                        "Error occured closing result set",e);
1803                }
1804            }
1805        }
1806
1807        return vTopLevelGroups;
1808    }
1809
1810    /**
1811     * Returns a list of class names of classes that can be children of this
1812     * object.
1813     */

1814    abstract public List getChildClassNames();
1815
1816    /**
1817     * Returns a list all archived children of this parent object
1818     *
1819     * @return the list of archived children
1820     * @throws DataAccessException if there is an error populating the
1821     * list of archived children
1822     */

1823    public List getArchivedChildren() throws DataAccessException {
1824        try {
1825
1826            if (isLiveVersion() == false) {
1827                AbstractParentObject liveVersion =
1828                    (AbstractParentObject) getLiveVersion();
1829
1830                if (liveVersion != null) {
1831                    m_archivedChildren = liveVersion.getArchivedChildren();
1832                } else if (isHistorical() == true) {
1833                    if (m_bIsArchivedChildrenPopulated == false) {
1834                        populateArchivedChildrenFromDatabase(false);
1835                    }
1836                } else {
1837                    m_archivedChildren = new Vector();
1838                }
1839            } else {
1840                if (m_bIsArchivedChildrenPopulated == false) {
1841                    populateArchivedChildrenFromDatabase(false);
1842                }
1843            }
1844        } catch (PopulateException e) {
1845            throw new DataAccessException(
1846                "Error occured populating archived children",
1847                e);
1848        }
1849
1850        //return a differnet List to protect the memeber variable from modification
1851
return new ArrayList(m_archivedChildren);
1852    }
1853
1854    /*----------------------------------------------------------------------------
1855    Protected Methods
1856    -----------------------------------------------------------------------------*/

1857
1858    /**
1859     * Returns the column reference for a column in the parent-child
1860     * relationship table.
1861     *
1862     * @param sChildTableName the relationship table name
1863     * @param sCol the column, tag or attribute name
1864     * @return the corresponding column reference
1865     * @throws DataStoreException if the <code>sCol</code> reference is invalid
1866     */

1867    protected ColumnRef getGroupChildJoinColumnRef(
1868        String JavaDoc sChildTableName,
1869        String JavaDoc sCol)
1870        throws DataStoreException {
1871        ColumnRef colref = null;
1872
1873        StringBuffer JavaDoc sbuf =
1874            new StringBuffer JavaDoc(getDBTableName()).append(JOIN_TO).append(
1875                sChildTableName);
1876
1877        String JavaDoc sTable = sbuf.toString();
1878
1879        if (sCol.equals(CLMN_CHILD_KEY) == true
1880            || sCol.equals(AbstractParentObject.TAG_CHILDREN)) {
1881            colref = new ColumnRef(sTable, CLMN_CHILD_KEY, ColumnRef.NUMBER);
1882        } else if (
1883            sCol.equals(CLMN_PARENT_KEY) == true
1884                || sCol.equals(TAG_GROUP) == true) {
1885            colref = new ColumnRef(sTable, CLMN_PARENT_KEY, ColumnRef.NUMBER);
1886        } else if (sCol.equals(CLMN_DATE) == true) {
1887            colref = new ColumnRef(sTable, CLMN_DATE, ColumnRef.DATE);
1888        } else if (
1889            sCol.equals(CLMN_DEFAULT_LINK) == true
1890                || sCol.equals(ATTRIB_DEFAULT) == true) {
1891            colref = new ColumnRef(sTable, CLMN_DEFAULT_LINK, ColumnRef.NUMBER);
1892        } else if (sCol.equals(CLMN_POSITION) == true) {
1893            colref = new ColumnRef(sTable, CLMN_POSITION, ColumnRef.NUMBER);
1894        }
1895
1896        if (colref == null) {
1897            throw new InvalidColumnReferenceException();
1898        }
1899
1900        return colref;
1901    }
1902
1903    /* (non-Javadoc)
1904     * @see org.openharmonise.rm.resources.AbstractEditableObject#delete(boolean)
1905     */

1906    protected void delete(boolean bDeleteHist)
1907        throws
1908            DataStoreException,
1909            DataAccessException,
1910            EditException,
1911            PopulateException {
1912
1913        try {
1914            List children = getChildren();
1915
1916            if (children.isEmpty() == false) {
1917                while (children.size() > 0) {
1918                    AbstractChildObject child =
1919                        (AbstractChildObject) children.get(0);
1920
1921                    if (child.getRealParent().equals(this)) {
1922                        child.delete(bDeleteHist);
1923                    } else {
1924                        removeChild(child);
1925                        saveNonCoreData();
1926                    }
1927                }
1928
1929                m_children.clear();
1930            }
1931        } catch (DataAccessException e) {
1932            throw new EditException(
1933                "Error occured accesing data",e);
1934        } catch (PopulateException e) {
1935            throw new EditException(
1936                "Error occured populating object",e);
1937        } catch (DataStoreException e) {
1938            throw new EditException(
1939                "Error occured deleting branch child",e);
1940        }
1941
1942        super.delete(bDeleteHist);
1943    }
1944
1945    /* (non-Javadoc)
1946     * @see org.openharmonise.rm.resources.AbstractEditableObject#saveNonCoreData()
1947     */

1948    protected void saveNonCoreData() throws EditException {
1949        boolean bIsApproved = false;
1950
1951        if(isLockThread() == false) {
1952            throw new EditException("This object has been locked by another thread");
1953        }
1954        
1955        try {
1956            if (getStatus() == Status.APPROVED) {
1957                bIsApproved = true;
1958            }
1959        } catch (DataAccessException e) {
1960            throw new EditException(
1961                "Error occured getting status",e);
1962        }
1963
1964        if (bIsApproved == true && isHistorical() == false) {
1965            //ensure children variables populated for resave
1966
try {
1967                populateChildrenFromDatabase();
1968            } catch (PopulateException e) {
1969                throw new EditException(
1970                    "Error occured populating object",e);
1971            }
1972
1973            //save changes in content (ie group children, link data) without creating unapproved version.
1974
if (m_bIsContentsChanged == true) {
1975                //remove children to be removed
1976
DeleteStatement delete = new DeleteStatement();
1977
1978                Iterator remove_iter =
1979                    new Vector(m_remove_children).listIterator();
1980
1981                while (remove_iter.hasNext()) {
1982                    try {
1983                        OrderableCachePointer ptr =
1984                            (OrderableCachePointer) remove_iter.next();
1985                        AbstractChildObject child =
1986                            (AbstractChildObject) ptr.getObject();
1987                        
1988                        if(m_logger.isLoggable(Level.FINER)) {
1989                            m_logger.logp(Level.FINER,
1990                                            this.getClass().getName(),
1991                                            "saveNonCoreData",
1992                                            "Deleteing DB child entry for "
1993                                            + child.getClass().getName()
1994                                            + ", id - "
1995                                            + child.getId()
1996                                            + "posn -"
1997                                            + ptr.getPosition()
1998                                            + "for parent ,id - "
1999                                            + getId());
2000                        }
2001
2002                        // if the m_add_children vector also contains
2003
// the object to be removed, then
2004
// remove it from the m_add_children vector
2005
if (m_add_children.contains(ptr) == true) {
2006                            m_add_children.remove(ptr);
2007                        }
2008
2009                        child.removeParent(this);
2010                        child.removeEditEventListener(this);
2011
2012                        Integer JavaDoc intId = new Integer JavaDoc(child.getId());
2013                        boolean bIsReal = m_real_children.contains(intId);
2014
2015                        delete.addWhereCondition(
2016                            getGroupChildJoinColumnRef(
2017                                child.getDBTableName(),
2018                                TAG_CHILDREN),
2019                            "=",
2020                            child.getKey());
2021                        delete.addWhereCondition(
2022                            getGroupChildJoinColumnRef(
2023                                child.getDBTableName(),
2024                                TAG_GROUP),
2025                            "=",
2026                            m_nObjectKey);
2027                        delete.addWhereCondition(
2028                            getGroupChildJoinColumnRef(
2029                                child.getDBTableName(),
2030                                CLMN_POSITION),
2031                            "=",
2032                            ptr.getPosition());
2033
2034                        m_dsi.execute(delete);
2035
2036                        delete.clear();
2037
2038                        m_children.remove(ptr);
2039
2040                        if (bIsReal == true) {
2041                            m_real_children.remove(intId);
2042                        }
2043                    } catch (DataAccessException e) {
2044                        throw new EditException(
2045                            "Error accessing child data",e);
2046                    } catch (CacheException e) {
2047                        throw new EditException(
2048                            "Error getting object from cache",e);
2049                    } catch (DataStoreException e) {
2050                        throw new EditException(
2051                            "Error deleting data from DB",e);
2052                    } catch (PopulateException e) {
2053                        throw new EditException(
2054                            "Error removing groups as parent from child",e);
2055                    }
2056                }
2057
2058                //clear list
2059
m_remove_children.clear();
2060
2061                InsertStatement insert = new InsertStatement();
2062
2063                //insert new children
2064
Iterator iter = this.m_add_children.listIterator();
2065
2066                int nDefault = 0;
2067
2068                while (iter.hasNext()) {
2069                    try {
2070                        OrderableCachePointer ptr =
2071                            (OrderableCachePointer) iter.next();
2072                        AbstractChildObject child =
2073                            (AbstractChildObject) ptr.getObject();
2074                        
2075                        if(m_logger.isLoggable(Level.FINER)) {
2076                            m_logger.logp(Level.FINER,
2077                                            this.getClass().getName(),
2078                                            "saveNonCoreData",
2079                                            "Adding DB child entry for "
2080                                            + child.getClass().getName()
2081                                            + ", id - "
2082                                            + child.getId()
2083                                            + " for parent ,id - "
2084                                            + getId());
2085                        }
2086
2087                        Integer JavaDoc intId = new Integer JavaDoc(child.getId());
2088                        boolean bIsReal = m_add_real_children.contains(intId);
2089
2090                        if (bIsReal == true) {
2091                            child.setRealParent(this);
2092                        } else {
2093                            child.addParent(this);
2094                        }
2095                        child.addEditEventListener(this);
2096
2097                        insert.addColumnValue(
2098                            getGroupChildJoinColumnRef(
2099                                child.getDBTableName(),
2100                                TAG_CHILDREN),
2101                            child.getKey());
2102                        insert.addColumnValue(
2103                            getGroupChildJoinColumnRef(
2104                                child.getDBTableName(),
2105                                TAG_GROUP),
2106                            m_nObjectKey);
2107
2108                        nDefault = 0;
2109
2110                        if (bIsReal == true) {
2111                            nDefault = 1;
2112                        }
2113
2114                        insert.addColumnValue(
2115                            getGroupChildJoinColumnRef(
2116                                child.getDBTableName(),
2117                                AbstractChildObject.CLMN_DEFAULT_LINK),
2118                            nDefault);
2119
2120                        insert.addColumnValue(
2121                            getGroupChildJoinColumnRef(
2122                                child.getDBTableName(),
2123                                CLMN_POSITION),
2124                            ptr.getPosition());
2125
2126                        m_dsi.execute(insert);
2127
2128                        insert.clear();
2129                        m_children.add(ptr);
2130                        if (bIsReal == true) {
2131                            m_real_children.add(intId);
2132                        }
2133
2134                        iter.remove();
2135
2136                    } catch (DataAccessException e) {
2137                        throw new EditException(
2138                            "Error occured accessing data",e);
2139                    } catch (DataStoreException e) {
2140                        throw new EditException(
2141                            "Error occured inserting child data to DB",e);
2142                    } catch (CacheException e) {
2143                        throw new EditException(
2144                            "Error occured getting object from cache",e);
2145                    } catch (PopulateException e) {
2146                        throw new EditException(
2147                            "Error occured adding group to child",e);
2148                    }
2149
2150                }
2151
2152                //clear 'add' lists
2153
m_add_children.clear();
2154                m_add_real_children.clear();
2155                
2156                //get sorted kids so we don't order them all the time
2157
m_children = new ArrayList(getOrderedChildPointers());
2158
2159                m_bIsContentsChanged = false;
2160            }
2161        }
2162    }
2163
2164    /* (non-Javadoc)
2165     * @see org.openharmonise.rm.resources.AbstractObject#fullPopulate()
2166     */

2167    protected void fullPopulate() throws PopulateException {
2168        if (m_bIsChildrenPopulated == false) {
2169            populateChildrenFromDatabase();
2170        }
2171
2172        super.fullPopulate();
2173    }
2174
2175    /**
2176     * Adds the object which the given XML element represents as a
2177     * child to this parent object.
2178     *
2179     * @param el the XML element representing the new child
2180     * @throws InvalidChildException if the new child is invalid for this
2181     * parent
2182     * @throws PopulateException if there is an error creating an object
2183     * from the XML element
2184     */

2185    protected void addChild(Element el)
2186        throws InvalidChildException, PopulateException {
2187
2188        AbstractChildObject obj;
2189        try {
2190            obj =
2191                (
2192                    AbstractChildObject) HarmoniseObjectFactory
2193                        .instantiatePublishableObject(
2194                    this.m_dsi,
2195                    el,
2196                    null);
2197
2198            this.addChild(obj);
2199        } catch (HarmoniseFactoryException e) {
2200            throw new PopulateException(
2201                "Problem occured creating object from XML element",e);
2202        }
2203
2204    }
2205
2206    /**
2207     * Removes the object which is represented by the given XML element
2208     * from the children of this object.
2209     *
2210     * @param el the XML element representing a child
2211     * @throws PopulateException if an error occurs creating an object from the XML element
2212     */

2213    protected void removeChild(Element el) throws PopulateException {
2214
2215        try {
2216            AbstractChildObject obj =
2217                (
2218                    AbstractChildObject) HarmoniseObjectFactory
2219                        .instantiatePublishableObject(
2220                    this.m_dsi,
2221                    el,
2222                    null);
2223
2224            removeChild(obj);
2225        } catch (HarmoniseFactoryException e) {
2226            throw new PopulateException(
2227                "Error occured creating object from XML",e);
2228        }
2229
2230    }
2231
2232    /*----------------------------------------------------------------------------
2233    Private Functions
2234    -----------------------------------------------------------------------------*/

2235
2236    /**
2237     * Clears the list of archived children.
2238     *
2239     */

2240    private void clearArchivedChildren() {
2241        m_archivedChildren = null;
2242        m_allArchivedChildren = null;
2243        m_bIsArchivedChildrenPopulated = false;
2244        m_bIsAllArchivedChildrenPopulated = false;
2245    }
2246
2247    /**
2248     * Returns all archived descendants of this object.
2249     *
2250     * @return the list of archived descendants
2251     * @throws DataAccessException if an error occurs while populating the
2252     * list of archived descendants
2253     */

2254    private List getAllArchivedChildren() throws DataAccessException {
2255        try {
2256            if (isPopulated() == false) {
2257                populateFromDatabase();
2258            }
2259
2260            if (isLiveVersion() == false) {
2261                AbstractParentObject liveVersion =
2262                    (AbstractParentObject) getLiveVersion();
2263
2264                if (liveVersion != null) {
2265                    m_allArchivedChildren =
2266                        liveVersion.getAllArchivedChildren();
2267                } else {
2268                    m_allArchivedChildren = new Vector();
2269                }
2270            } else {
2271                if (m_bIsAllArchivedChildrenPopulated == false) {
2272                    populateArchivedChildrenFromDatabase(true);
2273                }
2274            }
2275        } catch (PopulateException e) {
2276            throw new DataAccessException(
2277                "Error occured populating archived children",e);
2278        }
2279
2280        return new ArrayList(m_allArchivedChildren);
2281    }
2282
2283    /**
2284     * Returns an object from the factory appropriate to the
2285     * given element.
2286     *
2287     * @param el the XML representing an object
2288     * @return the object created from the XML element
2289     * @throws HarmoniseFactoryException if an error occurs accessing the object
2290     * from the <code>HarmoniseObjectFactory</code>
2291     */

2292    private Object JavaDoc getObjectFromFactory(Element el)
2293        throws HarmoniseFactoryException {
2294        return (Object JavaDoc) HarmoniseObjectFactory.instantiatePublishableObject(
2295            this.m_dsi,
2296            el,
2297            null);
2298    }
2299
2300    /**
2301     * Returns <code>true</code> if specified child is a child of this object
2302     * and is not a <code>AbstractParentObject</code>.
2303     * @param child the child object
2304     * @return <code>true</code> if specified child is a child of this object
2305     * and is not a <code>AbstractParentObject</code>
2306     * @throws DataAccessException if there is an error populating the list of children
2307     */

2308    private boolean isLeafChild(AbstractChildObject child)
2309        throws DataAccessException {
2310        //fill data member
2311
if (m_bIsChildrenPopulated == false) {
2312            try {
2313                populateChildrenFromDatabase();
2314            } catch (PopulateException e) {
2315                throw new DataAccessException(
2316                    "Error occured populating kids:" + e.getLocalizedMessage());
2317            }
2318        }
2319
2320        return (
2321            m_children.contains(child)
2322                && (child instanceof AbstractParentObject) == false);
2323    }
2324
2325    /**
2326     * Populates this object's list of children from the database.
2327     *
2328     * @throws PopulateException if an error occurs populating list
2329     */

2330    private synchronized void populateChildrenFromDatabase() throws PopulateException {
2331        if (m_bIsChildrenPopulated == false) {
2332
2333            if(m_logger.isLoggable(Level.FINER)) {
2334                m_logger.logp(Level.FINER, this.getClass().getName(), "populateChildrenFromDatabase", "populating children for parent, id - " + m_nId + ", key - " + m_nObjectKey);
2335            }
2336            
2337            if (isPopulated() == false) {
2338                populateFromDatabase();
2339            }
2340
2341            if (m_children == null) {
2342                m_children = new Vector();
2343            }
2344
2345            if (m_real_children == null) {
2346                m_real_children = new Vector();
2347            }
2348
2349            List childClassNames = getChildClassNames();
2350
2351            if ((this.m_nId != AbstractObject.NOTDBSAVED_ID)
2352                && childClassNames != null
2353                && childClassNames.size() > 0) {
2354                SelectStatement select = new SelectStatement();
2355
2356                Iterator iter = childClassNames.iterator();
2357                while (iter.hasNext()) {
2358
2359                    ColumnRef idColref;
2360                    ColumnRef typeColref;
2361                    ColumnRef linkColref;
2362                    try {
2363                        String JavaDoc sChildClassName = (String JavaDoc) iter.next();
2364
2365                        String JavaDoc sChildTableName = null;
2366
2367                        try {
2368                            sChildTableName =
2369                                DatabaseInfo.getInstance().getTableName(
2370                                    sChildClassName);
2371                        } catch (DataStoreException e) {
2372                            throw new PopulateException(
2373                                "Error getting table name",
2374                                e);
2375                        }
2376
2377                        idColref = getColumnRef(sChildClassName, ATTRIB_ID);
2378
2379                        linkColref =
2380                            getGroupChildJoinColumnRef(
2381                                sChildTableName,
2382                                AbstractChildObject.CLMN_DEFAULT_LINK);
2383                        typeColref = getColumnRef(sChildClassName, ATTRIB_TYPE);
2384
2385                        select.addSelectColumn(idColref); //1
2386
select.addSelectColumn(linkColref); //2
2387
select.addSelectColumn(typeColref); //3
2388
ColumnRef posCol =
2389                            getGroupChildJoinColumnRef(
2390                                sChildTableName,
2391                                CLMN_POSITION);
2392                        select.addSelectColumn(posCol); //4
2393

2394                        Collection coreRefs =
2395                            AbstractParentObject.getCoreColumnRefs(
2396                                sChildClassName);
2397                        Iterator resIter = coreRefs.iterator();
2398
2399                        while (resIter.hasNext() == true) {
2400                            select.addSelectColumn((ColumnRef) resIter.next());
2401                        }
2402
2403                        select.setOrderBy(posCol);
2404
2405                        //join children to join table
2406
ColumnRef joinColumn1 =
2407                            getColumnRef(
2408                                sChildClassName,
2409                                AbstractObject.ATTRIB_KEY);
2410                        ColumnRef joinColumn2 =
2411                            getGroupChildJoinColumnRef(
2412                                sChildTableName,
2413                                TAG_CHILDREN);
2414
2415                        select.addJoinCondition(joinColumn1, joinColumn2);
2416
2417                        ColumnRef whereColumn =
2418                            getGroupChildJoinColumnRef(
2419                                sChildTableName,
2420                                TAG_GROUP);
2421
2422                        select.addWhereCondition(
2423                            whereColumn,
2424                            "=",
2425                            m_nObjectKey);
2426                        select.setOrderBy(joinColumn2);
2427                    } catch (DataStoreException e) {
2428                        throw new PopulateException(
2429                            "Error occured building query",e);
2430                    }
2431
2432                    ResultSet rs = null;
2433
2434                    try {
2435                        rs = m_dsi.execute(select);
2436
2437                        int nId = 0;
2438
2439                        while (rs.next()) {
2440                            nId = rs.getInt(idColref.getColumn());
2441
2442                            AbstractProfiledObject tmpChild =
2443                                (
2444                                    AbstractProfiledObject) HarmoniseObjectFactory
2445                                        .instantiatePublishableObject(
2446                                    this.m_dsi,
2447                                    rs.getString(typeColref.getColumn()),
2448                                    nId);
2449
2450                            tmpChild.addEditEventListener(this);
2451
2452                            if (tmpChild.isPopulated() == false) {
2453                                tmpChild.populateFromResultSetRow(rs, select);
2454                            }
2455
2456                            OrderableCachePointer ptr = null;
2457
2458                            ptr =
2459                                new OrderableCachePointer(
2460                                    CacheHandler.getInstance(
2461                                        m_dsi).getCachePointer(
2462                                        tmpChild));
2463
2464                            int nIndex = rs.getInt(4);
2465
2466                            if (nIndex > m_nMaxIndex) {
2467                                m_nMaxIndex = nIndex;
2468                            }
2469
2470                            ptr.setPosition(nIndex);
2471
2472                            m_children.add(ptr);
2473
2474                            if (rs.getBoolean(linkColref.getColumn())) {
2475                                m_real_children.add(new Integer JavaDoc(nId));
2476                            }
2477                        }
2478                        
2479                        //sort now so we don't have to do it all the time
2480
m_children = new ArrayList(getOrderedChildPointers());
2481                    } catch (HarmoniseFactoryException e) {
2482                        throw new PopulateException(
2483                            "Error occured instantiating object from factory",e);
2484                    } catch (DataStoreException e) {
2485                        throw new PopulateException(
2486                            "Error occured processing query",e);
2487                    } catch (SQLException e) {
2488                        throw new PopulateException(
2489                            "SQL error",e);
2490                    } catch (CacheException e) {
2491                        throw new PopulateException(
2492                            "Error occured getting cache pointer",e);
2493                    } finally {
2494                        if (rs != null) {
2495                            try {
2496                                rs.close();
2497                            } catch (SQLException e) {
2498                                throw new PopulateException(
2499                                    "Error occured closing result set",e);
2500                            }
2501                        }
2502
2503                        m_bIsChildrenPopulated = true;
2504                    }
2505                    select.clear();
2506                }
2507
2508            } else {
2509                m_bIsChildrenPopulated = true;
2510            }
2511        }
2512    }
2513
2514    /**
2515     * Populates the list of archived children or descendants from the database.
2516     *
2517     * @param bAllChildren <code>true</code> if the archived descendant list
2518     * should be populated, otherwise the list of archived children will be populated
2519     * @throws PopulateException if an error occurs populating the list
2520     */

2521    private void populateArchivedChildrenFromDatabase(boolean bAllChildren)
2522        throws PopulateException {
2523
2524        List archive = null;
2525
2526        if (bAllChildren == true) {
2527            if (m_allArchivedChildren == null) {
2528                m_allArchivedChildren = new Vector();
2529            }
2530
2531            archive = m_allArchivedChildren;
2532        } else {
2533            if (m_archivedChildren == null) {
2534                m_archivedChildren = new Vector();
2535            }
2536
2537            archive = m_archivedChildren;
2538        }
2539
2540        List children = null;
2541        try {
2542            children = getChildren();
2543        } catch (DataAccessException e) {
2544            throw new PopulateException(
2545                "Error occured getting children",e);
2546        }
2547
2548        // get the constructor we need
2549
List classNames = this.getChildClassNames();
2550
2551        Iterator iter = classNames.iterator();
2552
2553        while (iter.hasNext()) {
2554
2555            String JavaDoc sClassname = (String JavaDoc) iter.next();
2556            Class JavaDoc childClass = null;
2557            try {
2558                childClass = Class.forName(sClassname);
2559            } catch (ClassNotFoundException JavaDoc e) {
2560                throw new PopulateException(
2561                    "Error occured getting class for child",e);
2562            }
2563
2564            SelectStatement select = new SelectStatement();
2565
2566            try {
2567                ColumnRef histIdColumn =
2568                    AbstractObject.getColumnRef(
2569                        sClassname,
2570                        AbstractObject.ATTRIB_ID,
2571                        true);
2572
2573                select.addSelectColumn(histIdColumn);
2574                select.addSelectColumn(
2575                    AbstractObject.getColumnRef(
2576                        sClassname,
2577                        AbstractObject.TAG_NAME,
2578                        true));
2579                select.addSelectColumn(
2580                    AbstractEditableObject.getColumnRef(
2581                        sClassname,
2582                        AbstractEditableObject.TAG_VERSION,
2583                        true));
2584                select.addSelectColumn(
2585                    AbstractEditableObject.getColumnRef(
2586                        sClassname,
2587                        AbstractEditableObject.TAG_VERSION_COMMENT,
2588                        true));
2589                select.addSelectColumn(
2590                    AbstractEditableObject.getColumnRef(
2591                        sClassname,
2592                        AbstractEditableObject.TAG_VERSION_DATE,
2593                        true));
2594                select.addSelectColumn(
2595                    AbstractEditableObject.getColumnRef(
2596                        sClassname,
2597                        AbstractObject.ATTRIB_KEY,
2598                        true));
2599
2600                ColumnRef whereColumn =
2601                    AbstractChildObject.getColumnRef(
2602                        sClassname,
2603                        AbstractChildObject.TAG_PATH,
2604                        true);
2605
2606                if (bAllChildren) {
2607                    select.addWhereCondition(
2608                        whereColumn,
2609                        "LIKE",
2610                        getFullPath() + "%");
2611                } else {
2612                    select.addWhereCondition(whereColumn, "=", getFullPath());
2613                }
2614
2615                ColumnRef liveIdColumn =
2616                    AbstractObject.getColumnRef(sClassname, ATTRIB_ID);
2617
2618                //hist id not in live id list
2619
SelectStatement nestedSelect = new SelectStatement();
2620
2621                nestedSelect.addSelectColumn(liveIdColumn);
2622
2623                select.addWhereCondition(histIdColumn, "not in", nestedSelect);
2624
2625                ColumnRef parentIdColumn =
2626                    AbstractEditableObject.getColumnRef(
2627                        sClassname,
2628                        TAG_LIVE_VERSION,
2629                        false);
2630
2631                //hist id not in live parent_id list
2632
SelectStatement nestedSelect2 = new SelectStatement();
2633
2634                nestedSelect2.addSelectColumn(parentIdColumn);
2635
2636                select.addWhereCondition(histIdColumn, "not in", nestedSelect2);
2637
2638                select.addOrderBy(
2639                    AbstractObject.getColumnRef(
2640                        sClassname,
2641                        AbstractObject.ATTRIB_KEY,
2642                        true),SelectStatement.ORDER_DESCENDING);
2643
2644            } catch (DataAccessException e) {
2645                throw new PopulateException("Error occured accessing data", e);
2646            } catch (DataStoreException e) {
2647                throw new PopulateException("Error occured building query", e);
2648            }
2649
2650            ResultSet rs = null;
2651
2652            try {
2653                rs = m_dsi.execute(select);
2654
2655                Vector ids = new Vector();
2656
2657                while (rs.next()) {
2658                    int nId = rs.getInt(1);
2659                    Integer JavaDoc intId = new Integer JavaDoc(nId);
2660
2661                    if (ids.contains(intId) == false) {
2662                        AbstractChildObject obj =
2663                            (AbstractChildObject) childClass.newInstance();
2664
2665                        obj.setDataStoreInterface(m_dsi);
2666                        obj.setId(nId);
2667                        obj.setHistorical(true);
2668
2669                        obj.populateFromResultSetRow(rs, select);
2670
2671                        obj.setRealParent(this);
2672                        obj.addEditEventListener(this);
2673
2674                        archive.add(obj);
2675                        ids.add(intId);
2676                    }
2677                }
2678            } catch (SQLException e) {
2679                throw new PopulateException(
2680                    "SQL error",e);
2681            } catch (IllegalArgumentException JavaDoc e) {
2682                throw new PopulateException(
2683                    "Illegal argument error",e);
2684            } catch (InstantiationException JavaDoc e) {
2685                throw new PopulateException(
2686                    "Instantiation error",e);
2687            } catch (IllegalAccessException JavaDoc e) {
2688                throw new PopulateException(
2689                    "Illegal access error",e);
2690            } catch (DataStoreException e) {
2691                throw new PopulateException(
2692                    "Error occured processing query",e);
2693            } finally {
2694                if (rs != null) {
2695                    try {
2696                        rs.close();
2697                    } catch (SQLException e) {
2698                        throw new PopulateException(
2699                            "Error occured closing result set",e);
2700                    }
2701                }
2702
2703                if (bAllChildren) {
2704                    m_bIsAllArchivedChildrenPopulated = true;
2705                } else {
2706                    m_bIsArchivedChildrenPopulated = true;
2707                }
2708            }
2709
2710        }
2711    }
2712    
2713    /* (non-Javadoc)
2714     * @see org.openharmonise.rm.resources.lifecycle.EditEventListener#workflowObjectArchived(org.openharmonise.rm.resources.lifecycle.EditEvent)
2715     */

2716    public void workflowObjectArchived(EditEvent event) {
2717        Editable source = (Editable) event.getSource();
2718
2719        //if source is a child act accordingly
2720
if (source instanceof AbstractChildObject) {
2721            AbstractChildObject childSource = (AbstractChildObject) source;
2722
2723            //if child is a valid child of this parent clear all archived children lists
2724
//so that they can be repopulated if necessary
2725
//Note: there is no way to check whether it's valid to add the result
2726
//of the event to the archived lists as the original child will no longer
2727
//be a child of the parent
2728
if (isValidChild(childSource) == true) {
2729
2730                if (m_bIsArchivedChildrenPopulated == true) {
2731                    m_bIsArchivedChildrenPopulated = false;
2732                    m_archivedChildren.clear();
2733                }
2734
2735                if (m_bIsAllArchivedChildrenPopulated == true) {
2736                    m_bIsAllArchivedChildrenPopulated = false;
2737                    m_allArchivedChildren.clear();
2738                }
2739            }
2740
2741        }
2742        
2743        super.workflowObjectArchived(event);
2744
2745    }
2746
2747    /* (non-Javadoc)
2748     * @see org.openharmonise.rm.resources.lifecycle.EditEventListener#workflowObjectLocked(org.openharmonise.rm.resources.lifecycle.EditEvent)
2749     */

2750    public void workflowObjectLocked(EditEvent event) {
2751        super.workflowObjectLocked(event);
2752    }
2753
2754    /* (non-Javadoc)
2755     * @see org.openharmonise.rm.resources.lifecycle.EditEventListener#workflowObjectReactivated(org.openharmonise.rm.resources.lifecycle.EditEvent)
2756     */

2757    public void workflowObjectReactivated(EditEvent event) {
2758        Object JavaDoc src = event.getSource();
2759
2760        //if source of event has been archived it's no longer
2761
//valid it to have listed in the archive
2762
if (src instanceof AbstractChildObject) {
2763
2764            if (m_bIsAllArchivedChildrenPopulated == true) {
2765                m_allArchivedChildren.remove(src);
2766            }
2767
2768            if (m_bIsArchivedChildrenPopulated == true) {
2769                m_archivedChildren.remove(src);
2770            }
2771        }
2772        
2773        super.workflowObjectReactivated(event);
2774    }
2775
2776    /* (non-Javadoc)
2777     * @see org.openharmonise.rm.resources.lifecycle.EditEventListener#workflowObjectSaved(org.openharmonise.rm.resources.lifecycle.EditEvent)
2778     */

2779    public void workflowObjectSaved(EditEvent event) {
2780        super.workflowObjectSaved(event);
2781    }
2782
2783    /* (non-Javadoc)
2784     * @see org.openharmonise.rm.resources.lifecycle.EditEventListener#workflowObjectStatusChanged(org.openharmonise.rm.resources.lifecycle.EditEvent)
2785     */

2786    public void workflowObjectStatusChanged(EditEvent event) {
2787        //if the source is a child object then the chances are it's been approved
2788
//we can therefore no longer access it's old id (maybe by the key but wouldn't
2789
//rely on it) so we have to clear all children
2790
if (event.getSource() instanceof AbstractChildObject) {
2791            clearChildren();
2792        }
2793        
2794        super.workflowObjectStatusChanged(event);
2795    }
2796
2797    /* (non-Javadoc)
2798     * @see org.openharmonise.rm.resources.lifecycle.EditEventListener#workflowObjectUnlocked(org.openharmonise.rm.resources.lifecycle.EditEvent)
2799     */

2800    public void workflowObjectUnlocked(EditEvent event) {
2801        super.workflowObjectUnlocked(event);
2802
2803    }
2804
2805    /**
2806     * Subclass of <code>CachePointer</code> which stores position data,
2807     * allowing an orderable list to be created and maintained.
2808     *
2809     * @author Michael Bell
2810     * @version $Revision: 1.6 $
2811     *
2812     */

2813    private class OrderableCachePointer extends CachePointer {
2814
2815        /**
2816         * Index of this cache pointer in list
2817         */

2818        private int m_nPosition = -1;
2819
2820        /**
2821         * Constructs a cache pointer which does not reference any object
2822         */

2823        public OrderableCachePointer() {
2824            super();
2825        }
2826
2827        /**
2828         * Constructs an orderable cache pointer based in the specified
2829         * <code>CachePointer</code>
2830         *
2831         * @param ptr the <code>CachePointer</code> to base this object on
2832         */

2833        public OrderableCachePointer(CachePointer ptr) {
2834            this.setCache(ptr.getCache());
2835            this.setKey(ptr.getKey());
2836        }
2837
2838        /**
2839         * Constructs a cache pointer which references the object found in
2840         * cache <code>cache</code> with cache key <code>key</code>.
2841         *
2842         * @param key the cache key
2843         * @param cache the cache
2844         */

2845        public OrderableCachePointer(Object JavaDoc key, AbstractCache cache) {
2846            super(key, cache);
2847        }
2848
2849        /**
2850         * Returns the index of this cache pointer
2851         *
2852         * @return the index of this cache pointer
2853         */

2854        public int getPosition() {
2855            return m_nPosition;
2856        }
2857
2858        /**
2859         * Sets the index of this cache pointer
2860         *
2861         * @param i the index of this cache pointer
2862         */

2863        public void setPosition(int i) {
2864            m_nPosition = i;
2865        }
2866
2867        /* (non-Javadoc)
2868         * @see java.lang.Object#toString()
2869         */

2870        public String JavaDoc toString() {
2871            String JavaDoc result = null;
2872
2873            StringBuffer JavaDoc strbuf = new StringBuffer JavaDoc();
2874
2875            try {
2876                strbuf.append(
2877                    ((AbstractChildObject) getObject()).getName()).append(
2878                    " ").append(
2879                    m_nPosition);
2880                result = strbuf.toString();
2881            } catch (DataAccessException e) {
2882                m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
2883            } catch (CacheException e) {
2884                m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
2885            }
2886
2887            return result;
2888        }
2889
2890    /**
2891     * Returns a cache pointer which references the given
2892     * child object
2893     *
2894     * @param child the child object
2895     * @return an cache pointer
2896     * @throws PopulateException if there is an error populating the list of
2897     * children
2898     * @throws CacheException if there is an error accessing the object held
2899     * in an orderable cache pointer
2900     */

2901    public CachePointer getCachePointer() {
2902      return new CachePointer(this.getKey(), this.getCache());
2903    }
2904    
2905        /* (non-Javadoc)
2906         * @see java.lang.Object#equals(java.lang.Object)
2907         */

2908        public boolean equals(Object JavaDoc obj) {
2909            boolean bEq = false;
2910
2911            if (obj instanceof CachePointer) {
2912                CachePointer ptr = (CachePointer) obj;
2913
2914                if (this == ptr) {
2915                    bEq = true;
2916                } else if (
2917                    ptr.getCache().equals(m_cache) == true
2918                        && ptr.getKey().equals(m_cache_key) == true) {
2919                    bEq = true;
2920
2921                    if (ptr instanceof OrderableCachePointer
2922                        && bEq == true
2923                        && ((OrderableCachePointer) ptr).m_nPosition
2924                            != this.m_nPosition) {
2925                        bEq = false;
2926                    }
2927                }
2928            }
2929
2930            return bEq;
2931        }
2932
2933    }
2934
2935    /**
2936     *
2937     * Comparator class for <code>OrderableCachePointer</code> sorting
2938     *
2939     * @author Michael Bell
2940     * @version $Revision: 1.6 $
2941     *
2942     */

2943    private class OrderableCachePointerComparator implements Comparator {
2944
2945        /* (non-Javadoc)
2946         * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
2947         */

2948        public int compare(Object JavaDoc arg1, Object JavaDoc arg2) {
2949            OrderableCachePointer ptr1 = (OrderableCachePointer) arg1;
2950            OrderableCachePointer ptr2 = (OrderableCachePointer) arg2;
2951
2952            int nCompare = 0;
2953            int nPos1 = ptr1.getPosition();
2954            int nPos2 = ptr2.getPosition();
2955
2956            if (nPos1 != nPos2) {
2957
2958                //makre sure that any index of -1 gets pushed to the end
2959
//of the list
2960
if (nPos2 == -1) {
2961                    nCompare = 1;
2962                } else {
2963                    nCompare = nPos1 - nPos2;
2964                }
2965
2966            } else {
2967
2968                try {
2969                    AbstractChildObject child1 =
2970                        (AbstractChildObject) ptr1.getObject();
2971                    AbstractChildObject child2 =
2972                        (AbstractChildObject) ptr2.getObject();
2973
2974                    nCompare = child1.compareTo(child2);
2975                } catch (CacheException e) {
2976                    m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
2977                    nCompare = 0;
2978                }
2979            }
2980
2981            return nCompare;
2982        }
2983
2984    }
2985
2986    /**
2987     * Returns an ordered set of this object's children
2988     *
2989     * @return an ordered set of this object's children
2990     */

2991    private Set getOrderedChildPointers() {
2992        TreeSet sortedSet = new TreeSet(new OrderableCachePointerComparator());
2993        sortedSet.addAll(m_children);
2994
2995        return sortedSet;
2996    }
2997    
2998    /**
2999     * Returns an orderable cache pointer which references the given
3000     * child object.
3001     *
3002     * @param child the child object
3003     * @return an orderable cache pointer
3004     * @throws PopulateException if there is an error populating the list of
3005     * children
3006     * @throws CacheException if there is an error accessing the object held
3007     * in an orderable cache pointer
3008     */

3009    private OrderableCachePointer getCachePointer(AbstractChildObject child) throws PopulateException, CacheException {
3010        if(m_bIsChildrenPopulated == false) {
3011            populateChildrenFromDatabase();
3012        }
3013        OrderableCachePointer result = null;
3014        Iterator iter = m_children.iterator();
3015        boolean bFound = false;
3016        while (iter.hasNext() && bFound == false) {
3017            OrderableCachePointer ptr = (OrderableCachePointer) iter.next();
3018            
3019            if(((AbstractChildObject)ptr.getObject()).getId() == child.getId() &&
3020          ((AbstractChildObject)ptr.getObject()).getClass().equals(child.getClass())) {
3021                bFound = true;
3022                result = ptr;
3023            }
3024        }
3025        
3026        return result;
3027    }
3028
3029    /* (non-Javadoc)
3030     * @see org.openharmonise.rm.dsi.DataStoreObject#getInstanceColumnRef(java.lang.String, boolean)
3031     */

3032    public ColumnRef getInstanceColumnRef(String JavaDoc sColumn, boolean bIsHist)
3033        throws DataStoreException {
3034            ColumnRef returnColRef = null;
3035
3036        if (sColumn.equals(TAG_SUBGROUPS) == true) {
3037            returnColRef = this.getParentChildJoinColumnRef(TAG_CHILDREN);
3038        } else if (
3039            sColumn.equals(TAG_GROUP) == true) {
3040                returnColRef = this.getParentChildJoinColumnRef(sColumn);
3041        }
3042
3043        if (returnColRef != null) {
3044            return returnColRef;
3045        } else {
3046            return super.getInstanceColumnRef(sColumn,bIsHist);
3047        }
3048    }
3049
3050}
3051
Popular Tags