KickJava   Java API By Example, From Geeks To Geeks.

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


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.dsi.*;
26 import org.openharmonise.commons.dsi.dml.*;
27 import org.openharmonise.commons.xml.XMLUtils;
28 import org.openharmonise.rm.*;
29 import org.openharmonise.rm.dsi.*;
30 import org.openharmonise.rm.factory.*;
31 import org.openharmonise.rm.publishing.*;
32 import org.openharmonise.rm.resources.*;
33 import org.openharmonise.rm.resources.lifecycle.EditException;
34 import org.openharmonise.rm.resources.metadata.properties.*;
35 import org.openharmonise.rm.resources.metadata.properties.domains.Domain;
36 import org.openharmonise.rm.resources.metadata.properties.ranges.*;
37 import org.openharmonise.rm.resources.publishing.Template;
38 import org.openharmonise.rm.search.Search;
39 import org.w3c.dom.*;
40
41
42 /**
43  * <code>Profile</code> represents a collection of <code>AbstractPropertyInstance</code>s.
44  *
45  * @author Michael Bell
46  * @version $Revision: 1.8 $
47  *
48  */

49 public class Profile
50     extends AbstractObject
51     implements Publishable, DataStoreObject, Cloneable JavaDoc {
52
53     // XML constants
54
private static final String JavaDoc CONST_TRUE = "true";
55     
56     /**
57      * Profile XML element name
58      */

59     public static final String JavaDoc TAG_PROFILE = "Profile";
60
61     /**
62      * Property value XML element name
63      */

64     public static final String JavaDoc TAG_PROPERTY_VALUE = "PropertyValue";
65
66     /**
67      * 'Is default' XML attribute name
68      */

69     public static final String JavaDoc ATTRIB_ISDEFAULT = "isdefault";
70     
71     /**
72      * Profiled object key XML attribute name
73      */

74     public static final String JavaDoc ATTRIB_OBJECT_KEY = "objectKey";
75     
76     /**
77      * Value of <code>ATTRIB_ISDEFAULT</code> which indicates
78      * that a <code>Profile</code> is default
79      */

80     public static final String JavaDoc IS_DEFAULT_PROFILE_VALUE = "1";
81     
82     /**
83      * 'default' XML attribute name
84      */

85     public static final String JavaDoc ATTRIB_DEFAULT = "default";
86     
87     /**
88      * All property instance XML element name
89      */

90     public static final String JavaDoc TAG_ALLPROPERTYINSTANCES =
91         "AllPropertyInstances";
92
93     //DB constants
94
/**
95      * Version comment database column name
96      */

97     private static final String JavaDoc CLMN_VERSION_COMMENT = "version_comment";
98     
99     /**
100      * Object key database column name
101      */

102     private static final String JavaDoc CLMN_OBJECT_KEY = "object_key";
103     
104     /**
105      * 'is default' database column name
106      */

107     private static final String JavaDoc CLMN_IS_DEFAULT = "is_default";
108     
109     /**
110      * <code>String</code> constant extension used for building profile
111      * database table name. The naming convention for <code>Profile</code>
112      * database table names is as follows:
113      *
114      * AbstractProfiledObject.getTableName() + EXT_PROFILE
115      */

116     protected static final String JavaDoc EXT_PROFILE = "_profile";
117     
118     /**
119      * The profile database sequence name
120      */

121     private static final String JavaDoc SEQ_PROFILE = "seq_profile";
122
123     /**
124      * <code>String</code> constant used for unknown profiles
125      */

126     public static final String JavaDoc UNKNOWN_PROFILE = "?";
127     
128     /**
129      * <code>String</code> constant to indicate temporary profiles
130      * that will not be saved
131      */

132     public static final String JavaDoc TEXT_MARKER = "XXXX";
133
134
135     /**
136      * <code>Map</code> to hold all <code>PropertyInstanceStore</code>s
137      */

138     private Map m_propStores = new Hashtable();
139     
140     /**
141      * The version comment for this profile
142      */

143     protected String JavaDoc m_sVersionComment = null;
144     
145     /**
146      * <code>true</code> if this is a new <code>Profile</code>
147      */

148     private boolean m_bNew = false;
149     
150     /**
151      * The profiled object this <code>Profile</code> belongs to
152      */

153     private AbstractProfiledObject m_profObj = null;
154     
155     /**
156      * <code>boolean</code> flag to indicate that the historical status has changed
157      */

158     private boolean m_bIsHistoricalChange = false;
159     
160     /**
161      * <code>boolean</code> flag to indicate that this is a default <code>Profile</code>
162      */

163     private boolean m_bIsDefault = false;
164     
165     /**
166      * Logger for this class
167      */

168     private static final Logger m_logger = Logger.getLogger(Profile.class.getName());
169
170     /**
171      * Constructs a <code>Profile</code> without an interface to the
172      * data store.
173      *
174      */

175     public Profile() {
176         super();
177     }
178
179     /**
180      * Constructs a <code>Profile</code> with an interface to the data store.
181      *
182      * @param dbintrf the data store interface
183      */

184     public Profile(AbstractDataStoreInterface dbintrf) {
185         super(dbintrf);
186         m_bNew = true;
187         m_sTable = UNKNOWN_PROFILE;
188
189     }
190
191     /**
192      * Constructs a <code>Profile</code> which has an interface to the data store
193      * and a reference to it's 'owner' <code>AbstractProfiledObject</code>.
194      *
195      * @param dbintrf the data store interface
196      * @param obj the 'owning' profiled object
197      */

198     public Profile(
199         AbstractDataStoreInterface dbintrf,
200         AbstractProfiledObject obj) {
201         super(dbintrf, obj.isHistorical());
202         m_bNew = true;
203         m_profObj = obj;
204
205     }
206
207     /**
208      * Constructs the <code>Profile</code> with the given id, a reference to it's
209      * 'owning' <code>AbstractProfiledObject</code> and an interface to the data
210      * store.
211      *
212      * @param dbintrf the data store interface
213      * @param nId the profile id
214      * @param obj the 'owning' profiled object
215      */

216     public Profile(
217         AbstractDataStoreInterface dbintrf,
218         int nId,
219         AbstractProfiledObject obj) {
220         super(dbintrf, nId,0, obj.isHistorical());
221
222         m_profObj = obj;
223
224     }
225
226     /* (non-Javadoc)
227      * @see org.openharmonise.rm.resources.AbstractObject#isChanged()
228      */

229     public boolean isChanged() throws DataAccessException {
230         boolean bReturn = super.isChanged();
231
232         // if necessary check propertyInstances too but only if we have to
233
if (bReturn == false) {
234             Iterator iter = null;
235
236             iter = m_propStores.values().iterator();
237
238             while (iter.hasNext() == true && bReturn == false) {
239                 PropertyInstanceStore propStore =
240                     (PropertyInstanceStore) iter.next();
241                 bReturn = propStore.isChanged();
242             }
243
244         }
245
246         return bReturn;
247     }
248
249     /**
250      * Returns <code>true</code> if this <code>Profile</code> is the default
251      * for its owning <code>AbstractProfiledObject</code>, otherwise <code>false</code>.
252      *
253      * @return <code>true</code> if this <code>Profile</code> is the default
254      * @throws DataAccessException if an error occurs populating this profile
255      * from the database
256      */

257     public boolean isDefault() throws DataAccessException {
258         if ((m_bIsDefault == false) && (m_bIsPopulated == false)) {
259             try {
260                 populateFromDatabase();
261             } catch (PopulateException pop_e) {
262                 throw new DataAccessException(pop_e.getLocalizedMessage());
263             }
264         }
265
266         return m_bIsDefault;
267     }
268
269     /**
270      * Returns <code>true</code> if this <code>Profile</code> is new,
271      * otherwise <code>false</code>.
272      *
273      * @return <code>true</code> if this <code>Profile</code> is new
274      */

275     public boolean isNew() {
276         return m_bNew;
277     }
278
279     /**
280      * Returns the list of all property instances contained in this
281      * <code>Profile</code>.
282      *
283      * @return the list of all property instances of the profile
284      * @throws DataAccessException if an error occurs populating this profile
285      * from the database
286      */

287     public List getPropertyInstances() throws DataAccessException {
288
289         //ensure all propInsts are loaded
290
try {
291           if (isNew() == false) {
292             populatePropertyInstancesFromDatabase();
293           }
294         } catch (PopulateException pop_e) {
295             throw new DataAccessException(
296                 "Problem occured when populating",pop_e);
297         }
298
299         Vector props = new Vector();
300
301         Iterator iter = this.m_propStores.values().iterator();
302
303         while (iter.hasNext()) {
304             PropertyInstanceStore propStore =
305                 (PropertyInstanceStore) iter.next();
306             
307             Collection propInsts = propStore.getValues();
308             
309             Iterator propiter = propInsts.iterator();
310             
311             List deadProps = new ArrayList();
312             
313             while (propiter.hasNext()) {
314                 AbstractPropertyInstance propInst = (AbstractPropertyInstance) propiter.next();
315                 
316                 Property prop = propInst.getProperty();
317                 
318                 //need to check if property still exists by
319
//asking for property from prop inst
320
//if it no longer exist have to delete prop inst from prof
321
if(prop != null) {
322                     props.add(propInst);
323                 } else {
324                     try {
325                         deletePropertyInstanceData(propInst);
326                         if(m_logger.isLoggable(Level.INFO)) {
327                             m_logger.logp(Level.INFO,this.getClass().getName(),"getPropertyInstances","Deleting dead property instance on " + m_profObj.getClass().getName() + " " + m_profObj.getKey());
328                         }
329                         deadProps.add(propInst);
330                     } catch (InvalidPropertyInstanceException e) {
331                         m_logger.log(Level.WARNING, "error removing dead property instance", e);
332                     } catch (ProfileException e) {
333                         m_logger.log(Level.WARNING, "error removing dead property instance", e);
334                     } catch (DataAccessException e) {
335                         m_logger.log(Level.WARNING, "error removing dead property instance", e);
336                     }
337                 }
338             }
339             
340             if(deadProps.size() > 0) {
341                 Iterator deadPropIter = deadProps.iterator();
342                 
343                 while (deadPropIter.hasNext()) {
344                     AbstractPropertyInstance propInst = (AbstractPropertyInstance) deadPropIter.next();
345                     propStore.removePropertyInstance(propInst);
346                 }
347             }
348             
349         }
350
351         return props;
352     }
353
354
355     /**
356      * Sets whether this <code>Profile</code> is the default for the owning
357      * <code>AbstractProfiledObject</code>.
358      *
359      * @param bIsDefault <code>true</code> if this <code>Profile</code> is
360      * the default, otherwise <code>false</code>.
361      */

362     public void setIsDefault(boolean bIsDefault) {
363         m_bIsDefault = bIsDefault;
364     }
365
366     /* (non-Javadoc)
367      * @see org.openharmonise.rm.resources.AbstractObject#setHistorical(boolean)
368      */

369     public void setHistorical(boolean bIsHistorical) {
370         m_bIsHistoricalChange = true;
371         super.setHistorical(bIsHistorical);
372
373         try {
374             if(m_propStores.size() > 0) {
375                 // pass historical property to PropertyInstance
376
Iterator iter = getPropertyInstances().iterator();
377     
378                  while (iter.hasNext()) {
379                      AbstractPropertyInstance next =
380                          (AbstractPropertyInstance) iter.next();
381                      next.setHistorical(bIsHistorical);
382                  }
383             }
384             
385         } catch (DataAccessException e) {
386             // TODO can't throw exception, so log
387
m_logger.log(Level.WARNING, e.getLocalizedMessage(),e);
388             
389         }
390     }
391
392     /**
393      * Sets the version comment for this version of the <code>Profile</code>.
394      *
395      * @param sComment the version comment
396      */

397     public void setVersionComment(String JavaDoc sComment) {
398         if (isPopulated() == true) {
399             if (m_sVersionComment == null && sComment != null) {
400                 setIsChanged(true);
401             } else if (m_sVersionComment.equals(sComment) == false) {
402                 setIsChanged(true);
403             }
404         }
405
406         m_sVersionComment = sComment;
407     }
408
409     /**
410      * Returns the version comment for this <code>Profile</code>.
411      *
412      * @return the version comment for this <code>Profile</code>
413      * @throws DataAccessException if an error occurs populating this profile
414      * from the database
415      */

416     public String JavaDoc getVersionComment() throws DataAccessException {
417         if (isPopulated() == false && m_sVersionComment == null) {
418             try {
419                 populateFromDatabase();
420             } catch (PopulateException e) {
421                 throw new DataAccessException(
422                     "Problem occurred populating profile",e);
423             }
424         }
425
426         return m_sVersionComment;
427     }
428
429     /**
430      * Returns the list of properties which can be added to this <code>Profile</code>, dependant
431      * on the profiled object associated.
432      *
433      * @return the list of properties which can be added to this <code>Profile</code>
434      * @throws DataAccessException if
435      */

436     public List getAvailableProperties() throws DataAccessException {
437
438         if (m_profObj == null) {
439             throw new DataAccessException("No profiled object attached to this profile");
440         }
441
442         List propList = null;
443         
444         propList = Domain.getAvailableProperties(m_dsi,m_profObj);
445             
446
447         return propList;
448     }
449
450     /**
451      * Returns <code>true<code> if the specified <code>AbstractPropertyInstance</code>
452      * is valid for this <code>Profile</code>.
453      *
454      * @param propInst the property instance
455      * @return <code>true<code> if the specified <code>AbstractPropertyInstance</code>
456      * is valid
457      * @throws ProfileException if an error occurs getting the <code>Property</code>
458      * associated to the given property instance
459      */

460     public boolean isValidPropertyInstance(AbstractPropertyInstance propInst)
461         throws ProfileException {
462
463         boolean bIsValid = false;
464
465         try {
466             Property propInstProp = propInst.getProperty();
467             
468             bIsValid = isValidProperty(propInstProp);
469         } catch (DataAccessException e) {
470             throw new ProfileException(e.getLocalizedMessage(),e);
471         }
472         
473         
474         return bIsValid;
475
476     }
477     
478     /**
479      * Returns <code>true</code> an instance of the specified <code>Property</code>
480      * can be added to this <code>Profile</code>
481      *
482      * @param prop the <code>Property</code>
483      * @return <code>true</code> an instance of the specified <code>Property</code>
484      * can be added to this <code>Profile</code>
485      */

486     public boolean isValidProperty(Property prop) {
487         boolean bIsValid = false;
488
489         try {
490             if(prop != null) {
491                 List availProps = getAvailableProperties();
492
493                 bIsValid = availProps.contains(prop);
494             }
495
496         } catch (DataAccessException da_e) {
497             m_logger.log(Level.WARNING, da_e.getLocalizedMessage(), da_e);
498             
499             bIsValid = false;
500         }
501
502         return bIsValid;
503
504     }
505
506     /**
507      * Adds a property instance to this <code>Profile</code>.
508      *
509      * @param propInst the property instance to add
510      * @throws ProfileException if the given property instance is invalid
511      * or there is an error getting details from the property instance
512      */

513     public void addPropertyInstance(AbstractPropertyInstance propInst)
514         throws ProfileException {
515         propInst.setProfile(this);
516
517         if (propInst == null) {
518             throw new InvalidPropertyInstanceException("null property passed in");
519         } else if (isValidPropertyInstance(propInst) == false) {
520             throw new InvalidPropertyInstanceException("Invalid property passed in");
521         }
522
523         try {
524
525             String JavaDoc sKey = propInst.getName();
526             if (sKey.length() == 0) {
527                 throw new InvalidPropertyInstanceException("Invalid key");
528             }
529
530             Property prop = propInst.getProperty();
531             
532             if(hasProperty(prop) == false) {
533             
534                 PropertyInstanceStore propStore =
535                     this.getPropertyInstanceStore(prop);
536                 
537                 propStore.addPropertyInstance(propInst);
538             } else {
539                 throw new InvalidPropertyInstanceException("Profile already has property instance - " + sKey);
540             }
541
542         } catch (DataAccessException da_e) {
543             throw new ProfileException(
544                 "Error occured accessing property instance name",da_e);
545         }
546
547     }
548
549     /**
550      * Removes instances of the specified <code>Property</code> from this
551      * <code>Profile</code>.
552      *
553      * @param prop the <code>Property</code> to remove
554      * @throws ProfileException if an error occurs removing the property
555      * from this <code>Profile</code>
556      */

557     public void removeProperty(Property prop) throws ProfileException {
558         try {
559             PropertyInstanceStore propStore = getPropertyInstanceStore(prop);
560
561             if (propStore.isPopulated() == false) {
562                 populatePropertyInstanceStore(propStore);
563             }
564
565             propStore.removePropertyInstance(prop);
566         } catch (DataAccessException e) {
567             throw new ProfileException(
568                 "Error occured getting property instances",e);
569         } catch (PopulateException e) {
570             throw new ProfileException(
571                 "Error occured populating prop insts",e);
572         }
573     }
574
575     /**
576      * Returns <code>true</code> if the <code>Profile</code> has an instance of the
577      * specified <code>Property</code>.
578      *
579      * @param prop the <code>Property</code>
580      * @throws DataAccessException if there is an error populating the property
581      * instances of this <code>Profile></code>
582      *
583      */

584     public boolean hasProperty(Property prop)
585         throws DataAccessException {
586         try {
587             AbstractPropertyInstance propInst = getPropertyInstance(prop);
588             return (propInst != null);
589         } catch (InvalidPropertyInstanceException e) {
590             return false;
591         }
592     }
593
594     /**
595      * Returns the instance of the given <code>Property</code> held by this
596      * <code>Profile</code> if there is one.
597      *
598      * @param property the <code>Property</code>
599      * @return the instance of the given <code>Property</code>,
600      * <code>null</code> if there is no instance
601      * @throws InvalidPropertyInstanceException if the specified <code>Property</code>
602      * is invalid for this <code>Profile</code>
603      * @throws DataAccessException if there is an error populating this
604      * <code>Profile</code>
605      */

606     public AbstractPropertyInstance getPropertyInstance(Property property)
607         throws InvalidPropertyInstanceException, DataAccessException {
608         AbstractPropertyInstance propReturn = null;
609
610         PropertyInstanceStore propStore = null;
611
612         propStore = getPropertyInstanceStore(property);
613
614         if (propStore.isPopulated() == false) {
615             try {
616                 populatePropertyInstanceStore(propStore);
617             } catch (PopulateException e) {
618                 throw new DataAccessException(
619                     "Problem occurred populate values",e);
620             }
621         }
622
623         propReturn = propStore.getPropertyInstance(property);
624         
625         if(propReturn != null && property.exists() == false) {
626             try {
627                 deletePropertyInstanceData(propReturn);
628             } catch (InvalidPropertyInstanceException e) {
629                 m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
630                 throw new DataAccessException(e);
631             } catch (ProfileException e) {
632                 m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
633                 throw new DataAccessException(e);
634             } catch (DataAccessException e) {
635                 m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
636                 throw new DataAccessException(e);
637             }
638         }
639
640         return propReturn;
641     }
642
643     /**
644      * Returns a instance of the <code>Property</code> with the specified
645      * name if one exists in this <code>Profile</code>.
646      *
647      * @param sPropName the name of the <code>Property</code>
648      * @return the instance of the <code>Property</code>,
649      * <code>null</code> no instance exists
650      *
651      * @throws InvalidPropertyInstanceException if the specified <code>Property</code>
652      * is invalid for this <code>Profile</code>
653      * @throws DataAccessException if there is an error populating this
654      * <code>Profile</code>
655      */

656     public AbstractPropertyInstance getPropertyInstance(String JavaDoc sPropName)
657         throws InvalidPropertyInstanceException, DataAccessException {
658         AbstractPropertyInstance propReturn = null;
659     
660             try {
661               Property prop = PropertyFactory.getPropertyFromName(m_dsi, sPropName);
662               propReturn = getPropertyInstance(prop);
663             } catch (HarmoniseFactoryException e) {
664               throw new DataAccessException("Problem occurred getting property from name:", e);
665             }
666         
667
668         return propReturn;
669     }
670
671     /**
672      * Saves this <code>Profile</code> to the data store.
673      *
674      * @param proObj the 'owner' <code>AbstractProfiledObject</code>
675      * @return the resultant <code>Profile</code> of the save operation
676      * @throws ProfileException if a profiled object is not specified
677      * or, if this is not a new <code>Profile</code>, there is an error populating
678      * this <code>Profile</code> with existing property instances
679      * @throws EditException if there is an error saving the data to the
680      * database
681      */

682     public Profile save(AbstractProfiledObject proObj)
683         throws ProfileException, EditException {
684         if (proObj == null) {
685             throw new ProfileException("No ProfiledObject given so can't save");
686         }
687
688         // before we start ensure that we have the correct info
689
if (m_bIsPopulated == false) {
690             try {
691                 populateFromDatabase();
692             } catch (PopulateException e) {
693                 throw new ProfileException("Problem occurred populating the profile", e);
694             }
695         }
696
697         try {
698
699             if (isNew() == false && isPropertyInstancesPopulated() == false) {
700                 populatePropertyInstancesFromDatabase();
701             }
702         } catch (DataAccessException da_e) {
703             throw new ProfileException("Error occured while accessing property instances:", da_e);
704         } catch (PopulateException pop_e) {
705             throw new ProfileException("Error occured while accessing property instances:", pop_e);
706         }
707
708         //check to see if profiled object has changed
709
boolean bProfObjChange = false;
710
711         try {
712             bProfObjChange = (m_profObj.getKey() != proObj.getKey());
713         } catch (DataAccessException da_e) {
714             throw new ProfileException("Problem occurred accessing data from profiled object:", da_e);
715         }
716
717         //ensure that profiled object is set
718
m_profObj = proObj;
719
720         Profile profileReturn = null;
721         // if this is a new profile, create a new record
722
if ((m_nId == 0)
723             || (m_nId == AbstractObject.NOTDBSAVED_ID)
724             || m_bIsHistoricalChange) {
725             //do this before getting the id sequence so that the equals()
726
//comparison doesn't try to call populateFromDatabase() on a
727
//id not in the database. Comprende?!
728
int nIsDefault = 0;
729             if (proObj.isDefaultProfile(this)) {
730                 nIsDefault = 1;
731             }
732             try {
733
734                 //gets new id even if historical because it's been cleared in the markAsNew method
735
m_nId = m_dsi.getSequenceNextValue(SEQ_PROFILE);
736
737                 // insert into correct profile table
738
InsertStatement insert = new InsertStatement();
739
740                 insert.addColumnValue(
741                     this.getInstanceColumnRef(ATTRIB_ID, false),
742                     m_nId);
743                 insert.addColumnValue(
744                     this.getInstanceColumnRef(ATTRIB_KEY, false),
745                     proObj.getKey());
746                 insert.addColumnValue(
747                     this.getInstanceColumnRef(TAG_NAME, false),
748                     m_sName);
749                 if (m_sSummary != null) {
750                     insert.addColumnValue(
751                         this.getInstanceColumnRef(TAG_SUMMARY, false),
752                         m_sSummary);
753                 }
754
755                 if (m_sVersionComment != null) {
756                     insert.addColumnValue(
757                         this.getInstanceColumnRef(CLMN_VERSION_COMMENT, false),
758                         m_sVersionComment);
759                 }
760                 
761                 if(m_sType != null) {
762                     insert.addColumnValue(
763                         this.getInstanceColumnRef(ATTRIB_TYPE, false),
764                     m_sType);
765                 }
766
767                 insert.addColumnValue(
768                     this.getInstanceColumnRef(CLMN_IS_DEFAULT, false),
769                     nIsDefault);
770                 m_dsi.execute(insert);
771                 // insert properties
772
Iterator iter = getPropertyInstances().iterator();
773                 int nErrors = 0;
774                 List errorDescs = null;
775                 while (iter.hasNext()) {
776                     AbstractPropertyInstance next =
777                             (AbstractPropertyInstance) iter.next();
778                     //try to save all prop insts even if individual propInsts fail
779
try {
780                         
781                         next.save(this);
782                     } catch(InvalidPropertyInstanceException val_e) {
783                         //remove offending prop inst
784
removePropertyInstance(next);
785                         nErrors++;
786                         if(errorDescs == null) {
787                             errorDescs = new ArrayList();
788                         }
789                         errorDescs.add(val_e.getLocalizedMessage() + " - " + next.toString());
790                     }
791                 }
792                 //reset flags
793
m_bIsChanged = false;
794                 iter = m_propStores.values().iterator();
795                 
796                 while (iter.hasNext()) {
797                     PropertyInstanceStore propStore = (PropertyInstanceStore) iter.next();
798                     propStore.setIsChanged(false);
799                 }
800                 
801                 m_bIsHistoricalChange = false;
802                 m_bIsPopulated = true;
803                 m_bNew = false;
804                 profileReturn = this;
805                 
806                 if(nErrors > 0) {
807                     throw new EditException("Problem saving prop insts - " + errorDescs);
808                 }
809                 
810             } catch (DataStoreException ds_e) {
811                 throw new ProfileException("Problem occured saving profile:", ds_e);
812             } catch (DataAccessException da_e) {
813                 throw new ProfileException("Problem occured saving profile:", da_e);
814             } catch (SQLException sql_e) {
815                 throw new ProfileException("Problem occured saving profile:", sql_e);
816             }
817         } else if (m_bIsChanged == true || bProfObjChange == true) {
818             // if this is an existing profile and changes have been made,
819
// create a new version
820
// do this by temporarily setting our id to NOTDBSAVED_PRO_ID and cloning ourselves
821
Profile profileNew = (Profile) this.clone();
822             try {
823                 profileNew.markAsNew();
824             } catch (PopulateException e) {
825                 throw new EditException(
826                     "Problem occurred marking object as new",e);
827             }
828             profileReturn = profileNew.save(proObj);
829         } else {
830             // nothing to do, just return the profile as is
831
profileReturn = this;
832         }
833         return profileReturn;
834     }
835
836     /**
837      * Deletes this <code>Profile</code> from the database.
838      *
839      * @throws ProfileException if an error occurs deleting this
840      * <code>Profile</code> from the database
841      */

842     public void delete() throws ProfileException {
843         if (m_nId == NOTDBSAVED_ID) {
844             return;
845         }
846
847         ResultSet rs = null;
848         try {
849
850             if (isPropertyInstancesPopulated() == false) {
851                 populatePropertyInstancesFromDatabase();
852             }
853
854             //delete general prop insts first
855
Iterator iter = m_propStores.values().iterator();
856
857             while (iter.hasNext()) {
858                 PropertyInstanceStore propStore =
859                     (PropertyInstanceStore) iter.next();
860
861                 deletePropertyInstances(propStore);
862             }
863
864             DeleteStatement delete = new DeleteStatement();
865
866             delete.addWhereCondition(
867                 getInstanceColumnRef(ATTRIB_ID, false),
868                 "=",
869                 m_nId);
870
871             m_dsi.execute(delete);
872             //reset all datamembers
873
m_nId = NOTDBSAVED_ID;
874         } catch (DataStoreException ds_e) {
875             throw new ProfileException(
876                 "Problem occured deleting profile:",ds_e);
877         } catch (DataAccessException e) {
878             throw new ProfileException(
879                 "Problem occured populating property instances:",e);
880         } catch (PopulateException e) {
881             throw new ProfileException(
882                 "Problem occured populating property instances:",e);
883         } finally {
884             if (rs != null) {
885                 try {
886                     rs.close();
887                 } catch (SQLException sql_e) {
888                     throw new ProfileException(
889                         "Problem occured closing result set",sql_e);
890                 }
891
892             }
893         }
894     }
895
896     /**
897      * Matches this <code>Profile</code> against the given <code>Profile</code>.
898      *
899      * @param prof the <code>Profile</code> to match this
900      * <code>Profile</code> against
901      *
902      * @return <code>true</code> if both <code>Profile</code>s match
903      * @throws ProfileException if any errors occur
904      */

905     public boolean match(Profile prof) throws ProfileException {
906         boolean bMatch = false;
907         try {
908
909             Iterator iter = getPropertyInstances().iterator();
910             while (iter.hasNext()) {
911                 AbstractPropertyInstance thisProp =
912                     (AbstractPropertyInstance) iter.next();
913                 AbstractPropertyInstance otherProp =
914                     prof.getPropertyInstance(thisProp.getProperty());
915                 bMatch = thisProp.match(otherProp);
916                 if (bMatch == false) {
917                     break;
918                 }
919             }
920         } catch (DataAccessException da_e) {
921             throw new ProfileException(
922                 "Problem occurred accessing properties",da_e);
923         }
924
925         return bMatch;
926     }
927     
928     /**
929      * Matches this <code>Profile</code> against the given <code>Profile</code>.
930      *
931      * @param prof the <code>Profile</code> to match this
932      * <code>Profile</code> against
933      *
934      * @return <code>true</code> if both <code>Profile</code>s match
935      * @throws ProfileException if any errors occur
936      */

937     public boolean match(List propInstList) throws ProfileException {
938         boolean bMatch = false;
939         try {
940
941             Iterator iter = propInstList.iterator();
942             
943             while (iter.hasNext()) {
944                 AbstractPropertyInstance otherProp =
945                     (AbstractPropertyInstance) iter.next();
946                 AbstractPropertyInstance thisProp =
947                     getPropertyInstance(otherProp.getProperty());
948                 
949                 bMatch = otherProp.match(thisProp);
950                 if (bMatch == false) {
951                     break;
952                 }
953             }
954         } catch (DataAccessException da_e) {
955             throw new ProfileException(
956                 "Problem occurred accessing properties",da_e);
957         }
958
959         return bMatch;
960     }
961
962
963     /* (non-Javadoc)
964      * @see java.lang.Object#toString()
965      */

966     public String JavaDoc toString() {
967         StringBuffer JavaDoc strbuf = new StringBuffer JavaDoc();
968         try {
969             strbuf
970                 .append(" Summary:")
971                 .append(m_sSummary)
972                 .append(" Id:")
973                 .append(m_nId)
974                 .append(" Profile Table:")
975                 .append(m_sTable)
976                 .append(" name:")
977                 .append(m_sName)
978                 .append("[value][labels]:{");
979             String JavaDoc sName = "";
980
981             Iterator propStoreIterator = m_propStores.values().iterator();
982             
983             while (propStoreIterator.hasNext()) {
984                 PropertyInstanceStore propStore = (PropertyInstanceStore) propStoreIterator.next();
985                 
986                 if(propStore.m_propInsts != null) {
987                     Iterator propInstIter = propStore.m_propInsts.values().iterator();
988             
989                     while (propInstIter.hasNext()) {
990                         AbstractPropertyInstance propInst = (AbstractPropertyInstance) propInstIter.next();
991                         sName = propInst.getProperty().getName();
992                         List values = propInst.getValues();
993
994                         strbuf.append(sName).append(": ");
995                         
996                         if(values != null) {
997                             //need to avoid possible infnite recursion
998
//with toString() on ChildObjectPropertyInstances
999
if(propInst instanceof ChildObjectPropertyInstance) {
1000                                Iterator valIter = values.iterator();
1001                                
1002                                while (valIter.hasNext()) {
1003                                    AbstractChildObject child = (AbstractChildObject) valIter.next();
1004                                    strbuf.append(child.getClass().getName()).append(":").append(child.getId());
1005                                    if(valIter.hasNext()) {
1006                                        strbuf.append(",");
1007                                    }
1008                                }
1009                            } else {
1010                                strbuf.append(values);
1011                            }
1012                        }
1013                        strbuf.append(".");
1014                    }
1015                }
1016                
1017            }
1018
1019            strbuf.append("}. ");
1020        } catch (Exception JavaDoc e) {
1021            strbuf.append("Exception :").append(e.getMessage());
1022        }
1023
1024        return strbuf.toString();
1025    }
1026
1027    /* (non-Javadoc)
1028     * @see org.openharmonise.rm.publishing.Publishable#publish(org.w3c.dom.Element, org.openharmonise.rm.publishing.HarmoniseOutput, org.openharmonise.rm.publishing.State)
1029     */

1030    public Element publish(Element topEl, HarmoniseOutput xmlDoc, State state)
1031        throws PublishException {
1032
1033        Element docEl = xmlDoc.createElement(topEl.getTagName());
1034        
1035        if (((String JavaDoc) topEl.getTagName()).equals(TAG_PROFILE)) {
1036            String JavaDoc sTempName = null;
1037
1038            try {
1039
1040                sTempName = getName();
1041            } catch (DataAccessException da_e) {
1042                sTempName = "There was an error getting the name";
1043            }
1044
1045            if ((sTempName == null) || sTempName.equalsIgnoreCase("")) {
1046                sTempName = topEl.getAttribute(Profile.ATTRIB_NAME);
1047            }
1048
1049            docEl.setAttribute(ATTRIB_NAME, sTempName);
1050            if (m_nId != NOTDBSAVED_ID) {
1051                docEl.setAttribute(ATTRIB_ID, Integer.toString(m_nId));
1052            }
1053
1054            String JavaDoc sDefault = topEl.getAttribute(ATTRIB_DEFAULT);
1055            if (sDefault.equals(CONST_TRUE)) {
1056                docEl.setAttribute(ATTRIB_ISDEFAULT, CONST_TRUE);
1057            }
1058        }
1059
1060        NodeList nodes = topEl.getChildNodes();
1061        Element formEl;
1062        Element el = null;
1063        Text txt = null;
1064        String JavaDoc sTagName;
1065        for (int i = 0; i < nodes.getLength(); i++) {
1066            if (nodes.item(i).getNodeType() != Node.ELEMENT_NODE) {
1067                continue;
1068            }
1069
1070            formEl = (Element) nodes.item(i);
1071            sTagName = formEl.getTagName();
1072            if (sTagName.equals(TAG_SUMMARY)) {
1073                el = xmlDoc.createElement(sTagName);
1074                try {
1075
1076                    txt = xmlDoc.createTextNode(getSummary());
1077                    el.appendChild(txt);
1078                } catch (DataAccessException da_e) {
1079                    txt =
1080                        xmlDoc.createTextNode(
1081                            "A problem occured accessing the summary");
1082                    el.appendChild(txt);
1083                }
1084                docEl.appendChild(el);
1085            } else if (
1086                sTagName.equals(AbstractEditableObject.TAG_VERSION_COMMENT)) {
1087                el = xmlDoc.createElement(sTagName);
1088                try {
1089                    txt = xmlDoc.createTextNode(getVersionComment());
1090                    el.appendChild(txt);
1091                } catch (DataAccessException da_e) {
1092                    txt =
1093                        xmlDoc.createTextNode(
1094                            "A problem occured accessing the version comment");
1095                    el.appendChild(txt);
1096                }
1097                docEl.appendChild(el);
1098            } else if (
1099                sTagName.equals(
1100                    AbstractPropertyInstance.TAG_PROPERTYINSTANCE)) {
1101                        AbstractPropertyInstance propInstance = null;
1102                String JavaDoc sPropName = null;
1103                try {
1104                    NodeList propNodes = formEl.getElementsByTagName(Property.TAG_PROPERTY);
1105                    Element propEl = (Element)propNodes.item(0);
1106                    Element nameEl = XMLUtils.getFirstNamedChild(propEl, TAG_NAME);
1107                    if(nameEl != null) {
1108                        sPropName = XMLUtils.getChildTextValue(nameEl);
1109                        propInstance = getPropertyInstance(sPropName);
1110                    } else {
1111                        Element pathEl = XMLUtils.getFirstNamedChild(propEl, Property.TAG_PATH);
1112                        String JavaDoc sPath = XMLUtils.getChildTextValue(pathEl);
1113                        Property prop = (Property) HarmoniseObjectFactory.instantiateHarmoniseObject(m_dsi, Property.class.getName(), sPath);
1114                        propInstance = getPropertyInstance(prop);
1115                    }
1116                    
1117                } catch (DOMException e) {
1118                    txt =
1119                        xmlDoc.createTextNode(
1120                            "A problem occured processing the property elements");
1121                    el.appendChild(txt);
1122                } catch (InvalidPropertyInstanceException e) {
1123                    el = e.publish(xmlDoc);
1124                } catch (DataAccessException e) {
1125                    throw new PublishException(
1126                        "An error occured when trying to access a PropertyInstance",e);
1127                } catch (HarmoniseFactoryException e) {
1128                    el = e.publish(xmlDoc);
1129                }
1130
1131                if (propInstance != null) {
1132                    el = propInstance.publish(formEl, xmlDoc, state);
1133                    docEl.appendChild(el);
1134                }
1135                
1136
1137            } else if (sTagName.equals(TAG_ALLPROPERTYINSTANCES)) {
1138                try {
1139                    
1140                    NamedNodeMap attrs = formEl.getAttributes();
1141
1142                    Element propInstEl =
1143                        xmlDoc.createElement(
1144                            AbstractPropertyInstance.TAG_PROPERTYINSTANCE);
1145                            
1146                    Element propEl = xmlDoc.createElement(
1147                        Property.TAG_PROPERTY);
1148                    
1149                    propInstEl.appendChild(propEl);
1150                    
1151                    Element valueEl = xmlDoc.createElement(AbstractPropertyInstance.TAG_PROP_INSTANCE_VALUES);
1152                    
1153                    for(int j = 0; j<attrs.getLength();j++) {
1154                        Attr attr = (Attr) attrs.item(j);
1155                        
1156                        valueEl.setAttribute(attr.getName(), attr.getValue());
1157                    }
1158                    
1159                    propInstEl.appendChild(valueEl);
1160                    
1161                    //get the <AllPropertyInstances/> tag for compound props
1162
Element allPropEl = xmlDoc.createElement(TAG_ALLPROPERTYINSTANCES);
1163                    
1164                    for(int j = 0; j<attrs.getLength();j++) {
1165                        Attr attr = (Attr) attrs.item(j);
1166    
1167                        allPropEl.setAttribute(attr.getName(), attr.getValue());
1168                    }
1169                    
1170                    Element templateEl = XMLUtils.getFirstNamedChild(formEl, Template.TAG_TEMPLATE);
1171                    
1172                    if(templateEl != null) {
1173                        templateEl = (Element) xmlDoc.importNode(templateEl, true);
1174                        allPropEl.appendChild(templateEl.cloneNode(true));
1175                    }
1176                    
1177                    Element origPropEl = XMLUtils.getFirstNamedChild(formEl, Property.TAG_PROPERTY);
1178                    
1179                    if(origPropEl != null) {
1180                        NodeList propChildren = origPropEl.getChildNodes();
1181                            
1182                        for (int j = 0; j < propChildren.getLength(); j++) {
1183                            Node node =
1184                                (Node) propChildren.item(j);
1185                            propEl.appendChild(xmlDoc.importNode(node,true));
1186                            
1187                        }
1188                    }
1189                    
1190                    Element propCloneEl = (Element) propEl.cloneNode(true);
1191                    
1192                    allPropEl.appendChild(propCloneEl);
1193                    
1194                    Element condEl = XMLUtils.getFirstNamedChild(formEl, Search.TAG_CONDITIONS);
1195                    
1196                    Collection propInsts = null;
1197                    
1198                    if(condEl == null) {
1199                        propInsts = getPropertyInstances();
1200                    } else {
1201                        List condProps = getConditionalPropertyInstances(condEl);
1202                        propInsts = getMatchingPropertyInstances(condProps);
1203                    }
1204                    
1205                    Iterator iter = propInsts.iterator();
1206                    
1207                    while (iter.hasNext()) {
1208                        AbstractPropertyInstance propInst =
1209                            (AbstractPropertyInstance) iter.next();
1210                            
1211                        if(templateEl != null) {
1212                            if(propInst instanceof ChildObjectPropertyInstance) {
1213                                valueEl.appendChild(templateEl);
1214                            }
1215                        }
1216                        
1217                        if(propInst instanceof ProfilePropertyInstance) {
1218                           valueEl.appendChild(allPropEl);
1219                           
1220                       }
1221                            
1222                        el = propInst.publish(propInstEl, xmlDoc, state);
1223                        docEl.appendChild(el);
1224                        
1225                        if(templateEl != null) {
1226                            if(propInst instanceof ChildObjectPropertyInstance) {
1227                                valueEl.removeChild(templateEl);
1228                            }
1229                        }
1230                        
1231                        if(propInst instanceof ProfilePropertyInstance) {
1232                            valueEl.removeChild(allPropEl);
1233                        }
1234                    }
1235                } catch (DataAccessException da_e) {
1236                    throw new PublishException(
1237                        "An error occured when trying to access the PropertyInstances",da_e);
1238                }
1239            } else {
1240                // copy all nodes we don't recognise
1241
docEl.appendChild(xmlDoc.copyNode(formEl));
1242            }
1243        }
1244
1245        return docEl;
1246    }
1247
1248    /**
1249     * Returns a <code>List</code> of <code>AbstractPropertyInstance</code>s
1250     * whose defining <code>Property</code>s have the given conditional
1251     * <code>AbstractPropertyInstance</code>s in their <code>Profile</code>.
1252     *
1253     * @param condProps
1254     * @return
1255     */

1256    public List getMatchingPropertyInstances(List condProps) throws DataAccessException {
1257        List propInsts = new ArrayList();
1258        
1259        Iterator iter = getPropertyInstances().iterator();
1260        
1261        while (iter.hasNext()) {
1262            AbstractPropertyInstance propInst = (AbstractPropertyInstance) iter.next();
1263            
1264            Property prop = propInst.getProperty();
1265            
1266            Profile propProf = prop.getProfile();
1267            
1268            try {
1269                if(propProf.match(condProps) == true) {
1270                    propInsts.add(propInst);
1271                }
1272            } catch(InvalidPropertyInstanceException e) {
1273                //ignore invalid properties
1274
if(m_logger.isLoggable(Level.FINE)) {
1275                    m_logger.logp(Level.FINE, this.getClass().getName(), "getMatchingPropertyInstances", "Ignoring property - " + prop.getName());
1276                }
1277                
1278            } catch (ProfileException e) {
1279                throw new DataAccessException(e);
1280            }
1281        }
1282        
1283        return propInsts;
1284    }
1285
1286    /**
1287     * Returns a <code>List</code> of <code>AbstractPropertyInstance</code>s
1288     * which have been represented in the specified 'Conditions' XML element.
1289     *
1290     * @param condEl the 'Conditions' XML element
1291     * @return a <code>List</code> of <code>AbstractPropertyInstance</code>s
1292     */

1293    private List getConditionalPropertyInstances(Element condEl) throws PublishException {
1294        List propInsts = new ArrayList();
1295        
1296        if(condEl.getTagName().equals(Search.TAG_CONDITIONS) == true) {
1297            List nodes = XMLUtils.getChildrenByName(condEl, AbstractPropertyInstance.TAG_PROPERTYINSTANCE);
1298            
1299            for (Iterator iter = nodes.iterator(); iter.hasNext();) {
1300                Element propInstEl = (Element) iter.next();
1301                
1302                try {
1303                    AbstractPropertyInstance propInst = PropertyInstanceFactory.getPropertyInstance(m_dsi, propInstEl);
1304                    
1305                    propInst.populate(propInstEl, null);
1306                
1307                    propInsts.add(propInst);
1308                } catch (DataAccessException e) {
1309                    throw new PublishException(e);
1310                } catch (HarmoniseFactoryException e) {
1311                    throw new PublishException(e);
1312                } catch (PopulateException e) {
1313                    throw new PublishException(e);
1314                }
1315            }
1316        }
1317        
1318        return propInsts;
1319    }
1320
1321    /* (non-Javadoc)
1322     * @see org.openharmonise.rm.publishing.Publishable#populate(org.w3c.dom.Element, org.openharmonise.rm.publishing.State)
1323     */

1324    public void populate(Element xmlElement, State state)
1325        throws PopulateException {
1326
1327        if (xmlElement.getTagName().equals(TAG_PROFILE) == false) {
1328            throw new PopulateException(
1329                "Expecting " + TAG_PROFILE + " got " + xmlElement.getTagName());
1330        }
1331        try {
1332            if(((AbstractChildObject)m_profObj).getParents().isEmpty()){
1333                throw new PopulateDependencyException("Profiled object must have a parent before populating profile");
1334            }
1335        } catch (DataAccessException e) {
1336            throw new PopulateException(e);
1337        }
1338
1339        try {
1340            String JavaDoc sName = xmlElement.getAttribute(ATTRIB_NAME);
1341            if(sName != null && sName.length()>0) {
1342                setName(sName);
1343            }
1344        } catch (InvalidNameException e) {
1345            throw new PopulateException(e);
1346        }
1347        NodeList nodes = xmlElement.getChildNodes();
1348        Element formEl;
1349        String JavaDoc sTagName;
1350        String JavaDoc sProperty;
1351        Vector values = new Vector();
1352        Element el;
1353        NodeList valueNodes;
1354        NodeList availableValueNodes;
1355        for (int i = 0; i < nodes.getLength(); i++) {
1356            if (nodes.item(i).getNodeType() != Node.ELEMENT_NODE) {
1357                continue;
1358            }
1359
1360            formEl = (Element) nodes.item(i);
1361            sTagName = formEl.getTagName();
1362            Text txt = null;
1363            if (sTagName.equals(TAG_SUMMARY)) {
1364                txt = (Text) formEl.getFirstChild();
1365                setSummary(txt.getNodeValue());
1366            } else if (
1367                sTagName.equals(AbstractEditableObject.TAG_VERSION_COMMENT)) {
1368                txt = (Text) formEl.getFirstChild();
1369                setVersionComment(txt.getNodeValue());
1370            } else if (
1371                sTagName.equals(
1372                    AbstractPropertyInstance.TAG_PROPERTYINSTANCE)) {
1373                        
1374                try {
1375                    AbstractPropertyInstance propInst = PropertyInstanceFactory.getPropertyInstance(m_dsi, formEl, this);
1376                    Property prop = propInst.getProperty();
1377                    if(hasProperty(prop)) {
1378                        propInst = this.getPropertyInstance(prop);
1379                    } else {
1380                        addPropertyInstance(propInst);
1381                    }
1382                
1383                    propInst.populate(formEl, state);
1384                    
1385                } catch (DataAccessException e) {
1386                    throw new PopulateException(e);
1387                } catch (HarmoniseFactoryException e) {
1388                    throw new PopulateException(e);
1389                } catch (ProfileException e) {
1390                    throw new PopulateException(e);
1391                }
1392                
1393            }
1394        }
1395    }
1396
1397    /**
1398     * Populates the <code>Profile</code> data.
1399     *
1400     * @throws ProfileException
1401     */

1402    public void fillProfileData() throws ProfileException {
1403        try {
1404
1405            if (m_bIsPopulated == false) {
1406                populateFromDatabase();
1407            }
1408
1409            if (isPropertyInstancesPopulated() == false) {
1410                populatePropertyInstancesFromDatabase();
1411            }
1412        } catch (PopulateException pop_e) {
1413            throw new ProfileException(
1414                "Problem occured populating Profile",pop_e);
1415        } catch (DataAccessException da_e) {
1416            throw new ProfileException(
1417                "Problem occured populating Profile",da_e);
1418        }
1419    }
1420
1421    /* (non-Javadoc)
1422     * @see org.openharmonise.rm.dsi.DataStoreObject#getDBTableName()
1423     */

1424    public String JavaDoc getDBTableName() {
1425        String JavaDoc sTable = getDBTableName(m_profObj);
1426
1427        return sTable;
1428    }
1429
1430    /* (non-Javadoc)
1431     * @see org.openharmonise.rm.dsi.DataStoreObject#getInstanceJoinConditions(java.lang.String, boolean)
1432     */

1433    public JoinConditions getInstanceJoinConditions(
1434        String JavaDoc sObjectTag,
1435        boolean bIsOuter)
1436        throws DataStoreException {
1437
1438        return null;
1439    }
1440
1441    /* (non-Javadoc)
1442     * @see org.openharmonise.rm.dsi.DataStoreObject#processResultSet(org.openharmonise.commons.dsi.CachedResultSet, org.openharmonise.commons.dsi.dml.SelectStatement)
1443     */

1444    public List processResultSet(
1445        CachedResultSet resultSet,
1446        SelectStatement select) {
1447        //Not implemented as it's pretty complicated to handle with
1448
//the possibility of profile property instances
1449
//and objects will be populated when the data is requested
1450
//anyway, if indeed it's not already populated
1451
return null;
1452    }
1453
1454    /* (non-Javadoc)
1455     * @see org.openharmonise.rm.dsi.DataStoreObject#processResultSet(org.openharmonise.commons.dsi.CachedResultSet, org.openharmonise.commons.dsi.dml.SelectStatement, int)
1456     */

1457    public List processResultSet(
1458        CachedResultSet resultSet,
1459        SelectStatement select,
1460        int limit) {
1461        //Not implemented as it's pretty complicated to handle with
1462
//the possibility of profile property instances
1463
//and objects will be populated when the data is requested
1464
//anyway, if indeed it's not already populated
1465
return null;
1466    }
1467
1468    /* (non-Javadoc)
1469     * @see java.lang.Object#clone()
1470     */

1471    public Object JavaDoc clone() {
1472        //Note: if exception is thrown it is gonna cause problems with
1473
//saving, etc so I've elected to throw a RuntimeException
1474
try {
1475            if (m_bIsPopulated == false) {
1476                populateFromDatabase();
1477            }
1478            
1479            if(isPropertyInstancesPopulated() == false) {
1480                populatePropertyInstancesFromDatabase();
1481            }
1482
1483            AbstractPropertyInstance nextProp = null;
1484            //clone the profile
1485
Profile other = (Profile) super.clone();
1486
1487            //iterate through prop insts to clone and add to cloned profile
1488
Iterator iter = m_propStores.keySet().iterator();
1489            other.m_propStores = new Hashtable();
1490
1491            while (iter.hasNext()) {
1492                String JavaDoc sKey = (String JavaDoc) iter.next();
1493                PropertyInstanceStore propStore =
1494                    (PropertyInstanceStore) this.m_propStores.get(sKey);
1495                //note that the propstore clone method is not called as it
1496
//will have a relationship with this Profile rather
1497
//than the new cloned one
1498
other.m_propStores.put(sKey, other.new PropertyInstanceStore(propStore));
1499            }
1500
1501            return other;
1502        } catch (PopulateException e) {
1503            m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
1504            throw new IllegalStateException JavaDoc(
1505                "Problem occured during clone" + e.getLocalizedMessage());
1506        } catch (DataAccessException e) {
1507            m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
1508            throw new IllegalStateException JavaDoc(
1509                "Problem occured during clone" + e.getLocalizedMessage());
1510        }
1511    }
1512
1513    /* (non-Javadoc)
1514     * @see org.openharmonise.rm.dsi.DataStoreObject#getInstanceColumnRef(java.lang.String, boolean)
1515     */

1516    public ColumnRef getInstanceColumnRef(String JavaDoc sColumn, boolean bIsHist)
1517        throws DataStoreException {
1518        ColumnRef returnColRef = null;
1519
1520        returnColRef = getColumnRef(m_profObj, sColumn);
1521
1522        if (returnColRef != null) {
1523            return returnColRef;
1524        } else {
1525            return super.getInstanceColumnRef(sColumn, bIsHist);
1526        }
1527    }
1528
1529    /**
1530     * Returns the database table name for the <code>Profile</code> of the
1531     * specified <code>AbstractProfiledObject</code>.
1532     *
1533     * @param profObj the profiled object
1534     * @return the database table name for the <code>Profile</code> of the
1535     * specified <code>AbstractProfiledObject</code>
1536     */

1537    public static String JavaDoc getDBTableName(AbstractProfiledObject profObj) {
1538        String JavaDoc sTable = UNKNOWN_PROFILE;
1539
1540        if (profObj != null) {
1541            StringBuffer JavaDoc sbuf = new StringBuffer JavaDoc();
1542
1543            sbuf.append(profObj.getDBTableName()).append(EXT_PROFILE);
1544
1545            if (profObj.isHistorical() == true) {
1546                sbuf.append(EXT_HIST);
1547            }
1548
1549            sTable = sbuf.toString();
1550        }
1551
1552        return sTable;
1553    }
1554
1555    /**
1556     * Returns the appropriate <code>ColumnRef</code> for the column of the
1557     * <code>Profile</code> for the given <code>AbstractProfiledObject</code>.
1558     *
1559     * @param profObj the profiled object
1560     * @param sColumn the column name
1561     * @return the appropriate <code>ColumnRef</code> for the specified column
1562     * @throws DataStoreException if the specified column does not match any
1563     * valid columns
1564     */

1565    public static ColumnRef getColumnRef(
1566        AbstractProfiledObject profObj,
1567        String JavaDoc sColumn)
1568        throws DataStoreException {
1569        ColumnRef returnColRef = null;
1570        return getColumnRef(profObj.getClass().getName(), sColumn, profObj.isHistorical());
1571    }
1572    
1573    /**
1574     * Returns the table name for the object of the class name given, taking account
1575     * for whether the historical table is needed or not.
1576     *
1577     * @param sClassname the class name of an <code>AbstractObject</code>
1578     * @param bHist <code>true</code> if the table name is
1579     * associated with a historical object
1580     * @return the table name for the object
1581     * @throws DataStoreException if an error occurs
1582     */

1583    public static String JavaDoc getTableName(String JavaDoc sClassname,boolean bHist) throws DataStoreException {
1584        String JavaDoc sTable = null;
1585        
1586        StringBuffer JavaDoc sbuf = new StringBuffer JavaDoc();
1587        
1588        sbuf.append(AbstractObject.getTableName(sClassname, false));
1589        
1590        sbuf.append(EXT_PROFILE);
1591        
1592        if(bHist == true) {
1593            sbuf.append(EXT_HIST);
1594        }
1595        
1596        return sbuf.toString();
1597    }
1598    
1599    /**
1600     * Returns a column reference appropriate for the given
1601     * parameters.
1602     *
1603     * @param sClassname the class name of an <code>AbstractObject</code>
1604     * @param sColumn the column, tag or attribute name
1605     * @param bHist <code>true</code> if the column reference is
1606     * associated with a historical object
1607     * @return the column reference corresponding to the parameters
1608     * @throws DataStoreException if an error occurs
1609     */

1610    public static ColumnRef getColumnRef(
1611        String JavaDoc sClassname,
1612        String JavaDoc sColumn,
1613        boolean bHist)
1614        throws DataStoreException {
1615        ColumnRef returnColRef = null;
1616        String JavaDoc sTable = getTableName(sClassname,bHist);
1617
1618        if (sColumn.equals(ATTRIB_OBJECT_KEY) == true
1619            || sColumn.equals(CLMN_OBJECT_KEY) == true) {
1620            returnColRef =
1621                new ColumnRef(sTable, CLMN_OBJECT_KEY, ColumnRef.NUMBER);
1622        } else if (
1623            sColumn.equals(CLMN_IS_DEFAULT) == true
1624                || sColumn.equals(Profile.ATTRIB_ISDEFAULT) == true) {
1625            returnColRef =
1626                new ColumnRef(sTable, CLMN_IS_DEFAULT, ColumnRef.NUMBER);
1627        } else if (
1628            sColumn.equals(AbstractEditableObject.TAG_VERSION_COMMENT) == true
1629                || sColumn.equals(CLMN_VERSION_COMMENT) == true) {
1630            returnColRef =
1631                new ColumnRef(sTable, CLMN_VERSION_COMMENT, ColumnRef.TEXT);
1632        }
1633
1634        if (returnColRef == null) {
1635            returnColRef = AbstractObject.getColumnRef(sClassname, sColumn);
1636            if (returnColRef != null) {
1637                returnColRef.setTable(sTable);
1638            }
1639        }
1640
1641        return returnColRef;
1642    }
1643
1644    /**
1645     * Updates the data in the database for this <code>Profile</code>.
1646     *
1647     * @throws PopulateException if any errors occur saving the profile details
1648     * to the database
1649     * @throws EditException if any errors occur saving the property instances
1650     * to the database
1651     */

1652    public void update() throws PopulateException, EditException {
1653
1654        //first populate if necessary
1655
if (m_bIsPopulated == false) {
1656            populateFromDatabase();
1657        }
1658
1659        try {
1660
1661            if (isPropertyInstancesPopulated() == false) {
1662                populatePropertyInstancesFromDatabase();
1663            }
1664        } catch (DataAccessException da_e) {
1665            throw new PopulateException(
1666                "Error occured while accessing property instances",da_e);
1667        }
1668
1669        //update property instances
1670
updatePropertyInstances();
1671
1672        //Update profile data
1673
UpdateStatement update = new UpdateStatement();
1674
1675        try {
1676
1677            if (m_sSummary != null) {
1678                update.addColumnValue(
1679                    getInstanceColumnRef(TAG_SUMMARY, false),
1680                    m_sSummary);
1681            }
1682
1683            if (m_sVersionComment != null) {
1684                update.addColumnValue(
1685                    getInstanceColumnRef(Profile.CLMN_VERSION_COMMENT, false),
1686                    m_sVersionComment);
1687            }
1688
1689            int nIsDefault = 0;
1690            if (m_bIsDefault) {
1691                nIsDefault = 1;
1692            }
1693
1694            update.addColumnValue(
1695                getInstanceColumnRef(CLMN_IS_DEFAULT, false),
1696                nIsDefault);
1697            update.addWhereCondition(
1698                getInstanceColumnRef(ATTRIB_ID, false),
1699                "=",
1700                m_nId);
1701        } catch (DataStoreException ds_e) {
1702            throw new PopulateException(
1703                "Problem occurred while building update statement",ds_e);
1704        }
1705
1706        try {
1707
1708            m_dsi.executeUpdate(update);
1709            
1710        } catch (DataStoreException ds_e) {
1711            throw new PopulateException(
1712                "Problem occurred while processing update statement",ds_e);
1713        }
1714    }
1715
1716    /* (non-Javadoc)
1717     * @see org.openharmonise.rm.publishing.Publishable#getTagName()
1718     */

1719    public String JavaDoc getTagName() {
1720        return TAG_PROFILE;
1721    }
1722
1723    /*--------------------------------------------------------------------------
1724                    
1725    Protected Functions
1726    
1727    ---------------------------------------------------------------------------*/

1728
1729    /**
1730     * Returns the <code>AbstractProfiledObject</code> associated with this
1731     * <code>Profile</code>.
1732     */

1733    protected AbstractProfiledObject getProfiledObject() {
1734        return m_profObj;
1735    }
1736
1737    /* (non-Javadoc)
1738     * @see org.openharmonise.rm.resources.AbstractObject#populateFromResultSetRow(java.sql.ResultSet, org.openharmonise.commons.dsi.dml.SelectStatement)
1739     */

1740    protected void populateFromResultSetRow(
1741        ResultSet rs,
1742        SelectStatement select)
1743        throws PopulateException {
1744
1745        if (isPopulated() == false) {
1746            super.populateFromResultSetRow(rs, select);
1747
1748            String JavaDoc sTemp = "";
1749            ColumnRef colref = null;
1750            boolean bIsHist = isHistorical();
1751
1752            try {
1753                colref =
1754                    getInstanceColumnRef(
1755                        AbstractEditableObject.TAG_VERSION_COMMENT,
1756                        bIsHist);
1757
1758                if (select.containsSelectColumn(colref) == true) {
1759                    m_sVersionComment =
1760                        rs.getString(select.getResultSetIndex(colref));
1761                }
1762
1763                colref = getInstanceColumnRef(ATTRIB_ISDEFAULT, bIsHist);
1764
1765                if (select.containsSelectColumn(colref) == true) {
1766                    m_bIsDefault =
1767                        rs.getBoolean(select.getResultSetIndex(colref));
1768                }
1769
1770                
1771            } catch (DataStoreException ds_e) {
1772                throw new PopulateException(ds_e.getLocalizedMessage());
1773            } catch (SQLException sql_e) {
1774                throw new PopulateException(sql_e.getLocalizedMessage());
1775            }
1776        }
1777    }
1778
1779    /* (non-Javadoc)
1780     * @see org.openharmonise.rm.resources.AbstractObject#populateFromDatabase()
1781     */

1782    protected void populateFromDatabase() throws PopulateException {
1783        super.populateFromDatabase();
1784    }
1785
1786    /* (non-Javadoc)
1787     * @see org.openharmonise.rm.resources.AbstractObject#addColumnsToPopulateQuery(org.openharmonise.commons.dsi.dml.SelectStatement, boolean)
1788     */

1789    protected void addColumnsToPopulateQuery(
1790        SelectStatement select,
1791        boolean bIsHist)
1792        throws DataStoreException {
1793
1794        select.addSelectColumn(
1795            getInstanceColumnRef(
1796                AbstractEditableObject.TAG_VERSION_COMMENT,
1797                bIsHist));
1798        select.addSelectColumn(getInstanceColumnRef(ATTRIB_ISDEFAULT, bIsHist));
1799        super.addColumnsToPopulateQuery(select, bIsHist);
1800    }
1801
1802    /**
1803     * Populates all the property instances in this <code>Profile</code>.
1804     *
1805     * @throws PopulateException if an error occurs accessing the data from
1806     * the database
1807     */

1808    protected void populatePropertyInstancesFromDatabase()
1809        throws PopulateException {
1810        try {
1811
1812            initialisePropertyInstanceStores();
1813        } catch (DataAccessException e) {
1814            throw new PopulateException(
1815                "Problem occurred populating property instances",e);
1816        }
1817
1818        Iterator iter = m_propStores.values().iterator();
1819
1820        while (iter.hasNext()) {
1821            PropertyInstanceStore propStore =
1822                (PropertyInstanceStore) iter.next();
1823            
1824            populatePropertyInstanceStore(propStore);
1825        }
1826    }
1827
1828    /**
1829     * Populates the <code>ProfilePropertyInstance</code>s held by this
1830     * <code>Profile</code>.
1831     *
1832     * @throws PopulateException if any errors occur
1833     */

1834    protected synchronized void populateProfilePropertyInstances()
1835        throws PopulateException {
1836        PropertyInstanceStore propStore =
1837            (PropertyInstanceStore) m_propStores.get(Profile.class.getName());
1838
1839        if (propStore.isPopulated() == false) {
1840
1841            SelectStatement select = new SelectStatement();
1842
1843            boolean bIsHist = isHistorical();
1844
1845            ColumnRef dataPropIdCol = null;
1846            
1847            try {
1848
1849                String JavaDoc sProfDataTable =
1850                    ProfilePropertyInstance.getDBTableName(this);
1851
1852                select.addSelectColumn(
1853                    getProfileDataColumn(
1854                        sProfDataTable,
1855                        AbstractPropertyInstance.CLMN_ID));
1856
1857                dataPropIdCol = getProfileDataColumn(
1858                            sProfDataTable,
1859                            AbstractPropertyInstance.CLMN_PROPERTY_ID);
1860
1861                select.addSelectColumn(dataPropIdCol);
1862
1863                select.addSelectColumn(
1864                    getProfileDataColumn(
1865                        sProfDataTable,
1866                        AbstractPropertyInstance.CLMN_VERSION_COMMENT));
1867
1868                select.addSelectColumn(
1869                    getProfileDataColumn(sProfDataTable, CLMN_NAME));
1870
1871                select.addSelectColumn(
1872                    getProfileDataColumn(sProfDataTable, CLMN_SUMMARY));
1873
1874                ColumnRef profId_colref =
1875                    getProfileDataColumn(
1876                        sProfDataTable,
1877                        ProfilePropertyInstance.CLMN_PROFILE_PARENT);
1878
1879                select.addWhereCondition(profId_colref, "=", m_nId);
1880
1881                //need to add order by to ensure that all property instances
1882
//of a property get handled consecutively
1883
select.setOrderBy(dataPropIdCol);
1884
1885            } catch (DataStoreException da_e) {
1886                throw new PopulateException(
1887                    "Error occured building query",da_e);
1888            }
1889
1890            ResultSet rs = null;
1891
1892            try {
1893                int nProfId = 0;
1894                int nPropId = 0;
1895                rs = m_dsi.execute(select);
1896                ProfilePropertyInstance propInst = null;
1897                while (rs.next()) {
1898                    nProfId = rs.getInt(1);
1899                    nPropId = rs.getInt(2);
1900                    if (propInst == null
1901                        || propInst.getProperty().getId() != nPropId) {
1902                        //before we're done set populated flag
1903
if(propInst != null) {
1904                            propInst.setIsPopulated(true);
1905                        }
1906                        
1907                        propInst = new ProfilePropertyInstance(m_dsi, this);
1908
1909                        Property prop =
1910                            (Property) HarmoniseObjectFactory.instantiateHarmoniseObject(
1911                                m_dsi,
1912                                Property.class.getName(),
1913                                nPropId);
1914                        
1915                        //if prop no longer exists we hve to delete all prop insts with
1916
//this prop and not add it to this profile
1917
if(prop == null) {
1918                            if(m_logger.isLoggable(Level.INFO)) {
1919                                m_logger.logp(Level.INFO, this.getClass().getName(), "populateGeneralPropertyInstances", "Property " + nPropId + " no longer exists so removing value");
1920                            }
1921                            
1922                            ProfileValue prof = new ProfileValue(m_dsi, nProfId, m_profObj);
1923                            prof.setName(rs.getString(4));
1924                            prof.setSummary(rs.getString(5));
1925                            
1926                            try {
1927                                prof.delete();
1928                            } catch (ProfileException e) {
1929                                //won't escalate this as the profile value
1930
//will only hang around for this version of
1931
//the object and the behaviour of this
1932
//object should be fine
1933
m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
1934                            }
1935                            
1936                            propInst = null;
1937                            continue;
1938                        }
1939
1940                        propInst.setProperty(prop);
1941                        propInst.setVersionComment(rs.getString(3));
1942
1943                        propStore.addPropertyInstance(propInst);
1944                    }
1945
1946                    ProfileValue prof = new ProfileValue(m_dsi, nProfId, m_profObj);
1947                    prof.setName(rs.getString(4));
1948                    prof.setSummary(rs.getString(5));
1949                    prof.setProperty(propInst.getProperty());
1950                    propInst.addValue(prof,nProfId);
1951                }
1952                if(propInst != null) {
1953                    propInst.setIsPopulated(true);
1954                }
1955
1956                propStore.setIsPopulated(true);
1957            } catch (SQLException sql_e) {
1958                throw new PopulateException(
1959                    "Error occured processing query",sql_e);
1960            } catch (HarmoniseFactoryException f_e) {
1961                throw new PopulateException(
1962                    "Error occured getting property from factory",f_e);
1963            } catch (DataStoreException ds_e) {
1964                throw new PopulateException(
1965                    "Error occured processing query",ds_e);
1966            } catch (DataAccessException da_e) {
1967                throw new PopulateException(
1968                    "Error occured populating property instance",da_e);
1969            } catch (InvalidPropertyValueException ipv_e) {
1970                // do nothing - the value just won't be added
1971
m_logger.log(Level.FINE,"Ignoring exception",ipv_e);
1972            } catch (InvalidNameException e) {
1973                throw new PopulateException(e);
1974            } finally {
1975                if (rs != null) {
1976                    try {
1977
1978                        rs.close();
1979                    } catch (SQLException sql_e) {
1980                        throw new PopulateException(
1981                            "Had trouble closing result set",sql_e);
1982                    }
1983                }
1984            }
1985
1986        }
1987    }
1988
1989    /**
1990     * Populates the <code>GeneralPropertyInstance</code>s held by this
1991     * <code>Profile</code>.
1992     *
1993     * @throws PopulateException if any errors occur
1994     */

1995    protected synchronized void populateGeneralPropertyInstances()
1996        throws PopulateException {
1997        PropertyInstanceStore propStore =
1998            (PropertyInstanceStore) m_propStores.get(
1999                GeneralPropertyInstance.class.getName());
2000
2001        if (propStore.isPopulated() == false) {
2002
2003            SelectStatement select = new SelectStatement();
2004
2005            boolean bIsHist = isHistorical();
2006            ColumnRef dataPropIdCol = null;
2007            
2008            try {
2009
2010                String JavaDoc sProfDataTable =
2011                    GeneralPropertyInstance.getDBTableName(this);
2012
2013                select.addSelectColumn(
2014                    getProfileDataColumn(
2015                        sProfDataTable,
2016                        AbstractPropertyInstance.CLMN_ID));
2017
2018                dataPropIdCol = getProfileDataColumn(
2019                            sProfDataTable,
2020                            AbstractPropertyInstance.CLMN_PROPERTY_ID);
2021                
2022                select.addSelectColumn(dataPropIdCol);
2023
2024                ColumnRef ver_com_colref =
2025                    getProfileDataColumn(
2026                        sProfDataTable,
2027                        AbstractPropertyInstance.CLMN_VERSION_COMMENT);
2028
2029                select.addSelectColumn(ver_com_colref);
2030                select.addSelectColumn(
2031                    getProfileDataColumn(
2032                        sProfDataTable,
2033                        GeneralPropertyInstance.CLMN_VALUE));
2034
2035                ColumnRef profId_colref =
2036                    getProfileDataColumn(
2037                        sProfDataTable,
2038                        GeneralPropertyInstance.CLMN_PROFILE_ID);
2039
2040                select.addWhereCondition(profId_colref, "=", m_nId);
2041                
2042                //need to add order by to ensure that all property instances
2043
//of a property get handled consecutively
2044
select.setOrderBy(dataPropIdCol);
2045
2046            } catch (DataStoreException da_e) {
2047                throw new PopulateException(
2048                    "Error occured building query",da_e);
2049            }
2050
2051            ResultSet rs = null;
2052
2053            try {
2054
2055                rs = m_dsi.execute(select);
2056                GeneralPropertyInstance propInst = null;
2057                while (rs.next()) {
2058                    int nPropId = rs.getInt(2);
2059                    if (propInst == null
2060                        || propInst.getProperty().getId() != nPropId) {
2061                        if(propInst != null) {
2062                            propInst.setIsPopulated(true);
2063                        }
2064                        propInst = new GeneralPropertyInstance(m_dsi, this);
2065
2066                        Property prop =
2067                            (Property) HarmoniseObjectFactory.instantiateHarmoniseObject(
2068                                m_dsi,
2069                                Property.class.getName(),
2070                                nPropId);
2071                        
2072                        //if prop no longer exists we hve to delete all prop insts with
2073
//this prop and not add it to this profile
2074
if(prop == null) {
2075                            if(m_logger.isLoggable(Level.INFO)) {
2076                                m_logger.logp(Level.INFO, this.getClass().getName(), "populateGeneralPropertyInstances", "Property " + nPropId + " no longer exists so removing value");
2077                            }
2078                            
2079                            DeleteStatement delete = new DeleteStatement();
2080                            
2081                            delete.addWhereCondition(dataPropIdCol, "=", nPropId);
2082                            
2083                            m_dsi.execute(delete);
2084                            
2085                            propInst = null;
2086                            
2087                            continue;
2088                        }
2089                        
2090                        propInst.setProperty(prop);
2091                        propInst.setVersionComment(rs.getString(3));
2092
2093                        propStore.addPropertyInstance(propInst);
2094                    }
2095                    propInst.addValue(rs.getString(4), rs.getInt(1));
2096            
2097                }
2098                if(propInst != null) {
2099                    propInst.setIsPopulated(true);
2100                }
2101
2102                propStore.setIsPopulated(true);
2103            } catch (SQLException sql_e) {
2104                throw new PopulateException(
2105                    "Error occured processing query",sql_e);
2106            } catch (HarmoniseFactoryException f_e) {
2107                throw new PopulateException(
2108                    "Error occured getting property from factory",f_e);
2109            } catch (DataStoreException ds_e) {
2110                throw new PopulateException(
2111                    "Error occured processing query",ds_e);
2112            } catch (DataAccessException da_e) {
2113                throw new PopulateException(
2114                    "Error occured populating property instance",da_e);
2115            } catch (InvalidPropertyValueException ipv_e) {
2116                //do nothing - the value just won't be added
2117
m_logger.log(Level.FINE,"Ignoring exception",ipv_e);
2118            } finally {
2119                if (rs != null) {
2120                    try {
2121
2122                        rs.close();
2123                    } catch (SQLException sql_e) {
2124                        throw new PopulateException(
2125                            "Had trouble closing result set",sql_e);
2126                    }
2127                }
2128            }
2129        }
2130    }
2131
2132    /**
2133     * Populates the <code>ChildObjectPropertyInstance</code>s, of the type
2134     * specified by the class name given, held by this <code>Profile</code>.
2135     *
2136     * @param sTableName the database table name of the <code>AbstractChildObject</code>
2137     * class which can be values for the property instances to be populated
2138     *
2139     * @throws PopulateException if any errors occur
2140     */

2141    protected synchronized void populateChildObjectPropertyInstances(String JavaDoc sTableName)
2142        throws PopulateException {
2143        PropertyInstanceStore propStore =
2144            (PropertyInstanceStore) m_propStores.get(sTableName);
2145
2146        if (propStore.isPopulated() == false) {
2147
2148            SelectStatement select = new SelectStatement();
2149
2150            boolean bIsHist = isHistorical();
2151            ColumnRef dataPropIdCol = null;
2152                
2153            try {
2154
2155                String JavaDoc sProfDataTable =
2156                    ChildObjectPropertyInstance.constructDBTableName(
2157                        this,
2158                        sTableName);
2159                String JavaDoc sClassname = propStore.getAssociatedClassname();
2160                        
2161                ColumnRef valIdCol = AbstractObject.getColumnRef(sClassname, ATTRIB_ID);
2162                ColumnRef valTypeCol = AbstractObject.getColumnRef(sClassname, ATTRIB_TYPE);
2163                ColumnRef propTypeCol = AbstractObject.getColumnRef(Property.class.getName(),AbstractObject.ATTRIB_TYPE);
2164                ColumnRef propIdCol = AbstractObject.getColumnRef(Property.class.getName(),AbstractObject.ATTRIB_ID);
2165                
2166                dataPropIdCol = getProfileDataColumn(
2167                sProfDataTable,
2168                AbstractPropertyInstance.CLMN_PROPERTY_ID);
2169                
2170                ColumnRef objIdCol = getProfileDataColumn(
2171                sProfDataTable,
2172                ChildObjectPropertyInstance.CLMN_OBJECT_ID);
2173
2174                select.addSelectColumn(
2175                    getProfileDataColumn(
2176                        sProfDataTable,
2177                        AbstractPropertyInstance.CLMN_ID));
2178
2179                select.addSelectColumn(dataPropIdCol);
2180
2181                ColumnRef ver_com_colref =
2182                    getProfileDataColumn(
2183                        sProfDataTable,
2184                        AbstractPropertyInstance.CLMN_VERSION_COMMENT);
2185
2186                select.addSelectColumn(ver_com_colref);
2187                select.addSelectColumn(objIdCol);
2188                        
2189                select.addSelectColumn(valTypeCol);
2190                select.addSelectColumn(propTypeCol);
2191                
2192
2193                ColumnRef profId_colref =
2194                    getProfileDataColumn(
2195                        sProfDataTable,
2196                        AbstractPropertyInstance.CLMN_PROFILE_ID);
2197                        
2198                select.addJoinCondition(valIdCol, objIdCol);
2199                select.addJoinCondition(propIdCol, dataPropIdCol);
2200                
2201                select.addWhereCondition(profId_colref, "=", m_nId);
2202                
2203                //need to add order by to ensure that all property instances
2204
//of a property get handled consecutively
2205
select.setOrderBy(dataPropIdCol);
2206
2207            } catch (DataStoreException da_e) {
2208                throw new PopulateException(
2209                    "Error occured building query",da_e);
2210            }
2211
2212            ResultSet rs = null;
2213
2214            try {
2215                int nPropId = 0;
2216                rs = m_dsi.execute(select);
2217                ChildObjectPropertyInstance propInst = null;
2218                while (rs.next()) {
2219                    nPropId = rs.getInt(2);
2220                    
2221                    if (propInst == null
2222                        || propInst.getProperty().getId() != nPropId) {
2223                        if(propInst != null) {
2224                            propInst.setIsPopulated(true);
2225                        }
2226                        
2227                        Property prop = (Property) HarmoniseObjectFactory.instantiateHarmoniseObject(
2228                                            m_dsi,
2229                                            rs.getString(6),
2230                                            nPropId);
2231                        
2232                        //if prop no longer exists we hve to delete all prop insts with
2233
//this prop and not add it to this profile
2234
if(prop == null) {
2235                            if(m_logger.isLoggable(Level.INFO)) {
2236                                m_logger.logp(Level.INFO, this.getClass().getName(), "populateGeneralPropertyInstances", "Property " + nPropId + " no longer exists so removing value");
2237                            }
2238                            
2239                            DeleteStatement delete = new DeleteStatement();
2240                            
2241                            delete.addWhereCondition(dataPropIdCol, "=", nPropId);
2242                            
2243                            m_dsi.execute(delete);
2244                            
2245                            propInst = null;
2246                            
2247                            continue;
2248                        }
2249
2250                        Range range = prop.getRange();
2251                        
2252                        if(range == null) {
2253                            throw new PopulateException("No range attached to property");
2254                        }
2255                        
2256                        propInst = (ChildObjectPropertyInstance) range.getPropertyInstanceClass().newInstance();
2257                        propInst.setDataStoreInterface(m_dsi);
2258                        propInst.setProfile(this);
2259                        
2260
2261                        propInst.setProperty(prop);
2262                        propInst.setVersionComment(rs.getString(3));
2263
2264                        propStore.addPropertyInstance(propInst);
2265                    }
2266
2267                    AbstractChildObject child =
2268                        (
2269                            AbstractChildObject) HarmoniseObjectFactory
2270                                .instantiateHarmoniseObject(
2271                            m_dsi,
2272                            rs.getString(5),
2273                            rs.getInt(4));
2274
2275                    propInst.addValue(child,rs.getInt(1));
2276                }
2277                if(propInst != null) {
2278                    propInst.setIsPopulated(true);
2279                }
2280
2281                propStore.setIsPopulated(true);
2282            } catch (SQLException sql_e) {
2283                throw new PopulateException(
2284                    "Error occured processing query",sql_e);
2285            } catch (HarmoniseFactoryException f_e) {
2286                throw new PopulateException(
2287                    "Error occured getting property from factory",f_e);
2288            } catch (DataStoreException ds_e) {
2289                throw new PopulateException(
2290                    "Error occured processing query",ds_e);
2291            } catch (DataAccessException da_e) {
2292                throw new PopulateException(
2293                    "Error occured populating property instance",da_e);
2294            } catch (InvalidPropertyValueException ipv_e) {
2295                //do nothing - the value just won't be added
2296
m_logger.log(Level.FINE,"Ignoring exception",ipv_e);
2297            } catch (InstantiationException JavaDoc e) {
2298                throw new PopulateException(e.getLocalizedMessage(),e);
2299            } catch (IllegalAccessException JavaDoc e) {
2300                throw new PopulateException(e.getLocalizedMessage(),e);
2301            } catch (ClassNotFoundException JavaDoc e) {
2302                throw new PopulateException(e.getLocalizedMessage(),e);
2303            } finally {
2304                if (rs != null) {
2305                    try {
2306
2307                        rs.close();
2308                    } catch (SQLException sql_e) {
2309                        throw new PopulateException(
2310                            "Had trouble closing result set",sql_e);
2311                    }
2312                }
2313            }
2314        }
2315    }
2316
2317    
2318    /*--------------------------------------------------------------------------
2319                    
2320    Private Functions
2321    
2322    ---------------------------------------------------------------------------*/

2323
2324    /**
2325     * Returns the <code>ColumnRef</code> for the profile data associated with
2326     * the specified table and column.
2327     *
2328     * @param sTable the property instance database table
2329     * @param sCol the column name
2330     * @return the matching column reference for the specified table and column
2331     * @throws DataStoreException if no valid column references match the
2332     * specified table and column
2333     */

2334    private ColumnRef getProfileDataColumn(String JavaDoc sTable, String JavaDoc sCol)
2335        throws DataStoreException {
2336        ColumnRef returnColRef = null;
2337
2338        if (sCol.equals(AbstractPropertyInstance.CLMN_PROPERTY_ID) == true) {
2339            returnColRef =
2340                new ColumnRef(
2341                    sTable,
2342                    AbstractPropertyInstance.CLMN_PROPERTY_ID,
2343                    ColumnRef.NUMBER);
2344        } else if (
2345            sCol.equals(GeneralPropertyInstance.CLMN_PROFILE_ID) == true) {
2346            returnColRef =
2347                new ColumnRef(
2348                    sTable,
2349                    GeneralPropertyInstance.CLMN_PROFILE_ID,
2350                    ColumnRef.NUMBER);
2351        } else if (
2352            sCol.equals(AbstractPropertyInstance.CLMN_VERSION_COMMENT)
2353                == true) {
2354            returnColRef =
2355                new ColumnRef(
2356                    sTable,
2357                    AbstractPropertyInstance.CLMN_VERSION_COMMENT,
2358                    ColumnRef.TEXT);
2359        } else if (sCol.equals(GeneralPropertyInstance.CLMN_VALUE) == true) {
2360            returnColRef =
2361                new ColumnRef(
2362                    sTable,
2363                    GeneralPropertyInstance.CLMN_VALUE,
2364                    ColumnRef.TEXT);
2365        } else if (sCol.equals(GeneralPropertyInstance.CLMN_ID) == true) {
2366            returnColRef =
2367                new ColumnRef(
2368                    sTable,
2369                    GeneralPropertyInstance.CLMN_ID,
2370                    ColumnRef.NUMBER);
2371        } else if (
2372            sCol.equals(ProfilePropertyInstance.CLMN_PROFILE_PARENT) == true) {
2373            returnColRef =
2374                new ColumnRef(
2375                    sTable,
2376                    ProfilePropertyInstance.CLMN_PROFILE_PARENT,
2377                    ColumnRef.NUMBER);
2378        } else if (sCol.equals(CLMN_NAME) == true) {
2379            returnColRef = new ColumnRef(sTable, CLMN_NAME, ColumnRef.NUMBER);
2380        } else if (sCol.equals(CLMN_SUMMARY) == true) {
2381            returnColRef =
2382                new ColumnRef(sTable, CLMN_SUMMARY, ColumnRef.NUMBER);
2383        } else if (
2384            sCol.equals(ChildObjectPropertyInstance.CLMN_OBJECT_ID) == true) {
2385            returnColRef =
2386                new ColumnRef(
2387                    sTable,
2388                    ChildObjectPropertyInstance.CLMN_OBJECT_ID,
2389                    ColumnRef.NUMBER);
2390        }
2391
2392        if (returnColRef != null) {
2393            return returnColRef;
2394        } else {
2395            throw new InvalidColumnReferenceException(sCol);
2396        }
2397    }
2398
2399    /**
2400     * Returns <code>true</code> if all the property instances have been
2401     * populated, otherwise <code>false</code>.
2402     *
2403     * @return <code>true</code> if all the property instances have been
2404     * populated, otherwise <code>false</code>
2405     * @throws DataAccessException if any errors occur accessing property
2406     * instance data
2407     */

2408    private boolean isPropertyInstancesPopulated() throws DataAccessException {
2409        boolean bIsPopulated = true;
2410
2411        initialisePropertyInstanceStores();
2412
2413        Iterator iter = m_propStores.values().iterator();
2414
2415        while (bIsPopulated == true && iter.hasNext()) {
2416            PropertyInstanceStore propStore =
2417                (PropertyInstanceStore) iter.next();
2418            if (propStore.isPopulated() == false) {
2419                bIsPopulated = false;
2420            }
2421        }
2422
2423        return bIsPopulated;
2424    }
2425
2426    /**
2427     * Initialises the collection of <code>PropertyInstanceStore</code>s.
2428     *
2429     * @throws DataAccessException if an error occurs finding the available
2430     * properties or initialising the appropriate <code>PropertyInstanceStore</code>s
2431     *
2432     */

2433    private void initialisePropertyInstanceStores()
2434        throws DataAccessException {
2435        String JavaDoc sKey = null;
2436        String JavaDoc sClassname = null;
2437
2438        List props = getAvailableProperties();
2439
2440        Iterator iter = props.iterator();
2441        
2442        while (iter.hasNext()) {
2443            Property prop = (Property) iter.next();
2444
2445            if (isPropertyInstanceProfile(prop) == true) {
2446                sKey = Profile.class.getName();
2447
2448            } else if (isPropertyInstanceChildObject(prop) == true) {
2449                Range range = prop.getRange();
2450                if(m_profObj instanceof AbstractChildObject) {
2451                    sClassname = ((ChildObjectRange)range).getChildObjectValueClassName((AbstractChildObject) m_profObj);
2452                } else {
2453                    sClassname = range.getObject();
2454                }
2455                
2456                try {
2457                    sKey = DatabaseInfo.getInstance().getTableName(sClassname);
2458                } catch (DataStoreException e) {
2459                    throw new DataAccessException("Trouble finding class for " + sKey);
2460                }
2461                
2462            } else {
2463                sKey = GeneralPropertyInstance.class.getName();
2464            }
2465
2466            if (m_propStores.containsKey(sKey) == false) {
2467                if(sClassname == null) {
2468                    m_propStores.put(sKey, new PropertyInstanceStore(sKey));
2469                } else {
2470                    m_propStores.put(sKey, new PropertyInstanceStore(sKey,sClassname));
2471                }
2472            }
2473        }
2474    }
2475
2476    /**
2477     * Returns <code>true</code> if the specified <code>Property</code>
2478     * represents a general datatype property.
2479     *
2480     * @param prop the <code>Property</code> to test
2481     * @return <code>true</code> if the <code>Property</code> given
2482     * represents a general datatype property.
2483     * @throws DataAccessException if there is an error accessing the
2484     * <code>Range</code> of the <code>Property</code>
2485     */

2486    private boolean isPropertyInstanceGeneral(Property prop)
2487        throws DataAccessException {
2488        boolean bIsGen = false;
2489        if(prop != null) {
2490            Range range = prop.getRange();
2491    
2492            try{
2493                if (GeneralPropertyInstance.class.isAssignableFrom(range.getPropertyInstanceClass())) {
2494                    bIsGen = true;
2495                }
2496            } catch (ClassNotFoundException JavaDoc e) {
2497                m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
2498            }
2499        }
2500
2501        return bIsGen;
2502    }
2503
2504    /**
2505     * Returns <code>true</code> if the specified <code>Property</code>
2506     * represents an <code>AbstractChildObject</code> datatype property.
2507     *
2508     * @param prop the <code>Property</code> to test
2509     * @return <code>true</code> if the specified <code>Property</code>
2510     * represents an <code>AbstractChildObject</code> datatype property.
2511     * @throws DataAccessException if there is an error accessing the
2512     * <code>Range</code> of the <code>Property</code>
2513     */

2514    private boolean isPropertyInstanceChildObject(Property prop)
2515        throws DataAccessException {
2516
2517        boolean bIsChild = false;
2518        if(prop != null) {
2519        
2520            Range range = prop.getRange();
2521            
2522            if(range != null) {
2523                try{
2524                    if (ChildObjectPropertyInstance.class.isAssignableFrom(range.getPropertyInstanceClass())) {
2525                        bIsChild = true;
2526                    }
2527                } catch (ClassNotFoundException JavaDoc e) {
2528                    m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
2529                }
2530            }
2531        }
2532
2533        return bIsChild;
2534    }
2535
2536    /**
2537     * Returns <code>true</code> if the specified <code>Property</code>
2538     * represents a <code>Profile</code> datatype property.
2539     *
2540     * @param prop the <code>Property</code> to test
2541     * @return <code>true</code> if the specified <code>Property</code>
2542     * represents a <code>Profile</code> datatype property.
2543     * @throws DataAccessException if there is an error accessing the
2544     * <code>Range</code> of the <code>Property</code>
2545     */

2546    private boolean isPropertyInstanceProfile(Property prop)
2547        throws DataAccessException {
2548
2549        boolean bIsProfile = false;
2550        if(prop != null) {
2551            
2552            Range range = prop.getRange();
2553            if(range != null) {
2554                try {
2555                    if (ProfilePropertyInstance.class.isAssignableFrom(range.getPropertyInstanceClass())) {
2556                        bIsProfile = true;
2557                    }
2558                } catch (ClassNotFoundException JavaDoc e) {
2559                    m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
2560                }
2561            }
2562        }
2563
2564        return bIsProfile;
2565    }
2566
2567    /**
2568     * Updates all property instance data in the database.
2569     *
2570     * @throws PopulateException if there is an error accessing data held in
2571     * the property instances
2572     * @throws EditException if there is an error saving the data to the database
2573     */

2574    private void updatePropertyInstances()
2575        throws PopulateException, EditException {
2576        Iterator iter = m_propStores.values().iterator();
2577
2578        while (iter.hasNext()) {
2579
2580            try {
2581                ((PropertyInstanceStore) iter.next()).update();
2582            } catch (ProfileException e) {
2583                throw new PopulateException(e.getLocalizedMessage(),e);
2584            }
2585
2586        }
2587    }
2588
2589    /**
2590     * Deletes all property instances from the database for the specified
2591     * <code>PropertyInstanceStore</code>.
2592     *
2593     * @param store the <code>PropertyInstanceStore</code> to delete
2594     * @throws ProfileException if an error occurs deleting the data
2595     * from the database
2596     */

2597    private void deletePropertyInstances(PropertyInstanceStore store)
2598        throws ProfileException {
2599        String JavaDoc sStoreLabel = store.getLabel();
2600
2601        if (sStoreLabel.equals(Profile.class.getName()) == true) {
2602            Iterator iter = store.getValues().iterator();
2603
2604            while (iter.hasNext()) {
2605                ProfilePropertyInstance propInst =
2606                    (ProfilePropertyInstance) iter.next();
2607
2608                propInst.delete();
2609            }
2610        } else {
2611            DeleteStatement delete = new DeleteStatement();
2612
2613            String JavaDoc sDataTable = null;
2614
2615            if (sStoreLabel.equals(GeneralPropertyInstance.class.getName())
2616                == true) {
2617                sDataTable = GeneralPropertyInstance.getDBTableName(this);
2618            } else {
2619                try {
2620                    sDataTable =
2621                        ChildObjectPropertyInstance.getDBTableName(
2622                            this,
2623                            store.getAssociatedClassname());
2624                } catch (DataStoreException e) {
2625                    throw new ProfileException(
2626                        "Problem finding profile data table",e);
2627                }
2628            }
2629
2630            try {
2631                ColumnRef profId_colref =
2632                    getProfileDataColumn(
2633                        sDataTable,
2634                        GeneralPropertyInstance.CLMN_PROFILE_ID);
2635
2636                delete.addWhereCondition(profId_colref, "=", m_nId);
2637                m_dsi.execute(delete);
2638            } catch (DataStoreException e) {
2639                throw new ProfileException(
2640                    "Error occured deleting property instances",e);
2641            }
2642
2643        }
2644
2645    }
2646
2647    /**
2648     * Populates the given <code>PropertyInstanceStore</code> from the database.
2649     *
2650     * @param propStore the <code>PropertyInstanceStore</code> to populate
2651     * @throws PopulateException if there is an error populating the
2652     * <code>PropertyInstanceStore</code>
2653     */

2654    private void populatePropertyInstanceStore(PropertyInstanceStore propStore)
2655        throws PopulateException {
2656        if(propStore.isPopulated() == false) {
2657            if (propStore
2658                .getLabel()
2659                .equals(GeneralPropertyInstance.class.getName())
2660                == true) {
2661                populateGeneralPropertyInstances();
2662            } else if (
2663                propStore.getLabel().equals(Profile.class.getName()) == true) {
2664                populateProfilePropertyInstances();
2665            } else {
2666                //assume it's a store for child object prop insts
2667
populateChildObjectPropertyInstances(propStore.getLabel());
2668            }
2669        }
2670        
2671    }
2672
2673    /**
2674     * Returns the <code>PropertyInstanceStore</code> associated with the specified
2675     * <code>Property</code>.
2676     *
2677     * @param prop the <code>Property</code>
2678     * @return the <code>PropertyInstanceStore</code> associated with the specified
2679     * <code>Property</code>
2680     * @throws InvalidPropertyInstanceException if the specified <code>Property</code>
2681     * is invalid for this <code>Profile</code>
2682     * @throws DataAccessException if there is an error getting the <code>Range</code>
2683     * for the <code>Property</code>
2684     */

2685    private PropertyInstanceStore getPropertyInstanceStore(Property prop)
2686        throws InvalidPropertyInstanceException, DataAccessException {
2687        PropertyInstanceStore propStore = null;
2688        String JavaDoc sKey = null;
2689        String JavaDoc sClassname = null;
2690
2691        if (isValidProperty(prop) == false) {
2692            
2693            String JavaDoc sPropName = null;
2694            
2695            if(prop != null) {
2696                sPropName = prop.getName();
2697            }
2698            
2699            throw new InvalidPropertyInstanceException(
2700                "Property not valid on [" + m_profObj + "]:" + sPropName);
2701        }
2702
2703        if (isPropertyInstanceChildObject(prop) == true) {
2704            ChildObjectRange range = (ChildObjectRange) prop.getRange();
2705            if(m_profObj instanceof AbstractChildObject) {
2706                sClassname = range.getChildObjectValueClassName((AbstractChildObject) m_profObj);
2707            } else {
2708                sClassname = prop.getRange().getObject();
2709            }
2710            
2711            try {
2712                sKey = DatabaseInfo.getInstance().getTableName(sClassname);
2713            } catch (DataStoreException e) {
2714                throw new DataAccessException("Trouble finding class for " + sKey);
2715            }
2716
2717        } else if (isPropertyInstanceGeneral(prop) == true) {
2718            sKey = GeneralPropertyInstance.class.getName();
2719
2720        } else if (isPropertyInstanceProfile(prop) == true) {
2721            sKey = Profile.class.getName();
2722        } else {
2723            throw new InvalidPropertyInstanceException("Property not allowed in profile");
2724        }
2725
2726        propStore = (PropertyInstanceStore) m_propStores.get(sKey);
2727
2728        if (propStore == null) {
2729            //double checked synchronized block to avoid concurrency problems
2730
synchronized (m_propStores) {
2731                propStore = (PropertyInstanceStore) m_propStores.get(sKey);
2732
2733                if (propStore == null) {
2734                    if(sClassname == null) {
2735                        propStore = new PropertyInstanceStore(sKey);
2736                    } else {
2737                        propStore = new PropertyInstanceStore(sKey,sClassname);
2738                    }
2739                    
2740                    m_propStores.put(sKey, propStore);
2741                }
2742            }
2743            
2744        }
2745
2746        return propStore;
2747    }
2748
2749    /**
2750     * Returns the <code>PropertyInstanceStore</code> assocated with the
2751     * <code>Property</code> of the specified name.
2752     *
2753     * @param sPropName the name of the <code>Property</code>
2754     * @return the <code>PropertyInstanceStore</code> assocated with the
2755     * <code>Property</code> of the specified name.
2756     */

2757    private PropertyInstanceStore getPropertyInstanceStore(String JavaDoc sPropName) {
2758        PropertyInstanceStore propStoreResult = null;
2759
2760        Iterator iter = m_propStores.keySet().iterator();
2761
2762        while (iter.hasNext() == true && propStoreResult == null) {
2763            PropertyInstanceStore propStore =
2764                (PropertyInstanceStore) m_propStores.get(iter.next());
2765
2766            if (propStore.contains(sPropName) == true) {
2767                propStoreResult = propStore;
2768            }
2769        }
2770
2771        return propStoreResult;
2772    }
2773    
2774    /**
2775     * Sets the profiled object for this profile.
2776     *
2777     * @param obj the profiled object
2778     */

2779    public void setProfiledObject(AbstractProfiledObject obj) {
2780        m_profObj = obj;
2781    }
2782
2783    /* (non-Javadoc)
2784     * @see java.lang.Object#equals(java.lang.Object)
2785     */

2786    public boolean equals(Object JavaDoc obj) {
2787        boolean bReturn = false;
2788
2789        if (obj instanceof Profile) {
2790            
2791            if (this == obj) {
2792                bReturn = true;
2793            } else if (
2794                obj.getClass().getName().equals(getClass().getName())
2795                    == true) {
2796                        
2797                try {
2798                    populateFromDatabase();
2799                } catch (PopulateException e) {
2800                    m_logger.log(Level.WARNING,e.getLocalizedMessage(),e);
2801                }
2802                
2803                Profile objCompare = (Profile) obj;
2804
2805                try {
2806                    if ((this.getId() != 0) && (objCompare.getId() != 0)) {
2807                        if (m_nId == objCompare.getId()) {
2808                            bReturn = true;
2809                        }
2810                    }
2811
2812                    if (bReturn == true && m_sName.equals(objCompare.getName())) {
2813                        bReturn = true;
2814                    }
2815                        
2816                    
2817                    if(bReturn == true) {
2818                        bReturn = match(objCompare);
2819                    }
2820                    
2821                } catch (Exception JavaDoc e) {
2822                    throw new RuntimeException JavaDoc(e.getMessage());
2823                }
2824            }
2825
2826        }
2827
2828        return bReturn;
2829    }
2830
2831    /* (non-Javadoc)
2832     * @see org.openharmonise.rm.resources.AbstractObject#isKeySupported()
2833     */

2834    protected boolean isKeySupported() {
2835        return false;
2836    }
2837
2838    /**
2839     * Returns <code>true</code> if this profile conforms to the restrictions
2840     * determined by the domains on the available properties.
2841     *
2842     * @return <code>true</code> if this profile conforms to the restrictions
2843     * determined by the domains on the available properties.
2844     *
2845     * @throws DataAccessException if any errors occur getting the available
2846     * properties for this <code>Profile</code>.
2847     */

2848    public boolean isValid(AbstractProfiledObject profObj) throws DataAccessException {
2849        boolean bIsValid = true;
2850        
2851        List props = Domain.getAvailableProperties(m_dsi, profObj);
2852        
2853        Iterator iter = props.iterator();
2854        
2855        while (iter.hasNext() && bIsValid == true) {
2856            Property prop = (Property) iter.next();
2857            Domain domain = prop.getDomain(profObj);
2858            
2859            try {
2860                if(hasProperty(prop) == true) {
2861                    AbstractPropertyInstance propInst = getPropertyInstance(prop);
2862                    
2863                    int nVals = propInst.getValues().size();
2864                    
2865                    if(domain.getMinOccurs() > nVals) {
2866                        if(m_logger.isLoggable(Level.INFO)) {
2867                            m_logger.logp(Level.INFO, this.getClass().getName(), "isValid", "MinOccurs is greater than number of vals for prop " + prop.getName() + " on object " + m_profObj.getClass().getName() + " key " + m_profObj.getKey());
2868                        }
2869                        bIsValid = false;
2870                    }
2871                    
2872                    if(domain.getMaxOccurs() > 0 && domain.getMaxOccurs() < nVals) {
2873                        if(m_logger.isLoggable(Level.INFO)) {
2874                            m_logger.logp(Level.INFO, this.getClass().getName(), "isValid", "MaxOccurs is less than number of vals for prop " + prop.getName() + " on object " + m_profObj.getClass().getName() + " key " + m_profObj.getKey());
2875                        }
2876                        bIsValid = false;
2877                    }
2878                } else {
2879                    if(domain.getMinOccurs() > 0) {
2880                        if(m_logger.isLoggable(Level.INFO)) {
2881                            m_logger.logp(Level.INFO, this.getClass().getName(), "isValid", "Mandatory prop inst does not exist for prop " + prop.getName() + " on object " + m_profObj.getClass().getName() + " key " + m_profObj.getKey());
2882                        }
2883                        bIsValid = false;
2884                    }
2885                }
2886            } catch (InvalidPropertyInstanceException e) {
2887                throw new DataAccessException(e.getLocalizedMessage(),e);
2888            }
2889        }
2890        
2891        return bIsValid;
2892    }
2893    
2894    /**
2895     * Removes the specified property instance from this <code>Profile</code>.
2896     *
2897     * @param propInst the property instance to remove
2898     * @throws InvalidPropertyInstanceException if the specified property instance
2899     * is invalid for this <code>Profile</code>
2900     * @throws DataAccessException if there is an error getting the
2901     * <code>Property</code> associated to the property instance
2902     */

2903    private void removePropertyInstance(AbstractPropertyInstance propInst) throws InvalidPropertyInstanceException, DataAccessException {
2904        PropertyInstanceStore propStore = getPropertyInstanceStore(propInst.getProperty());
2905        
2906        propStore.removePropertyInstance(propInst);
2907    }
2908
2909    /* (non-Javadoc)
2910     * @see org.openharmonise.rm.resources.AbstractObject#isHistorical()
2911     */

2912    public boolean isHistorical() {
2913        
2914        boolean bIsHist = super.isHistorical();
2915        
2916        //check that profile's in line with prof obj
2917
if(bIsHist == false && m_profObj != null && m_profObj.isHistorical() == true) {
2918            bIsHist = true;
2919            setHistorical(bIsHist);
2920        }
2921        
2922        return bIsHist;
2923    }
2924
2925    /* (non-Javadoc)
2926     * @see org.openharmonise.rm.resources.AbstractObject#markAsNew()
2927     */

2928    public void markAsNew() throws PopulateException {
2929        m_bNew = true;
2930        super.markAsNew();
2931    }
2932    
2933    /**
2934     * Returns the base class for the given class which is a concrete
2935     * implementation of <code>AbstractChildObject</code>.
2936     *
2937     * @param clss <code>Class</code> from which to find the base
2938     * <code>AbstractChildObject</code> implementation
2939     * @return the base class for the given class which is a concrete
2940     * implementation of <code>AbstractChildObject</code>
2941     */

2942    private Class JavaDoc getBaseChildObjectClass(Class JavaDoc clss) {
2943        Class JavaDoc returnClass = null;
2944        Class JavaDoc superClass = clss.getSuperclass();
2945        
2946        if(superClass.equals(AbstractChildObject.class)) {
2947            returnClass = clss;
2948        } else {
2949            returnClass = getBaseChildObjectClass(superClass);
2950        }
2951        
2952        return returnClass;
2953    }
2954
2955
2956    /**
2957     * Deletes the property instance held by this <code>Profile</code>
2958     * associated with the specified <code>Property</code>.
2959     *
2960     * @param prop the <code>Property</code>
2961     * @throws ProfileException
2962     * @throws InvalidPropertyInstanceException
2963     * @throws DataAccessException
2964     */

2965    private void deletePropertyInstance(Property prop) throws ProfileException, InvalidPropertyInstanceException, DataAccessException {
2966        
2967        AbstractPropertyInstance propInst = getPropertyInstance(prop);
2968        
2969        if(propInst instanceof ProfilePropertyInstance) {
2970            ProfilePropertyInstance profPropInst = (ProfilePropertyInstance) propInst;
2971            
2972            profPropInst.delete();
2973        } else {
2974            DeleteStatement delete = new DeleteStatement();
2975
2976            String JavaDoc sDataTable = propInst.getDBTableName();
2977
2978            try {
2979                ColumnRef profId_colref =
2980                    getProfileDataColumn(
2981                        sDataTable,
2982                        GeneralPropertyInstance.CLMN_PROFILE_ID);
2983
2984                delete.addWhereCondition(profId_colref, "=", m_nId);
2985                
2986                ColumnRef dataPropIdCol = getProfileDataColumn(
2987                        sDataTable,
2988                        AbstractPropertyInstance.CLMN_PROPERTY_ID);
2989                
2990                delete.addWhereCondition(dataPropIdCol, "=", prop.getId());
2991                
2992                m_dsi.execute(delete);
2993            } catch (DataStoreException e) {
2994                throw new ProfileException(
2995                    "Error occured deleting property instances",e);
2996            }
2997
2998        }
2999        
3000    }
3001    
3002
3003    private void deletePropertyInstanceData(AbstractPropertyInstance propInst) throws ProfileException, InvalidPropertyInstanceException, DataAccessException {
3004        
3005        if(propInst instanceof ProfilePropertyInstance) {
3006            ProfilePropertyInstance profPropInst = (ProfilePropertyInstance) propInst;
3007            
3008            profPropInst.delete();
3009        } else {
3010            DeleteStatement delete = new DeleteStatement();
3011
3012            String JavaDoc sDataTable = propInst.getDBTableName();
3013
3014            try {
3015                ColumnRef profId_colref =
3016                    getProfileDataColumn(
3017                        sDataTable,
3018                        GeneralPropertyInstance.CLMN_PROFILE_ID);
3019
3020                delete.addWhereCondition(profId_colref, "=", m_nId);
3021                
3022                ColumnRef colDataId =
3023                        getProfileDataColumn(
3024                                sDataTable,
3025                            AbstractPropertyInstance.CLMN_ID);
3026                
3027                delete.addWhereCondition(colDataId, "=", propInst.getId());
3028                
3029                m_dsi.execute(delete);
3030            } catch (DataStoreException e) {
3031                throw new ProfileException(
3032                    "Error occured deleting property instances",e);
3033            }
3034
3035        }
3036        
3037    }
3038
3039
3040    /**
3041     * A class to group concrete implementations of
3042     * <code>AbstractPropertyInstance</code> by type.
3043     *
3044     * @author Michael Bell
3045     * @version $Revision: 1.8 $
3046     *
3047     */

3048    private class PropertyInstanceStore implements Cloneable JavaDoc {
3049        /**
3050         * <code>boolean</code> flag to indicate whether this object has been
3051         * changed since it was populated
3052         */

3053        private boolean m_bIsChanged = false;
3054        /**
3055         * <code>boolean</code> flag to indicate whether this object has been
3056         * populated
3057         */

3058        private boolean m_bIsPopulated = false;
3059        /**
3060         * <code>Map</code> of <code>Property</code> names to
3061         * <code>AbstractPropertyInsatance</code>s
3062         */

3063        private Map m_propInsts = new Hashtable();
3064        /**
3065         * List of props which have been removed and need to be deleted on update
3066         */

3067        private List m_deadProps = new ArrayList();
3068        /**
3069         * The label assocaited to this <code>PropertyInstanceStore</code>
3070         */

3071        private String JavaDoc m_sLabel = null;
3072        /**
3073         * The class name associated with this <code>PropertyInstanceStore</code>
3074         */

3075        private String JavaDoc m_sClassname = null;
3076
3077        /**
3078         * Constructs a <code>PropertyInstanceStore</code> with the specified label
3079         *
3080         */

3081        PropertyInstanceStore(String JavaDoc sLabel) {
3082            m_sLabel = sLabel;
3083        }
3084        
3085        /**
3086         * Constructs a <code>PropertyInstanceStore</code> with the specified label
3087         * and a assocated class name
3088         *
3089         */

3090        PropertyInstanceStore(String JavaDoc sLabel, String JavaDoc sClassname) {
3091            m_sLabel = sLabel;
3092            m_sClassname = sClassname;
3093        }
3094        
3095        /**
3096         * Constructs a new property instance store which is a copy of the
3097         * passed in property instance store
3098         *
3099         * @param other property instance store to replicate
3100         */

3101        PropertyInstanceStore(PropertyInstanceStore other) {
3102            m_sLabel = other.m_sLabel;
3103            m_sClassname = other.m_sClassname;
3104            m_bIsChanged = other.m_bIsChanged;
3105            m_bIsPopulated = other.m_bIsPopulated;
3106            
3107            Iterator iter = other.m_propInsts.keySet().iterator();
3108
3109            while (iter.hasNext()) {
3110                String JavaDoc sKey = (String JavaDoc) iter.next();
3111                AbstractPropertyInstance propInst =
3112                    (AbstractPropertyInstance) other.m_propInsts.get(sKey);
3113
3114                m_propInsts.put(sKey, propInst.clone());
3115            }
3116        }
3117
3118        /**
3119         * Returns the label associated with this store
3120         *
3121         * @return the label associated with this store
3122         */

3123        String JavaDoc getLabel() {
3124            return m_sLabel;
3125        }
3126
3127        /**
3128         * Returns the associated class name with this store
3129         *
3130         * @return the associated class name with this store
3131         */

3132        String JavaDoc getAssociatedClassname() {
3133            return m_sClassname;
3134        }
3135
3136        /**
3137         * Returns <code>true</code> if any of the property instances in the
3138         * store have changed since being populated from the database
3139         *
3140         * @return <code>true</code> if any of the property instances in the
3141         * store have changed
3142         */

3143        boolean isChanged() {
3144
3145            if (m_bIsChanged == false) {
3146                Iterator iter = m_propInsts.values().iterator();
3147
3148                while (iter.hasNext() && m_bIsChanged == false) {
3149                    AbstractPropertyInstance next =
3150                        (AbstractPropertyInstance) iter.next();
3151
3152                    if (next.isChanged()) {
3153                        m_bIsChanged = true;
3154                    }
3155                }
3156            }
3157            return m_bIsChanged;
3158        }
3159
3160        /**
3161         * Marks this store as having been changed since being populated from
3162         * the database
3163         *
3164         * @param bIsChanged <code>true</code> to indicate that this store has
3165         * been changed, otherwise <code>false</code>
3166         */

3167        void setIsChanged(boolean bIsChanged) {
3168            m_bIsChanged = bIsChanged;
3169        }
3170
3171        /**
3172         * Returns <code>true</code> if this store has been populated
3173         *
3174         * @return <code>true</code> if this store has been populated
3175         */

3176        boolean isPopulated() {
3177            return m_bIsPopulated;
3178        }
3179
3180        /**
3181         * Marks this store as having been populated
3182         *
3183         * @param bIsPopulated <code>true</code> to indicate that this
3184         * store has been populated
3185         */

3186        void setIsPopulated(boolean bIsPopulated) {
3187            m_bIsPopulated = bIsPopulated;
3188        }
3189
3190        /**
3191         * Adds the specified property instance to this store
3192         *
3193         * @param propInst the property instance to add
3194         * @throws DataAccessException if there is an error getting the name
3195         * of the associated <code>Property</code>
3196         */

3197        void addPropertyInstance(AbstractPropertyInstance propInst)
3198            throws DataAccessException {
3199            if (m_bIsPopulated == true && m_propInsts.containsValue(propInst) == false) {
3200                m_bIsChanged = true;
3201            }
3202                
3203            m_propInsts.put(propInst.getName(), propInst);
3204        }
3205
3206        /**
3207         * Removes the specified property instance from the store
3208         *
3209         * @param prop the <code>Property</code> whose instances are to be
3210         * removed from this store
3211         * @throws DataAccessException if an error occurs getting the name of the
3212         * given <code>Property</code>
3213         */

3214        void removePropertyInstance(Property prop) throws DataAccessException {
3215            String JavaDoc sPropName = prop.getName();
3216            if (contains(prop) == true) {
3217                m_deadProps.add(m_propInsts.get(sPropName));
3218                m_propInsts.remove(sPropName);
3219                m_bIsChanged = true;
3220            }
3221        }
3222
3223        /**
3224         * Returns <code>true</code> if this store contains an
3225         * instance of the given <code>Property</code>.
3226         *
3227         * @param prop the <code>Property</code>
3228         * @return <code>true</code> if this store contains an
3229         * instance of the given <code>Property</code>
3230         * @throws DataAccessException if an error occurs getting the name of the
3231         * given <code>Property</code>
3232         */

3233        boolean contains(Property prop) throws DataAccessException {
3234            return contains(prop.getName());
3235        }
3236
3237        /**
3238         * Returns <code>true</code> if this store contains the specified
3239         * <code>AbstractPropertyInstance</code>.
3240         *
3241         * @param propInst the prperty instance whose presence is to be tested
3242         * @return <code>true</code> if this store contains the specified
3243         * <code>AbstractPropertyInstance</code>
3244         */

3245        boolean contains(AbstractPropertyInstance propInst) {
3246            return m_propInsts.containsValue(propInst);
3247        }
3248
3249        /**
3250         * Returns <code>true</code> if this store contains an instance
3251         * of the <code>Property</code> of the specified name.
3252         *
3253         * @param sPropName the <code>Property</code> name
3254         * @return <code>true</code> if this store contains an instance
3255         * of the <code>Property</code> of the specified name
3256         */

3257        public boolean contains(String JavaDoc sPropName) {
3258            return m_propInsts.containsKey(sPropName);
3259        }
3260
3261        /**
3262         * Returns the <code>AbstractPropertyInstance</code>s contained in this store.
3263         *
3264         * @return the <code>AbstractPropertyInstance</code>s contained in this store
3265         */

3266        Collection getValues() {
3267            return m_propInsts.values();
3268        }
3269
3270        /**
3271         * Returns the <code>AbstractPropertyInstance</code> from the store that
3272         * matches the given <code>Property</code>.
3273         *
3274         * @param prop the <code>Property</code> of the instance to be returned
3275         * @return the <code>AbstractPropertyInstance</code> from the store that
3276         * matches the given <code>Property</code>
3277         * @throws DataAccessException if there is an error getting the name of
3278         * the <code>Property</code>
3279         */

3280        AbstractPropertyInstance getPropertyInstance(Property prop)
3281            throws DataAccessException {
3282            return getPropertyInstance(prop.getName());
3283        }
3284
3285        /**
3286         * Returns the <code>AbstractPropertyInstance</code> from the store that
3287         * matches the specified <code>Property</code> name.
3288         *
3289         * @param sName the name of the <code>Property</code> to return an
3290         * instance of
3291         * @return the <code>AbstractPropertyInstance</code> from the store that
3292         * matches the specified <code>Property</code> name
3293         */

3294        AbstractPropertyInstance getPropertyInstance(String JavaDoc sName) {
3295            return (AbstractPropertyInstance) m_propInsts.get(sName);
3296        }
3297
3298        /* (non-Javadoc)
3299         * @see java.lang.Object#clone()
3300         */

3301        protected Object JavaDoc clone() throws CloneNotSupportedException JavaDoc {
3302            throw new CloneNotSupportedException JavaDoc("Bad - causes all sorts of problems to clone a nested class");
3303        }
3304
3305        /**
3306         * Removes the specified <code>AbstractPropertyInstance</code> from this
3307         * store
3308         *
3309         * @param propInst the <code>AbstractPropertyInstance</code> to remove
3310         * @throws DataAccessException if there is an error getting the name
3311         * of the associated <code>Property</code>
3312         */

3313        void removePropertyInstance(AbstractPropertyInstance propInst) throws DataAccessException {
3314            if(m_bIsPopulated == true && m_propInsts.containsValue(propInst) == true) {
3315                
3316                Object JavaDoc remObj = null;
3317                String JavaDoc sPropName = propInst.getName();
3318                
3319                if(sPropName != null) {
3320                    remObj = m_propInsts.remove(sPropName);
3321                }
3322                
3323                //in case prop insts property no longer exists
3324
if(remObj == null && m_propInsts.values().contains(propInst)) {
3325                    Iterator iter = m_propInsts.keySet().iterator();
3326                    Object JavaDoc propKey = null;
3327                    while (iter.hasNext()) {
3328                        Object JavaDoc key = (Object JavaDoc) iter.next();
3329                        
3330                        if(m_propInsts.get(key).equals(propInst)) {
3331                            propKey = key;
3332                        }
3333                    }
3334                    if(propKey != null) {
3335                        m_propInsts.remove(propKey);
3336                    }
3337                }
3338                m_deadProps.add(propInst);
3339                m_bIsChanged = true;
3340            }
3341            
3342        }
3343        
3344        /**
3345         * Updates all property instance data in the database for the specified
3346         * <code>PropertyInstanceStore</code>
3347         *
3348         * @throws PopulateException if there is an error accessing data held in
3349         * the property instances
3350         * @throws EditException if there is an error saving the data to the database
3351         */

3352        void update() throws ProfileException, EditException {
3353            Iterator iter = getValues().iterator();
3354
3355            while (iter.hasNext()) {
3356                AbstractPropertyInstance propInst =
3357                    (AbstractPropertyInstance) iter.next();
3358
3359                propInst.update(Profile.this);
3360            }
3361            
3362            for (Iterator propIter = m_deadProps.iterator(); propIter.hasNext();) {
3363                AbstractPropertyInstance propInst =
3364                    (AbstractPropertyInstance) propIter.next();
3365                
3366                propInst.update(Profile.this);
3367            }
3368            
3369            m_deadProps.clear();
3370            
3371            setIsChanged(false);
3372        }
3373
3374    }
3375
3376
3377}
3378
Popular Tags