0001: /*
0002: * The contents of this file are subject to the
0003: * Mozilla Public License Version 1.1 (the "License");
0004: * you may not use this file except in compliance with the License.
0005: * You may obtain a copy of the License at http://www.mozilla.org/MPL/
0006: *
0007: * Software distributed under the License is distributed on an "AS IS"
0008: * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
0009: * See the License for the specific language governing rights and
0010: * limitations under the License.
0011: *
0012: * The Initial Developer of the Original Code is Simulacra Media Ltd.
0013: * Portions created by Simulacra Media Ltd are Copyright (C) Simulacra Media Ltd, 2004.
0014: *
0015: * All Rights Reserved.
0016: *
0017: * Contributor(s):
0018: */
0019: package org.openharmonise.rm.metadata;
0020:
0021: import java.sql.*;
0022: import java.util.*;
0023: import java.util.logging.*;
0024:
0025: import org.openharmonise.commons.dsi.*;
0026: import org.openharmonise.commons.dsi.dml.*;
0027: import org.openharmonise.commons.xml.XMLUtils;
0028: import org.openharmonise.rm.*;
0029: import org.openharmonise.rm.dsi.*;
0030: import org.openharmonise.rm.factory.*;
0031: import org.openharmonise.rm.publishing.*;
0032: import org.openharmonise.rm.resources.*;
0033: import org.openharmonise.rm.resources.lifecycle.EditException;
0034: import org.openharmonise.rm.resources.metadata.properties.*;
0035: import org.openharmonise.rm.resources.metadata.properties.domains.Domain;
0036: import org.openharmonise.rm.resources.metadata.properties.ranges.*;
0037: import org.openharmonise.rm.resources.publishing.Template;
0038: import org.openharmonise.rm.search.Search;
0039: import org.w3c.dom.*;
0040:
0041: /**
0042: * <code>Profile</code> represents a collection of <code>AbstractPropertyInstance</code>s.
0043: *
0044: * @author Michael Bell
0045: * @version $Revision: 1.8.2.1 $
0046: *
0047: */
0048: public class Profile extends AbstractObject implements Publishable,
0049: DataStoreObject, Cloneable {
0050:
0051: // XML constants
0052: private static final String CONST_TRUE = "true";
0053:
0054: /**
0055: * Profile XML element name
0056: */
0057: public static final String TAG_PROFILE = "Profile";
0058:
0059: /**
0060: * Property value XML element name
0061: */
0062: public static final String TAG_PROPERTY_VALUE = "PropertyValue";
0063:
0064: /**
0065: * 'Is default' XML attribute name
0066: */
0067: public static final String ATTRIB_ISDEFAULT = "isdefault";
0068:
0069: /**
0070: * Profiled object key XML attribute name
0071: */
0072: public static final String ATTRIB_OBJECT_KEY = "objectKey";
0073:
0074: /**
0075: * Value of <code>ATTRIB_ISDEFAULT</code> which indicates
0076: * that a <code>Profile</code> is default
0077: */
0078: public static final String IS_DEFAULT_PROFILE_VALUE = "1";
0079:
0080: /**
0081: * 'default' XML attribute name
0082: */
0083: public static final String ATTRIB_DEFAULT = "default";
0084:
0085: /**
0086: * All property instance XML element name
0087: */
0088: public static final String TAG_ALLPROPERTYINSTANCES = "AllPropertyInstances";
0089:
0090: //DB constants
0091: /**
0092: * Version comment database column name
0093: */
0094: private static final String CLMN_VERSION_COMMENT = "version_comment";
0095:
0096: /**
0097: * Object key database column name
0098: */
0099: private static final String CLMN_OBJECT_KEY = "object_key";
0100:
0101: /**
0102: * 'is default' database column name
0103: */
0104: private static final String CLMN_IS_DEFAULT = "is_default";
0105:
0106: /**
0107: * <code>String</code> constant extension used for building profile
0108: * database table name. The naming convention for <code>Profile</code>
0109: * database table names is as follows:
0110: *
0111: * AbstractProfiledObject.getTableName() + EXT_PROFILE
0112: */
0113: protected static final String EXT_PROFILE = "_profile";
0114:
0115: /**
0116: * The profile database sequence name
0117: */
0118: private static final String SEQ_PROFILE = "seq_profile";
0119:
0120: /**
0121: * <code>String</code> constant used for unknown profiles
0122: */
0123: public static final String UNKNOWN_PROFILE = "?";
0124:
0125: /**
0126: * <code>String</code> constant to indicate temporary profiles
0127: * that will not be saved
0128: */
0129: public static final String TEXT_MARKER = "XXXX";
0130:
0131: /**
0132: * <code>Map</code> to hold all <code>PropertyInstanceStore</code>s
0133: */
0134: private Map m_propStores = new Hashtable();
0135:
0136: /**
0137: * The version comment for this profile
0138: */
0139: protected String m_sVersionComment = null;
0140:
0141: /**
0142: * <code>true</code> if this is a new <code>Profile</code>
0143: */
0144: private boolean m_bNew = false;
0145:
0146: /**
0147: * The profiled object this <code>Profile</code> belongs to
0148: */
0149: private AbstractProfiledObject m_profObj = null;
0150:
0151: /**
0152: * <code>boolean</code> flag to indicate that the historical status has changed
0153: */
0154: private boolean m_bIsHistoricalChange = false;
0155:
0156: /**
0157: * <code>boolean</code> flag to indicate that this is a default <code>Profile</code>
0158: */
0159: private boolean m_bIsDefault = false;
0160:
0161: /**
0162: * Logger for this class
0163: */
0164: private static final Logger m_logger = Logger
0165: .getLogger(Profile.class.getName());
0166:
0167: /**
0168: * Constructs a <code>Profile</code> without an interface to the
0169: * data store.
0170: *
0171: */
0172: public Profile() {
0173: super ();
0174: }
0175:
0176: /**
0177: * Constructs a <code>Profile</code> with an interface to the data store.
0178: *
0179: * @param dbintrf the data store interface
0180: */
0181: public Profile(AbstractDataStoreInterface dbintrf) {
0182: super (dbintrf);
0183: m_bNew = true;
0184: m_sTable = UNKNOWN_PROFILE;
0185:
0186: }
0187:
0188: /**
0189: * Constructs a <code>Profile</code> which has an interface to the data store
0190: * and a reference to it's 'owner' <code>AbstractProfiledObject</code>.
0191: *
0192: * @param dbintrf the data store interface
0193: * @param obj the 'owning' profiled object
0194: */
0195: public Profile(AbstractDataStoreInterface dbintrf,
0196: AbstractProfiledObject obj) {
0197: super (dbintrf, obj.isHistorical());
0198: m_bNew = true;
0199: m_profObj = obj;
0200:
0201: }
0202:
0203: /**
0204: * Constructs the <code>Profile</code> with the given id, a reference to it's
0205: * 'owning' <code>AbstractProfiledObject</code> and an interface to the data
0206: * store.
0207: *
0208: * @param dbintrf the data store interface
0209: * @param nId the profile id
0210: * @param obj the 'owning' profiled object
0211: */
0212: public Profile(AbstractDataStoreInterface dbintrf, int nId,
0213: AbstractProfiledObject obj) {
0214: super (dbintrf, nId, 0, obj.isHistorical());
0215:
0216: m_profObj = obj;
0217:
0218: }
0219:
0220: /* (non-Javadoc)
0221: * @see org.openharmonise.rm.resources.AbstractObject#isChanged()
0222: */
0223: public boolean isChanged() throws DataAccessException {
0224: boolean bReturn = super .isChanged();
0225:
0226: // if necessary check propertyInstances too but only if we have to
0227: if (bReturn == false) {
0228: Iterator iter = null;
0229:
0230: iter = m_propStores.values().iterator();
0231:
0232: while (iter.hasNext() == true && bReturn == false) {
0233: PropertyInstanceStore propStore = (PropertyInstanceStore) iter
0234: .next();
0235: bReturn = propStore.isChanged();
0236: }
0237:
0238: }
0239:
0240: return bReturn;
0241: }
0242:
0243: /**
0244: * Returns <code>true</code> if this <code>Profile</code> is the default
0245: * for its owning <code>AbstractProfiledObject</code>, otherwise <code>false</code>.
0246: *
0247: * @return <code>true</code> if this <code>Profile</code> is the default
0248: * @throws DataAccessException if an error occurs populating this profile
0249: * from the database
0250: */
0251: public boolean isDefault() throws DataAccessException {
0252: if ((m_bIsDefault == false) && (m_bIsPopulated == false)) {
0253: try {
0254: populateFromDatabase();
0255: } catch (PopulateException pop_e) {
0256: throw new DataAccessException(pop_e
0257: .getLocalizedMessage());
0258: }
0259: }
0260:
0261: return m_bIsDefault;
0262: }
0263:
0264: /**
0265: * Returns <code>true</code> if this <code>Profile</code> is new,
0266: * otherwise <code>false</code>.
0267: *
0268: * @return <code>true</code> if this <code>Profile</code> is new
0269: */
0270: public boolean isNew() {
0271: return m_bNew;
0272: }
0273:
0274: /**
0275: * Returns the list of all property instances contained in this
0276: * <code>Profile</code>.
0277: *
0278: * @return the list of all property instances of the profile
0279: * @throws DataAccessException if an error occurs populating this profile
0280: * from the database
0281: */
0282: public List getPropertyInstances() throws DataAccessException {
0283:
0284: //ensure all propInsts are loaded
0285: try {
0286: if (isNew() == false) {
0287: populatePropertyInstancesFromDatabase();
0288: }
0289: } catch (PopulateException pop_e) {
0290: throw new DataAccessException(
0291: "Problem occured when populating", pop_e);
0292: }
0293:
0294: Vector props = new Vector();
0295:
0296: Iterator iter = this .m_propStores.values().iterator();
0297:
0298: while (iter.hasNext()) {
0299: PropertyInstanceStore propStore = (PropertyInstanceStore) iter
0300: .next();
0301:
0302: Collection propInsts = propStore.getValues();
0303:
0304: Iterator propiter = propInsts.iterator();
0305:
0306: List deadProps = new ArrayList();
0307:
0308: while (propiter.hasNext()) {
0309: AbstractPropertyInstance propInst = (AbstractPropertyInstance) propiter
0310: .next();
0311:
0312: Property prop = propInst.getProperty();
0313:
0314: //need to check if property still exists by
0315: //asking for property from prop inst
0316: //if it no longer exist have to delete prop inst from prof
0317: if (prop != null) {
0318: props.add(propInst);
0319: } else {
0320: try {
0321: deletePropertyInstanceData(propInst);
0322: if (m_logger.isLoggable(Level.INFO)) {
0323: m_logger.logp(Level.INFO, this .getClass()
0324: .getName(), "getPropertyInstances",
0325: "Deleting dead property instance on "
0326: + m_profObj.getClass()
0327: .getName() + " "
0328: + m_profObj.getKey());
0329: }
0330: deadProps.add(propInst);
0331: } catch (InvalidPropertyInstanceException e) {
0332: m_logger
0333: .log(
0334: Level.WARNING,
0335: "error removing dead property instance",
0336: e);
0337: } catch (ProfileException e) {
0338: m_logger
0339: .log(
0340: Level.WARNING,
0341: "error removing dead property instance",
0342: e);
0343: } catch (DataAccessException e) {
0344: m_logger
0345: .log(
0346: Level.WARNING,
0347: "error removing dead property instance",
0348: e);
0349: }
0350: }
0351: }
0352:
0353: if (deadProps.size() > 0) {
0354: Iterator deadPropIter = deadProps.iterator();
0355:
0356: while (deadPropIter.hasNext()) {
0357: AbstractPropertyInstance propInst = (AbstractPropertyInstance) deadPropIter
0358: .next();
0359: propStore.removePropertyInstance(propInst);
0360: }
0361: }
0362:
0363: }
0364:
0365: return props;
0366: }
0367:
0368: /**
0369: * Sets whether this <code>Profile</code> is the default for the owning
0370: * <code>AbstractProfiledObject</code>.
0371: *
0372: * @param bIsDefault <code>true</code> if this <code>Profile</code> is
0373: * the default, otherwise <code>false</code>.
0374: */
0375: public void setIsDefault(boolean bIsDefault) {
0376: m_bIsDefault = bIsDefault;
0377: }
0378:
0379: /* (non-Javadoc)
0380: * @see org.openharmonise.rm.resources.AbstractObject#setHistorical(boolean)
0381: */
0382: public void setHistorical(boolean bIsHistorical) {
0383: m_bIsHistoricalChange = true;
0384: super .setHistorical(bIsHistorical);
0385:
0386: try {
0387: if (m_propStores.size() > 0) {
0388: // pass historical property to PropertyInstance
0389: Iterator iter = getPropertyInstances().iterator();
0390:
0391: while (iter.hasNext()) {
0392: AbstractPropertyInstance next = (AbstractPropertyInstance) iter
0393: .next();
0394: next.setHistorical(bIsHistorical);
0395: }
0396: }
0397:
0398: } catch (DataAccessException e) {
0399: // TODO can't throw exception, so log
0400: m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
0401:
0402: }
0403: }
0404:
0405: /**
0406: * Sets the version comment for this version of the <code>Profile</code>.
0407: *
0408: * @param sComment the version comment
0409: */
0410: public void setVersionComment(String sComment) {
0411: if (isPopulated() == true) {
0412: if (m_sVersionComment == null && sComment != null) {
0413: setIsChanged(true);
0414: } else if (m_sVersionComment.equals(sComment) == false) {
0415: setIsChanged(true);
0416: }
0417: }
0418:
0419: m_sVersionComment = sComment;
0420: }
0421:
0422: /**
0423: * Returns the version comment for this <code>Profile</code>.
0424: *
0425: * @return the version comment for this <code>Profile</code>
0426: * @throws DataAccessException if an error occurs populating this profile
0427: * from the database
0428: */
0429: public String getVersionComment() throws DataAccessException {
0430: if (isPopulated() == false && m_sVersionComment == null) {
0431: try {
0432: populateFromDatabase();
0433: } catch (PopulateException e) {
0434: throw new DataAccessException(
0435: "Problem occurred populating profile", e);
0436: }
0437: }
0438:
0439: return m_sVersionComment;
0440: }
0441:
0442: /**
0443: * Returns the list of properties which can be added to this <code>Profile</code>, dependant
0444: * on the profiled object associated.
0445: *
0446: * @return the list of properties which can be added to this <code>Profile</code>
0447: * @throws DataAccessException if
0448: */
0449: public List getAvailableProperties() throws DataAccessException {
0450:
0451: if (m_profObj == null) {
0452: throw new DataAccessException(
0453: "No profiled object attached to this profile");
0454: }
0455:
0456: List propList = null;
0457:
0458: propList = Domain.getAvailableProperties(m_dsi, m_profObj);
0459:
0460: return propList;
0461: }
0462:
0463: /**
0464: * Returns <code>true<code> if the specified <code>AbstractPropertyInstance</code>
0465: * is valid for this <code>Profile</code>.
0466: *
0467: * @param propInst the property instance
0468: * @return <code>true<code> if the specified <code>AbstractPropertyInstance</code>
0469: * is valid
0470: * @throws ProfileException if an error occurs getting the <code>Property</code>
0471: * associated to the given property instance
0472: */
0473: public boolean isValidPropertyInstance(
0474: AbstractPropertyInstance propInst) throws ProfileException {
0475:
0476: boolean bIsValid = false;
0477:
0478: try {
0479: Property propInstProp = propInst.getProperty();
0480:
0481: bIsValid = isValidProperty(propInstProp);
0482: } catch (DataAccessException e) {
0483: throw new ProfileException(e.getLocalizedMessage(), e);
0484: }
0485:
0486: return bIsValid;
0487:
0488: }
0489:
0490: /**
0491: * Returns <code>true</code> an instance of the specified <code>Property</code>
0492: * can be added to this <code>Profile</code>
0493: *
0494: * @param prop the <code>Property</code>
0495: * @return <code>true</code> an instance of the specified <code>Property</code>
0496: * can be added to this <code>Profile</code>
0497: */
0498: public boolean isValidProperty(Property prop) {
0499: boolean bIsValid = false;
0500:
0501: try {
0502: if (prop != null) {
0503: List availProps = getAvailableProperties();
0504:
0505: bIsValid = availProps.contains(prop);
0506: }
0507:
0508: } catch (DataAccessException da_e) {
0509: m_logger.log(Level.WARNING, da_e.getLocalizedMessage(),
0510: da_e);
0511:
0512: bIsValid = false;
0513: }
0514:
0515: return bIsValid;
0516:
0517: }
0518:
0519: /**
0520: * Adds a property instance to this <code>Profile</code>.
0521: *
0522: * @param propInst the property instance to add
0523: * @throws ProfileException if the given property instance is invalid
0524: * or there is an error getting details from the property instance
0525: */
0526: public void addPropertyInstance(AbstractPropertyInstance propInst)
0527: throws ProfileException {
0528: propInst.setProfile(this );
0529:
0530: if (propInst == null) {
0531: throw new InvalidPropertyInstanceException(
0532: "null property passed in");
0533: } else if (isValidPropertyInstance(propInst) == false) {
0534: throw new InvalidPropertyInstanceException(
0535: "Invalid property passed in");
0536: }
0537:
0538: try {
0539:
0540: String sKey = propInst.getName();
0541: if (sKey.length() == 0) {
0542: throw new InvalidPropertyInstanceException(
0543: "Invalid key");
0544: }
0545:
0546: Property prop = propInst.getProperty();
0547:
0548: if (hasProperty(prop) == false) {
0549:
0550: PropertyInstanceStore propStore = this
0551: .getPropertyInstanceStore(prop);
0552:
0553: propStore.addPropertyInstance(propInst);
0554: } else {
0555: throw new InvalidPropertyInstanceException(
0556: "Profile already has property instance - "
0557: + sKey);
0558: }
0559:
0560: } catch (DataAccessException da_e) {
0561: throw new ProfileException(
0562: "Error occured accessing property instance name",
0563: da_e);
0564: }
0565:
0566: }
0567:
0568: /**
0569: * Removes instances of the specified <code>Property</code> from this
0570: * <code>Profile</code>.
0571: *
0572: * @param prop the <code>Property</code> to remove
0573: * @throws ProfileException if an error occurs removing the property
0574: * from this <code>Profile</code>
0575: */
0576: public void removeProperty(Property prop) throws ProfileException {
0577: try {
0578: PropertyInstanceStore propStore = getPropertyInstanceStore(prop);
0579:
0580: if (propStore.isPopulated() == false) {
0581: populatePropertyInstanceStore(propStore);
0582: }
0583:
0584: propStore.removePropertyInstance(prop);
0585: } catch (DataAccessException e) {
0586: throw new ProfileException(
0587: "Error occured getting property instances", e);
0588: } catch (PopulateException e) {
0589: throw new ProfileException(
0590: "Error occured populating prop insts", e);
0591: }
0592: }
0593:
0594: /**
0595: * Returns <code>true</code> if the <code>Profile</code> has an instance of the
0596: * specified <code>Property</code>.
0597: *
0598: * @param prop the <code>Property</code>
0599: * @throws DataAccessException if there is an error populating the property
0600: * instances of this <code>Profile></code>
0601: *
0602: */
0603: public boolean hasProperty(Property prop)
0604: throws DataAccessException {
0605: try {
0606: AbstractPropertyInstance propInst = getPropertyInstance(prop);
0607: return (propInst != null);
0608: } catch (InvalidPropertyInstanceException e) {
0609: return false;
0610: }
0611: }
0612:
0613: /**
0614: * Returns the instance of the given <code>Property</code> held by this
0615: * <code>Profile</code> if there is one.
0616: *
0617: * @param property the <code>Property</code>
0618: * @return the instance of the given <code>Property</code>,
0619: * <code>null</code> if there is no instance
0620: * @throws InvalidPropertyInstanceException if the specified <code>Property</code>
0621: * is invalid for this <code>Profile</code>
0622: * @throws DataAccessException if there is an error populating this
0623: * <code>Profile</code>
0624: */
0625: public AbstractPropertyInstance getPropertyInstance(
0626: Property property) throws InvalidPropertyInstanceException,
0627: DataAccessException {
0628: AbstractPropertyInstance propReturn = null;
0629:
0630: PropertyInstanceStore propStore = null;
0631:
0632: propStore = getPropertyInstanceStore(property);
0633:
0634: if (propStore.isPopulated() == false) {
0635: try {
0636: populatePropertyInstanceStore(propStore);
0637: } catch (PopulateException e) {
0638: throw new DataAccessException(
0639: "Problem occurred populate values", e);
0640: }
0641: }
0642:
0643: propReturn = propStore.getPropertyInstance(property);
0644:
0645: if (propReturn != null && property.exists() == false) {
0646: try {
0647: deletePropertyInstanceData(propReturn);
0648: } catch (InvalidPropertyInstanceException e) {
0649: m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
0650: throw new DataAccessException(e);
0651: } catch (ProfileException e) {
0652: m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
0653: throw new DataAccessException(e);
0654: } catch (DataAccessException e) {
0655: m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
0656: throw new DataAccessException(e);
0657: }
0658: }
0659:
0660: return propReturn;
0661: }
0662:
0663: /**
0664: * Returns a instance of the <code>Property</code> with the specified
0665: * name if one exists in this <code>Profile</code>.
0666: *
0667: * @param sPropName the name of the <code>Property</code>
0668: * @return the instance of the <code>Property</code>,
0669: * <code>null</code> no instance exists
0670: *
0671: * @throws InvalidPropertyInstanceException if the specified <code>Property</code>
0672: * is invalid for this <code>Profile</code>
0673: * @throws DataAccessException if there is an error populating this
0674: * <code>Profile</code>
0675: */
0676: public AbstractPropertyInstance getPropertyInstance(String sPropName)
0677: throws InvalidPropertyInstanceException,
0678: DataAccessException {
0679: AbstractPropertyInstance propReturn = null;
0680:
0681: try {
0682: Property prop = PropertyFactory.getPropertyFromName(m_dsi,
0683: sPropName);
0684: propReturn = getPropertyInstance(prop);
0685: } catch (HarmoniseFactoryException e) {
0686: throw new DataAccessException(
0687: "Problem occurred getting property from name:", e);
0688: }
0689:
0690: return propReturn;
0691: }
0692:
0693: /**
0694: * Saves this <code>Profile</code> to the data store.
0695: *
0696: * @param proObj the 'owner' <code>AbstractProfiledObject</code>
0697: * @return the resultant <code>Profile</code> of the save operation
0698: * @throws ProfileException if a profiled object is not specified
0699: * or, if this is not a new <code>Profile</code>, there is an error populating
0700: * this <code>Profile</code> with existing property instances
0701: * @throws EditException if there is an error saving the data to the
0702: * database
0703: */
0704: public Profile save(AbstractProfiledObject proObj)
0705: throws ProfileException, EditException {
0706: if (proObj == null) {
0707: throw new ProfileException(
0708: "No ProfiledObject given so can't save");
0709: }
0710:
0711: // before we start ensure that we have the correct info
0712: if (m_bIsPopulated == false) {
0713: try {
0714: populateFromDatabase();
0715: } catch (PopulateException e) {
0716: throw new ProfileException(
0717: "Problem occurred populating the profile", e);
0718: }
0719: }
0720:
0721: try {
0722:
0723: if (isNew() == false
0724: && isPropertyInstancesPopulated() == false) {
0725: populatePropertyInstancesFromDatabase();
0726: }
0727: } catch (DataAccessException da_e) {
0728: throw new ProfileException(
0729: "Error occured while accessing property instances:",
0730: da_e);
0731: } catch (PopulateException pop_e) {
0732: throw new ProfileException(
0733: "Error occured while accessing property instances:",
0734: pop_e);
0735: }
0736:
0737: //check to see if profiled object has changed
0738: boolean bProfObjChange = false;
0739:
0740: try {
0741: bProfObjChange = (m_profObj.getKey() != proObj.getKey());
0742: } catch (DataAccessException da_e) {
0743: throw new ProfileException(
0744: "Problem occurred accessing data from profiled object:",
0745: da_e);
0746: }
0747:
0748: //ensure that profiled object is set
0749: m_profObj = proObj;
0750:
0751: Profile profileReturn = null;
0752: // if this is a new profile, create a new record
0753: if ((m_nId == 0) || (m_nId == AbstractObject.NOTDBSAVED_ID)
0754: || m_bIsHistoricalChange) {
0755: //do this before getting the id sequence so that the equals()
0756: //comparison doesn't try to call populateFromDatabase() on a
0757: //id not in the database. Comprende?!
0758: int nIsDefault = 0;
0759: if (proObj.isDefaultProfile(this )) {
0760: nIsDefault = 1;
0761: }
0762: try {
0763:
0764: //gets new id even if historical because it's been cleared in the markAsNew method
0765: m_nId = m_dsi.getSequenceNextValue(SEQ_PROFILE);
0766:
0767: // insert into correct profile table
0768: InsertStatement insert = new InsertStatement();
0769:
0770: insert.addColumnValue(this .getInstanceColumnRef(
0771: ATTRIB_ID, false), m_nId);
0772: insert.addColumnValue(this .getInstanceColumnRef(
0773: ATTRIB_KEY, false), proObj.getKey());
0774: insert.addColumnValue(this .getInstanceColumnRef(
0775: TAG_NAME, false), m_sName);
0776: if (m_sSummary != null) {
0777: insert.addColumnValue(this .getInstanceColumnRef(
0778: TAG_SUMMARY, false), m_sSummary);
0779: }
0780:
0781: if (m_sVersionComment != null) {
0782: insert.addColumnValue(this .getInstanceColumnRef(
0783: CLMN_VERSION_COMMENT, false),
0784: m_sVersionComment);
0785: }
0786:
0787: if (m_sType != null) {
0788: insert.addColumnValue(this .getInstanceColumnRef(
0789: ATTRIB_TYPE, false), m_sType);
0790: }
0791:
0792: insert.addColumnValue(this .getInstanceColumnRef(
0793: CLMN_IS_DEFAULT, false), nIsDefault);
0794: m_dsi.execute(insert);
0795: // insert properties
0796: Iterator iter = getPropertyInstances().iterator();
0797: int nErrors = 0;
0798: List errorDescs = null;
0799: while (iter.hasNext()) {
0800: AbstractPropertyInstance next = (AbstractPropertyInstance) iter
0801: .next();
0802: //try to save all prop insts even if individual propInsts fail
0803: try {
0804:
0805: next.save(this );
0806: } catch (InvalidPropertyInstanceException val_e) {
0807: //remove offending prop inst
0808: removePropertyInstance(next);
0809: nErrors++;
0810: if (errorDescs == null) {
0811: errorDescs = new ArrayList();
0812: }
0813: errorDescs.add(val_e.getLocalizedMessage()
0814: + " - " + next.toString());
0815: }
0816: }
0817: //reset flags
0818: m_bIsChanged = false;
0819: iter = m_propStores.values().iterator();
0820:
0821: while (iter.hasNext()) {
0822: PropertyInstanceStore propStore = (PropertyInstanceStore) iter
0823: .next();
0824: propStore.setIsChanged(false);
0825: }
0826:
0827: m_bIsHistoricalChange = false;
0828: m_bIsPopulated = true;
0829: m_bNew = false;
0830: profileReturn = this ;
0831:
0832: if (nErrors > 0) {
0833: throw new EditException(
0834: "Problem saving prop insts - " + errorDescs);
0835: }
0836:
0837: } catch (DataStoreException ds_e) {
0838: throw new ProfileException(
0839: "Problem occured saving profile:", ds_e);
0840: } catch (DataAccessException da_e) {
0841: throw new ProfileException(
0842: "Problem occured saving profile:", da_e);
0843: } catch (SQLException sql_e) {
0844: throw new ProfileException(
0845: "Problem occured saving profile:", sql_e);
0846: }
0847: } else if (m_bIsChanged == true || bProfObjChange == true) {
0848: // if this is an existing profile and changes have been made,
0849: // create a new version
0850: // do this by temporarily setting our id to NOTDBSAVED_PRO_ID and cloning ourselves
0851: Profile profileNew = (Profile) this .clone();
0852: try {
0853: profileNew.markAsNew();
0854: } catch (PopulateException e) {
0855: throw new EditException(
0856: "Problem occurred marking object as new", e);
0857: }
0858: profileReturn = profileNew.save(proObj);
0859: } else {
0860: // nothing to do, just return the profile as is
0861: profileReturn = this ;
0862: }
0863: return profileReturn;
0864: }
0865:
0866: /**
0867: * Deletes this <code>Profile</code> from the database.
0868: *
0869: * @throws ProfileException if an error occurs deleting this
0870: * <code>Profile</code> from the database
0871: */
0872: public void delete() throws ProfileException {
0873: if (m_nId == NOTDBSAVED_ID) {
0874: return;
0875: }
0876:
0877: ResultSet rs = null;
0878: try {
0879:
0880: if (isPropertyInstancesPopulated() == false) {
0881: populatePropertyInstancesFromDatabase();
0882: }
0883:
0884: //delete general prop insts first
0885: Iterator iter = m_propStores.values().iterator();
0886:
0887: while (iter.hasNext()) {
0888: PropertyInstanceStore propStore = (PropertyInstanceStore) iter
0889: .next();
0890:
0891: deletePropertyInstances(propStore);
0892: }
0893:
0894: DeleteStatement delete = new DeleteStatement();
0895:
0896: delete.addWhereCondition(getInstanceColumnRef(ATTRIB_ID,
0897: false), "=", m_nId);
0898:
0899: m_dsi.execute(delete);
0900: //reset all datamembers
0901: m_nId = NOTDBSAVED_ID;
0902: } catch (DataStoreException ds_e) {
0903: throw new ProfileException(
0904: "Problem occured deleting profile:", ds_e);
0905: } catch (DataAccessException e) {
0906: throw new ProfileException(
0907: "Problem occured populating property instances:", e);
0908: } catch (PopulateException e) {
0909: throw new ProfileException(
0910: "Problem occured populating property instances:", e);
0911: } finally {
0912: if (rs != null) {
0913: try {
0914: rs.close();
0915: } catch (SQLException sql_e) {
0916: throw new ProfileException(
0917: "Problem occured closing result set", sql_e);
0918: }
0919:
0920: }
0921: }
0922: }
0923:
0924: /**
0925: * Matches this <code>Profile</code> against the given <code>Profile</code>.
0926: *
0927: * @param prof the <code>Profile</code> to match this
0928: * <code>Profile</code> against
0929: *
0930: * @return <code>true</code> if both <code>Profile</code>s match
0931: * @throws ProfileException if any errors occur
0932: */
0933: public boolean match(Profile prof) throws ProfileException {
0934: boolean bMatch = false;
0935: try {
0936:
0937: Iterator iter = getPropertyInstances().iterator();
0938: while (iter.hasNext()) {
0939: AbstractPropertyInstance this Prop = (AbstractPropertyInstance) iter
0940: .next();
0941: AbstractPropertyInstance otherProp = prof
0942: .getPropertyInstance(this Prop.getProperty());
0943: bMatch = this Prop.match(otherProp);
0944: if (bMatch == false) {
0945: break;
0946: }
0947: }
0948: } catch (DataAccessException da_e) {
0949: throw new ProfileException(
0950: "Problem occurred accessing properties", da_e);
0951: }
0952:
0953: return bMatch;
0954: }
0955:
0956: /**
0957: * Matches this <code>Profile</code> against the given <code>Profile</code>.
0958: *
0959: * @param prof the <code>Profile</code> to match this
0960: * <code>Profile</code> against
0961: *
0962: * @return <code>true</code> if both <code>Profile</code>s match
0963: * @throws ProfileException if any errors occur
0964: */
0965: public boolean match(List propInstList) throws ProfileException {
0966: boolean bMatch = false;
0967: try {
0968:
0969: Iterator iter = propInstList.iterator();
0970:
0971: while (iter.hasNext()) {
0972: AbstractPropertyInstance otherProp = (AbstractPropertyInstance) iter
0973: .next();
0974: AbstractPropertyInstance this Prop = getPropertyInstance(otherProp
0975: .getProperty());
0976:
0977: bMatch = otherProp.match(this Prop);
0978: if (bMatch == false) {
0979: break;
0980: }
0981: }
0982: } catch (DataAccessException da_e) {
0983: throw new ProfileException(
0984: "Problem occurred accessing properties", da_e);
0985: }
0986:
0987: return bMatch;
0988: }
0989:
0990: /* (non-Javadoc)
0991: * @see java.lang.Object#toString()
0992: */
0993: public String toString() {
0994: StringBuffer strbuf = new StringBuffer();
0995: try {
0996: strbuf.append(" Summary:").append(m_sSummary)
0997: .append(" Id:").append(m_nId).append(
0998: " Profile Table:").append(m_sTable).append(
0999: " name:").append(m_sName).append(
1000: "[value][labels]:{");
1001: String sName = "";
1002:
1003: Iterator propStoreIterator = m_propStores.values()
1004: .iterator();
1005:
1006: while (propStoreIterator.hasNext()) {
1007: PropertyInstanceStore propStore = (PropertyInstanceStore) propStoreIterator
1008: .next();
1009:
1010: if (propStore.m_propInsts != null) {
1011: Iterator propInstIter = propStore.m_propInsts
1012: .values().iterator();
1013:
1014: while (propInstIter.hasNext()) {
1015: AbstractPropertyInstance propInst = (AbstractPropertyInstance) propInstIter
1016: .next();
1017: sName = propInst.getProperty().getName();
1018: List values = propInst.getValues();
1019:
1020: strbuf.append(sName).append(": ");
1021:
1022: if (values != null) {
1023: //need to avoid possible infnite recursion
1024: //with toString() on ChildObjectPropertyInstances
1025: if (propInst instanceof ChildObjectPropertyInstance) {
1026: Iterator valIter = values.iterator();
1027:
1028: while (valIter.hasNext()) {
1029: AbstractChildObject child = (AbstractChildObject) valIter
1030: .next();
1031: strbuf.append(
1032: child.getClass().getName())
1033: .append(":").append(
1034: child.getId());
1035: if (valIter.hasNext()) {
1036: strbuf.append(",");
1037: }
1038: }
1039: } else {
1040: strbuf.append(values);
1041: }
1042: }
1043: strbuf.append(".");
1044: }
1045: }
1046:
1047: }
1048:
1049: strbuf.append("}. ");
1050: } catch (Exception e) {
1051: strbuf.append("Exception :").append(e.getMessage());
1052: }
1053:
1054: return strbuf.toString();
1055: }
1056:
1057: /* (non-Javadoc)
1058: * @see org.openharmonise.rm.publishing.Publishable#publish(org.w3c.dom.Element, org.openharmonise.rm.publishing.HarmoniseOutput, org.openharmonise.rm.publishing.State)
1059: */
1060: public Element publish(Element topEl, HarmoniseOutput xmlDoc,
1061: State state) throws PublishException {
1062:
1063: Element docEl = xmlDoc.createElement(topEl.getTagName());
1064:
1065: if (((String) topEl.getTagName()).equals(TAG_PROFILE)) {
1066: String sTempName = null;
1067:
1068: try {
1069:
1070: sTempName = getName();
1071: } catch (DataAccessException da_e) {
1072: sTempName = "There was an error getting the name";
1073: }
1074:
1075: if ((sTempName == null) || sTempName.equalsIgnoreCase("")) {
1076: sTempName = topEl.getAttribute(Profile.ATTRIB_NAME);
1077: }
1078:
1079: docEl.setAttribute(ATTRIB_NAME, sTempName);
1080: if (m_nId != NOTDBSAVED_ID) {
1081: docEl.setAttribute(ATTRIB_ID, Integer.toString(m_nId));
1082: }
1083:
1084: String sDefault = topEl.getAttribute(ATTRIB_DEFAULT);
1085: if (sDefault.equals(CONST_TRUE)) {
1086: docEl.setAttribute(ATTRIB_ISDEFAULT, CONST_TRUE);
1087: }
1088: }
1089:
1090: NodeList nodes = topEl.getChildNodes();
1091: Element formEl;
1092: Element el = null;
1093: Text txt = null;
1094: String sTagName;
1095: for (int i = 0; i < nodes.getLength(); i++) {
1096: if (nodes.item(i).getNodeType() != Node.ELEMENT_NODE) {
1097: continue;
1098: }
1099:
1100: formEl = (Element) nodes.item(i);
1101: sTagName = formEl.getTagName();
1102: if (sTagName.equals(TAG_SUMMARY)) {
1103: el = xmlDoc.createElement(sTagName);
1104: try {
1105:
1106: txt = xmlDoc.createTextNode(getSummary());
1107: el.appendChild(txt);
1108: } catch (DataAccessException da_e) {
1109: txt = xmlDoc
1110: .createTextNode("A problem occured accessing the summary");
1111: el.appendChild(txt);
1112: }
1113: docEl.appendChild(el);
1114: } else if (sTagName
1115: .equals(AbstractEditableObject.TAG_VERSION_COMMENT)) {
1116: el = xmlDoc.createElement(sTagName);
1117: try {
1118: txt = xmlDoc.createTextNode(getVersionComment());
1119: el.appendChild(txt);
1120: } catch (DataAccessException da_e) {
1121: txt = xmlDoc
1122: .createTextNode("A problem occured accessing the version comment");
1123: el.appendChild(txt);
1124: }
1125: docEl.appendChild(el);
1126: } else if (sTagName
1127: .equals(AbstractPropertyInstance.TAG_PROPERTYINSTANCE)) {
1128: AbstractPropertyInstance propInstance = null;
1129: String sPropName = null;
1130: try {
1131: NodeList propNodes = formEl
1132: .getElementsByTagName(Property.TAG_PROPERTY);
1133: Element propEl = (Element) propNodes.item(0);
1134: Element nameEl = XMLUtils.getFirstNamedChild(
1135: propEl, TAG_NAME);
1136: if (nameEl != null) {
1137: sPropName = XMLUtils.getChildTextValue(nameEl);
1138: propInstance = getPropertyInstance(sPropName);
1139: } else {
1140: Element pathEl = XMLUtils.getFirstNamedChild(
1141: propEl, Property.TAG_PATH);
1142: String sPath = XMLUtils
1143: .getChildTextValue(pathEl);
1144: Property prop = (Property) HarmoniseObjectFactory
1145: .instantiateHarmoniseObject(m_dsi,
1146: Property.class.getName(), sPath);
1147: propInstance = getPropertyInstance(prop);
1148: }
1149:
1150: } catch (DOMException e) {
1151: txt = xmlDoc
1152: .createTextNode("A problem occured processing the property elements");
1153: el.appendChild(txt);
1154: } catch (InvalidPropertyInstanceException e) {
1155: el = e.publish(xmlDoc);
1156: } catch (DataAccessException e) {
1157: throw new PublishException(
1158: "An error occured when trying to access a PropertyInstance",
1159: e);
1160: } catch (HarmoniseFactoryException e) {
1161: el = e.publish(xmlDoc);
1162: }
1163:
1164: if (propInstance != null) {
1165: el = propInstance.publish(formEl, xmlDoc, state);
1166: docEl.appendChild(el);
1167: }
1168:
1169: } else if (sTagName.equals(TAG_ALLPROPERTYINSTANCES)) {
1170: try {
1171:
1172: NamedNodeMap attrs = formEl.getAttributes();
1173:
1174: Element propInstEl = xmlDoc
1175: .createElement(AbstractPropertyInstance.TAG_PROPERTYINSTANCE);
1176:
1177: Element propEl = xmlDoc
1178: .createElement(Property.TAG_PROPERTY);
1179:
1180: propInstEl.appendChild(propEl);
1181:
1182: Element valueEl = xmlDoc
1183: .createElement(AbstractPropertyInstance.TAG_PROP_INSTANCE_VALUES);
1184:
1185: for (int j = 0; j < attrs.getLength(); j++) {
1186: Attr attr = (Attr) attrs.item(j);
1187:
1188: valueEl.setAttribute(attr.getName(), attr
1189: .getValue());
1190: }
1191:
1192: propInstEl.appendChild(valueEl);
1193:
1194: //get the <AllPropertyInstances/> tag for compound props
1195: Element allPropEl = xmlDoc
1196: .createElement(TAG_ALLPROPERTYINSTANCES);
1197:
1198: for (int j = 0; j < attrs.getLength(); j++) {
1199: Attr attr = (Attr) attrs.item(j);
1200:
1201: allPropEl.setAttribute(attr.getName(), attr
1202: .getValue());
1203: }
1204:
1205: Element templateEl = XMLUtils.getFirstNamedChild(
1206: formEl, Template.TAG_TEMPLATE);
1207:
1208: if (templateEl != null) {
1209: templateEl = (Element) xmlDoc.importNode(
1210: templateEl, true);
1211: allPropEl.appendChild(templateEl
1212: .cloneNode(true));
1213: }
1214:
1215: Element origPropEl = XMLUtils.getFirstNamedChild(
1216: formEl, Property.TAG_PROPERTY);
1217:
1218: if (origPropEl != null) {
1219: NodeList propChildren = origPropEl
1220: .getChildNodes();
1221:
1222: for (int j = 0; j < propChildren.getLength(); j++) {
1223: Node node = (Node) propChildren.item(j);
1224: propEl.appendChild(xmlDoc.importNode(node,
1225: true));
1226:
1227: }
1228: }
1229:
1230: Element propCloneEl = (Element) propEl
1231: .cloneNode(true);
1232:
1233: allPropEl.appendChild(propCloneEl);
1234:
1235: Element condEl = XMLUtils.getFirstNamedChild(
1236: formEl, Search.TAG_CONDITIONS);
1237:
1238: Collection propInsts = null;
1239:
1240: if (condEl == null) {
1241: propInsts = getPropertyInstances();
1242: } else {
1243: List condProps = getConditionalPropertyInstances(condEl);
1244: propInsts = getMatchingPropertyInstances(condProps);
1245: }
1246:
1247: Iterator iter = propInsts.iterator();
1248:
1249: while (iter.hasNext()) {
1250: AbstractPropertyInstance propInst = (AbstractPropertyInstance) iter
1251: .next();
1252:
1253: if (templateEl != null) {
1254: if (propInst instanceof ChildObjectPropertyInstance) {
1255: valueEl.appendChild(templateEl);
1256: }
1257: }
1258:
1259: if (propInst instanceof ProfilePropertyInstance) {
1260: valueEl.appendChild(allPropEl);
1261:
1262: }
1263:
1264: el = propInst
1265: .publish(propInstEl, xmlDoc, state);
1266: docEl.appendChild(el);
1267:
1268: if (templateEl != null) {
1269: if (propInst instanceof ChildObjectPropertyInstance) {
1270: valueEl.removeChild(templateEl);
1271: }
1272: }
1273:
1274: if (propInst instanceof ProfilePropertyInstance) {
1275: valueEl.removeChild(allPropEl);
1276: }
1277: }
1278: } catch (DataAccessException da_e) {
1279: throw new PublishException(
1280: "An error occured when trying to access the PropertyInstances",
1281: da_e);
1282: }
1283: } else {
1284: // copy all nodes we don't recognise
1285: docEl.appendChild(xmlDoc.copyNode(formEl));
1286: }
1287: }
1288:
1289: return docEl;
1290: }
1291:
1292: /**
1293: * Returns a <code>List</code> of <code>AbstractPropertyInstance</code>s
1294: * whose defining <code>Property</code>s have the given conditional
1295: * <code>AbstractPropertyInstance</code>s in their <code>Profile</code>.
1296: *
1297: * @param condProps
1298: * @return
1299: */
1300: public List getMatchingPropertyInstances(List condProps)
1301: throws DataAccessException {
1302: List propInsts = new ArrayList();
1303:
1304: Iterator iter = getPropertyInstances().iterator();
1305:
1306: while (iter.hasNext()) {
1307: AbstractPropertyInstance propInst = (AbstractPropertyInstance) iter
1308: .next();
1309:
1310: Property prop = propInst.getProperty();
1311:
1312: Profile propProf = prop.getProfile();
1313:
1314: try {
1315: if (propProf.match(condProps) == true) {
1316: propInsts.add(propInst);
1317: }
1318: } catch (InvalidPropertyInstanceException e) {
1319: //ignore invalid properties
1320: if (m_logger.isLoggable(Level.FINE)) {
1321: m_logger.logp(Level.FINE,
1322: this .getClass().getName(),
1323: "getMatchingPropertyInstances",
1324: "Ignoring property - " + prop.getName());
1325: }
1326:
1327: } catch (ProfileException e) {
1328: throw new DataAccessException(e);
1329: }
1330: }
1331:
1332: return propInsts;
1333: }
1334:
1335: /**
1336: * Returns a <code>List</code> of <code>AbstractPropertyInstance</code>s
1337: * which have been represented in the specified 'Conditions' XML element.
1338: *
1339: * @param condEl the 'Conditions' XML element
1340: * @return a <code>List</code> of <code>AbstractPropertyInstance</code>s
1341: */
1342: private List getConditionalPropertyInstances(Element condEl)
1343: throws PublishException {
1344: List propInsts = new ArrayList();
1345:
1346: if (condEl.getTagName().equals(Search.TAG_CONDITIONS) == true) {
1347: List nodes = XMLUtils.getChildrenByName(condEl,
1348: AbstractPropertyInstance.TAG_PROPERTYINSTANCE);
1349:
1350: for (Iterator iter = nodes.iterator(); iter.hasNext();) {
1351: Element propInstEl = (Element) iter.next();
1352:
1353: try {
1354: AbstractPropertyInstance propInst = PropertyInstanceFactory
1355: .getPropertyInstance(m_dsi, propInstEl);
1356:
1357: propInst.populate(propInstEl, null);
1358:
1359: propInsts.add(propInst);
1360: } catch (DataAccessException e) {
1361: throw new PublishException(e);
1362: } catch (HarmoniseFactoryException e) {
1363: throw new PublishException(e);
1364: } catch (PopulateException e) {
1365: throw new PublishException(e);
1366: }
1367: }
1368: }
1369:
1370: return propInsts;
1371: }
1372:
1373: /* (non-Javadoc)
1374: * @see org.openharmonise.rm.publishing.Publishable#populate(org.w3c.dom.Element, org.openharmonise.rm.publishing.State)
1375: */
1376: public void populate(Element xmlElement, State state)
1377: throws PopulateException {
1378:
1379: if (xmlElement.getTagName().equals(TAG_PROFILE) == false) {
1380: throw new PopulateException("Expecting " + TAG_PROFILE
1381: + " got " + xmlElement.getTagName());
1382: }
1383: try {
1384: if (((AbstractChildObject) m_profObj).getParents()
1385: .isEmpty()) {
1386: throw new PopulateDependencyException(
1387: "Profiled object must have a parent before populating profile");
1388: }
1389: } catch (DataAccessException e) {
1390: throw new PopulateException(e);
1391: }
1392:
1393: try {
1394: String sName = xmlElement.getAttribute(ATTRIB_NAME);
1395: if (sName != null && sName.length() > 0) {
1396: setName(sName);
1397: }
1398: } catch (InvalidNameException e) {
1399: throw new PopulateException(e);
1400: }
1401: NodeList nodes = xmlElement.getChildNodes();
1402: Element formEl;
1403: String sTagName;
1404: String sProperty;
1405: Vector values = new Vector();
1406: Element el;
1407: NodeList valueNodes;
1408: NodeList availableValueNodes;
1409: for (int i = 0; i < nodes.getLength(); i++) {
1410: if (nodes.item(i).getNodeType() != Node.ELEMENT_NODE) {
1411: continue;
1412: }
1413:
1414: formEl = (Element) nodes.item(i);
1415: sTagName = formEl.getTagName();
1416: Text txt = null;
1417: if (sTagName.equals(TAG_SUMMARY)) {
1418: txt = (Text) formEl.getFirstChild();
1419: setSummary(txt.getNodeValue());
1420: } else if (sTagName
1421: .equals(AbstractEditableObject.TAG_VERSION_COMMENT)) {
1422: txt = (Text) formEl.getFirstChild();
1423: setVersionComment(txt.getNodeValue());
1424: } else if (sTagName
1425: .equals(AbstractPropertyInstance.TAG_PROPERTYINSTANCE)) {
1426:
1427: try {
1428: AbstractPropertyInstance propInst = PropertyInstanceFactory
1429: .getPropertyInstance(m_dsi, formEl, this );
1430: Property prop = propInst.getProperty();
1431: if (hasProperty(prop)) {
1432: propInst = this .getPropertyInstance(prop);
1433: } else {
1434: addPropertyInstance(propInst);
1435: }
1436:
1437: propInst.populate(formEl, state);
1438:
1439: } catch (DataAccessException e) {
1440: throw new PopulateException(e);
1441: } catch (HarmoniseFactoryException e) {
1442: throw new PopulateException(e);
1443: } catch (ProfileException e) {
1444: throw new PopulateException(e);
1445: }
1446:
1447: }
1448: }
1449: }
1450:
1451: /**
1452: * Populates the <code>Profile</code> data.
1453: *
1454: * @throws ProfileException
1455: */
1456: public void fillProfileData() throws ProfileException {
1457: try {
1458:
1459: if (m_bIsPopulated == false) {
1460: populateFromDatabase();
1461: }
1462:
1463: if (isPropertyInstancesPopulated() == false) {
1464: populatePropertyInstancesFromDatabase();
1465: }
1466: } catch (PopulateException pop_e) {
1467: throw new ProfileException(
1468: "Problem occured populating Profile", pop_e);
1469: } catch (DataAccessException da_e) {
1470: throw new ProfileException(
1471: "Problem occured populating Profile", da_e);
1472: }
1473: }
1474:
1475: /* (non-Javadoc)
1476: * @see org.openharmonise.rm.dsi.DataStoreObject#getDBTableName()
1477: */
1478: public String getDBTableName() {
1479: String sTable = getDBTableName(m_profObj);
1480:
1481: return sTable;
1482: }
1483:
1484: /* (non-Javadoc)
1485: * @see org.openharmonise.rm.dsi.DataStoreObject#getInstanceJoinConditions(java.lang.String, boolean)
1486: */
1487: public JoinConditions getInstanceJoinConditions(String sObjectTag,
1488: boolean bIsOuter) throws DataStoreException {
1489:
1490: return null;
1491: }
1492:
1493: /* (non-Javadoc)
1494: * @see org.openharmonise.rm.dsi.DataStoreObject#processResultSet(org.openharmonise.commons.dsi.CachedResultSet, org.openharmonise.commons.dsi.dml.SelectStatement)
1495: */
1496: public List processResultSet(CachedResultSet resultSet,
1497: SelectStatement select) {
1498: //Not implemented as it's pretty complicated to handle with
1499: //the possibility of profile property instances
1500: //and objects will be populated when the data is requested
1501: //anyway, if indeed it's not already populated
1502: return null;
1503: }
1504:
1505: /* (non-Javadoc)
1506: * @see org.openharmonise.rm.dsi.DataStoreObject#processResultSet(org.openharmonise.commons.dsi.CachedResultSet, org.openharmonise.commons.dsi.dml.SelectStatement, int)
1507: */
1508: public List processResultSet(CachedResultSet resultSet,
1509: SelectStatement select, int limit) {
1510: //Not implemented as it's pretty complicated to handle with
1511: //the possibility of profile property instances
1512: //and objects will be populated when the data is requested
1513: //anyway, if indeed it's not already populated
1514: return null;
1515: }
1516:
1517: /* (non-Javadoc)
1518: * @see java.lang.Object#clone()
1519: */
1520: public Object clone() {
1521: //Note: if exception is thrown it is gonna cause problems with
1522: //saving, etc so I've elected to throw a RuntimeException
1523: try {
1524: if (m_bIsPopulated == false) {
1525: populateFromDatabase();
1526: }
1527:
1528: if (isPropertyInstancesPopulated() == false) {
1529: populatePropertyInstancesFromDatabase();
1530: }
1531:
1532: AbstractPropertyInstance nextProp = null;
1533: //clone the profile
1534: Profile other = (Profile) super .clone();
1535:
1536: //iterate through prop insts to clone and add to cloned profile
1537: Iterator iter = m_propStores.keySet().iterator();
1538: other.m_propStores = new Hashtable();
1539:
1540: while (iter.hasNext()) {
1541: String sKey = (String) iter.next();
1542: PropertyInstanceStore propStore = (PropertyInstanceStore) this .m_propStores
1543: .get(sKey);
1544: //note that the propstore clone method is not called as it
1545: //will have a relationship with this Profile rather
1546: //than the new cloned one
1547: other.m_propStores.put(sKey,
1548: other.new PropertyInstanceStore(propStore));
1549: }
1550:
1551: return other;
1552: } catch (PopulateException e) {
1553: m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
1554: throw new IllegalStateException(
1555: "Problem occured during clone"
1556: + e.getLocalizedMessage());
1557: } catch (DataAccessException e) {
1558: m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
1559: throw new IllegalStateException(
1560: "Problem occured during clone"
1561: + e.getLocalizedMessage());
1562: }
1563: }
1564:
1565: /* (non-Javadoc)
1566: * @see org.openharmonise.rm.dsi.DataStoreObject#getInstanceColumnRef(java.lang.String, boolean)
1567: */
1568: public ColumnRef getInstanceColumnRef(String sColumn,
1569: boolean bIsHist) throws DataStoreException {
1570: ColumnRef returnColRef = null;
1571:
1572: returnColRef = getColumnRef(m_profObj, sColumn);
1573:
1574: if (returnColRef != null) {
1575: return returnColRef;
1576: } else {
1577: return super .getInstanceColumnRef(sColumn, bIsHist);
1578: }
1579: }
1580:
1581: /**
1582: * Returns the database table name for the <code>Profile</code> of the
1583: * specified <code>AbstractProfiledObject</code>.
1584: *
1585: * @param profObj the profiled object
1586: * @return the database table name for the <code>Profile</code> of the
1587: * specified <code>AbstractProfiledObject</code>
1588: */
1589: public static String getDBTableName(AbstractProfiledObject profObj) {
1590: String sTable = UNKNOWN_PROFILE;
1591:
1592: if (profObj != null) {
1593: StringBuffer sbuf = new StringBuffer();
1594:
1595: sbuf.append(profObj.getDBTableName()).append(EXT_PROFILE);
1596:
1597: if (profObj.isHistorical() == true) {
1598: sbuf.append(EXT_HIST);
1599: }
1600:
1601: sTable = sbuf.toString();
1602: }
1603:
1604: return sTable;
1605: }
1606:
1607: /**
1608: * Returns the appropriate <code>ColumnRef</code> for the column of the
1609: * <code>Profile</code> for the given <code>AbstractProfiledObject</code>.
1610: *
1611: * @param profObj the profiled object
1612: * @param sColumn the column name
1613: * @return the appropriate <code>ColumnRef</code> for the specified column
1614: * @throws DataStoreException if the specified column does not match any
1615: * valid columns
1616: */
1617: public static ColumnRef getColumnRef(
1618: AbstractProfiledObject profObj, String sColumn)
1619: throws DataStoreException {
1620: ColumnRef returnColRef = null;
1621: return getColumnRef(profObj.getClass().getName(), sColumn,
1622: profObj.isHistorical());
1623: }
1624:
1625: /**
1626: * Returns the table name for the object of the class name given, taking account
1627: * for whether the historical table is needed or not.
1628: *
1629: * @param sClassname the class name of an <code>AbstractObject</code>
1630: * @param bHist <code>true</code> if the table name is
1631: * associated with a historical object
1632: * @return the table name for the object
1633: * @throws DataStoreException if an error occurs
1634: */
1635: public static String getTableName(String sClassname, boolean bHist)
1636: throws DataStoreException {
1637: String sTable = null;
1638:
1639: StringBuffer sbuf = new StringBuffer();
1640:
1641: sbuf.append(AbstractObject.getTableName(sClassname, false));
1642:
1643: sbuf.append(EXT_PROFILE);
1644:
1645: if (bHist == true) {
1646: sbuf.append(EXT_HIST);
1647: }
1648:
1649: return sbuf.toString();
1650: }
1651:
1652: /**
1653: * Returns a column reference appropriate for the given
1654: * parameters.
1655: *
1656: * @param sClassname the class name of an <code>AbstractObject</code>
1657: * @param sColumn the column, tag or attribute name
1658: * @param bHist <code>true</code> if the column reference is
1659: * associated with a historical object
1660: * @return the column reference corresponding to the parameters
1661: * @throws DataStoreException if an error occurs
1662: */
1663: public static ColumnRef getColumnRef(String sClassname,
1664: String sColumn, boolean bHist) throws DataStoreException {
1665: ColumnRef returnColRef = null;
1666: String sTable = getTableName(sClassname, bHist);
1667:
1668: if (sColumn.equals(ATTRIB_OBJECT_KEY) == true
1669: || sColumn.equals(CLMN_OBJECT_KEY) == true) {
1670: returnColRef = new ColumnRef(sTable, CLMN_OBJECT_KEY,
1671: ColumnRef.NUMBER);
1672: } else if (sColumn.equals(CLMN_IS_DEFAULT) == true
1673: || sColumn.equals(Profile.ATTRIB_ISDEFAULT) == true) {
1674: returnColRef = new ColumnRef(sTable, CLMN_IS_DEFAULT,
1675: ColumnRef.NUMBER);
1676: } else if (sColumn
1677: .equals(AbstractEditableObject.TAG_VERSION_COMMENT) == true
1678: || sColumn.equals(CLMN_VERSION_COMMENT) == true) {
1679: returnColRef = new ColumnRef(sTable, CLMN_VERSION_COMMENT,
1680: ColumnRef.TEXT);
1681: }
1682:
1683: if (returnColRef == null) {
1684: returnColRef = AbstractObject.getColumnRef(sClassname,
1685: sColumn);
1686: if (returnColRef != null) {
1687: returnColRef.setTable(sTable);
1688: }
1689: }
1690:
1691: return returnColRef;
1692: }
1693:
1694: /**
1695: * Updates the data in the database for this <code>Profile</code>.
1696: *
1697: * @throws PopulateException if any errors occur saving the profile details
1698: * to the database
1699: * @throws EditException if any errors occur saving the property instances
1700: * to the database
1701: */
1702: public void update() throws PopulateException, EditException {
1703:
1704: //first populate if necessary
1705: if (m_bIsPopulated == false) {
1706: populateFromDatabase();
1707: }
1708:
1709: try {
1710:
1711: if (isPropertyInstancesPopulated() == false) {
1712: populatePropertyInstancesFromDatabase();
1713: }
1714: } catch (DataAccessException da_e) {
1715: throw new PopulateException(
1716: "Error occured while accessing property instances",
1717: da_e);
1718: }
1719:
1720: //update property instances
1721: updatePropertyInstances();
1722:
1723: //Update profile data
1724: UpdateStatement update = new UpdateStatement();
1725:
1726: try {
1727:
1728: if (m_sSummary != null) {
1729: update.addColumnValue(getInstanceColumnRef(TAG_SUMMARY,
1730: false), m_sSummary);
1731: }
1732:
1733: if (m_sVersionComment != null) {
1734: update.addColumnValue(getInstanceColumnRef(
1735: Profile.CLMN_VERSION_COMMENT, false),
1736: m_sVersionComment);
1737: }
1738:
1739: int nIsDefault = 0;
1740: if (m_bIsDefault) {
1741: nIsDefault = 1;
1742: }
1743:
1744: update.addColumnValue(getInstanceColumnRef(CLMN_IS_DEFAULT,
1745: false), nIsDefault);
1746: update.addWhereCondition(getInstanceColumnRef(ATTRIB_ID,
1747: false), "=", m_nId);
1748: } catch (DataStoreException ds_e) {
1749: throw new PopulateException(
1750: "Problem occurred while building update statement",
1751: ds_e);
1752: }
1753:
1754: try {
1755:
1756: m_dsi.executeUpdate(update);
1757:
1758: } catch (DataStoreException ds_e) {
1759: throw new PopulateException(
1760: "Problem occurred while processing update statement",
1761: ds_e);
1762: }
1763: }
1764:
1765: /* (non-Javadoc)
1766: * @see org.openharmonise.rm.publishing.Publishable#getTagName()
1767: */
1768: public String getTagName() {
1769: return TAG_PROFILE;
1770: }
1771:
1772: /*--------------------------------------------------------------------------
1773:
1774: Protected Functions
1775:
1776: ---------------------------------------------------------------------------*/
1777:
1778: /**
1779: * Returns the <code>AbstractProfiledObject</code> associated with this
1780: * <code>Profile</code>.
1781: */
1782: protected AbstractProfiledObject getProfiledObject() {
1783: return m_profObj;
1784: }
1785:
1786: /* (non-Javadoc)
1787: * @see org.openharmonise.rm.resources.AbstractObject#populateFromResultSetRow(java.sql.ResultSet, org.openharmonise.commons.dsi.dml.SelectStatement)
1788: */
1789: protected void populateFromResultSetRow(ResultSet rs,
1790: SelectStatement select) throws PopulateException {
1791:
1792: if (isPopulated() == false) {
1793: super .populateFromResultSetRow(rs, select);
1794:
1795: String sTemp = "";
1796: ColumnRef colref = null;
1797: boolean bIsHist = isHistorical();
1798:
1799: try {
1800: colref = getInstanceColumnRef(
1801: AbstractEditableObject.TAG_VERSION_COMMENT,
1802: bIsHist);
1803:
1804: if (select.containsSelectColumn(colref) == true) {
1805: m_sVersionComment = rs.getString(select
1806: .getResultSetIndex(colref));
1807: }
1808:
1809: colref = getInstanceColumnRef(ATTRIB_ISDEFAULT, bIsHist);
1810:
1811: if (select.containsSelectColumn(colref) == true) {
1812: m_bIsDefault = rs.getBoolean(select
1813: .getResultSetIndex(colref));
1814: }
1815:
1816: } catch (DataStoreException ds_e) {
1817: throw new PopulateException(ds_e.getLocalizedMessage());
1818: } catch (SQLException sql_e) {
1819: throw new PopulateException(sql_e.getLocalizedMessage());
1820: }
1821: }
1822: }
1823:
1824: /* (non-Javadoc)
1825: * @see org.openharmonise.rm.resources.AbstractObject#populateFromDatabase()
1826: */
1827: protected void populateFromDatabase() throws PopulateException {
1828: super .populateFromDatabase();
1829: }
1830:
1831: /* (non-Javadoc)
1832: * @see org.openharmonise.rm.resources.AbstractObject#addColumnsToPopulateQuery(org.openharmonise.commons.dsi.dml.SelectStatement, boolean)
1833: */
1834: protected void addColumnsToPopulateQuery(SelectStatement select,
1835: boolean bIsHist) throws DataStoreException {
1836:
1837: select.addSelectColumn(getInstanceColumnRef(
1838: AbstractEditableObject.TAG_VERSION_COMMENT, bIsHist));
1839: select.addSelectColumn(getInstanceColumnRef(ATTRIB_ISDEFAULT,
1840: bIsHist));
1841: super .addColumnsToPopulateQuery(select, bIsHist);
1842: }
1843:
1844: /**
1845: * Populates all the property instances in this <code>Profile</code>.
1846: *
1847: * @throws PopulateException if an error occurs accessing the data from
1848: * the database
1849: */
1850: protected void populatePropertyInstancesFromDatabase()
1851: throws PopulateException {
1852: try {
1853:
1854: initialisePropertyInstanceStores();
1855: } catch (DataAccessException e) {
1856: throw new PopulateException(
1857: "Problem occurred populating property instances", e);
1858: }
1859:
1860: Iterator iter = m_propStores.values().iterator();
1861:
1862: while (iter.hasNext()) {
1863: PropertyInstanceStore propStore = (PropertyInstanceStore) iter
1864: .next();
1865:
1866: populatePropertyInstanceStore(propStore);
1867: }
1868: }
1869:
1870: /**
1871: * Populates the <code>ProfilePropertyInstance</code>s held by this
1872: * <code>Profile</code>.
1873: *
1874: * @throws PopulateException if any errors occur
1875: */
1876: protected synchronized void populateProfilePropertyInstances()
1877: throws PopulateException {
1878: PropertyInstanceStore propStore = (PropertyInstanceStore) m_propStores
1879: .get(Profile.class.getName());
1880:
1881: if (propStore.isPopulated() == false) {
1882:
1883: SelectStatement select = new SelectStatement();
1884:
1885: boolean bIsHist = isHistorical();
1886:
1887: ColumnRef dataPropIdCol = null;
1888:
1889: try {
1890:
1891: String sProfDataTable = ProfilePropertyInstance
1892: .getDBTableName(this );
1893:
1894: select.addSelectColumn(getProfileDataColumn(
1895: sProfDataTable,
1896: AbstractPropertyInstance.CLMN_ID));
1897:
1898: dataPropIdCol = getProfileDataColumn(sProfDataTable,
1899: AbstractPropertyInstance.CLMN_PROPERTY_ID);
1900:
1901: select.addSelectColumn(dataPropIdCol);
1902:
1903: select.addSelectColumn(getProfileDataColumn(
1904: sProfDataTable,
1905: AbstractPropertyInstance.CLMN_VERSION_COMMENT));
1906:
1907: select.addSelectColumn(getProfileDataColumn(
1908: sProfDataTable, CLMN_NAME));
1909:
1910: select.addSelectColumn(getProfileDataColumn(
1911: sProfDataTable, CLMN_SUMMARY));
1912:
1913: ColumnRef profId_colref = getProfileDataColumn(
1914: sProfDataTable,
1915: ProfilePropertyInstance.CLMN_PROFILE_PARENT);
1916:
1917: select.addWhereCondition(profId_colref, "=", m_nId);
1918:
1919: //need to add order by to ensure that all property instances
1920: //of a property get handled consecutively
1921: select.setOrderBy(dataPropIdCol);
1922:
1923: } catch (DataStoreException da_e) {
1924: throw new PopulateException(
1925: "Error occured building query", da_e);
1926: }
1927:
1928: ResultSet rs = null;
1929:
1930: try {
1931: int nProfId = 0;
1932: int nPropId = 0;
1933: rs = m_dsi.execute(select);
1934: ProfilePropertyInstance propInst = null;
1935: while (rs.next()) {
1936: nProfId = rs.getInt(1);
1937: nPropId = rs.getInt(2);
1938: if (propInst == null
1939: || propInst.getProperty().getId() != nPropId) {
1940: //before we're done set populated flag
1941: if (propInst != null) {
1942: propInst.setIsPopulated(true);
1943: }
1944:
1945: propInst = new ProfilePropertyInstance(m_dsi,
1946: this );
1947:
1948: Property prop = (Property) HarmoniseObjectFactory
1949: .instantiateHarmoniseObject(m_dsi,
1950: Property.class.getName(),
1951: nPropId);
1952:
1953: //if prop no longer exists we hve to delete all prop insts with
1954: //this prop and not add it to this profile
1955: if (prop == null) {
1956: if (m_logger.isLoggable(Level.INFO)) {
1957: m_logger
1958: .logp(
1959: Level.INFO,
1960: this .getClass()
1961: .getName(),
1962: "populateGeneralPropertyInstances",
1963: "Property "
1964: + nPropId
1965: + " no longer exists so removing value");
1966: }
1967:
1968: ProfileValue prof = new ProfileValue(m_dsi,
1969: nProfId, m_profObj);
1970: prof.setName(rs.getString(4));
1971: prof.setSummary(rs.getString(5));
1972:
1973: try {
1974: prof.delete();
1975: } catch (ProfileException e) {
1976: //won't escalate this as the profile value
1977: //will only hang around for this version of
1978: //the object and the behaviour of this
1979: //object should be fine
1980: m_logger.log(Level.WARNING, e
1981: .getLocalizedMessage(), e);
1982: }
1983:
1984: propInst = null;
1985: continue;
1986: }
1987:
1988: propInst.setProperty(prop);
1989: propInst.setVersionComment(rs.getString(3));
1990:
1991: propStore.addPropertyInstance(propInst);
1992: }
1993:
1994: ProfileValue prof = new ProfileValue(m_dsi,
1995: nProfId, m_profObj);
1996: prof.setName(rs.getString(4));
1997: prof.setSummary(rs.getString(5));
1998: prof.setProperty(propInst.getProperty());
1999: propInst.addValue(prof, nProfId);
2000: }
2001: if (propInst != null) {
2002: propInst.setIsPopulated(true);
2003: }
2004:
2005: propStore.setIsPopulated(true);
2006: } catch (SQLException sql_e) {
2007: throw new PopulateException(
2008: "Error occured processing query", sql_e);
2009: } catch (HarmoniseFactoryException f_e) {
2010: throw new PopulateException(
2011: "Error occured getting property from factory",
2012: f_e);
2013: } catch (DataStoreException ds_e) {
2014: throw new PopulateException(
2015: "Error occured processing query", ds_e);
2016: } catch (DataAccessException da_e) {
2017: throw new PopulateException(
2018: "Error occured populating property instance",
2019: da_e);
2020: } catch (InvalidPropertyValueException ipv_e) {
2021: // do nothing - the value just won't be added
2022: m_logger.log(Level.FINE, "Ignoring exception", ipv_e);
2023: } catch (InvalidNameException e) {
2024: throw new PopulateException(e);
2025: } finally {
2026: if (rs != null) {
2027: try {
2028:
2029: rs.close();
2030: } catch (SQLException sql_e) {
2031: throw new PopulateException(
2032: "Had trouble closing result set", sql_e);
2033: }
2034: }
2035: }
2036:
2037: }
2038: }
2039:
2040: /**
2041: * Populates the <code>GeneralPropertyInstance</code>s held by this
2042: * <code>Profile</code>.
2043: *
2044: * @throws PopulateException if any errors occur
2045: */
2046: protected synchronized void populateGeneralPropertyInstances()
2047: throws PopulateException {
2048: PropertyInstanceStore propStore = (PropertyInstanceStore) m_propStores
2049: .get(GeneralPropertyInstance.class.getName());
2050:
2051: if (propStore.isPopulated() == false) {
2052:
2053: SelectStatement select = new SelectStatement();
2054:
2055: boolean bIsHist = isHistorical();
2056: ColumnRef dataPropIdCol = null;
2057:
2058: try {
2059:
2060: String sProfDataTable = GeneralPropertyInstance
2061: .getDBTableName(this );
2062:
2063: select.addSelectColumn(getProfileDataColumn(
2064: sProfDataTable,
2065: AbstractPropertyInstance.CLMN_ID));
2066:
2067: dataPropIdCol = getProfileDataColumn(sProfDataTable,
2068: AbstractPropertyInstance.CLMN_PROPERTY_ID);
2069:
2070: select.addSelectColumn(dataPropIdCol);
2071:
2072: ColumnRef ver_com_colref = getProfileDataColumn(
2073: sProfDataTable,
2074: AbstractPropertyInstance.CLMN_VERSION_COMMENT);
2075:
2076: select.addSelectColumn(ver_com_colref);
2077: select.addSelectColumn(getProfileDataColumn(
2078: sProfDataTable,
2079: GeneralPropertyInstance.CLMN_VALUE));
2080:
2081: ColumnRef profId_colref = getProfileDataColumn(
2082: sProfDataTable,
2083: GeneralPropertyInstance.CLMN_PROFILE_ID);
2084:
2085: select.addWhereCondition(profId_colref, "=", m_nId);
2086:
2087: //need to add order by to ensure that all property instances
2088: //of a property get handled consecutively
2089: select.setOrderBy(dataPropIdCol);
2090:
2091: } catch (DataStoreException da_e) {
2092: throw new PopulateException(
2093: "Error occured building query", da_e);
2094: }
2095:
2096: ResultSet rs = null;
2097:
2098: try {
2099:
2100: rs = m_dsi.execute(select);
2101: GeneralPropertyInstance propInst = null;
2102: while (rs.next()) {
2103: int nPropId = rs.getInt(2);
2104: if (propInst == null
2105: || propInst.getProperty().getId() != nPropId) {
2106: if (propInst != null) {
2107: propInst.setIsPopulated(true);
2108: }
2109: propInst = new GeneralPropertyInstance(m_dsi,
2110: this );
2111:
2112: Property prop = (Property) HarmoniseObjectFactory
2113: .instantiateHarmoniseObject(m_dsi,
2114: Property.class.getName(),
2115: nPropId);
2116:
2117: //if prop no longer exists we hve to delete all prop insts with
2118: //this prop and not add it to this profile
2119: if (prop == null) {
2120: if (m_logger.isLoggable(Level.INFO)) {
2121: m_logger
2122: .logp(
2123: Level.INFO,
2124: this .getClass()
2125: .getName(),
2126: "populateGeneralPropertyInstances",
2127: "Property "
2128: + nPropId
2129: + " no longer exists so removing value");
2130: }
2131:
2132: DeleteStatement delete = new DeleteStatement();
2133:
2134: delete.addWhereCondition(dataPropIdCol,
2135: "=", nPropId);
2136:
2137: m_dsi.execute(delete);
2138:
2139: propInst = null;
2140:
2141: continue;
2142: }
2143:
2144: propInst.setProperty(prop);
2145: propInst.setVersionComment(rs.getString(3));
2146:
2147: propStore.addPropertyInstance(propInst);
2148: }
2149: propInst.addValue(rs.getString(4), rs.getInt(1));
2150:
2151: }
2152: if (propInst != null) {
2153: propInst.setIsPopulated(true);
2154: }
2155:
2156: propStore.setIsPopulated(true);
2157: } catch (SQLException sql_e) {
2158: throw new PopulateException(
2159: "Error occured processing query", sql_e);
2160: } catch (HarmoniseFactoryException f_e) {
2161: throw new PopulateException(
2162: "Error occured getting property from factory",
2163: f_e);
2164: } catch (DataStoreException ds_e) {
2165: throw new PopulateException(
2166: "Error occured processing query", ds_e);
2167: } catch (DataAccessException da_e) {
2168: throw new PopulateException(
2169: "Error occured populating property instance",
2170: da_e);
2171: } catch (InvalidPropertyValueException ipv_e) {
2172: //do nothing - the value just won't be added
2173: m_logger.log(Level.FINE, "Ignoring exception", ipv_e);
2174: } finally {
2175: if (rs != null) {
2176: try {
2177:
2178: rs.close();
2179: } catch (SQLException sql_e) {
2180: throw new PopulateException(
2181: "Had trouble closing result set", sql_e);
2182: }
2183: }
2184: }
2185: }
2186: }
2187:
2188: /**
2189: * Populates the <code>ChildObjectPropertyInstance</code>s, of the type
2190: * specified by the class name given, held by this <code>Profile</code>.
2191: *
2192: * @param sTableName the database table name of the <code>AbstractChildObject</code>
2193: * class which can be values for the property instances to be populated
2194: *
2195: * @throws PopulateException if any errors occur
2196: */
2197: protected synchronized void populateChildObjectPropertyInstances(
2198: String sTableName) throws PopulateException {
2199: PropertyInstanceStore propStore = (PropertyInstanceStore) m_propStores
2200: .get(sTableName);
2201:
2202: if (propStore.isPopulated() == false) {
2203:
2204: SelectStatement select = new SelectStatement();
2205:
2206: boolean bIsHist = isHistorical();
2207: ColumnRef dataPropIdCol = null;
2208:
2209: try {
2210:
2211: String sProfDataTable = ChildObjectPropertyInstance
2212: .constructDBTableName(this , sTableName);
2213: String sClassname = propStore.getAssociatedClassname();
2214:
2215: ColumnRef valIdCol = AbstractObject.getColumnRef(
2216: sClassname, ATTRIB_ID);
2217: ColumnRef valTypeCol = AbstractObject.getColumnRef(
2218: sClassname, ATTRIB_TYPE);
2219: ColumnRef propTypeCol = AbstractObject.getColumnRef(
2220: Property.class.getName(),
2221: AbstractObject.ATTRIB_TYPE);
2222: ColumnRef propIdCol = AbstractObject.getColumnRef(
2223: Property.class.getName(),
2224: AbstractObject.ATTRIB_ID);
2225:
2226: dataPropIdCol = getProfileDataColumn(sProfDataTable,
2227: AbstractPropertyInstance.CLMN_PROPERTY_ID);
2228:
2229: ColumnRef objIdCol = getProfileDataColumn(
2230: sProfDataTable,
2231: ChildObjectPropertyInstance.CLMN_OBJECT_ID);
2232:
2233: select.addSelectColumn(getProfileDataColumn(
2234: sProfDataTable,
2235: AbstractPropertyInstance.CLMN_ID));
2236:
2237: select.addSelectColumn(dataPropIdCol);
2238:
2239: ColumnRef ver_com_colref = getProfileDataColumn(
2240: sProfDataTable,
2241: AbstractPropertyInstance.CLMN_VERSION_COMMENT);
2242:
2243: select.addSelectColumn(ver_com_colref);
2244: select.addSelectColumn(objIdCol);
2245:
2246: select.addSelectColumn(valTypeCol);
2247: select.addSelectColumn(propTypeCol);
2248:
2249: ColumnRef profId_colref = getProfileDataColumn(
2250: sProfDataTable,
2251: AbstractPropertyInstance.CLMN_PROFILE_ID);
2252:
2253: select.addJoinCondition(valIdCol, objIdCol);
2254: select.addJoinCondition(propIdCol, dataPropIdCol);
2255:
2256: select.addWhereCondition(profId_colref, "=", m_nId);
2257:
2258: //need to add order by to ensure that all property instances
2259: //of a property get handled consecutively
2260: select.setOrderBy(dataPropIdCol);
2261:
2262: } catch (DataStoreException da_e) {
2263: throw new PopulateException(
2264: "Error occured building query", da_e);
2265: }
2266:
2267: ResultSet rs = null;
2268:
2269: try {
2270: int nPropId = 0;
2271: rs = m_dsi.execute(select);
2272: ChildObjectPropertyInstance propInst = null;
2273: while (rs.next()) {
2274: nPropId = rs.getInt(2);
2275:
2276: if (propInst == null
2277: || propInst.getProperty().getId() != nPropId) {
2278: if (propInst != null) {
2279: propInst.setIsPopulated(true);
2280: }
2281:
2282: Property prop = (Property) HarmoniseObjectFactory
2283: .instantiateHarmoniseObject(m_dsi, rs
2284: .getString(6), nPropId);
2285:
2286: //if prop no longer exists we hve to delete all prop insts with
2287: //this prop and not add it to this profile
2288: if (prop == null) {
2289: if (m_logger.isLoggable(Level.INFO)) {
2290: m_logger
2291: .logp(
2292: Level.INFO,
2293: this .getClass()
2294: .getName(),
2295: "populateGeneralPropertyInstances",
2296: "Property "
2297: + nPropId
2298: + " no longer exists so removing value");
2299: }
2300:
2301: DeleteStatement delete = new DeleteStatement();
2302:
2303: delete.addWhereCondition(dataPropIdCol,
2304: "=", nPropId);
2305:
2306: m_dsi.execute(delete);
2307:
2308: propInst = null;
2309:
2310: continue;
2311: }
2312:
2313: Range range = prop.getRange();
2314:
2315: if (range == null) {
2316: throw new PopulateException(
2317: "No range attached to property");
2318: }
2319:
2320: propInst = (ChildObjectPropertyInstance) range
2321: .getPropertyInstanceClass()
2322: .newInstance();
2323: propInst.setDataStoreInterface(m_dsi);
2324: propInst.setProfile(this );
2325:
2326: propInst.setProperty(prop);
2327: propInst.setVersionComment(rs.getString(3));
2328:
2329: propStore.addPropertyInstance(propInst);
2330: }
2331:
2332: AbstractChildObject child = (AbstractChildObject) HarmoniseObjectFactory
2333: .instantiateHarmoniseObject(m_dsi, rs
2334: .getString(5), rs.getInt(4));
2335:
2336: propInst.addValue(child, rs.getInt(1));
2337: }
2338: if (propInst != null) {
2339: propInst.setIsPopulated(true);
2340: }
2341:
2342: propStore.setIsPopulated(true);
2343: } catch (SQLException sql_e) {
2344: throw new PopulateException(
2345: "Error occured processing query", sql_e);
2346: } catch (HarmoniseFactoryException f_e) {
2347: throw new PopulateException(
2348: "Error occured getting property from factory",
2349: f_e);
2350: } catch (DataStoreException ds_e) {
2351: throw new PopulateException(
2352: "Error occured processing query", ds_e);
2353: } catch (DataAccessException da_e) {
2354: throw new PopulateException(
2355: "Error occured populating property instance",
2356: da_e);
2357: } catch (InvalidPropertyValueException ipv_e) {
2358: //do nothing - the value just won't be added
2359: m_logger.log(Level.FINE, "Ignoring exception", ipv_e);
2360: } catch (InstantiationException e) {
2361: throw new PopulateException(e.getLocalizedMessage(), e);
2362: } catch (IllegalAccessException e) {
2363: throw new PopulateException(e.getLocalizedMessage(), e);
2364: } catch (ClassNotFoundException e) {
2365: throw new PopulateException(e.getLocalizedMessage(), e);
2366: } finally {
2367: if (rs != null) {
2368: try {
2369:
2370: rs.close();
2371: } catch (SQLException sql_e) {
2372: throw new PopulateException(
2373: "Had trouble closing result set", sql_e);
2374: }
2375: }
2376: }
2377: }
2378: }
2379:
2380: /*--------------------------------------------------------------------------
2381:
2382: Private Functions
2383:
2384: ---------------------------------------------------------------------------*/
2385:
2386: /**
2387: * Returns the <code>ColumnRef</code> for the profile data associated with
2388: * the specified table and column.
2389: *
2390: * @param sTable the property instance database table
2391: * @param sCol the column name
2392: * @return the matching column reference for the specified table and column
2393: * @throws DataStoreException if no valid column references match the
2394: * specified table and column
2395: */
2396: private ColumnRef getProfileDataColumn(String sTable, String sCol)
2397: throws DataStoreException {
2398: ColumnRef returnColRef = null;
2399:
2400: if (sCol.equals(AbstractPropertyInstance.CLMN_PROPERTY_ID) == true) {
2401: returnColRef = new ColumnRef(sTable,
2402: AbstractPropertyInstance.CLMN_PROPERTY_ID,
2403: ColumnRef.NUMBER);
2404: } else if (sCol.equals(GeneralPropertyInstance.CLMN_PROFILE_ID) == true) {
2405: returnColRef = new ColumnRef(sTable,
2406: GeneralPropertyInstance.CLMN_PROFILE_ID,
2407: ColumnRef.NUMBER);
2408: } else if (sCol
2409: .equals(AbstractPropertyInstance.CLMN_VERSION_COMMENT) == true) {
2410: returnColRef = new ColumnRef(sTable,
2411: AbstractPropertyInstance.CLMN_VERSION_COMMENT,
2412: ColumnRef.TEXT);
2413: } else if (sCol.equals(GeneralPropertyInstance.CLMN_VALUE) == true) {
2414: returnColRef = new ColumnRef(sTable,
2415: GeneralPropertyInstance.CLMN_VALUE, ColumnRef.TEXT);
2416: } else if (sCol.equals(GeneralPropertyInstance.CLMN_ID) == true) {
2417: returnColRef = new ColumnRef(sTable,
2418: GeneralPropertyInstance.CLMN_ID, ColumnRef.NUMBER);
2419: } else if (sCol
2420: .equals(ProfilePropertyInstance.CLMN_PROFILE_PARENT) == true) {
2421: returnColRef = new ColumnRef(sTable,
2422: ProfilePropertyInstance.CLMN_PROFILE_PARENT,
2423: ColumnRef.NUMBER);
2424: } else if (sCol.equals(CLMN_NAME) == true) {
2425: returnColRef = new ColumnRef(sTable, CLMN_NAME,
2426: ColumnRef.NUMBER);
2427: } else if (sCol.equals(CLMN_SUMMARY) == true) {
2428: returnColRef = new ColumnRef(sTable, CLMN_SUMMARY,
2429: ColumnRef.NUMBER);
2430: } else if (sCol
2431: .equals(ChildObjectPropertyInstance.CLMN_OBJECT_ID) == true) {
2432: returnColRef = new ColumnRef(sTable,
2433: ChildObjectPropertyInstance.CLMN_OBJECT_ID,
2434: ColumnRef.NUMBER);
2435: }
2436:
2437: if (returnColRef != null) {
2438: return returnColRef;
2439: } else {
2440: throw new InvalidColumnReferenceException(sCol);
2441: }
2442: }
2443:
2444: /**
2445: * Returns <code>true</code> if all the property instances have been
2446: * populated, otherwise <code>false</code>.
2447: *
2448: * @return <code>true</code> if all the property instances have been
2449: * populated, otherwise <code>false</code>
2450: * @throws DataAccessException if any errors occur accessing property
2451: * instance data
2452: */
2453: private boolean isPropertyInstancesPopulated()
2454: throws DataAccessException {
2455: boolean bIsPopulated = true;
2456:
2457: initialisePropertyInstanceStores();
2458:
2459: Iterator iter = m_propStores.values().iterator();
2460:
2461: while (bIsPopulated == true && iter.hasNext()) {
2462: PropertyInstanceStore propStore = (PropertyInstanceStore) iter
2463: .next();
2464: if (propStore.isPopulated() == false) {
2465: bIsPopulated = false;
2466: }
2467: }
2468:
2469: return bIsPopulated;
2470: }
2471:
2472: /**
2473: * Initialises the collection of <code>PropertyInstanceStore</code>s.
2474: *
2475: * @throws DataAccessException if an error occurs finding the available
2476: * properties or initialising the appropriate <code>PropertyInstanceStore</code>s
2477: *
2478: */
2479: private void initialisePropertyInstanceStores()
2480: throws DataAccessException {
2481: String sKey = null;
2482: String sClassname = null;
2483:
2484: List props = getAvailableProperties();
2485:
2486: Iterator iter = props.iterator();
2487:
2488: while (iter.hasNext()) {
2489: Property prop = (Property) iter.next();
2490:
2491: if (isPropertyInstanceProfile(prop) == true) {
2492: sKey = Profile.class.getName();
2493:
2494: } else if (isPropertyInstanceChildObject(prop) == true) {
2495: Range range = prop.getRange();
2496: if (m_profObj instanceof AbstractChildObject) {
2497: sClassname = ((ChildObjectRange) range)
2498: .getChildObjectValueClassName((AbstractChildObject) m_profObj);
2499: } else {
2500: sClassname = range.getObject();
2501: }
2502:
2503: try {
2504: sKey = DatabaseInfo.getInstance().getTableName(
2505: sClassname);
2506: } catch (DataStoreException e) {
2507: throw new DataAccessException(
2508: "Trouble finding class for " + sKey);
2509: }
2510:
2511: } else {
2512: sKey = GeneralPropertyInstance.class.getName();
2513: }
2514:
2515: if (m_propStores.containsKey(sKey) == false) {
2516: if (sClassname == null) {
2517: m_propStores.put(sKey, new PropertyInstanceStore(
2518: sKey));
2519: } else {
2520: m_propStores.put(sKey, new PropertyInstanceStore(
2521: sKey, sClassname));
2522: }
2523: }
2524: }
2525: }
2526:
2527: /**
2528: * Returns <code>true</code> if the specified <code>Property</code>
2529: * represents a general datatype property.
2530: *
2531: * @param prop the <code>Property</code> to test
2532: * @return <code>true</code> if the <code>Property</code> given
2533: * represents a general datatype property.
2534: * @throws DataAccessException if there is an error accessing the
2535: * <code>Range</code> of the <code>Property</code>
2536: */
2537: private boolean isPropertyInstanceGeneral(Property prop)
2538: throws DataAccessException {
2539: boolean bIsGen = false;
2540: if (prop != null) {
2541: Range range = prop.getRange();
2542:
2543: try {
2544: if (GeneralPropertyInstance.class
2545: .isAssignableFrom(range
2546: .getPropertyInstanceClass())) {
2547: bIsGen = true;
2548: }
2549: } catch (ClassNotFoundException e) {
2550: m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
2551: }
2552: }
2553:
2554: return bIsGen;
2555: }
2556:
2557: /**
2558: * Returns <code>true</code> if the specified <code>Property</code>
2559: * represents an <code>AbstractChildObject</code> datatype property.
2560: *
2561: * @param prop the <code>Property</code> to test
2562: * @return <code>true</code> if the specified <code>Property</code>
2563: * represents an <code>AbstractChildObject</code> datatype property.
2564: * @throws DataAccessException if there is an error accessing the
2565: * <code>Range</code> of the <code>Property</code>
2566: */
2567: private boolean isPropertyInstanceChildObject(Property prop)
2568: throws DataAccessException {
2569:
2570: boolean bIsChild = false;
2571: if (prop != null) {
2572:
2573: Range range = prop.getRange();
2574:
2575: if (range != null) {
2576: try {
2577: if (ChildObjectPropertyInstance.class
2578: .isAssignableFrom(range
2579: .getPropertyInstanceClass())) {
2580: bIsChild = true;
2581: }
2582: } catch (ClassNotFoundException e) {
2583: m_logger.log(Level.WARNING,
2584: e.getLocalizedMessage(), e);
2585: }
2586: }
2587: }
2588:
2589: return bIsChild;
2590: }
2591:
2592: /**
2593: * Returns <code>true</code> if the specified <code>Property</code>
2594: * represents a <code>Profile</code> datatype property.
2595: *
2596: * @param prop the <code>Property</code> to test
2597: * @return <code>true</code> if the specified <code>Property</code>
2598: * represents a <code>Profile</code> datatype property.
2599: * @throws DataAccessException if there is an error accessing the
2600: * <code>Range</code> of the <code>Property</code>
2601: */
2602: private boolean isPropertyInstanceProfile(Property prop)
2603: throws DataAccessException {
2604:
2605: boolean bIsProfile = false;
2606: if (prop != null) {
2607:
2608: Range range = prop.getRange();
2609: if (range != null) {
2610: try {
2611: if (ProfilePropertyInstance.class
2612: .isAssignableFrom(range
2613: .getPropertyInstanceClass())) {
2614: bIsProfile = true;
2615: }
2616: } catch (ClassNotFoundException e) {
2617: m_logger.log(Level.WARNING,
2618: e.getLocalizedMessage(), e);
2619: }
2620: }
2621: }
2622:
2623: return bIsProfile;
2624: }
2625:
2626: /**
2627: * Updates all property instance data in the database.
2628: *
2629: * @throws PopulateException if there is an error accessing data held in
2630: * the property instances
2631: * @throws EditException if there is an error saving the data to the database
2632: */
2633: private void updatePropertyInstances() throws PopulateException,
2634: EditException {
2635: Iterator iter = m_propStores.values().iterator();
2636:
2637: while (iter.hasNext()) {
2638:
2639: try {
2640: ((PropertyInstanceStore) iter.next()).update();
2641: } catch (ProfileException e) {
2642: throw new PopulateException(e.getLocalizedMessage(), e);
2643: }
2644:
2645: }
2646: }
2647:
2648: /**
2649: * Deletes all property instances from the database for the specified
2650: * <code>PropertyInstanceStore</code>.
2651: *
2652: * @param store the <code>PropertyInstanceStore</code> to delete
2653: * @throws ProfileException if an error occurs deleting the data
2654: * from the database
2655: */
2656: private void deletePropertyInstances(PropertyInstanceStore store)
2657: throws ProfileException {
2658: String sStoreLabel = store.getLabel();
2659:
2660: if (sStoreLabel.equals(Profile.class.getName()) == true) {
2661: Iterator iter = store.getValues().iterator();
2662:
2663: while (iter.hasNext()) {
2664: ProfilePropertyInstance propInst = (ProfilePropertyInstance) iter
2665: .next();
2666:
2667: propInst.delete();
2668: }
2669: } else {
2670: DeleteStatement delete = new DeleteStatement();
2671:
2672: String sDataTable = null;
2673:
2674: if (sStoreLabel.equals(GeneralPropertyInstance.class
2675: .getName()) == true) {
2676: sDataTable = GeneralPropertyInstance
2677: .getDBTableName(this );
2678: } else {
2679: try {
2680: sDataTable = ChildObjectPropertyInstance
2681: .getDBTableName(this , store
2682: .getAssociatedClassname());
2683: } catch (DataStoreException e) {
2684: throw new ProfileException(
2685: "Problem finding profile data table", e);
2686: }
2687: }
2688:
2689: try {
2690: ColumnRef profId_colref = getProfileDataColumn(
2691: sDataTable,
2692: GeneralPropertyInstance.CLMN_PROFILE_ID);
2693:
2694: delete.addWhereCondition(profId_colref, "=", m_nId);
2695: m_dsi.execute(delete);
2696: } catch (DataStoreException e) {
2697: throw new ProfileException(
2698: "Error occured deleting property instances", e);
2699: }
2700:
2701: }
2702:
2703: }
2704:
2705: /**
2706: * Populates the given <code>PropertyInstanceStore</code> from the database.
2707: *
2708: * @param propStore the <code>PropertyInstanceStore</code> to populate
2709: * @throws PopulateException if there is an error populating the
2710: * <code>PropertyInstanceStore</code>
2711: */
2712: private void populatePropertyInstanceStore(
2713: PropertyInstanceStore propStore) throws PopulateException {
2714: if (propStore.isPopulated() == false) {
2715: if (propStore.getLabel().equals(
2716: GeneralPropertyInstance.class.getName()) == true) {
2717: populateGeneralPropertyInstances();
2718: } else if (propStore.getLabel().equals(
2719: Profile.class.getName()) == true) {
2720: populateProfilePropertyInstances();
2721: } else {
2722: //assume it's a store for child object prop insts
2723: populateChildObjectPropertyInstances(propStore
2724: .getLabel());
2725: }
2726: }
2727:
2728: }
2729:
2730: /**
2731: * Returns the <code>PropertyInstanceStore</code> associated with the specified
2732: * <code>Property</code>.
2733: *
2734: * @param prop the <code>Property</code>
2735: * @return the <code>PropertyInstanceStore</code> associated with the specified
2736: * <code>Property</code>
2737: * @throws InvalidPropertyInstanceException if the specified <code>Property</code>
2738: * is invalid for this <code>Profile</code>
2739: * @throws DataAccessException if there is an error getting the <code>Range</code>
2740: * for the <code>Property</code>
2741: */
2742: private PropertyInstanceStore getPropertyInstanceStore(Property prop)
2743: throws InvalidPropertyInstanceException,
2744: DataAccessException {
2745: PropertyInstanceStore propStore = null;
2746: String sKey = null;
2747: String sClassname = null;
2748:
2749: if (isValidProperty(prop) == false) {
2750:
2751: String sPropName = null;
2752:
2753: if (prop != null) {
2754: sPropName = prop.getName();
2755: }
2756:
2757: throw new InvalidPropertyInstanceException(
2758: "Property not valid on [" + m_profObj + "]:"
2759: + sPropName);
2760: }
2761:
2762: if (isPropertyInstanceChildObject(prop) == true) {
2763: ChildObjectRange range = (ChildObjectRange) prop.getRange();
2764: if (m_profObj instanceof AbstractChildObject) {
2765: sClassname = range
2766: .getChildObjectValueClassName((AbstractChildObject) m_profObj);
2767: } else {
2768: sClassname = prop.getRange().getObject();
2769: }
2770:
2771: try {
2772: sKey = DatabaseInfo.getInstance().getTableName(
2773: sClassname);
2774: } catch (DataStoreException e) {
2775: throw new DataAccessException(
2776: "Trouble finding class for " + sKey);
2777: }
2778:
2779: } else if (isPropertyInstanceGeneral(prop) == true) {
2780: sKey = GeneralPropertyInstance.class.getName();
2781:
2782: } else if (isPropertyInstanceProfile(prop) == true) {
2783: sKey = Profile.class.getName();
2784: } else {
2785: throw new InvalidPropertyInstanceException(
2786: "Property not allowed in profile");
2787: }
2788:
2789: propStore = (PropertyInstanceStore) m_propStores.get(sKey);
2790:
2791: if (propStore == null) {
2792: //double checked synchronized block to avoid concurrency problems
2793: synchronized (m_propStores) {
2794: propStore = (PropertyInstanceStore) m_propStores
2795: .get(sKey);
2796:
2797: if (propStore == null) {
2798: if (sClassname == null) {
2799: propStore = new PropertyInstanceStore(sKey);
2800: } else {
2801: propStore = new PropertyInstanceStore(sKey,
2802: sClassname);
2803: }
2804:
2805: m_propStores.put(sKey, propStore);
2806: }
2807: }
2808:
2809: }
2810:
2811: return propStore;
2812: }
2813:
2814: /**
2815: * Returns the <code>PropertyInstanceStore</code> assocated with the
2816: * <code>Property</code> of the specified name.
2817: *
2818: * @param sPropName the name of the <code>Property</code>
2819: * @return the <code>PropertyInstanceStore</code> assocated with the
2820: * <code>Property</code> of the specified name.
2821: */
2822: private PropertyInstanceStore getPropertyInstanceStore(
2823: String sPropName) {
2824: PropertyInstanceStore propStoreResult = null;
2825:
2826: Iterator iter = m_propStores.keySet().iterator();
2827:
2828: while (iter.hasNext() == true && propStoreResult == null) {
2829: PropertyInstanceStore propStore = (PropertyInstanceStore) m_propStores
2830: .get(iter.next());
2831:
2832: if (propStore.contains(sPropName) == true) {
2833: propStoreResult = propStore;
2834: }
2835: }
2836:
2837: return propStoreResult;
2838: }
2839:
2840: /**
2841: * Sets the profiled object for this profile.
2842: *
2843: * @param obj the profiled object
2844: */
2845: public void setProfiledObject(AbstractProfiledObject obj) {
2846: m_profObj = obj;
2847: }
2848:
2849: /* (non-Javadoc)
2850: * @see java.lang.Object#equals(java.lang.Object)
2851: */
2852: public boolean equals(Object obj) {
2853: boolean bReturn = false;
2854:
2855: if (obj instanceof Profile) {
2856:
2857: if (this == obj) {
2858: bReturn = true;
2859: } else if (obj.getClass().getName().equals(
2860: getClass().getName()) == true) {
2861:
2862: try {
2863: populateFromDatabase();
2864: } catch (PopulateException e) {
2865: m_logger.log(Level.WARNING,
2866: e.getLocalizedMessage(), e);
2867: }
2868:
2869: Profile objCompare = (Profile) obj;
2870:
2871: try {
2872: if ((this .getId() != 0)
2873: && (objCompare.getId() != 0)) {
2874: if (m_nId == objCompare.getId()) {
2875: bReturn = true;
2876: }
2877: }
2878:
2879: if (bReturn == true
2880: && m_sName.equals(objCompare.getName())) {
2881: bReturn = true;
2882: }
2883:
2884: if (bReturn == true) {
2885: bReturn = match(objCompare);
2886: }
2887:
2888: } catch (Exception e) {
2889: throw new RuntimeException(e.getMessage());
2890: }
2891: }
2892:
2893: }
2894:
2895: return bReturn;
2896: }
2897:
2898: /* (non-Javadoc)
2899: * @see org.openharmonise.rm.resources.AbstractObject#isKeySupported()
2900: */
2901: protected boolean isKeySupported() {
2902: return false;
2903: }
2904:
2905: /**
2906: * Returns <code>true</code> if this profile conforms to the restrictions
2907: * determined by the domains on the available properties.
2908: *
2909: * @return <code>true</code> if this profile conforms to the restrictions
2910: * determined by the domains on the available properties.
2911: *
2912: * @throws DataAccessException if any errors occur getting the available
2913: * properties for this <code>Profile</code>.
2914: */
2915: public boolean isValid(AbstractProfiledObject profObj)
2916: throws DataAccessException {
2917: boolean bIsValid = true;
2918:
2919: List props = Domain.getAvailableProperties(m_dsi, profObj);
2920:
2921: Iterator iter = props.iterator();
2922:
2923: while (iter.hasNext() && bIsValid == true) {
2924: Property prop = (Property) iter.next();
2925: Domain domain = prop.getDomain(profObj);
2926:
2927: try {
2928: if (hasProperty(prop) == true) {
2929: AbstractPropertyInstance propInst = getPropertyInstance(prop);
2930:
2931: int nVals = propInst.getValues().size();
2932:
2933: if (domain.getMinOccurs() > nVals) {
2934: if (m_logger.isLoggable(Level.INFO)) {
2935: m_logger.logp(Level.INFO, this .getClass()
2936: .getName(), "isValid",
2937: "MinOccurs is greater than number of vals for prop "
2938: + prop.getName()
2939: + " on object "
2940: + m_profObj.getClass()
2941: .getName()
2942: + " key "
2943: + m_profObj.getKey());
2944: }
2945: bIsValid = false;
2946: }
2947:
2948: if (domain.getMaxOccurs() > 0
2949: && domain.getMaxOccurs() < nVals) {
2950: if (m_logger.isLoggable(Level.INFO)) {
2951: m_logger.logp(Level.INFO, this .getClass()
2952: .getName(), "isValid",
2953: "MaxOccurs is less than number of vals for prop "
2954: + prop.getName()
2955: + " on object "
2956: + m_profObj.getClass()
2957: .getName()
2958: + " key "
2959: + m_profObj.getKey());
2960: }
2961: bIsValid = false;
2962: }
2963: } else {
2964: if (domain.getMinOccurs() > 0) {
2965: if (m_logger.isLoggable(Level.INFO)) {
2966: m_logger.logp(Level.INFO, this .getClass()
2967: .getName(), "isValid",
2968: "Mandatory prop inst does not exist for prop "
2969: + prop.getName()
2970: + " on object "
2971: + m_profObj.getClass()
2972: .getName()
2973: + " key "
2974: + m_profObj.getKey());
2975: }
2976: bIsValid = false;
2977: }
2978: }
2979: } catch (InvalidPropertyInstanceException e) {
2980: throw new DataAccessException(e.getLocalizedMessage(),
2981: e);
2982: }
2983: }
2984:
2985: return bIsValid;
2986: }
2987:
2988: /**
2989: * Removes the specified property instance from this <code>Profile</code>.
2990: *
2991: * @param propInst the property instance to remove
2992: * @throws InvalidPropertyInstanceException if the specified property instance
2993: * is invalid for this <code>Profile</code>
2994: * @throws DataAccessException if there is an error getting the
2995: * <code>Property</code> associated to the property instance
2996: */
2997: private void removePropertyInstance(
2998: AbstractPropertyInstance propInst)
2999: throws InvalidPropertyInstanceException,
3000: DataAccessException {
3001: PropertyInstanceStore propStore = getPropertyInstanceStore(propInst
3002: .getProperty());
3003:
3004: propStore.removePropertyInstance(propInst);
3005: }
3006:
3007: /* (non-Javadoc)
3008: * @see org.openharmonise.rm.resources.AbstractObject#isHistorical()
3009: */
3010: public boolean isHistorical() {
3011:
3012: boolean bIsHist = super .isHistorical();
3013:
3014: //check that profile's in line with prof obj
3015: if (bIsHist == false && m_profObj != null
3016: && m_profObj.isHistorical() == true) {
3017: bIsHist = true;
3018: setHistorical(bIsHist);
3019: }
3020:
3021: return bIsHist;
3022: }
3023:
3024: /* (non-Javadoc)
3025: * @see org.openharmonise.rm.resources.AbstractObject#markAsNew()
3026: */
3027: public void markAsNew() throws PopulateException {
3028: m_bNew = true;
3029: super .markAsNew();
3030:
3031: markProfilePropertyInstanceValuesAsNew();
3032: }
3033:
3034: /**
3035: * Mark <code>ProfileValue</code> as new
3036: *
3037: * @throws PopulateException
3038: */
3039: private void markProfilePropertyInstanceValuesAsNew()
3040: throws PopulateException {
3041: PropertyInstanceStore propStore = (PropertyInstanceStore) m_propStores
3042: .get(Profile.class.getName());
3043:
3044: if (propStore != null) {
3045: Collection col = propStore.getValues();
3046:
3047: Iterator iter = col.iterator();
3048:
3049: while (iter.hasNext()) {
3050: ProfilePropertyInstance propInst = (ProfilePropertyInstance) iter
3051: .next();
3052:
3053: propInst.markValuesAsNew();
3054: }
3055: }
3056: }
3057:
3058: /**
3059: * Returns the base class for the given class which is a concrete
3060: * implementation of <code>AbstractChildObject</code>.
3061: *
3062: * @param clss <code>Class</code> from which to find the base
3063: * <code>AbstractChildObject</code> implementation
3064: * @return the base class for the given class which is a concrete
3065: * implementation of <code>AbstractChildObject</code>
3066: */
3067: private Class getBaseChildObjectClass(Class clss) {
3068: Class returnClass = null;
3069: Class super Class = clss.getSuperclass();
3070:
3071: if (super Class.equals(AbstractChildObject.class)) {
3072: returnClass = clss;
3073: } else {
3074: returnClass = getBaseChildObjectClass(super Class);
3075: }
3076:
3077: return returnClass;
3078: }
3079:
3080: /**
3081: * Deletes the property instance held by this <code>Profile</code>
3082: * associated with the specified <code>Property</code>.
3083: *
3084: * @param prop the <code>Property</code>
3085: * @throws ProfileException
3086: * @throws InvalidPropertyInstanceException
3087: * @throws DataAccessException
3088: */
3089: private void deletePropertyInstance(Property prop)
3090: throws ProfileException, InvalidPropertyInstanceException,
3091: DataAccessException {
3092:
3093: AbstractPropertyInstance propInst = getPropertyInstance(prop);
3094:
3095: if (propInst instanceof ProfilePropertyInstance) {
3096: ProfilePropertyInstance profPropInst = (ProfilePropertyInstance) propInst;
3097:
3098: profPropInst.delete();
3099: } else {
3100: DeleteStatement delete = new DeleteStatement();
3101:
3102: String sDataTable = propInst.getDBTableName();
3103:
3104: try {
3105: ColumnRef profId_colref = getProfileDataColumn(
3106: sDataTable,
3107: GeneralPropertyInstance.CLMN_PROFILE_ID);
3108:
3109: delete.addWhereCondition(profId_colref, "=", m_nId);
3110:
3111: ColumnRef dataPropIdCol = getProfileDataColumn(
3112: sDataTable,
3113: AbstractPropertyInstance.CLMN_PROPERTY_ID);
3114:
3115: delete.addWhereCondition(dataPropIdCol, "=", prop
3116: .getId());
3117:
3118: m_dsi.execute(delete);
3119: } catch (DataStoreException e) {
3120: throw new ProfileException(
3121: "Error occured deleting property instances", e);
3122: }
3123:
3124: }
3125:
3126: }
3127:
3128: private void deletePropertyInstanceData(
3129: AbstractPropertyInstance propInst) throws ProfileException,
3130: InvalidPropertyInstanceException, DataAccessException {
3131:
3132: if (propInst instanceof ProfilePropertyInstance) {
3133: ProfilePropertyInstance profPropInst = (ProfilePropertyInstance) propInst;
3134:
3135: profPropInst.delete();
3136: } else {
3137: DeleteStatement delete = new DeleteStatement();
3138:
3139: String sDataTable = propInst.getDBTableName();
3140:
3141: try {
3142: ColumnRef profId_colref = getProfileDataColumn(
3143: sDataTable,
3144: GeneralPropertyInstance.CLMN_PROFILE_ID);
3145:
3146: delete.addWhereCondition(profId_colref, "=", m_nId);
3147:
3148: ColumnRef colDataId = getProfileDataColumn(sDataTable,
3149: AbstractPropertyInstance.CLMN_ID);
3150:
3151: delete.addWhereCondition(colDataId, "=", propInst
3152: .getId());
3153:
3154: m_dsi.execute(delete);
3155: } catch (DataStoreException e) {
3156: throw new ProfileException(
3157: "Error occured deleting property instances", e);
3158: }
3159:
3160: }
3161:
3162: }
3163:
3164: /**
3165: * A class to group concrete implementations of
3166: * <code>AbstractPropertyInstance</code> by type.
3167: *
3168: * @author Michael Bell
3169: * @version $Revision: 1.8.2.1 $
3170: *
3171: */
3172: private class PropertyInstanceStore implements Cloneable {
3173: /**
3174: * <code>boolean</code> flag to indicate whether this object has been
3175: * changed since it was populated
3176: */
3177: private boolean m_bIsChanged = false;
3178: /**
3179: * <code>boolean</code> flag to indicate whether this object has been
3180: * populated
3181: */
3182: private boolean m_bIsPopulated = false;
3183: /**
3184: * <code>Map</code> of <code>Property</code> names to
3185: * <code>AbstractPropertyInsatance</code>s
3186: */
3187: private Map m_propInsts = new Hashtable();
3188: /**
3189: * List of props which have been removed and need to be deleted on update
3190: */
3191: private List m_deadProps = new ArrayList();
3192: /**
3193: * The label assocaited to this <code>PropertyInstanceStore</code>
3194: */
3195: private String m_sLabel = null;
3196: /**
3197: * The class name associated with this <code>PropertyInstanceStore</code>
3198: */
3199: private String m_sClassname = null;
3200:
3201: /**
3202: * Constructs a <code>PropertyInstanceStore</code> with the specified label
3203: *
3204: */
3205: PropertyInstanceStore(String sLabel) {
3206: m_sLabel = sLabel;
3207: }
3208:
3209: /**
3210: * Constructs a <code>PropertyInstanceStore</code> with the specified label
3211: * and a assocated class name
3212: *
3213: */
3214: PropertyInstanceStore(String sLabel, String sClassname) {
3215: m_sLabel = sLabel;
3216: m_sClassname = sClassname;
3217: }
3218:
3219: /**
3220: * Constructs a new property instance store which is a copy of the
3221: * passed in property instance store
3222: *
3223: * @param other property instance store to replicate
3224: */
3225: PropertyInstanceStore(PropertyInstanceStore other) {
3226: m_sLabel = other.m_sLabel;
3227: m_sClassname = other.m_sClassname;
3228: m_bIsChanged = other.m_bIsChanged;
3229: m_bIsPopulated = other.m_bIsPopulated;
3230:
3231: Iterator iter = other.m_propInsts.keySet().iterator();
3232:
3233: while (iter.hasNext()) {
3234: String sKey = (String) iter.next();
3235: AbstractPropertyInstance propInst = (AbstractPropertyInstance) other.m_propInsts
3236: .get(sKey);
3237:
3238: m_propInsts.put(sKey, propInst.clone());
3239: }
3240: }
3241:
3242: /**
3243: * Returns the label associated with this store
3244: *
3245: * @return the label associated with this store
3246: */
3247: String getLabel() {
3248: return m_sLabel;
3249: }
3250:
3251: /**
3252: * Returns the associated class name with this store
3253: *
3254: * @return the associated class name with this store
3255: */
3256: String getAssociatedClassname() {
3257: return m_sClassname;
3258: }
3259:
3260: /**
3261: * Returns <code>true</code> if any of the property instances in the
3262: * store have changed since being populated from the database
3263: *
3264: * @return <code>true</code> if any of the property instances in the
3265: * store have changed
3266: */
3267: boolean isChanged() {
3268:
3269: if (m_bIsChanged == false) {
3270: Iterator iter = m_propInsts.values().iterator();
3271:
3272: while (iter.hasNext() && m_bIsChanged == false) {
3273: AbstractPropertyInstance next = (AbstractPropertyInstance) iter
3274: .next();
3275:
3276: if (next.isChanged()) {
3277: m_bIsChanged = true;
3278: }
3279: }
3280: }
3281: return m_bIsChanged;
3282: }
3283:
3284: /**
3285: * Marks this store as having been changed since being populated from
3286: * the database
3287: *
3288: * @param bIsChanged <code>true</code> to indicate that this store has
3289: * been changed, otherwise <code>false</code>
3290: */
3291: void setIsChanged(boolean bIsChanged) {
3292: m_bIsChanged = bIsChanged;
3293: }
3294:
3295: /**
3296: * Returns <code>true</code> if this store has been populated
3297: *
3298: * @return <code>true</code> if this store has been populated
3299: */
3300: boolean isPopulated() {
3301: return m_bIsPopulated;
3302: }
3303:
3304: /**
3305: * Marks this store as having been populated
3306: *
3307: * @param bIsPopulated <code>true</code> to indicate that this
3308: * store has been populated
3309: */
3310: void setIsPopulated(boolean bIsPopulated) {
3311: m_bIsPopulated = bIsPopulated;
3312: }
3313:
3314: /**
3315: * Adds the specified property instance to this store
3316: *
3317: * @param propInst the property instance to add
3318: * @throws DataAccessException if there is an error getting the name
3319: * of the associated <code>Property</code>
3320: */
3321: void addPropertyInstance(AbstractPropertyInstance propInst)
3322: throws DataAccessException {
3323: if (m_bIsPopulated == true
3324: && m_propInsts.containsValue(propInst) == false) {
3325: m_bIsChanged = true;
3326: }
3327:
3328: m_propInsts.put(propInst.getName(), propInst);
3329: }
3330:
3331: /**
3332: * Removes the specified property instance from the store
3333: *
3334: * @param prop the <code>Property</code> whose instances are to be
3335: * removed from this store
3336: * @throws DataAccessException if an error occurs getting the name of the
3337: * given <code>Property</code>
3338: */
3339: void removePropertyInstance(Property prop)
3340: throws DataAccessException {
3341: String sPropName = prop.getName();
3342: if (contains(prop) == true) {
3343: m_deadProps.add(m_propInsts.get(sPropName));
3344: m_propInsts.remove(sPropName);
3345: m_bIsChanged = true;
3346: }
3347: }
3348:
3349: /**
3350: * Returns <code>true</code> if this store contains an
3351: * instance of the given <code>Property</code>.
3352: *
3353: * @param prop the <code>Property</code>
3354: * @return <code>true</code> if this store contains an
3355: * instance of the given <code>Property</code>
3356: * @throws DataAccessException if an error occurs getting the name of the
3357: * given <code>Property</code>
3358: */
3359: boolean contains(Property prop) throws DataAccessException {
3360: return contains(prop.getName());
3361: }
3362:
3363: /**
3364: * Returns <code>true</code> if this store contains the specified
3365: * <code>AbstractPropertyInstance</code>.
3366: *
3367: * @param propInst the prperty instance whose presence is to be tested
3368: * @return <code>true</code> if this store contains the specified
3369: * <code>AbstractPropertyInstance</code>
3370: */
3371: boolean contains(AbstractPropertyInstance propInst) {
3372: return m_propInsts.containsValue(propInst);
3373: }
3374:
3375: /**
3376: * Returns <code>true</code> if this store contains an instance
3377: * of the <code>Property</code> of the specified name.
3378: *
3379: * @param sPropName the <code>Property</code> name
3380: * @return <code>true</code> if this store contains an instance
3381: * of the <code>Property</code> of the specified name
3382: */
3383: public boolean contains(String sPropName) {
3384: return m_propInsts.containsKey(sPropName);
3385: }
3386:
3387: /**
3388: * Returns the <code>AbstractPropertyInstance</code>s contained in this store.
3389: *
3390: * @return the <code>AbstractPropertyInstance</code>s contained in this store
3391: */
3392: Collection getValues() {
3393: return m_propInsts.values();
3394: }
3395:
3396: /**
3397: * Returns the <code>AbstractPropertyInstance</code> from the store that
3398: * matches the given <code>Property</code>.
3399: *
3400: * @param prop the <code>Property</code> of the instance to be returned
3401: * @return the <code>AbstractPropertyInstance</code> from the store that
3402: * matches the given <code>Property</code>
3403: * @throws DataAccessException if there is an error getting the name of
3404: * the <code>Property</code>
3405: */
3406: AbstractPropertyInstance getPropertyInstance(Property prop)
3407: throws DataAccessException {
3408: return getPropertyInstance(prop.getName());
3409: }
3410:
3411: /**
3412: * Returns the <code>AbstractPropertyInstance</code> from the store that
3413: * matches the specified <code>Property</code> name.
3414: *
3415: * @param sName the name of the <code>Property</code> to return an
3416: * instance of
3417: * @return the <code>AbstractPropertyInstance</code> from the store that
3418: * matches the specified <code>Property</code> name
3419: */
3420: AbstractPropertyInstance getPropertyInstance(String sName) {
3421: return (AbstractPropertyInstance) m_propInsts.get(sName);
3422: }
3423:
3424: /* (non-Javadoc)
3425: * @see java.lang.Object#clone()
3426: */
3427: protected Object clone() throws CloneNotSupportedException {
3428: throw new CloneNotSupportedException(
3429: "Bad - causes all sorts of problems to clone a nested class");
3430: }
3431:
3432: /**
3433: * Removes the specified <code>AbstractPropertyInstance</code> from this
3434: * store
3435: *
3436: * @param propInst the <code>AbstractPropertyInstance</code> to remove
3437: * @throws DataAccessException if there is an error getting the name
3438: * of the associated <code>Property</code>
3439: */
3440: void removePropertyInstance(AbstractPropertyInstance propInst)
3441: throws DataAccessException {
3442: if (m_bIsPopulated == true
3443: && m_propInsts.containsValue(propInst) == true) {
3444:
3445: Object remObj = null;
3446: String sPropName = propInst.getName();
3447:
3448: if (sPropName != null) {
3449: remObj = m_propInsts.remove(sPropName);
3450: }
3451:
3452: //in case prop insts property no longer exists
3453: if (remObj == null
3454: && m_propInsts.values().contains(propInst)) {
3455: Iterator iter = m_propInsts.keySet().iterator();
3456: Object propKey = null;
3457: while (iter.hasNext()) {
3458: Object key = (Object) iter.next();
3459:
3460: if (m_propInsts.get(key).equals(propInst)) {
3461: propKey = key;
3462: }
3463: }
3464: if (propKey != null) {
3465: m_propInsts.remove(propKey);
3466: }
3467: }
3468: m_deadProps.add(propInst);
3469: m_bIsChanged = true;
3470: }
3471:
3472: }
3473:
3474: /**
3475: * Updates all property instance data in the database for the specified
3476: * <code>PropertyInstanceStore</code>
3477: *
3478: * @throws PopulateException if there is an error accessing data held in
3479: * the property instances
3480: * @throws EditException if there is an error saving the data to the database
3481: */
3482: void update() throws ProfileException, EditException {
3483: Iterator iter = getValues().iterator();
3484:
3485: while (iter.hasNext()) {
3486: AbstractPropertyInstance propInst = (AbstractPropertyInstance) iter
3487: .next();
3488:
3489: propInst.update(Profile.this );
3490: }
3491:
3492: for (Iterator propIter = m_deadProps.iterator(); propIter
3493: .hasNext();) {
3494: AbstractPropertyInstance propInst = (AbstractPropertyInstance) propIter
3495: .next();
3496:
3497: propInst.update(Profile.this );
3498: }
3499:
3500: m_deadProps.clear();
3501:
3502: setIsChanged(false);
3503: }
3504:
3505: }
3506:
3507: }
|