KickJava   Java API By Example, From Geeks To Geeks.

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


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.SelectStatement;
28 import org.openharmonise.rm.*;
29 import org.openharmonise.rm.dsi.*;
30 import org.openharmonise.rm.publishing.*;
31 import org.openharmonise.rm.resources.publishing.Template;
32 import org.w3c.dom.*;
33
34
35 /**
36  * The abstract class for the core objects of Harmonise, handling the very basic data handling for data such as
37  * system identifiers, name and summary and incorporating core functionality to be built on
38  * by implementing classes.
39  *
40  * @author Michael Bell
41  * @version $Revision: 1.5 $
42  *
43  */

44 public abstract class AbstractObject
45     implements Cloneable JavaDoc, Comparable JavaDoc, Publishable, DataStoreObject, CacheableObject {
46     
47     // Constants
48
/**
49      * Constant for a unsaved identifier
50      */

51     public static final int NOTDBSAVED_ID = 0;
52     
53     /**
54      * Constant for a unsaved object key
55      */

56     public static final int NOTDBSAVED_KEY = 0;
57
58     //XML constants
59
/**
60      * HarmoniseObject XML tag name
61      */

62     public static final String JavaDoc TAG_HARMONISE_OBJECT = "HarmoniseObject";
63     
64     /**
65      * Name tag name
66      */

67     public static final String JavaDoc TAG_NAME = "Name";
68     
69     /**
70      * Summary tag name
71      */

72     public static final String JavaDoc TAG_SUMMARY = "Summary";
73     
74     /**
75      * Link tag name
76      */

77     public static final String JavaDoc TAG_LINK = "Link";
78     
79     /**
80      * Link text tag name
81      */

82     public static final String JavaDoc TAG_LINK_TEXT = "LinkText";
83     
84     /**
85      * Link image tag name
86      */

87     public static final String JavaDoc TAG_LINK_IMAGE = "LinkImage";
88     
89     /**
90      * Object key attribute name
91      */

92     public static final String JavaDoc ATTRIB_KEY = "key";
93     
94     /**
95      * Object id attribute name
96      */

97     public static final String JavaDoc ATTRIB_ID = "id";
98     /**
99      * Object name attribute name
100      */

101     public static final String JavaDoc ATTRIB_NAME = "name";
102     
103     /**
104      * Object type attribute name
105      */

106     public static final String JavaDoc ATTRIB_TYPE = "type";
107     
108     /**
109      * Alternative object type attribute
110      */

111     public static final String JavaDoc ATTRIB_OBJECT_TYPE = "objectType";
112     
113     /**
114      * Historical attribute
115      */

116     public static final String JavaDoc ATTRIB_HISTORICAL = "historical";
117
118     //DB constants
119
/**
120      * Id database column name
121      */

122     protected static final String JavaDoc CLMN_ID = "id";
123     
124     /**
125      * Object key databse column name
126      */

127     private static final String JavaDoc CLMN_KEY = "object_key";
128     
129     /**
130      * Object name column name
131      */

132     protected static final String JavaDoc CLMN_NAME = "name";
133     
134     /**
135      * Object summary column name
136      */

137     protected static final String JavaDoc CLMN_SUMMARY = "summary";
138     
139     /**
140      * Object type column name
141      */

142     private static final String JavaDoc CLMN_TYPE = "type";
143     
144     /**
145      * Historical extension for database table names
146      */

147     public static final String JavaDoc EXT_HIST = "_hist";
148
149     // Attributes common to all objects
150
/**
151      * Object id
152      */

153     protected int m_nId = NOTDBSAVED_ID;
154     
155     /**
156      * Object key
157      */

158     protected int m_nObjectKey = NOTDBSAVED_KEY;
159     
160     /**
161      * Object name
162      */

163     protected String JavaDoc m_sName = "";
164     
165     /**
166      * Object summary
167      */

168     protected String JavaDoc m_sSummary = "";
169     
170     /**
171      * Historical flag, <code>true</code> if this is a historical object
172      */

173     private boolean m_bHistorical = false;
174     
175     /**
176      * Type of object, will be the name of the class this should be
177      * instantiated as by default
178      */

179     protected String JavaDoc m_sType;
180     
181     /**
182      * Hashcode value for this object
183      */

184     private int m_nHashcode = 0;
185     
186     /**
187      * Data store interface for this object
188      */

189     protected AbstractDataStoreInterface m_dsi = null;
190     
191     /**
192      * Populated flag, <code>true</code> if this object has been populated
193      * from the database
194      */

195     protected boolean m_bIsPopulated = false;
196     
197     /**
198      * Changed flag, <code>true</code> if this object has been changed
199      * (as compared to the data stored in the database)
200      */

201     protected boolean m_bIsChanged = false;
202     
203     /**
204      * The database table containing this object's data
205      */

206     protected String JavaDoc m_sTable = null;
207     
208     /**
209      * List of cache listeners
210      */

211     private List m_cache_listeners = new ArrayList();
212     
213     /**
214      * Logger for this class
215      */

216     static private Logger m_logger = Logger.getLogger(AbstractObject.class.getName());
217     
218     //initialiser block
219
{
220         m_sType = this.getClass().getName();
221         m_sTable = getDBTableName(); //ensure that table name is set
222
}
223
224     /**
225      * Constructs a new or anonymous instance without an interface
226      * to the database.
227      */

228     public AbstractObject() {
229         super();
230     }
231
232     /**
233      * Standard constructor for a new or anonymous resource,
234      * registering an <code>AbstractDataStoreInterface</code> to use
235      * with all database communications.
236      *
237      * @param con the interface to the database
238      */

239     public AbstractObject(AbstractDataStoreInterface con) {
240         m_dsi = con;
241     }
242
243     /**
244      * Standard constructor for a new or anonymous historical resource,
245      * registering an <code>AbstractDataStoreInterface</code> to use with all
246      * database communications.
247      *
248      * @param con the interface to the database
249      */

250     public AbstractObject(AbstractDataStoreInterface con, boolean bIsHist) {
251         this(con);
252         m_bHistorical = bIsHist;
253     }
254
255     /**
256       * Standard constructor for an existing resource,
257       * registering an <code>AbstractDataStoreInterface</code> to use
258       * with all database communications.
259       *
260       * @param con the interface to the database
261       * @param nId the id of the resource
262      */

263     public AbstractObject(AbstractDataStoreInterface con, int nId) {
264         this(con);
265         m_nId = nId;
266     }
267
268     /**
269      * Standard constructor for an existing resource which may be historical.
270      *
271      * @param con the interface to the database
272      * @param nId the id of the resource
273      * @param nKey the unique key of the resource
274      * @param bIsHist <code>true</code> if the resource is historical
275      */

276     public AbstractObject(
277         AbstractDataStoreInterface con,
278         int nId,
279         int nKey,
280         boolean bIsHist) {
281         this(con, nId);
282         m_bHistorical = bIsHist;
283     }
284
285     /**
286      * Returns <code>true</code> if this resource exists in the database.
287      *
288      * @return <code>true</code> if resource exists
289      */

290     public boolean exists() {
291         boolean bIsExist = false;
292         ResultSet rs = null;
293         try {
294             if(m_nId > NOTDBSAVED_ID || m_nObjectKey > NOTDBSAVED_KEY) {
295                 if(m_bIsPopulated == false) {
296                     
297                     SelectStatement select = new SelectStatement();
298                     
299                     ColumnRef refCol = null;
300                     int nRef = 0;
301                     if(m_bHistorical == false || isKeySupported() == false) {
302                         refCol = getInstanceColumnRef(ATTRIB_ID,m_bHistorical);
303                         nRef = m_nId;
304                     } else {
305                         refCol = getInstanceColumnRef(ATTRIB_KEY,m_bHistorical);
306                         nRef = m_nObjectKey;
307                     }
308                     
309                     select.addSelectColumn(refCol);
310                     select.addWhereCondition(refCol, "=", nRef);
311                     
312                     rs = m_dsi.execute(select);
313                     
314                     if(rs.next()) {
315                         bIsExist = true;
316                     }
317                 } else {
318                     bIsExist = true;
319                 }
320             }
321             
322         } catch (DataStoreException e) {
323             m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
324             bIsExist = false;
325         } catch (SQLException e) {
326             m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
327             bIsExist = false;
328         } finally {
329             if(rs != null) {
330                 try {
331                     rs.close();
332                 } catch (SQLException e) {
333                     m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
334                 }
335             }
336         }
337
338         return bIsExist;
339     }
340
341     /**
342      * Returns the object id.
343      *
344      * @return the id of the object
345      */

346     public int getId() {
347         return m_nId;
348     }
349
350
351     /**
352      * Sets the object's unique identifier key.
353      *
354      * @param nKey the object's unique identifier key
355      */

356     public void setKey(int nKey) {
357         m_nObjectKey = nKey;
358     }
359
360     /**
361      * Returns the unique identifier key
362      *
363      * @return the objects unique identifier key
364      * @throws DataAccessException if an error occurs populating this object
365      */

366     public int getKey() throws DataAccessException {
367         if ((m_nObjectKey == NOTDBSAVED_KEY) && (m_bIsPopulated == false)) {
368             try {
369                 populateFromDatabase();
370             } catch (PopulateException e) {
371                 throw new DataAccessException(e.getLocalizedMessage());
372             }
373
374         }
375
376         return m_nObjectKey;
377     }
378
379     /**
380      * Returns the object name.
381      *
382      * @return the name of the object
383      * @throws DataAccessException if an error occurs populating this object
384      */

385     public String JavaDoc getName() throws DataAccessException {
386         if ((m_sName == null || m_sName.length() == 0)
387             && (m_bIsPopulated == false)) {
388             try {
389                 populateFromDatabase();
390             } catch (PopulateException e) {
391                 throw new DataAccessException("populate error",e);
392             }
393         }
394
395         return m_sName;
396     }
397
398     /**
399      * Sets the object name.
400      *
401      * @param sName the name of the object
402      */

403     public void setName(String JavaDoc sName) throws InvalidNameException {
404         if (m_bIsPopulated) {
405             if (m_sName.equals(sName) == false) {
406                 m_bIsChanged = true;
407             }
408         }
409
410         m_sName = sName;
411     }
412
413     /**
414      * Set the object summary.
415      *
416      * @param sSummary the object summary
417      */

418     public void setSummary(String JavaDoc sSummary) {
419         if (sSummary == null) {
420             sSummary = "";
421         }
422
423         if (m_bIsPopulated) {
424             if ((m_sSummary == null && sSummary != null)
425                 || (m_sSummary.trim().equals(sSummary.trim()) == false)) {
426                 m_bIsChanged = true;
427             }
428         }
429
430         m_sSummary = sSummary;
431     }
432     
433     /**
434      * Sets the data store interface for this object if this object does not already
435      * have an interface to the data store.
436      *
437      * Note: This method is a convenience method for objects created with the empty
438      * constructor, changing the data store interface on an existing object could lead
439      * to unpredictable behaviour. At some point in the future we may support the switching of
440      * datastores such that an object can be populated from one datastore and saved to
441      * another but this is not the case at present.
442      *
443      * @param dsi the data store interface
444      * @throws PopulateException if this object already has a data store interface
445      */

446     public void setDataStoreInterface(AbstractDataStoreInterface dsi) throws PopulateException {
447         if(m_dsi != null && dsi.equals(m_dsi) == false) {
448             throw new PopulateException("Can't switch data store interfaces");
449         }
450         
451         m_dsi = dsi;
452     }
453     
454     /**
455      * Returns the datastore interface associated with this object.
456      *
457      * @return the datastore interface associated with this object
458      */

459     public AbstractDataStoreInterface getDataStoreInterface() {
460         return m_dsi;
461     }
462
463     /**
464      * Returns the object summary.
465      *
466      * @return the object summary
467      * @throws DataAccessException if an error occurs populating this object
468      */

469     public String JavaDoc getSummary() throws DataAccessException {
470         if ((m_sSummary == null || m_sSummary.length() == 0)
471             && !m_bIsPopulated) {
472             try {
473                 populateFromDatabase();
474             } catch (PopulateException e) {
475                 throw new DataAccessException(e.getLocalizedMessage());
476             }
477         }
478
479         return m_sSummary;
480     }
481
482     /**
483      * Sets the type (default class name) for this object.
484      *
485      * @param type the type for this object
486      */

487     public void setType(String JavaDoc type) {
488
489         if (m_bIsPopulated) {
490             if (m_sType.equals(type) == false) {
491                 m_bIsChanged = true;
492             }
493         }
494
495         m_sType = type;
496     }
497
498     /**
499      * Returns the object type (default class name) for this object.
500      *
501      * @return the object type (default class name) for this object
502      * @throws DataAccessException if an error occurs populating this object
503      */

504     public String JavaDoc getType() throws DataAccessException {
505         if ((m_sType.length() == 0) && (m_bIsPopulated == false)) {
506             try {
507                 populateFromDatabase();
508             } catch (PopulateException e) {
509                 throw new DataAccessException(e.getLocalizedMessage());
510             }
511         }
512
513         return m_sType;
514     }
515
516     /**
517      * Sets whether this object is historical.
518      *
519      * @param bIsHistorical The is historical flag
520      */

521     public void setHistorical(boolean bIsHistorical) {
522         this.m_bHistorical = bIsHistorical;
523     }
524
525     /**
526      * Returns <code>true</code> if this object is a historical object.
527      *
528      * @return <code>true</code> if this object is a historical object
529      */

530     public boolean isHistorical() {
531         return m_bHistorical;
532     }
533
534     /**
535      * Returns <code>true</code> if this object's data has been changed (as
536      * compared to the data held in the database).
537      *
538      * @return <code>true</code> if this object's data has been changed
539      * @throws DataAccessException if there is an error populating this object
540      */

541     public boolean isChanged() throws DataAccessException {
542         if (m_bIsPopulated == false && m_bIsChanged == false) {
543             try {
544                 populateFromDatabase();
545             } catch (PopulateException e) {
546                 throw new DataAccessException("Data access error",e);
547             }
548         }
549
550         return m_bIsChanged;
551     }
552
553     /**
554      * Sets the object changed flag.
555      *
556      * @param bIsChanged <code>true</code> to set this object as having been changed
557      */

558     public void setIsChanged(boolean bIsChanged) {
559         m_bIsChanged = bIsChanged;
560     }
561
562     /* (non-Javadoc)
563      * @see java.lang.Object#equals(java.lang.Object)
564      */

565     public boolean equals(Object JavaDoc obj) {
566         boolean bReturn = false;
567
568         try {
569             populateFromDatabase();
570         } catch (PopulateException e) {
571             //rather than throwing a RuntimeException(), I'm
572
//electing to do nothing here - log it though
573
m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
574         }
575
576         if (obj instanceof AbstractObject) {
577
578             if (this == obj) {
579                 bReturn = true;
580             } else if (
581                 obj.getClass().getName().equals(getClass().getName())
582                     == true) {
583                 AbstractObject objCompare = (AbstractObject) obj;
584
585                 try {
586                     if ((this.getKey() != 0) && (objCompare.getKey() != 0)) {
587                         if (m_nObjectKey == objCompare.getKey()) {
588                             bReturn = true;
589                         }
590                     } else {
591                         try {
592                             if (m_sName.equals(objCompare.getName())) {
593                                 bReturn = true;
594                             }
595                         } catch (Exception JavaDoc e) {
596                         }
597                     }
598                 } catch (Exception JavaDoc e) {
599                     throw new RuntimeException JavaDoc(e.getMessage());
600                 }
601             }
602
603         }
604
605         return bReturn;
606     }
607
608     /* (non-Javadoc)
609      * @see java.lang.Object#hashCode()
610      */

611     public int hashCode() {
612
613         if (m_nHashcode == 0) {
614             int nHash = 17;
615
616             try {
617                 populateFromDatabase();
618             } catch (PopulateException e) {
619                 //rather than throwing a RuntimeException(), I'm
620
//electing to do nothing here - log it though
621
m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
622             }
623
624             nHash = 37 * nHash + m_nId;
625             nHash = 37 * nHash + m_nObjectKey;
626             if (m_sName != null) {
627                 nHash = 37 * nHash + m_sName.hashCode();
628             }
629             if (m_sSummary != null) {
630                 nHash = 37 * nHash + m_sSummary.hashCode();
631             }
632             m_nHashcode = nHash;
633         }
634
635         return m_nHashcode;
636     }
637
638     /* (non-Javadoc)
639      * @see org.openharmonise.rm.publishing.Publishable#populate(org.w3c.dom.Element, org.openharmonise.rm.publishing.State)
640      */

641     public void populate(Element xmlElement, State state)
642         throws PopulateException {
643         String JavaDoc sTagName = xmlElement.getTagName();
644         Text txt = null;
645         String JavaDoc sTemp = null;
646
647         if (sTagName.equals(getTagName()) == true) {
648             sTemp = xmlElement.getAttribute(ATTRIB_ID);
649
650             if (!sTemp.equals("")) {
651                 m_nId = Integer.parseInt(sTemp);
652             }
653
654             NodeList nodes = xmlElement.getChildNodes();
655             List postponedNodes = new Vector();
656
657             for (int i = 0; i < nodes.getLength(); i++) {
658                 if (nodes.item(i).getNodeType() != Node.ELEMENT_NODE) {
659                     continue;
660                 }
661
662                 Element el = null;
663                 try {
664                     el = (Element) nodes.item(i);
665                     populate(el, state);
666                 } catch (PopulateDependencyException e) {
667                     postponedNodes.add(el);
668                 }
669             }
670             for (int i = 0; i < postponedNodes.size(); i++) {
671                 Element el = (Element)postponedNodes.get(i);
672                 populate(el, state);
673             }
674         } else if (sTagName.equals(TAG_NAME)) {
675             txt = (Text) xmlElement.getFirstChild();
676             try {
677                 setName(txt.getNodeValue());
678             } catch (InvalidNameException e) {
679                 throw new PopulateException(e);
680             }
681         } else if (sTagName.equals(TAG_SUMMARY)) {
682             txt = (Text) xmlElement.getFirstChild();
683             setSummary(txt.getNodeValue());
684         }
685     }
686
687     /* (non-Javadoc)
688      * @see org.openharmonise.rm.publishing.Publishable#publish(org.openharmonise.rm.resources.publishing.Template, org.openharmonise.rm.publishing.HarmoniseOutput, org.openharmonise.rm.publishing.State)
689      */

690     public Element publish(Template template, HarmoniseOutput xmlDoc, State state)
691         throws PublishException {
692         Element resultEl = null;
693
694         try {
695
696             resultEl =
697                 publish(template.getTemplateRootElement(), xmlDoc, state);
698         } catch (DataAccessException de){
699             throw new PublishException(de.getLocalizedMessage(),de);
700         } catch (Exception JavaDoc e) {
701             throw new PublishException(e.getLocalizedMessage(),e);
702         }
703
704         return resultEl;
705     }
706
707     /* (non-Javadoc)
708      * @see org.openharmonise.rm.publishing.Publishable#publish(org.w3c.dom.Element, org.openharmonise.rm.publishing.HarmoniseOutput, org.openharmonise.rm.publishing.State)
709      */

710     public Element publish(Element topEl, HarmoniseOutput xmlDoc, State state)
711         throws PublishException {
712         Element docEl = null;
713         NodeList nodes = null;
714         Text txt = null;
715         String JavaDoc sTagName = topEl.getTagName();
716
717         try {
718
719             if (topEl.getTagName().equals(getTagName()) || topEl.getTagName().equals(TAG_HARMONISE_OBJECT)) {
720                 docEl = xmlDoc.createElement(getTagName());
721
722                 docEl.setAttribute(ATTRIB_ID, Integer.toString(m_nId));
723
724                 nodes = topEl.getChildNodes();
725             } else if (sTagName.equals(TAG_NAME)) {
726                 docEl = xmlDoc.createElement(sTagName);
727                 txt = xmlDoc.createTextNode(getName());
728                 docEl.appendChild(txt);
729                 xmlDoc.copyChildren(docEl, topEl, new Vector());
730             } else if (sTagName.equals(TAG_SUMMARY)) {
731                 docEl = xmlDoc.createElement(sTagName);
732                 txt = xmlDoc.createTextNode(getSummary());
733                 docEl.appendChild(txt);
734                 xmlDoc.copyChildren(docEl, topEl, new Vector());
735             } else if (
736                 sTagName.equals(TAG_LINK)
737                     || sTagName.equals(TAG_LINK_TEXT)
738                     || sTagName.equals(TAG_LINK_IMAGE)) {
739                 // allow link text to only contain text, rather than a publishable object,
740
// if it contains text copy this only.
741
// note we check that it's a link_text tag, and that it has only *one*
742
// child node (of type text), because <LinkText> <DocumentTitle/>
743
// </LinkText> counts the whitespace as a child text node
744
// that is <LinkText>Help</LinkText> works.
745
Node childnode = topEl.getFirstChild();
746
747                 if ((sTagName.equals(TAG_LINK_TEXT)
748                     || sTagName.equals(TAG_LINK_IMAGE))
749                     && (childnode.getNodeType() == Node.TEXT_NODE)
750                     && ((topEl.getChildNodes()).getLength() == 1)) {
751                     docEl = (Element) xmlDoc.copyNode(topEl);
752                 } else {
753                     docEl = xmlDoc.createElement(sTagName);
754
755                     NodeList childnodes = topEl.getChildNodes();
756
757                     for (int k = 0; k < childnodes.getLength(); k++) {
758                         if (childnodes.item(k).getNodeType()
759                             == Node.ELEMENT_NODE) {
760                             Element tempEl =
761                                 publish(
762                                     (Element) childnodes.item(k),
763                                     xmlDoc,
764                                     state);
765
766                             if (tempEl != null) {
767                                 docEl.appendChild(tempEl);
768                             }
769                         }
770                     }
771                 }
772             }
773
774             // recurse through the children if there are any
775
Element formEl;
776             Element el;
777
778             if (nodes != null) {
779                 for (int i = 0; i < nodes.getLength(); i++) {
780                     if (nodes.item(i).getNodeType() != Node.ELEMENT_NODE) {
781                         continue;
782                     }
783
784                     formEl = (Element) nodes.item(i);
785                     el = publish(formEl, xmlDoc, state);
786
787                     if (el != null) {
788                         docEl.appendChild(el);
789                     }
790                 }
791             }
792
793         } catch (DataAccessException e) {
794             throw new PublishException(e.getLocalizedMessage(),e);
795         } catch (Exception JavaDoc ex) {
796             throw new PublishException(ex.getLocalizedMessage(),ex);
797         }
798
799         return docEl;
800     }
801
802     /* (non-Javadoc)
803      * @see org.openharmonise.rm.dsi.DataStoreObject#getInstanceColumnRef(java.lang.String, boolean)
804      */

805     public ColumnRef getInstanceColumnRef(String JavaDoc sColumn, boolean bIsHist)
806         throws DataStoreException {
807         String JavaDoc sDBTable = getTableName(bIsHist);
808
809         return getObjectColumnRef(sDBTable, sColumn);
810     }
811
812     /**
813      * Returns a column reference appropriate for the given
814      * <code>AbstractObject</code> and column name.
815      *
816      * @param obj an <code>AbstractObject</code> object
817      * @param sColumn the column, tag or attribute name
818      * @return the column reference corresponding to the object and column
819      * name given
820      * @throws DataStoreException if an error occurs
821      */

822     public static ColumnRef getColumnRef(AbstractObject obj, String JavaDoc sColumn)
823         throws DataStoreException {
824         String JavaDoc sTable = obj.getDBTableName();
825
826         return getObjectColumnRef(sTable, sColumn);
827     }
828
829     /**
830      * Returns a column reference appropriate for the given
831      * <code>AbstractObject</code> and column name.
832      *
833      * @param sClassname the class name of an <code>AbstractObject</code>
834      * @param sColumn the column, tag or attribute name
835      * @return the column reference corresponding to the class name and column
836      * name given
837      * @throws DataStoreException if an error occurs
838      */

839     public static ColumnRef getColumnRef(String JavaDoc sClassname, String JavaDoc sColumn)
840         throws DataStoreException {
841         return getColumnRef(sClassname, sColumn, false);
842     }
843
844     /**
845      * Returns a column reference appropriate for the given
846      * parameters.
847      *
848      * @param sClassname the class name of an <code>AbstractObject</code>
849      * @param sColumn the column, tag or attribute name
850      * @param bHist <code>true</code> if the column reference is
851      * associated with a historical object
852      * @return the column reference corresponding to the parameters
853      * @throws DataStoreException if an error occurs
854      */

855     public static ColumnRef getColumnRef(
856         String JavaDoc sClassname,
857         String JavaDoc sColumn,
858         boolean bHist)
859         throws DataStoreException {
860         ColumnRef returnColRef = null;
861         String JavaDoc sTable = getTableName(sClassname,bHist);
862
863         return getObjectColumnRef(sTable, sColumn);
864     }
865     
866     /**
867      * Returns the table name for the object of the class name given, taking account
868      * for whether the historical table is needed or not.
869      *
870      * @param sClassname the class name of an <code>AbstractObject</code>
871      * @param bHist <code>true</code> if the table name is
872      * associated with a historical object
873      * @return the table name for the object
874      * @throws DataStoreException if an error occurs
875      */

876     public static String JavaDoc getTableName(String JavaDoc sClassname,boolean bHist) throws DataStoreException {
877         String JavaDoc sTable = null;
878
879         try {
880             //check this class is an AbstractObject implementation
881
Class JavaDoc clss = Class.forName(sClassname);
882             Class JavaDoc absObjClass = AbstractObject.class;
883             if (absObjClass.isAssignableFrom(clss) == false) {
884                 throw new DataStoreException("Classname isn't AbstractObject");
885             }
886
887             sTable = DatabaseInfo.getInstance().getTableName(sClassname);
888
889             if (bHist == true) {
890                 sTable = sTable + EXT_HIST;
891             }
892         } catch (ClassNotFoundException JavaDoc e) {
893             throw new DataStoreException(
894                 "Unable to get table name for class" + e.getLocalizedMessage());
895         }
896         
897         return sTable;
898     }
899
900
901     /* (non-Javadoc)
902      * @see java.lang.Object#clone()
903      */

904     public Object JavaDoc clone() {
905         try {
906             if (!m_bIsPopulated) {
907                 try {
908                     populateFromDatabase();
909                 } catch (PopulateException e) {
910                     throw new DataAccessException(e.getLocalizedMessage());
911                 }
912             }
913
914             AbstractObject other = (AbstractObject) super.clone();
915
916             return other;
917         } catch (CloneNotSupportedException JavaDoc e) {
918             m_logger.log(Level.WARNING, e.getMessage(), e);
919
920             return null;
921         } catch (Exception JavaDoc e) {
922             m_logger.log(Level.WARNING, e.getMessage(), e);
923
924             return null;
925         }
926     }
927
928     /**
929      * Clears all data contained in object, the object does however
930      * retain its id.
931      *
932      */

933     public void clear() {
934         m_nObjectKey = NOTDBSAVED_KEY;
935         m_sName = "";
936         m_sSummary = "";
937
938         m_bHistorical = false;
939         m_bIsPopulated = false;
940         m_bIsChanged = false;
941     }
942
943     /* (non-Javadoc)
944      * @see java.lang.Comparable#compareTo(java.lang.Object)
945      */

946     public int compareTo(Object JavaDoc obj) {
947         int nCompare = 0;
948         try {
949             String JavaDoc sName = getName();
950     
951             AbstractObject abObj = (AbstractObject) obj;
952
953             nCompare = sName.compareTo(abObj.getName());
954         } catch (DataAccessException e) {
955             m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
956         }
957
958         return nCompare;
959     }
960
961     /* (non-Javadoc)
962      * @see org.openharmonise.rm.dsi.DataStoreObject#getDBTableName()
963      */

964     public abstract String JavaDoc getDBTableName();
965
966     /*----------------------------------------------------------------------------
967     Protected Functions
968     -----------------------------------------------------------------------------*/

969
970     /**
971      * Returns a collection of column refs representing the object's core data
972      * @return a collection of column refs representing the object's core data
973      * @throws DataStoreException if an error occurs getting the column references
974      */

975     protected static Collection getCoreColumnRefs(String JavaDoc sClassname)
976         throws DataStoreException {
977         ArrayList list = new ArrayList();
978
979         list.add(getColumnRef(sClassname, TAG_NAME));
980         list.add(getColumnRef(sClassname, TAG_SUMMARY));
981         list.add(getColumnRef(sClassname, ATTRIB_KEY));
982
983         return list;
984     }
985
986     /**
987      * Returns the historical table name for this object.
988      *
989      * @return the historical table name for this object
990      */

991     protected String JavaDoc getHistoricalDBTableName() {
992         return m_sTable + EXT_HIST;
993     }
994     
995     /**
996      * Returns the database table name for an object of this object's type.
997      *
998      * @param bIsHist <code>true</code> if the historical table is needed
999      * @return the database table name for an object of this object's type
1000     */

1001    protected String JavaDoc getTableName(boolean bIsHist) {
1002        String JavaDoc sTable = m_sTable;
1003        
1004        if(bIsHist == true) {
1005            sTable = m_sTable + EXT_HIST;
1006        }
1007        
1008        return sTable;
1009    }
1010
1011    /**
1012     * Ensures that this object is fully poplated from the database.
1013     * @throws PopulateException
1014     */

1015    protected void fullPopulate() throws PopulateException {
1016        populateFromDatabase();
1017    }
1018
1019    /**
1020     * Populates this object's core data from the database.
1021     *
1022     * @throws PopulateException if an error occurs getting data from database
1023     */

1024    protected synchronized void populateFromDatabase() throws PopulateException {
1025        if (m_nId != NOTDBSAVED_ID && m_bIsPopulated == false) {
1026            
1027            if(m_logger.isLoggable(Level.FINER)) {
1028                m_logger.logp(Level.FINER, this.getClass().getName(), "populateFromDatabase", "populating object, id - " + m_nId + ", key - " + m_nObjectKey);
1029            }
1030            
1031            if (isHistorical() && (m_nObjectKey == NOTDBSAVED_KEY && isKeySupported())) {
1032                throw new PopulateException("Can't populate hisorical version without knowing object key");
1033            }
1034
1035            ResultSet rs = null;
1036
1037            try {
1038
1039                SelectStatement select = new SelectStatement();
1040
1041                addColumnsToPopulateQuery(select, m_bHistorical);
1042
1043                if (m_bHistorical == false || isKeySupported() == false) {
1044                    select.addWhereCondition(
1045                        getInstanceColumnRef(ATTRIB_ID, m_bHistorical),
1046                        "=",
1047                        m_nId);
1048                } else {
1049                    select.addWhereCondition(
1050                        getInstanceColumnRef(ATTRIB_KEY, m_bHistorical),
1051                        "=",
1052                        m_nObjectKey);
1053                }
1054
1055                rs = m_dsi.execute(select);
1056
1057                boolean bResultFound = false;
1058                // flag to check if there were any results found
1059

1060                while (rs.next() == true) {
1061                    populateFromResultSetRow(
1062                        rs,
1063                        select);
1064
1065                    if (bResultFound == false) {
1066                        bResultFound = true;
1067                    }
1068                }
1069
1070                if (bResultFound == false) {
1071                    throw new ObjectNotFoundException(
1072                        "Could not find a "
1073                            + getClass().getName()
1074                            + " object with id = "
1075                            + getId());
1076                    
1077                }
1078                
1079
1080                m_bIsPopulated = true; // results were found
1081
} catch (DataStoreException ds_e) {
1082                throw new PopulateException(ds_e);
1083            } catch (SQLException sql_e) {
1084                throw new PopulateException(sql_e);
1085            } finally {
1086
1087                if (rs != null) {
1088                    try {
1089                        rs.close();
1090                    } catch (SQLException e) {
1091                        throw new PopulateException(e.getLocalizedMessage());
1092                    }
1093                }
1094            }
1095
1096        } else {
1097            m_bIsPopulated = true;
1098        }
1099    }
1100
1101    /**
1102     * Returns <code>true</code> if this object has a unique identifier key
1103     * as well as the identifier attribute.
1104     *
1105     * Note: This depends on how historical versions of this object are
1106     * handled. If all versions of the object need to have the same id, to
1107     * allow a consistent logical id, the key is used to identify versions.
1108     *
1109     * @return <code>true</code> if this object has a unique identifier key
1110     * as well as the identifier attribute
1111     */

1112    protected abstract boolean isKeySupported();
1113
1114    /**
1115     * Adds columns to the select query for population of the object.
1116     *
1117     * Note: this method is used by <code>populateFromDatabase</code>
1118     * to construct its query.
1119     *
1120     * @param select the select statment to add columns to
1121     * @throws DataStoreException if an error occurs building the select statement
1122     */

1123    protected void addColumnsToPopulateQuery(
1124        SelectStatement select,
1125        boolean bIsHist)
1126        throws DataStoreException {
1127
1128        try {
1129            ColumnRefCache cache = ColumnRefCache.getInstance();
1130            
1131            select.addSelectColumn(cache.getColumnRef(this,TAG_NAME, bIsHist));
1132            select.addSelectColumn(cache.getColumnRef(this,TAG_SUMMARY, bIsHist));
1133            select.addSelectColumn(cache.getColumnRef(this,ATTRIB_TYPE, bIsHist));
1134            select.addSelectColumn(cache.getColumnRef(this,ATTRIB_KEY, bIsHist));
1135            
1136        } catch (CacheException e) {
1137            throw new DataStoreException("Cache error",e);
1138        }
1139
1140    }
1141
1142    /**
1143     * Returns <code>true</code> if object has been populated.
1144     *
1145     * @return <code>true</code> if object has been populated
1146     */

1147    protected boolean isPopulated() {
1148        return m_bIsPopulated;
1149    }
1150
1151    /**
1152     * Populates this object from the given result set.
1153     *
1154     * Note: this method must only handle data in the current row
1155     *
1156     * @param rs the result set
1157     * @param select the select statement used to generate the result set
1158     *
1159     * @throws PopulateException if an error occurs getting data from the result set
1160     */

1161    protected void populateFromResultSetRow(ResultSet rs, SelectStatement select)
1162        throws PopulateException {
1163        if (isPopulated() == false) {
1164            String JavaDoc sTemp = "";
1165
1166            try {
1167                ColumnRefCache cache = ColumnRefCache.getInstance();
1168                
1169                ColumnRef nameCol = cache.getColumnRef(this,CLMN_NAME,m_bHistorical);
1170                
1171                if (select.containsSelectColumn(nameCol) == true) {
1172                    
1173                    sTemp = rs.getString(select.getResultSetIndex(nameCol));
1174
1175                    if ((sTemp != null) && (sTemp.length() > 0)) {
1176                        if ((m_sName == null) || (m_sName.length() == 0)) {
1177                            m_sName = sTemp;
1178                        } else if (m_sName.equals(sTemp) == false) {
1179                            m_bIsChanged = true;
1180                        }
1181                    }
1182                }
1183
1184                ColumnRef summaryCol = cache.getColumnRef(this,CLMN_SUMMARY,m_bHistorical);
1185                if (select.containsSelectColumn(summaryCol) == true) {
1186                    sTemp = rs.getString(select.getResultSetIndex(summaryCol));
1187
1188                    if ((sTemp != null) && (sTemp.length() > 0)) {
1189                        if ((m_sSummary == null)
1190                            || (m_sSummary.length() == 0)) {
1191                            m_sSummary = sTemp;
1192                        } else if (m_sSummary.equals(sTemp) == false) {
1193                            m_bIsChanged = true;
1194                        }
1195                    }
1196                }
1197
1198                ColumnRef typeCol = cache.getColumnRef(this,CLMN_TYPE,m_bHistorical);
1199                
1200                if (select.containsSelectColumn(typeCol) == true) {
1201                    sTemp = rs.getString(select.getResultSetIndex(typeCol));
1202
1203                    if ((sTemp != null) && (sTemp.length() > 0)) {
1204                        setType(sTemp);
1205                    }
1206                }
1207
1208                ColumnRef keyCol = cache.getColumnRef(this,CLMN_KEY,m_bHistorical);
1209                if (select.containsSelectColumn(keyCol) == true) {
1210                    int nKey = rs.getInt(select.getResultSetIndex(keyCol));
1211
1212                    if (nKey > 0) {
1213                        setKey(nKey);
1214                    }
1215                }
1216
1217            } catch (SQLException e) {
1218                try {
1219                    System.out.println("!!" + m_dsi.getSelectStatement(select));
1220                } catch (DataStoreException e1) {
1221                    m_logger.log(Level.WARNING, e.getLocalizedMessage(), e1);
1222                }
1223                
1224                throw new PopulateException("SQL error",e);
1225            } catch (CacheException e) {
1226                throw new PopulateException("Cache error getting col ref",e);
1227            }
1228        }
1229    }
1230
1231    /**
1232     * Marks an object as a new object, correctly setting all of the
1233     * appropriate flags.
1234     *
1235     * @throws PopulateException if an error occurs
1236     */

1237    protected void markAsNew() throws PopulateException {
1238        m_nId = NOTDBSAVED_ID;
1239        m_bIsPopulated = true;
1240        m_bIsChanged = true;
1241    }
1242    
1243
1244    /**
1245     * Set method for id, here for completeness, should use constructor.
1246     *
1247     * Note: Once an object's id has been assigned within the framework it can not
1248     * be reassigned. This method should only be used in conjunction with the empty
1249     * constructor to create an instance of an object with a specific identifier.
1250     *
1251     * @param nId The id of the object
1252     */

1253    public void setId(int nId) {
1254        if (isPopulated() == true) {
1255          if (m_nId != NOTDBSAVED_ID && nId != m_nId) {
1256            m_bIsChanged = true;
1257          }
1258        }
1259
1260        m_nId = nId;
1261    }
1262
1263    /**
1264     * Returns a column reference of the correct type given the table and column
1265     * identifier. The column identifier may be an XML tag.
1266     *
1267     * @param sDBTable the database table
1268     * @param sColumn the column, tag or attribute name
1269     * @return the appropriate column reference
1270     * @throws DataStoreException if an error occurs
1271     * @throws InvalidColumnReferenceException if the given column name is
1272     * invalid
1273     */

1274    protected static ColumnRef getObjectColumnRef(
1275        String JavaDoc sDBTable,
1276        String JavaDoc sColumn)
1277        throws DataStoreException {
1278        ColumnRef returnColRef = null;
1279
1280        if (sColumn.equals(TAG_NAME) == true
1281            || sColumn.equals(CLMN_NAME) == true) {
1282            returnColRef = new ColumnRef(sDBTable, CLMN_NAME, ColumnRef.TEXT);
1283        } else if (
1284            sColumn.equals(TAG_SUMMARY) == true
1285                || sColumn.equals(CLMN_SUMMARY) == true) {
1286            returnColRef =
1287                new ColumnRef(sDBTable, CLMN_SUMMARY, ColumnRef.TEXT);
1288        } else if (
1289            sColumn.equals(ATTRIB_KEY) == true
1290                || sColumn.equals(CLMN_KEY) == true) {
1291            returnColRef = new ColumnRef(sDBTable, CLMN_KEY, ColumnRef.NUMBER);
1292        } else if (
1293            sColumn.equals(ATTRIB_ID) == true
1294                || sColumn.equals(CLMN_ID) == true) {
1295            returnColRef = new ColumnRef(sDBTable, CLMN_ID, ColumnRef.NUMBER);
1296        } else if (
1297            sColumn.equals(ATTRIB_OBJECT_TYPE) == true
1298                || sColumn.equals(ATTRIB_TYPE) == true
1299                || sColumn.equals(CLMN_TYPE) == true) {
1300            returnColRef = new ColumnRef(sDBTable, CLMN_TYPE, ColumnRef.TEXT);
1301        }
1302
1303        if (returnColRef == null) {
1304            throw new InvalidColumnReferenceException(sColumn);
1305        }
1306
1307        return returnColRef;
1308    }
1309    
1310    /* (non-Javadoc)
1311     * @see org.openharmonise.commons.cache.CacheableObject#addCacheListener(org.openharmonise.commons.cache.CacheListener)
1312     */

1313    public void addCacheListener(CacheListener listener) {
1314        m_cache_listeners.add(listener);
1315
1316    }
1317    
1318    /* (non-Javadoc)
1319     * @see org.openharmonise.commons.cache.CacheableObject#getCacheListeners()
1320     */

1321    public List getCacheListeners() {
1322        return m_cache_listeners;
1323    }
1324    
1325    /* (non-Javadoc)
1326     * @see org.openharmonise.commons.cache.CacheableObject#removeCacheListener(org.openharmonise.commons.cache.CacheListener)
1327     */

1328    public void removeCacheListener(CacheListener listener) {
1329        m_cache_listeners.remove(listener);
1330
1331    }
1332
1333    /* (non-Javadoc)
1334     * @see org.openharmonise.commons.cache.CacheableObject#notifyCacheListeners()
1335     */

1336    public void notifyCacheListeners() {
1337        for (Iterator iter = m_cache_listeners.iterator(); iter.hasNext();) {
1338            CacheListener listener = (CacheListener) iter.next();
1339            listener.objectRemovedFromCache(this);
1340        }
1341
1342    }
1343}
Popular Tags