KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openharmonise > rm > metadata > AbstractPropertyInstance


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.metadata;
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.commons.xml.XMLUtils;
29 import org.openharmonise.rm.*;
30 import org.openharmonise.rm.dsi.DataStoreObject;
31 import org.openharmonise.rm.factory.*;
32 import org.openharmonise.rm.publishing.*;
33 import org.openharmonise.rm.resources.*;
34 import org.openharmonise.rm.resources.lifecycle.EditException;
35 import org.openharmonise.rm.resources.metadata.properties.*;
36 import org.openharmonise.rm.resources.metadata.properties.domains.Domain;
37 import org.openharmonise.rm.resources.publishing.Template;
38 import org.w3c.dom.*;
39
40
41 /**
42  * Abstract class to handle the basic functionality for an instance of a
43  * <code>Property</code>.
44  *
45  * @author Michael Bell
46  * @version $Revision: 1.5 $
47  *
48  */

49 public abstract class AbstractPropertyInstance
50     implements Cloneable JavaDoc, DataStoreObject, Publishable {
51     
52     /**
53      * The comment associated with this version of the property instance
54      */

55     private String JavaDoc m_sVersionComment;
56     
57     /**
58      * The suffix attached to the historical property instance database
59      * table name
60      */

61     protected static final String JavaDoc EXT_HIST = "_hist";
62     
63     /**
64      * Array of valid operators which can be used for comparing against
65      * property instance values
66      */

67     private static final String JavaDoc[] saValidOperators =
68         {
69             ">",
70             "<",
71             "=",
72             ">=",
73             "<=",
74             "!=",
75             "<>",
76             "IN",
77             "CONTAINS",
78             "BETWEEN",
79             "STARTS_WITH",
80             "LOGINEQUALS",
81             "LOGINNOT",
82             "NOT IN",
83             "NULL" };
84
85     // DB constants
86
/**
87      * Id database column name
88      */

89     protected static final String JavaDoc CLMN_ID = "id";
90     
91     /**
92      * Profile id database column name
93      */

94     protected static final String JavaDoc CLMN_PROFILE_ID = "profile_id";
95     
96     /**
97      * Property id database column name
98      */

99     protected static final String JavaDoc CLMN_PROPERTY_ID = "property_id";
100     
101     /**
102      * Version comment database column name
103      */

104     protected static final String JavaDoc CLMN_VERSION_COMMENT = "version_comment";
105     
106     /**
107      * Property instance id sequence name
108      */

109     protected static final String JavaDoc SEQ_PROFILE_DATA = "seq_profile_data";
110
111     //XML constants
112
/**
113      * Object type attribute name
114      */

115     public static final String JavaDoc ATTRIB_OBJECT_TYPE = "objectType";
116     
117     /**
118      * Property id attribute name
119      */

120     public static final String JavaDoc ATTRIB_PROPERTY_ID = "propId";
121     
122     /**
123      * Operator attribute name
124      */

125     public static final String JavaDoc ATTRIB_OPERATOR = "operator";
126     
127     /**
128      * Property instance values tag name
129      */

130     public static final String JavaDoc TAG_PROP_INSTANCE_VALUES =
131         "PropertyInstanceValues";
132     /**
133      * Property instance tag name
134      */

135     public static final String JavaDoc TAG_PROPERTYINSTANCE = "PropertyInstance";
136     
137     /**
138      * Generic property instance value tag name
139      */

140     public static final String JavaDoc TAG_VALUE = "Value";
141     
142     /**
143      * Attach XML element name
144      */

145     public static final String JavaDoc TAG_ATTACH = "Attach";
146     
147     /**
148      * Detach XML element name
149      */

150     public static final String JavaDoc TAG_DETACH = "Detach";
151
152     // Attributes
153
/**
154      * The owning profile
155      */

156     //TODO this creates a cyclic dependency and so another solution
157
//would be preferable
158
protected Profile m_profile = null;
159     
160     /**
161      * A weak reference to the <code>Property</code> this instance is an
162      * instance of
163      */

164     protected CachePointer m_property_ptr = null;
165     
166     /**
167      * The list of property instance values
168      */

169     protected List m_values = null;
170     
171     /**
172      * The list of property instance values to be saved on the next save
173      * operation
174      */

175     protected List m_values2Add = null;
176     
177     /**
178      * The list of property instance values to be removed on the
179      * next save operation
180      */

181     protected List m_values2Remove = null;
182     
183     /**
184      * The list of ids corresponding to the current list of
185      * property instance values
186      */

187     protected List m_valueIds = null;
188     
189     /**
190      * The current operator to be used in any value comparisons
191      */

192     protected String JavaDoc m_sOperator = "=";
193     
194     /**
195      * <code>boolean</code> flag which indicates whether this property instance
196      * can be saved to the database
197      */

198     protected boolean m_bIsTemporary = false;
199     
200     /**
201      * The data store interface
202      */

203     protected AbstractDataStoreInterface m_dsi = null;
204     
205     /**
206      * <code>boolean</code> flag which indicates whether any data has been
207      * changed since the object was populated from the database
208      */

209     private boolean m_bIsChanged = false;
210     
211     /**
212      * <code>boolean</code> flag which indicates whether this object
213      * has been populated from the database
214      */

215     private boolean m_bIsPopulated = false;
216     
217     /**
218      * <code>boolean</code> flag which indicates whether this object is
219      * a historical version
220      */

221     private boolean m_bIsHistorical = false;
222     
223     /**
224      * The database table holding data for this property instance
225      */

226     protected String JavaDoc m_sDataTable = null;
227     
228     /**
229      * <code>String</code> constant for unknown data values
230      */

231     private static final String JavaDoc CONST_UNKNOWN = "unknown";
232     
233     /**
234      * Logger for this class
235      */

236     private static final Logger m_logger = Logger.getLogger(AbstractPropertyInstance.class.getName());
237
238     //initialiser block
239
{
240         m_values = new Vector();
241         m_valueIds = new Vector();
242         m_values2Add = new Vector();
243         m_values2Remove = new Vector();
244     }
245
246     /**
247      * Constructs a property instance
248      */

249     public AbstractPropertyInstance() {
250     }
251
252     /**
253      * Constructs a property instance with an interface to the data store.
254      *
255      * @param dbint the data store interface
256      */

257     public AbstractPropertyInstance(AbstractDataStoreInterface dbint) {
258         m_dsi = dbint;
259     }
260
261     /**
262       * Constructs a property instance with an interface to
263       * the data store and a reference to the <code>Profile</code> which
264       * will contain this property instance.
265       *
266       * @param dbintrf the data store interface
267       * @param profile the owner <code>Profile</code>
268       */

269     public AbstractPropertyInstance(
270         AbstractDataStoreInterface dbintrf,
271         Profile profile) {
272         this(dbintrf);
273         m_profile = profile;
274         setDBTable(profile);
275     }
276
277     /**
278      * Constructs a property instance of the specified <code>Property</code>
279      * with an interface to the data store.
280      *
281      * @param dbintrf the data store interface
282      * @param prop the <code>Property</code> that this object is an instance of
283      */

284     public AbstractPropertyInstance(
285         AbstractDataStoreInterface dbintrf,
286         Property prop) {
287         this(dbintrf);
288
289         try {
290             m_property_ptr =
291                 CacheHandler.getInstance(m_dsi).getCachePointer(prop);
292         } catch (CacheException e) {
293             m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
294         }
295     }
296
297     /**
298       * Constructs a property instance with an interface to the data store,
299       * a reference to the <code>Profile</code> which will contain this
300       * property instance and a reference to the <code>Property</code>
301       * identified by the specified id.
302       *
303       * @param dbintrf the data store interface
304       * @param nPropertyId the id of the <code>Property</code> that this object is an instance of
305       * @param profile the owner <code>Profile</code>
306       */

307     public AbstractPropertyInstance(
308         AbstractDataStoreInterface dbintrf,
309         int nPropertyId,
310         Profile profile) {
311         this(dbintrf);
312         Property prop = new Property(dbintrf, nPropertyId);
313         try {
314             m_property_ptr =
315                 CacheHandler.getInstance(m_dsi).getCachePointer(prop);
316         } catch (CacheException e) {
317             m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
318         }
319         m_profile = profile;
320         setDBTable(profile);
321     }
322
323     /**
324       * Constructs a property instance with an interface to the data store,
325       * a reference to the <code>Profile</code> which will contain this
326       * property instance and a reference to the <code>Property</code>
327       * which this object is an instance of.
328       *
329       * @param dbintrf the data store interface
330       * @param property the <code>Property</code>
331       * @param profile the owner <code>Profile</code>
332       */

333     public AbstractPropertyInstance(
334         AbstractDataStoreInterface dbintrf,
335         Property property,
336         Profile profile) {
337         this(dbintrf, property);
338         m_profile = profile;
339         setDBTable(profile);
340     }
341
342     /**
343      * Sets profile data table name.
344      *
345      * @param profile the profile data table name
346      */

347     abstract protected void setDBTable(Profile profile);
348
349     /**
350      * Returns the <code>Property</code> for which this object is
351      * an instance.
352      *
353      * @return the <code>Property</code> for which this object is
354      * an instance
355      */

356     public Property getProperty() throws DataAccessException {
357         Property prop = null;
358         try {
359             if (m_property_ptr != null) {
360                 prop = (Property) m_property_ptr.getObject();
361                 
362                 if(prop.exists() == false) {
363                     m_logger.logp(Level.INFO, this.getClass().getName(), "getProperty", "Property " + m_property_ptr.getKey() + " for property instance no longer exists");
364                     prop = null;
365                 }
366             }
367
368         } catch (CacheException e) {
369             throw new DataAccessException(e.getLocalizedMessage(), e);
370         }
371
372         return prop;
373     }
374
375     /**
376      * Sets the <code>Property</code> for which this object is
377      * an instance.
378      *
379      * @param prop the <code>Property</code> for which this object is
380      * an instance
381      */

382     public void setProperty(Property prop) throws PopulateException {
383         try {
384             m_property_ptr =
385                 CacheHandler.getInstance(m_dsi).getCachePointer(prop);
386         } catch (CacheException e) {
387             throw new PopulateException(e.getLocalizedMessage(), e);
388         }
389     }
390
391     /**
392      * Sets the <code>Profile</code> which will contain this property
393      * instance.
394      *
395      * @param prof the <code>Profile</code> which will contain this property
396      * instance
397      */

398     public void setProfile(Profile prof) {
399         this.m_profile = prof;
400         setDBTable(prof);
401     }
402
403     /**
404      * Returns the <code>Profile</code> which contains this property instance.
405      *
406      * @return the <code>Profile</code> this property instance is contained by
407      *
408      */

409     public Profile getProfile() {
410         return m_profile;
411     }
412
413     /**
414      * Returns <code>true</code> if this property instance is temporary
415      * and will therefore not be saved to the database.
416      *
417      * @return <code>true</code> if this property instance is temporary
418      */

419     public boolean isTemporary() {
420         return m_bIsTemporary;
421     }
422
423     /**
424      * Sets whether this property instance is temporary. A temporary
425      * property instance is not saved to the database.
426      *
427      * @return bIsTemporary <code>true</code> if this property instance
428      * is to be temporary, otherwise <code>false</code>
429     */

430     public void setIsTemporary(boolean bIsTemporary) {
431         m_bIsTemporary = bIsTemporary;
432     }
433
434     /**
435      * Sets the comment associated to this version of the object.
436      *
437      * @param sComment the version comment
438      */

439     public void setVersionComment(String JavaDoc sComment) {
440         m_sVersionComment = sComment;
441     }
442
443     /**
444      * Returns the comment associated with this version.
445      *
446      * @return the comment associated with this version
447      */

448     public String JavaDoc getVersionComment() {
449         return m_sVersionComment;
450     }
451
452     /**
453      * Returns the operator associated to this property instance, for use
454      * in comparisons.
455      *
456      * @return the operator associated to this property instance
457      */

458     public String JavaDoc getOperator() {
459         return m_sOperator;
460     }
461
462     /**
463      * Returns the name of the <code>Property</code> this object is an
464      * instance of.
465      *
466      * @return the name of the <code>Property</code> this object is an
467      * instance of.
468      * @throws DataAccessException if there is an error accessing the
469      * name of the <code>Property</code>
470      */

471     public String JavaDoc getName() throws DataAccessException {
472         String JavaDoc sName = null;
473         Property prop = getProperty();
474         
475         if(prop != null) {
476             sName = prop.getName();
477         }
478
479         return sName;
480     }
481
482     /* (non-Javadoc)
483      * @see org.openharmonise.rm.dsi.DataStoreObject#getDBTableName()
484      */

485     public String JavaDoc getDBTableName() {
486
487         return m_sDataTable;
488     }
489
490     /**
491      * Sets the operator to be used in comparisons involving this
492      * property instance.
493      *
494      * @param sOperator the operator to be used in comparisons involving
495      * this property instance
496      */

497     public void setOperator(String JavaDoc sOperator) {
498         m_sOperator = sOperator;
499     }
500
501     /**
502      * Returns the list values of this property instance.
503      *
504      * @return the list values of this property instance
505      */

506     public List getValues() {
507         return m_values;
508     }
509
510     /**
511      * Sets the values of this instance.
512      *
513      * @param values a list of values
514      */

515     public void setValues(List values) throws InvalidPropertyValueException {
516         m_values = new Vector();
517         m_values.addAll(values);
518
519         if (values.size() != 0) {
520             if (m_bIsPopulated == true) {
521                 setIsChanged(true);
522             }
523         }
524     }
525
526     /**
527      * Removes the specified value from this instance's list of values.
528      *
529      * @param val the value to remove
530      */

531     public void removeValue(Object JavaDoc val) {
532         if (m_values != null && m_values.contains(val) == true) {
533             m_values.remove(val);
534
535             if (m_bIsPopulated == true) {
536                 setIsChanged(true);
537                 m_values2Remove.add(val);
538             }
539         }
540     }
541
542     /**
543      *
544      * Returns the first value of this property instance's values.
545      * If there are no values a <code>null</code> is returned.
546      *
547      * @return the first value in the list of values
548      */

549     public Object JavaDoc getValue() {
550         Object JavaDoc objReturn = null;
551
552         if (m_values != null && m_values.size() > 0) {
553             objReturn = m_values.get(0);
554         }
555
556         return objReturn;
557     }
558
559     /**
560      * Clears the list of values.
561      */

562     public void clearValues() {
563         if (m_values != null) {
564             m_values.clear();
565         }
566     }
567
568     /**
569      * Returns <code>true</code> if this object has values.
570      *
571      * @return <code>true</code> if this object has values.
572      */

573     public boolean hasValues() {
574         boolean bReturn = true;
575
576         if ((m_values == null) || (m_values.size() == 0)) {
577             bReturn = false;
578         }
579
580         return bReturn;
581     }
582
583     /**
584      * Returns a value at the specified index in the list of values.
585      * Returns <code>null</code> if no value exists at that index.
586      *
587      * @return the value at the specified index
588      */

589     public Object JavaDoc getValue(int nIndex) {
590         Object JavaDoc objReturn = null;
591
592         if (m_values != null) {
593             if (m_values.size() > nIndex) {
594                 objReturn = m_values.get(nIndex);
595             }
596         }
597
598         return objReturn;
599     }
600
601     /**
602      * Merge the given property instance with this property instance.
603      *
604      * @param the property instance to merge with this instance
605      */

606     public boolean merge(AbstractPropertyInstance property) {
607         boolean bReturn = false;
608
609         if (m_property_ptr.equals(property.m_property_ptr)) {
610             int nNumberValues = property.getValues().size();
611
612             for (int i = 0; i < nNumberValues; i++) {
613                 if (m_values.contains(property.getValue(i)) == false) {
614                     m_values.add(property.getValue(i));
615                     bReturn = true;
616                 }
617             }
618         }
619
620         return bReturn;
621     }
622
623
624     /* (non-Javadoc)
625      * @see java.lang.Object#equals(java.lang.Object)
626      */

627     public boolean equals(Object JavaDoc obj) {
628         boolean bRtn = false;
629
630         AbstractPropertyInstance propInstance = (AbstractPropertyInstance) obj;
631
632         if ((propInstance.hasValues() == false)
633             && (this.hasValues() == false)) {
634             bRtn = true;
635         } else if (propInstance.hasValues() != this.hasValues()) {
636             bRtn = false;
637         } else {
638             if (m_property_ptr.equals(propInstance.m_property_ptr)) {
639                 List vLocalValues = this.getValues();
640                 List vRemoteValues = propInstance.getValues();
641
642                 if (vLocalValues.containsAll(vRemoteValues)
643                     && vRemoteValues.containsAll(vLocalValues)) {
644                     bRtn = true;
645                 }
646             }
647         }
648
649         return bRtn;
650     }
651
652     /**
653      * Returns <code>true</code> if this object matches the
654      * given <code>AbstractPropertyInstance</code>.
655      *
656      * @param propInst the property instance to match
657      * @return <code>true</code> if this object matches the
658      * given <code>AbstractPropertyInstance</code>.
659      * @throws ProfileException if an error occurs
660      */

661     abstract public boolean match(AbstractPropertyInstance propInst)
662         throws ProfileException;
663
664     /* (non-Javadoc)
665      * @see java.lang.Object#clone()
666      */

667     public Object JavaDoc clone() {
668
669         AbstractPropertyInstance other = null;
670         //Note: if exception is thrown it is gonna cause problems with
671
//saving, etc so I've elected to throw a RuntimeException
672
try {
673
674             other = (AbstractPropertyInstance) super.clone();
675
676             //setValues clones vector
677
if (m_values != null) {
678
679                 other.m_values = new Vector();
680
681                 Iterator iter = m_values.iterator();
682
683                 while (iter.hasNext()) {
684                     Object JavaDoc objVal = (Object JavaDoc) iter.next();
685
686                     if (objVal instanceof AbstractObject) {
687                         other.m_values.add(((AbstractObject) objVal).clone());
688                     } else {
689                         other.m_values.add(objVal);
690                     }
691                 }
692
693                 if (m_valueIds != null) {
694                     other.setValueIds(m_valueIds);
695                 }
696             }
697
698             if (m_values2Add != null) {
699                 other.m_values2Add = new Vector(m_values2Add);
700             }
701
702             if (m_values2Remove != null) {
703                 other.m_values2Remove = new Vector(m_values2Remove);
704             }
705         } catch (CloneNotSupportedException JavaDoc cu_e) {
706             m_logger.log(Level.WARNING, cu_e.getLocalizedMessage(), cu_e);
707             throw new IllegalStateException JavaDoc(
708                 "Problem occured during clone:" + cu_e.getLocalizedMessage());
709         }
710
711         return other;
712     }
713
714     /* (non-Javadoc)
715      * @see org.openharmonise.rm.dsi.DataStoreObject#getInstanceColumnRef(java.lang.String, boolean)
716      */

717     public ColumnRef getInstanceColumnRef(String JavaDoc sColumn, boolean bIsHist)
718         throws DataStoreException {
719         ColumnRef returnColRef = null;
720         String JavaDoc sDBTable = getDBTableName();
721
722         if (sColumn.equals(AbstractObject.ATTRIB_ID) == true
723             || sColumn.equals(CLMN_ID) == true) {
724             returnColRef = new ColumnRef(sDBTable, CLMN_ID, ColumnRef.NUMBER);
725         } else if (
726             sColumn.equals(CLMN_PROFILE_ID) == true
727                 || sColumn.equals(Profile.TAG_PROFILE) == true) {
728             returnColRef =
729                 new ColumnRef(sDBTable, CLMN_PROFILE_ID, ColumnRef.NUMBER);
730         } else if (
731             sColumn.equals(CLMN_PROPERTY_ID) == true
732                 || sColumn.equals(Property.TAG_PROPERTY) == true) {
733             returnColRef =
734                 new ColumnRef(sDBTable, CLMN_PROPERTY_ID, ColumnRef.NUMBER);
735         } else if (
736             sColumn.equals(AbstractEditableObject.TAG_VERSION_COMMENT) == true
737                 || sColumn.equals(CLMN_VERSION_COMMENT) == true) {
738             returnColRef =
739                 new ColumnRef(sDBTable, CLMN_VERSION_COMMENT, ColumnRef.TEXT);
740         }
741
742         if (returnColRef != null) {
743             return returnColRef;
744         } else {
745             throw new InvalidColumnReferenceException(sColumn);
746         }
747     }
748
749     /* (non-Javadoc)
750      * @see org.openharmonise.rm.publishing.Publishable#publish(org.openharmonise.rm.resources.publishing.Template, org.openharmonise.rm.publishing.HarmoniseOutput, org.openharmonise.rm.publishing.State)
751      */

752     public Element publish(Template template, HarmoniseOutput xmlDoc, State state)
753         throws PublishException {
754         Element resultEl = null;
755
756         try {
757
758             resultEl =
759                 publish(template.getTemplateRootElement(), xmlDoc, state);
760         } catch (Exception JavaDoc e) {
761             throw new PublishException(
762                 "Error occured while publishing",e);
763         }
764
765         return resultEl;
766     }
767
768     /* (non-Javadoc)
769      * @see org.openharmonise.rm.publishing.Publishable#publish(org.w3c.dom.Element, org.openharmonise.rm.publishing.HarmoniseOutput, org.openharmonise.rm.publishing.State)
770      */

771     public Element publish(Element formEl, HarmoniseOutput xmlDoc, State state)
772         throws PublishException {
773
774         Element el = null;
775
776         String JavaDoc sTagname = formEl.getTagName();
777
778         if (sTagname.equals(TAG_PROPERTYINSTANCE) == true) {
779
780             el = xmlDoc.createElement(TAG_PROPERTYINSTANCE);
781             String JavaDoc sPropName = CONST_UNKNOWN;
782             try {
783                 sPropName = getProperty().getName();
784             } catch (DataAccessException da_e) {
785                 m_logger.log(Level.WARNING, da_e.getLocalizedMessage(), da_e);
786                 sPropName = CONST_UNKNOWN;
787             }
788             Property prop = null;
789
790             try {
791                 prop = getProperty();
792                 el.setAttribute(AbstractObject.ATTRIB_NAME, sPropName);
793                 el.setAttribute(
794                     AbstractObject.ATTRIB_ID,
795                     (String JavaDoc) m_property_ptr.getKey());
796
797                 el.setAttribute(
798                     ATTRIB_OBJECT_TYPE,
799                     prop.getRange().getObject());
800             } catch (DataAccessException e) {
801                 throw new PublishException(
802                     "Error occured acessing range object:"
803                         + e.getLocalizedMessage());
804             }
805
806             // copy all caption, error nodes etc (if any exist)
807
Vector vIgnoreTags = new Vector();
808             vIgnoreTags.add(TAG_PROP_INSTANCE_VALUES);
809             vIgnoreTags.add(Property.TAG_PROPERTY);
810             xmlDoc.copyChildren(el, formEl, vIgnoreTags);
811
812             //now publish all child nodes
813
NodeList nodes = formEl.getChildNodes();
814
815             for (int i = 0; i < nodes.getLength(); i++) {
816                 if (nodes.item(i).getNodeType() == Node.ELEMENT_NODE) {
817                     Element tempEl = (Element) nodes.item(i);
818                     el.appendChild(publish(tempEl, xmlDoc, state));
819                 }
820             }
821
822         } else if (sTagname.equals(Property.TAG_PROPERTY)) {
823
824
825             try {
826                 Property prop = getProperty();
827
828                 if(prop != null) {
829                     Element templateEl = (Element) XMLUtils.getFirstNamedChild(formEl, Template.TAG_TEMPLATE);
830
831                     Template template = null;
832                     if(templateEl != null) {
833                         try {
834                             template =
835                                 (Template) HarmoniseObjectFactory.instantiateHarmoniseObject(
836                                     m_dsi,
837                                     templateEl,
838                                     state);
839                         } catch (HarmoniseFactoryException e) {
840                             throw new PublishException(e.getLocalizedMessage(),e);
841                         }
842                     }
843
844                     if(template != null) {
845                         el = prop.publish(template, xmlDoc, state);
846                     } else {
847                         el = xmlDoc.createElement(Property.TAG_PROPERTY);
848
849                         el.setAttribute(AbstractObject.ATTRIB_ID, String.valueOf(prop.getId()));
850
851                         Element nameEl = xmlDoc.createElement(AbstractObject.TAG_NAME);
852
853                         nameEl.appendChild(xmlDoc.createTextNode(prop.getName()));
854
855                         el.appendChild(nameEl);
856                         
857                         Element displayNameEl = xmlDoc.createElement(AbstractChildObject.TAG_DISPLAY_NAME);
858
859                         displayNameEl.appendChild(xmlDoc.createTextNode(prop.getDisplayName()));
860
861                         el.appendChild(displayNameEl);
862                     }
863                 } else {
864                     el = xmlDoc.createElement(Property.TAG_PROPERTY);
865                 }
866             } catch (DataAccessException e) {
867                 throw new PublishException(e.getLocalizedMessage(),e);
868             }
869         }
870
871         return el;
872     }
873
874     /* (non-Javadoc)
875      * @see org.openharmonise.rm.publishing.Publishable#populate(org.w3c.dom.Element, org.openharmonise.rm.publishing.State)
876      */

877     public void populate(Element xmlElement, State state)
878         throws PopulateException {
879         String JavaDoc sTagName = xmlElement.getTagName();
880
881         try {
882             if (sTagName.equals(TAG_PROPERTYINSTANCE) == true) {
883                 String JavaDoc sOperator = xmlElement.getAttribute(ATTRIB_OPERATOR);
884                 // get the operator
885

886                 if (sOperator != null && sOperator.length() > 0) {
887                     //set the operator for this property instance
888
setOperator(sOperator);
889                 }
890
891                 // get the child nodes
892
NodeList nodes = xmlElement.getChildNodes();
893
894                 for (int i = 0; i < nodes.getLength(); i++) {
895                     if (nodes.item(i).getNodeType() != Node.ELEMENT_NODE) {
896                         continue;
897                     }
898
899                     Element el = (Element) nodes.item(i);
900                     populate(el, state);
901                 }
902             } else if (sTagName.equals(Property.TAG_PROPERTY) == true) {
903                 Element nameElm =
904                     XMLUtils.getFirstNamedChild(
905                         xmlElement,
906                         AbstractObject.TAG_NAME);
907                 Property prop = null;
908
909                 if (nameElm != null) {
910                     String JavaDoc sPropName = nameElm.getFirstChild().getNodeValue();
911                     // get the value of the node
912
prop =
913                         PropertyFactory.getPropertyFromName(m_dsi, sPropName);
914                 } else {
915                     prop =
916                         (
917                             Property) HarmoniseObjectFactory
918                                 .instantiatePublishableObject(
919                             m_dsi,
920                             xmlElement,
921                             state);
922                 }
923
924                 prop.populate(xmlElement, state);
925                 // populate the property from the element
926
setProperty(prop);
927                 // set this property to be the property for this property instance
928
} else if (sTagName.equals(TAG_PROP_INSTANCE_VALUES) == true) {
929                 populate(xmlElement, state);
930             } else {
931                 throw new PopulateException("Invalid Tag name: " + sTagName);
932             }
933         } catch (HarmoniseFactoryException e) {
934             throw new PopulateException(
935                 "Error getting property from factory:",
936                 e);
937         }
938     }
939
940     /*-------------------------------------------------------------------------------------
941     Protected Methods
942     --------------------------------------------------------------------------------------*/

943
944     /**
945      * Saves this property instance to the database.
946      *
947      * @param profile the owning <code>Profile</code> for this
948      * property instance. The <code>Profile</code> determines which
949      * database table the data get saved to.
950      *
951      * @throws ProfileException if the property instance can not be
952      * saved due to a lack of either an associated <code>Profile</code>
953      * or <code>Property</code>
954      * @throws EditException if any other errors occur while saving data
955      */

956     protected void save(Profile prof) throws ProfileException, EditException {
957         if ((m_bIsTemporary == false) && hasValues() == true) {
958             //make sure database table is current
959
setDBTable(prof);
960
961             ResultSet rs = null;
962             InsertStatement insert = new InsertStatement();
963             int i = 0;
964             String JavaDoc sTable = getDBTableName();
965             boolean bIsHist = isHistorical();
966
967             int nId = 0;
968
969             m_valueIds.clear();
970
971             for (i = 0; i < m_values.size(); i++) {
972                 Object JavaDoc objVal = m_values.get(i);
973
974                 insert.clear();
975                 try {
976                     if (i >= m_valueIds.size()) {
977                         nId = m_dsi.getSequenceNextValue(SEQ_PROFILE_DATA);
978
979                         m_valueIds.add(new Integer JavaDoc(nId));
980                     } else {
981
982                         nId = ((Integer JavaDoc) m_valueIds.get(i)).intValue();
983
984                     }
985
986                     int nPropId = getProperty().getId();
987                     int nProfId = prof.getId();
988
989                     //ensure we're inserting a valid property id
990

991                     if (nPropId <= 0) {
992                         throw new InvalidPropertyInstanceException(
993                             "Property had invalid id - "
994                                 + m_property_ptr.getKey());
995                     }
996
997                     if (nProfId <= 0) {
998                         throw new InvalidPropertyInstanceException(
999                             "Profile had invalid id - " + nProfId);
1000                    }
1001
1002                    insert.setTable(sTable);
1003
1004                    insert.addColumnValue(
1005                        this.getInstanceColumnRef(CLMN_PROFILE_ID, bIsHist),
1006                        nProfId);
1007                    insert.addColumnValue(
1008                        this.getInstanceColumnRef(CLMN_PROPERTY_ID, bIsHist),
1009                        nPropId);
1010                    insert.addColumnValue(
1011                        this.getInstanceColumnRef(CLMN_ID, bIsHist),
1012                        nId);
1013                    insert.addColumnValue(
1014                        this.getColumnForData(),
1015                        this.getValueToStoreForValue(objVal));
1016                    if (m_sVersionComment != null) {
1017
1018                        insert.addColumnValue(
1019                            getInstanceColumnRef(
1020                                AbstractEditableObject.TAG_VERSION_COMMENT,
1021                                bIsHist),
1022                            m_sVersionComment);
1023                    }
1024
1025                    m_dsi.execute(insert);
1026
1027                } catch (DataStoreException e) {
1028                    throw new ProfileException(
1029                        "Error occurred processing insert",
1030                        e);
1031                } catch (SQLException sql_e) {
1032                    throw new ProfileException(
1033                        "Error occurred processing insert",
1034                        sql_e);
1035                } catch (DataAccessException e) {
1036                    throw new ProfileException(
1037                        "Error occurred processing insert",
1038                        e);
1039                }
1040            }
1041
1042            m_values2Add.clear();
1043            m_values2Remove.clear();
1044
1045            m_bIsChanged = false;
1046            m_bIsPopulated = true;
1047        }
1048    }
1049
1050    /**
1051     * Updates this property instance in the database.
1052     *
1053     * @param prof the owning <code>Profile</code> for this property instance
1054     * @throws ProfileException if any errors occur saving the data
1055     * @throws EditException if any other errors occur saving the data
1056     */

1057    protected void update(Profile prof)
1058        throws ProfileException, EditException {
1059
1060        if (isPopulated() == true && isChanged() == true) {
1061            InsertStatement insert = new InsertStatement();
1062            DeleteStatement delete = new DeleteStatement();
1063
1064            int i = 0;
1065            String JavaDoc sTable = getDBTableName();
1066
1067            boolean bIsHist = isHistorical();
1068            int nId = 0; // the next id
1069

1070            // save the values to be saved
1071
for (i = 0; i < m_values2Add.size(); i++) {
1072                Object JavaDoc objVal = m_values2Add.get(i);
1073
1074                insert.clear();
1075
1076                try {
1077                    if (isHistorical() == false) {
1078                        nId = m_dsi.getSequenceNextValue(SEQ_PROFILE_DATA);
1079
1080                        m_valueIds.add(new Integer JavaDoc(nId));
1081                    } else {
1082
1083                        nId = ((Integer JavaDoc) m_valueIds.get(i)).intValue();
1084
1085                    }
1086
1087                    insert.setTable(sTable);
1088
1089                    insert.addColumnValue(
1090                        this.getInstanceColumnRef(CLMN_PROFILE_ID, bIsHist),
1091                        prof.getId());
1092                    insert.addColumnValue(
1093                        this.getInstanceColumnRef(CLMN_PROPERTY_ID, bIsHist),
1094                        getProperty().getId());
1095                    insert.addColumnValue(
1096                        this.getInstanceColumnRef(CLMN_ID, bIsHist),
1097                        nId);
1098                    insert.addColumnValue(
1099                        this.getColumnForData(),
1100                        this.getValueToStoreForValue(objVal));
1101                    if (m_sVersionComment != null) {
1102
1103                        insert.addColumnValue(
1104                            getInstanceColumnRef(
1105                                AbstractEditableObject.TAG_VERSION_COMMENT,
1106                                bIsHist),
1107                            m_sVersionComment);
1108                    }
1109
1110                    m_dsi.execute(insert);
1111
1112                } catch (DataStoreException e) {
1113                    throw new ProfileException(
1114                        "Error occurred processing insert",
1115                        e);
1116                } catch (SQLException sql_e) {
1117                    throw new ProfileException(
1118                        "Error occurred processing insert",
1119                        sql_e);
1120                } catch (DataAccessException e) {
1121                    throw new ProfileException(
1122                        "Error occurred processing insert",
1123                        e);
1124                }
1125            }
1126
1127            for (i = 0; i < m_values2Remove.size(); i++) {
1128                Object JavaDoc objVal = m_values2Remove.get(i);
1129
1130                delete.clear();
1131
1132                try {
1133                    delete.setTable(sTable);
1134
1135                    delete.addWhereCondition(
1136                        getColumnForData(),
1137                        "=",
1138                        getValueToStoreForValue(objVal));
1139
1140                    delete.addWhereCondition(
1141                        this.getInstanceColumnRef(CLMN_PROFILE_ID, bIsHist),
1142                        "=",
1143                        prof.getId());
1144
1145                    m_dsi.execute(delete);
1146                } catch (DataStoreException e) {
1147                    throw new ProfileException(
1148                        "Error occurred processing insert",
1149                        e);
1150                }
1151            }
1152        } else if (isPopulated() == false) {
1153            //if this happens to be a new property instance on the profile
1154
save(prof);
1155        }
1156
1157        m_values2Add.clear();
1158        m_values2Remove.clear();
1159
1160        m_bIsChanged = false;
1161        m_bIsPopulated = true;
1162
1163    }
1164
1165    /**
1166     * Sets this property instance as having changed since being populated
1167     * from the database.
1168     *
1169     * @param bIsChanged <code>true</code> if this property instance
1170     * has been changed, otherwise <code>false</code>
1171     */

1172    protected void setIsChanged(boolean bIsChanged) {
1173        m_bIsChanged = true;
1174    }
1175
1176    /**
1177     * Returns <code>true</code> if this property instance has changed
1178     * since populated from the database, otherwise <code>false</code>
1179     * @return <code>true</code> if this property instance has changed
1180     * since populated from the database.
1181     */

1182    protected boolean isChanged() {
1183        return m_bIsChanged;
1184    }
1185
1186    /**
1187     * Returns <code>true</code> if this property instance is historical,
1188     * otherwise <code>false</code>.
1189     *
1190     * @return <code>true</code> if this property instance is historical
1191     */

1192    protected boolean isHistorical() {
1193        return m_bIsHistorical;
1194    }
1195
1196    /**
1197     * Sets this property instance as being historical.
1198     *
1199     * @param bIsHist <code>true</code> if this property insatnce is
1200     * to be historical
1201     */

1202    protected void setHistorical(boolean bIsHist) {
1203        m_bIsHistorical = bIsHist;
1204
1205    }
1206
1207    /**
1208     * Adds a value to this property instance.
1209     *
1210     * @param obj the value to add
1211     * @throws InvalidPropertyValueException if the value is invalid for
1212     * this property instance
1213     */

1214    protected void addValue(Object JavaDoc obj) throws PopulateException {
1215        if ((m_values.contains(obj) == false)) {
1216
1217            if(m_logger.isLoggable(Level.FINE)) {
1218                
1219                try {
1220                    StringBuffer JavaDoc sbuf = new StringBuffer JavaDoc();
1221                    
1222                    sbuf.append("adding value ")
1223                        .append(obj)
1224                        .append(" to property instance ")
1225                        .append(getName());
1226                    
1227                    AbstractProfiledObject profObj = getProfiledObject();
1228                    
1229                    if(profObj != null) {
1230                        sbuf.append("for ")
1231                            .append(profObj.getClass().getName())
1232                            .append(" ")
1233                            .append(profObj.getKey());
1234                    }
1235                    
1236                    m_logger.logp(Level.FINE, this.getClass().getName(),"addValue",sbuf.toString());
1237                } catch (DataAccessException e) {
1238                    m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
1239                }
1240            }
1241            
1242            // TODO: For a search, domain is not applicable
1243
// but there may be an occasion where we may
1244
// create a property instance without a profile.
1245
// So, in the save method we should do a check
1246
// if the value is valid or not.
1247
// probably this bit of code could move to the
1248
// save method.
1249
if (m_profile != null) {
1250                AbstractProfiledObject profObj = m_profile.getProfiledObject();
1251
1252                try {
1253                    Property prop = getProperty();
1254                    Domain domain = prop.getDomain(profObj);
1255
1256                    if (domain != null) {
1257                        int nMax = domain.getMaxOccurs();
1258
1259                        if (nMax > 0 && m_values.size() >= nMax) {
1260                            String JavaDoc sPropName = prop.getName();
1261                            
1262                            if(m_logger.isLoggable(Level.INFO)) {
1263                                StringBuffer JavaDoc sbuf = new StringBuffer JavaDoc();
1264                                
1265                                sbuf.append("Have reached maximum number of values for this property - ")
1266                                    .append(sPropName)
1267                                    .append(" on object ");
1268                                
1269                                if(profObj != null) {
1270                                    sbuf.append(profObj.getClass().getName())
1271                                        .append(" key - ")
1272                                        .append(profObj.getKey());
1273                                }
1274                                
1275                                m_logger.logp(Level.INFO, this.getClass().getName(),"addValue",sbuf.toString());
1276                                
1277                            }
1278                            
1279                            throw new InvalidPropertyValueException("Have reached maximum number of values for this property - " + sPropName);
1280                        }
1281                    }
1282                } catch (DataAccessException e) {
1283                    if(m_logger.isLoggable(Level.WARNING)) {
1284                        StringBuffer JavaDoc sbuf = new StringBuffer JavaDoc();
1285                        
1286                        sbuf.append("Have reached maximum number of values for a property")
1287                            .append(" on object ");
1288                        
1289                        if(profObj != null) {
1290                            try {
1291                                sbuf.append(profObj.getClass().getName())
1292                                    .append(" key - ")
1293                                    .append(profObj.getKey());
1294                            } catch (DataAccessException e1) {
1295                                m_logger.log(Level.WARNING, e1.getLocalizedMessage(), e1);
1296                            }
1297                        }
1298                        
1299                        m_logger.logp(Level.WARNING, this.getClass().getName(),"addValue",sbuf.toString());
1300                        
1301                    }
1302                    
1303                    throw new PopulateException(
1304                        "Had problem getting domain for this profiled object - "
1305                            + profObj.getClass().getName(),
1306                        e);
1307                }
1308            }
1309
1310            m_values.add(obj);
1311
1312            if (m_bIsPopulated == true) {
1313
1314                setIsChanged(true);
1315                m_values2Add.add(obj);
1316            }
1317        }
1318    }
1319
1320    /**
1321     * Adds the given object as a value to this property instance with
1322     * the associated id.
1323     *
1324     * @param val the value to add
1325     * @param nId the id of the value
1326     *
1327     * @throws InvalidPropertyValueException if the value is invalid for
1328     * this property instance
1329     */

1330    protected void addValue(Object JavaDoc val, int nId)
1331        throws PopulateException {
1332        if (val != null) {
1333            if (m_values == null) {
1334                m_values = new Vector();
1335            }
1336
1337            if (m_valueIds == null) {
1338                m_valueIds = new Vector();
1339            }
1340
1341            addValue(val);
1342            m_valueIds.add(new Integer JavaDoc(nId));
1343        }
1344    }
1345
1346    /**
1347     * Sets this object as having been populated.
1348     *
1349     * @param bIsPopulated <code>true</code> to indicate that this property
1350     * instance has been populated from the database
1351     */

1352    protected void setIsPopulated(boolean bIsPopulated) {
1353        m_bIsPopulated = bIsPopulated;
1354        m_bIsChanged = false;
1355    }
1356
1357    /**
1358     * Returns the column reference for the data column for this property
1359     * instance.
1360     *
1361     * Utility method to ensure sub classes will implement the required
1362     * functionality to get column reference to the value column of the
1363     * database table
1364     *
1365     * @return the column reference for the data column for this property
1366     * instance.
1367     * @throws DataStoreException if an error occurs constructing the
1368     * column reference
1369     */

1370    abstract protected ColumnRef getColumnForData() throws DataStoreException;
1371
1372    /**
1373     * Returns a representation of the specified value suitable
1374     * for saving to the database.
1375     *
1376     * @param val the value
1377     * @return a representation of the specified value suitable
1378     * for saving to the database.
1379     * @throws ProfileException if an error occurs transforming the value
1380     * to a representation suitable for the database
1381     */

1382    abstract protected Object JavaDoc getValueToStoreForValue(Object JavaDoc val)
1383        throws ProfileException;
1384
1385    /*-------------------------------------------------------------------------------------
1386        Private Methods
1387        --------------------------------------------------------------------------------------*/

1388
1389    /**
1390     * Sets the value ids of this property instance.
1391     *
1392     * Note that the ordering of the ids must match the ordering of their
1393     * associated values.
1394     *
1395     * @param values the list of value ids
1396     */

1397    private void setValueIds(List valueIds) {
1398        m_valueIds = new Vector();
1399
1400        m_valueIds.addAll(valueIds);
1401    }
1402
1403    /* (non-Javadoc)
1404     * @see org.openharmonise.rm.publishing.Publishable#getTagName()
1405     */

1406    public String JavaDoc getTagName() {
1407        return TAG_PROPERTYINSTANCE;
1408    }
1409
1410    /**
1411     * Returns <code>true</code> if this property instance has been populated
1412     * from the database.
1413     *
1414     * @return <code>true</code> if this property instance has been populated
1415     * from the database
1416     */

1417    public boolean isPopulated() {
1418        return m_bIsPopulated;
1419    }
1420
1421    /**
1422     * Sets the data store interface
1423     *
1424     * @param dsi the data store interface
1425     */

1426    public void setDataStoreInterface(AbstractDataStoreInterface dsi) {
1427        m_dsi = dsi;
1428
1429    }
1430    
1431    /**
1432     * Returns the profiled object which this property instance is
1433     * assocated with.
1434     *
1435     * @return the profiled object which this property instance is
1436     * assocated with.
1437     */

1438    protected AbstractProfiledObject getProfiledObject() {
1439        AbstractProfiledObject profObj = null;
1440
1441        if(m_profile != null) {
1442            profObj = m_profile.getProfiledObject();
1443        }
1444        return profObj;
1445    }
1446    
1447    /* (non-Javadoc)
1448     * @see org.openharmonise.rm.dsi.DataStoreObject#getId()
1449     */

1450    public int getId() {
1451        //returning dummy value as there is no id associated with a
1452
//property instance, method is needed to implement DataStoreeObject
1453
return -1;
1454    }
1455
1456}
Popular Tags