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.resources;
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.SelectStatement;
0027: import org.openharmonise.rm.*;
0028: import org.openharmonise.rm.dsi.DataStoreObject;
0029: import org.openharmonise.rm.factory.HarmoniseObjectFactory;
0030: import org.openharmonise.rm.metadata.*;
0031: import org.openharmonise.rm.publishing.*;
0032: import org.openharmonise.rm.resources.lifecycle.*;
0033: import org.openharmonise.rm.resources.metadata.properties.Property;
0034: import org.w3c.dom.*;
0035:
0036: /**
0037: * Abstract class which adds metadata functionality to the
0038: * <code>AbstractEditableObject</code> class.
0039: *
0040: * @author Michael Bell
0041: * @version $Revision: 1.4 $
0042: *
0043: */
0044: public abstract class AbstractProfiledObject extends
0045: AbstractEditableObject implements Editable, Publishable,
0046: DataStoreObject, Cloneable {
0047: private static final String CONST_TRUE = "true";
0048: /**
0049: * Flag which determines whether profile restrictions should be ignored
0050: * during a change of status
0051: */
0052: private boolean m_bIgnoreProfileRestrictions = false;
0053: /**
0054: * The default profile name
0055: */
0056: public static final String DEFAULT_PROFILE_NAME = "default";
0057: /**
0058: * <code>Map</code> of all profiles this profiled object has. The profiles are
0059: * keyed by their name field
0060: */
0061: protected Map m_profiles = null;
0062: /**
0063: * The <code>Map</code> key of the default profile
0064: */
0065: protected String m_sDefaultKey = null;
0066: /**
0067: * List of profiles to be removed during the next <code>save()</code> operation
0068: */
0069: protected List m_profiles2Remove = null;
0070:
0071: /**
0072: * Logger for this class
0073: */
0074: private static final Logger m_logger = Logger
0075: .getLogger(AbstractProfiledObject.class.getName());
0076:
0077: //initialiser block
0078: {
0079: m_profiles = Collections.synchronizedMap(new HashMap());
0080: m_profiles2Remove = new Vector();
0081: }
0082:
0083: /**
0084: * Constructs a new or anonymous resource without an interface
0085: * to the database
0086: */
0087: public AbstractProfiledObject() {
0088: super ();
0089: }
0090:
0091: /** Constructor for a new or anonymous resource.
0092: *
0093: * @param dbintrf the data store interface
0094: */
0095: public AbstractProfiledObject(AbstractDataStoreInterface dbintrf) {
0096: super (dbintrf);
0097:
0098: }
0099:
0100: /**
0101: * Standard constructor for an existing resource,
0102: * registering an <code>AbstractDataStoreInterface</code> to use
0103: * with all database communications.
0104: *
0105: * @param dbintrf the interface to the database
0106: * @param nId the id of the resource
0107: */
0108: public AbstractProfiledObject(AbstractDataStoreInterface dbintrf,
0109: int nId) {
0110: super (dbintrf, nId);
0111:
0112: }
0113:
0114: /**
0115: * Standard constructor for an existing resource which may be historical.
0116: *
0117: * @param dbintrf the interface to the database
0118: * @param nId the id of the resource
0119: * @param nKey the unique key of the resource
0120: * @param bIsHist <code>true</code> if the resource is historical
0121: */
0122: public AbstractProfiledObject(AbstractDataStoreInterface dbintrf,
0123: int nId, int nKey, boolean bIsHist) {
0124: super (dbintrf, nId, nKey, bIsHist);
0125:
0126: }
0127:
0128: /**
0129: * Returns a list of this resource's <code>Profile</code>s.
0130: *
0131: * @return a list of this resource's <code>Profile</code>s
0132: * @throws DataAccessException if an error occurs populating this resource
0133: */
0134: public List getProfiles() throws DataAccessException {
0135: if (m_bIsPopulated == false) {
0136: try {
0137: populateFromDatabase();
0138: } catch (PopulateException e) {
0139: throw new DataAccessException(e.getLocalizedMessage());
0140: }
0141: }
0142:
0143: return new Vector((Collection) m_profiles.values());
0144: }
0145:
0146: /**
0147: * Returns a <code>Map</code> of profiles.
0148: *
0149: * @return <code>Map</code> of profiles, keyed by their profile names
0150: * @throws DataAccessException if an error occurs populating this object
0151: */
0152: public Map getProfilesMap() throws DataAccessException {
0153: if (m_bIsPopulated == false) {
0154: try {
0155: populateFromDatabase();
0156: } catch (PopulateException e) {
0157: throw new DataAccessException(e.getLocalizedMessage());
0158: }
0159: }
0160:
0161: return new Hashtable(m_profiles);
0162: }
0163:
0164: /* (non-Javadoc)
0165: * @see org.openharmonise.rm.resources.AbstractObject#isChanged()
0166: */
0167: public boolean isChanged() throws DataAccessException {
0168: boolean bReturn = super .isChanged();
0169:
0170: if (bReturn == false) {
0171: Iterator iter = m_profiles.values().iterator();
0172:
0173: Profile nextProf;
0174:
0175: while (iter.hasNext() && bReturn == false) {
0176: nextProf = (Profile) iter.next();
0177:
0178: if (nextProf.isChanged()
0179: || (nextProf.getId() == NOTDBSAVED_ID)) {
0180: bReturn = true;
0181: setIsChanged(bReturn);
0182: }
0183: }
0184: }
0185:
0186: return bReturn;
0187: }
0188:
0189: /**
0190: * Set the profiles of this object.
0191: *
0192: * @param profiles the list profiles
0193: *
0194: * @throws InvalidProfileException if an invalid profile is found in the list,
0195: * for example if a profile does not have a valid name
0196: */
0197: protected void setProfiles(List profiles)
0198: throws InvalidProfileException {
0199: if (m_bIsPopulated) {
0200: m_bIsChanged = true;
0201: }
0202:
0203: Iterator iter = profiles.iterator();
0204:
0205: m_profiles.clear();
0206:
0207: while (iter.hasNext()) {
0208: Profile tmpProf = (Profile) iter.next();
0209: String sName = null;
0210:
0211: try {
0212:
0213: sName = tmpProf.getName();
0214:
0215: } catch (DataAccessException da_e) {
0216: throw new InvalidProfileException(
0217: "Couldn't access profile name", da_e);
0218: }
0219:
0220: m_profiles.put(sName, tmpProf);
0221: }
0222: }
0223:
0224: /**
0225: * Sets the profiles of this object.
0226: *
0227: * @param profiles a <code>Map</code> of profiles
0228: */
0229: protected void setProfiles(Map profiles) {
0230: if (m_bIsPopulated) {
0231: m_bIsChanged = true;
0232: }
0233:
0234: m_profiles.clear();
0235:
0236: Iterator iter = profiles.keySet().iterator();
0237:
0238: while (iter.hasNext()) {
0239: Object key = iter.next();
0240:
0241: m_profiles.put(key, profiles.get(key));
0242: }
0243: }
0244:
0245: /**
0246: * Returns the default <code>Profile</code> for this object.
0247: *
0248: * @return the default <code>Profile</code> for this object
0249: *
0250: * @throws DataAccessException if an error occurs populating this object
0251: */
0252: public Profile getProfile() throws DataAccessException {
0253: Profile profileReturn = null;
0254:
0255: if ((m_profiles != null) && (m_sDefaultKey != null)) {
0256: profileReturn = (Profile) m_profiles.get(m_sDefaultKey);
0257: } else if ((m_bIsPopulated == false)
0258: && (m_nId != AbstractObject.NOTDBSAVED_ID)
0259: && (m_profiles == null || m_profiles.size() == 0)) {
0260:
0261: try {
0262: populateFromDatabase();
0263: } catch (PopulateException e) {
0264: throw new DataAccessException(
0265: "Problem occured populating profile", e);
0266: }
0267: profileReturn = getProfile();
0268: } else if ((m_profiles != null) && (m_profiles.size() > 0)) {
0269: Iterator iter = m_profiles.values().iterator();
0270:
0271: profileReturn = (Profile) iter.next();
0272: }
0273:
0274: return profileReturn;
0275: }
0276:
0277: /**
0278: * Returns the property instance of the given name from the default
0279: * profile.
0280: *
0281: * @param sPropName the name of the property
0282: * @return the property instance corresponding to the property name
0283: * @throws InvalidPropertyInstanceException if the property is invalid
0284: * for this object
0285: * @throws DataAccessException if there is an error populating this
0286: * object
0287: */
0288: public AbstractPropertyInstance getPropertyInstance(String sPropName)
0289: throws InvalidPropertyInstanceException,
0290: DataAccessException {
0291: AbstractPropertyInstance propInst = null;
0292: List profs = getProfiles();
0293:
0294: Iterator iter = profs.iterator();
0295:
0296: while (iter.hasNext() && propInst == null) {
0297: Profile prof = (Profile) iter.next();
0298:
0299: propInst = prof.getPropertyInstance(sPropName);
0300: }
0301:
0302: return propInst;
0303: }
0304:
0305: /**
0306: * Returns the <code>AbstractPropertyInstance</code> associated
0307: * with the specified <code>Property</code> from a <code>Profile</code>
0308: * of this object.
0309: *
0310: * @param prop
0311: * @return
0312: * @throws InvalidPropertyInstanceException
0313: * @throws DataAccessException
0314: */
0315: public AbstractPropertyInstance getPropertyInstance(Property prop)
0316: throws InvalidPropertyInstanceException,
0317: DataAccessException {
0318: AbstractPropertyInstance propInst = null;
0319: List profs = getProfiles();
0320:
0321: Iterator iter = profs.iterator();
0322:
0323: while (iter.hasNext() && propInst == null) {
0324: Profile prof = (Profile) iter.next();
0325:
0326: propInst = prof.getPropertyInstance(prop);
0327: }
0328:
0329: return propInst;
0330: }
0331:
0332: /** Sets the default <code>Profile</code>.
0333: *
0334: * @param profile the default <code>Profile</code>
0335: *
0336: * @throws InvalidProfileException if the profile name is invalid
0337: */
0338: public void setProfile(Profile profile)
0339: throws InvalidProfileException {
0340: String sNewKey = null;
0341:
0342: profile.setProfiledObject(this );
0343:
0344: try {
0345: sNewKey = profile.getName();
0346: } catch (DataAccessException e) {
0347: throw new InvalidProfileException(
0348: "Error occured get name of profile", e);
0349: }
0350:
0351: if (sNewKey == null || sNewKey.length() == 0) {
0352: sNewKey = DEFAULT_PROFILE_NAME;
0353: try {
0354: profile.setName(sNewKey);
0355: } catch (InvalidNameException e) {
0356: throw new InvalidProfileException(e);
0357: }
0358: }
0359:
0360: if ((m_sDefaultKey != null)
0361: && (m_sDefaultKey.equals(sNewKey) == false)) {
0362: Profile oldDefProf = (Profile) m_profiles
0363: .get(m_sDefaultKey);
0364: oldDefProf.setIsDefault(false);
0365:
0366: if (m_bIsPopulated) {
0367: oldDefProf.setIsChanged(true);
0368: }
0369: }
0370:
0371: if (sNewKey.equals(m_sDefaultKey) == false) {
0372: m_sDefaultKey = sNewKey;
0373: profile.setIsDefault(true);
0374: m_profiles.put(m_sDefaultKey, profile);
0375:
0376: if (m_bIsPopulated) {
0377: profile.setIsChanged(true);
0378: }
0379: } else {
0380: m_sDefaultKey = sNewKey;
0381: profile.setIsDefault(true);
0382: m_profiles.put(m_sDefaultKey, profile);
0383:
0384: if (m_bIsPopulated) {
0385: profile.setIsChanged(true);
0386: }
0387: }
0388: }
0389:
0390: /**
0391: * Returns the <code>Profile</code> of this object
0392: * with the specified name.
0393: *
0394: * @param sName the name of the profile
0395: * @return the profile with the specified name
0396: * @throws DataAccessException if an error occurs populating this object
0397: */
0398: public Profile getProfile(String sName) throws DataAccessException {
0399: Profile profileReturn = null;
0400:
0401: if (m_profiles != null) {
0402: profileReturn = (Profile) m_profiles.get(sName);
0403: }
0404:
0405: if ((m_bIsPopulated == false) && (profileReturn == null)) {
0406: try {
0407: populateFromDatabase();
0408: } catch (PopulateException e) {
0409: throw new DataAccessException(
0410: "Error occured populating profiles", e);
0411: }
0412: profileReturn = getProfile(sName);
0413: }
0414:
0415: return profileReturn;
0416: }
0417:
0418: /**
0419: * Returns the number of profiles.
0420: *
0421: * @return the number of profiles
0422: *
0423: * @throws DataAccessException if an error occurs populating this object
0424: */
0425: public int getNumProfiles() throws DataAccessException {
0426: if (m_bIsPopulated == false) {
0427: try {
0428: populateFromDatabase();
0429: } catch (PopulateException e) {
0430: throw new DataAccessException(e.getLocalizedMessage());
0431: }
0432: }
0433:
0434: if (m_profiles != null) {
0435: return m_profiles.size();
0436: } else {
0437: return 0;
0438: }
0439: }
0440:
0441: /**
0442: * Add the given <code>Profile</code> to this object.
0443: *
0444: * @param profile the new <code>Profile</code> to add.
0445: *
0446: * @throws InvalidProfileException if the given profile is invalid,
0447: * for example if the profile has an invalid name
0448: */
0449: public void addProfile(Profile profile)
0450: throws InvalidProfileException {
0451: try {
0452:
0453: String sProfName = profile.getName();
0454:
0455: if (m_profiles.containsKey(sProfName) == true) {
0456: throw new InvalidProfileException(
0457: "Can't have 2 profiles of the same name");
0458: }
0459:
0460: // set the profiled object to be the
0461: // current object
0462: profile.setProfiledObject(this );
0463:
0464: //if profiles empty set profile as default
0465: if ((m_profiles.size() == 0)
0466: || (profile.isDefault() == true)) {
0467: setProfile(profile);
0468: } else {
0469: m_profiles.put(sProfName, profile);
0470: }
0471: } catch (InvalidProfileException ip_e) {
0472: throw ip_e;
0473: } catch (DataAccessException da_e) {
0474: throw new InvalidProfileException(
0475: "Error occured getting data from new profile:",
0476: da_e);
0477: }
0478: }
0479:
0480: /**
0481: * Removes the specified <code>Profile</code> from this object.
0482: *
0483: * @param sProfile the <code>Profile</code> to remove
0484: *
0485: * @throws DataAccessException if there was an error populating this
0486: * object
0487: */
0488: public void removeProfile(String sProfile)
0489: throws DataAccessException {
0490: if (m_bIsPopulated == false) {
0491: try {
0492: populateFromDatabase();
0493: } catch (PopulateException e) {
0494: throw new DataAccessException(e.getLocalizedMessage());
0495: }
0496: }
0497:
0498: Object prof = m_profiles.remove(sProfile); // get the profile
0499:
0500: if (prof != null) {
0501: m_profiles2Remove.add(prof);
0502: setIsChanged(true); // the object was changed
0503: }
0504: }
0505:
0506: /**
0507: * Sets the <code>Profile</code> with the specified name
0508: * as the default.
0509: *
0510: * @param sProfile the name of the <code>Profile</code> to be the default
0511: *
0512: * @throws InvalidProfileException if the named <code>Profile</code> does
0513: * not exist
0514: * @throws DataAccessException if there is an error populating this object
0515: */
0516: protected void setDefaultProfile(String sName)
0517: throws InvalidProfileException, DataAccessException {
0518:
0519: if (m_bIsPopulated == false) {
0520: try {
0521: populateFromDatabase();
0522: } catch (PopulateException e) {
0523: throw new DataAccessException(e.getLocalizedMessage());
0524: }
0525: }
0526:
0527: if (m_profiles.containsKey(sName)) {
0528: m_sDefaultKey = sName;
0529: } else {
0530: throw new InvalidProfileException("Profile does not exist");
0531: }
0532: }
0533:
0534: /* (non-Javadoc)
0535: * @see org.openharmonise.rm.resources.AbstractEditableObject#delete(boolean)
0536: */
0537: protected void delete(boolean bDeleteHistory)
0538: throws DataStoreException, DataAccessException,
0539: EditException, PopulateException {
0540:
0541: if (isPopulated() == false) {
0542: populateFromDatabase();
0543: }
0544:
0545: Iterator iter = m_profiles.keySet().iterator();
0546:
0547: while (iter.hasNext()) {
0548: String proName = (String) iter.next();
0549: Profile pro = (Profile) m_profiles.get(proName);
0550: try {
0551: pro.delete();
0552: } catch (ProfileException e) {
0553: throw new EditException(
0554: "Error occured deleting profile", e);
0555: }
0556: }
0557:
0558: m_profiles.clear();
0559:
0560: super .delete(bDeleteHistory);
0561: }
0562:
0563: /* (non-Javadoc)
0564: * @see org.openharmonise.rm.publishing.Publishable#populate(org.w3c.dom.Element, org.openharmonise.rm.publishing.State)
0565: */
0566: public void populate(Element xmlElement, State state)
0567: throws PopulateException {
0568: String sTagName = xmlElement.getTagName();
0569: Text txt = null;
0570: Profile pro = null;
0571:
0572: if (sTagName.equals(Profile.TAG_PROFILE)) {
0573: try {
0574:
0575: String sProName = xmlElement
0576: .getAttribute(Profile.ATTRIB_NAME);
0577:
0578: if ((sProName != null)
0579: && (sProName.equals("") == false)) {
0580: pro = getProfile(sProName);
0581: } else {
0582: pro = getProfile();
0583: }
0584:
0585: boolean bIsNewProfile = false;
0586:
0587: if (pro == null) {
0588: bIsNewProfile = true;
0589: pro = new Profile(m_dsi, this );
0590: }
0591:
0592: pro.populate(xmlElement, state);
0593:
0594: if (xmlElement.getAttribute(Profile.ATTRIB_DEFAULT)
0595: .equals(Profile.IS_DEFAULT_PROFILE_VALUE)) {
0596: setProfile(pro);
0597: } else if (bIsNewProfile == true) {
0598: addProfile(pro);
0599: }
0600: } catch (DataAccessException da_e) {
0601: throw new PopulateException(
0602: "Error occured accessing data", da_e);
0603: } catch (InvalidProfileException e) {
0604: throw new PopulateException("Populating profile", e);
0605: }
0606: } else {
0607: super .populate(xmlElement, state);
0608: }
0609: }
0610:
0611: /* (non-Javadoc)
0612: * @see org.openharmonise.rm.publishing.Publishable#publish(org.w3c.dom.Element, org.openharmonise.rm.publishing.HarmoniseOutput, org.openharmonise.rm.publishing.State)
0613: */
0614: public Element publish(Element topEl, HarmoniseOutput xmlDoc,
0615: State state) throws PublishException {
0616: String sTagName = topEl.getTagName();
0617: Element docEl = null;
0618: Text txt = null;
0619:
0620: // deal with tags that will be needed by all objects
0621: if (sTagName.equals(Profile.TAG_PROFILE)) {
0622: try {
0623: Profile pro = null;
0624:
0625: if (topEl.getAttribute(Profile.ATTRIB_DEFAULT).equals(
0626: CONST_TRUE)) {
0627: //get default profile
0628: pro = getProfile();
0629:
0630: } else {
0631: String sProName = topEl
0632: .getAttribute(Profile.ATTRIB_NAME);
0633:
0634: if ((sProName != null)
0635: && (sProName.equals("") == false)) {
0636:
0637: pro = getProfile(sProName);
0638: }
0639: }
0640:
0641: if (pro != null) {
0642: docEl = pro.publish(topEl, xmlDoc, state);
0643:
0644: } else {
0645: pro = new Profile(m_dsi, this );
0646: docEl = pro.publish(topEl, xmlDoc, state);
0647: }
0648: } catch (DataAccessException da_e) {
0649: throw new PublishException(
0650: "Error occured accessing profile", da_e);
0651: }
0652: } else {
0653: // if we get here then nothing processes this tag, so pass it up
0654: docEl = super .publish(topEl, xmlDoc, state);
0655: }
0656:
0657: return docEl;
0658: }
0659:
0660: /**
0661: * Returns <code>true</code> if the specified profile is this object's
0662: * default profile.
0663: *
0664: * @param prof the profile to test default status on
0665: * @return <code>true</code> if the specified profile is the default
0666: */
0667: public boolean isDefaultProfile(Profile prof) {
0668: ColumnRef returnColRef = null;
0669:
0670: Profile defaultProf = (Profile) m_profiles.get(m_sDefaultKey);
0671:
0672: return defaultProf.equals(prof);
0673: }
0674:
0675: /* (non-Javadoc)
0676: * @see org.openharmonise.rm.dsi.DataStoreObject#processResultSet(org.openharmonise.commons.dsi.CachedResultSet, org.openharmonise.commons.dsi.dml.SelectStatement)
0677: */
0678: public List processResultSet(CachedResultSet rs,
0679: SelectStatement select) {
0680: return processResultSet(rs, select, -1);
0681: }
0682:
0683: /* (non-Javadoc)
0684: * @see org.openharmonise.rm.dsi.DataStoreObject#processResultSet(org.openharmonise.commons.dsi.CachedResultSet, org.openharmonise.commons.dsi.dml.SelectStatement, int)
0685: */
0686: public List processResultSet(CachedResultSet rs,
0687: SelectStatement select, int nLimit) {
0688:
0689: Vector rObjs = new Vector(16);
0690:
0691: int nResultCount = 0;
0692:
0693: try {
0694: int nId = -1;
0695: Vector vIds = new Vector(16);
0696: AbstractProfiledObject pobj = null;
0697: String sIdColName = null;
0698:
0699: while (rs.next()) {
0700: if ((nLimit < 0 || nResultCount < nLimit)) {
0701: try {
0702: sIdColName = this .getInstanceColumnRef(
0703: AbstractObject.ATTRIB_ID, false)
0704: .getColumn();
0705: nId = rs.getInt(sIdColName);
0706:
0707: if (vIds.contains(new Integer(nId)) == false) {
0708: pobj = (AbstractProfiledObject) HarmoniseObjectFactory
0709: .instantiatePublishableObject(
0710: this .m_dsi, this .getClass()
0711: .getName(), nId);
0712: }
0713:
0714: if (rs.hasCurrentRowBeenRead() == false) {
0715:
0716: pobj.populateFromResultSetRow(rs, select);
0717:
0718: rs.markCurrentRowAsRead();
0719: rs.clearRow(sIdColName);
0720: }
0721:
0722: if (vIds.contains(new Integer(nId)) == false) {
0723: rObjs.add(pobj);
0724: vIds.add(new Integer(nId));
0725: }
0726: } catch (Exception e) {
0727: m_logger.log(Level.WARNING, e
0728: .getLocalizedMessage(), e);
0729: }
0730: } else {
0731: break;
0732: }
0733:
0734: nResultCount++;
0735: }
0736: } catch (Exception e) {
0737: m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
0738: }
0739:
0740: return rObjs;
0741: }
0742:
0743: /* (non-Javadoc)
0744: * @see java.lang.Object#clone()
0745: */
0746: public Object clone() {
0747: // Note: if exception is thrown it is gonna cause problems with
0748: //saving, etc so I've elected to throw a RuntimeException
0749: AbstractProfiledObject other = null;
0750:
0751: try {
0752:
0753: if (!m_bIsPopulated) {
0754: populateFromDatabase();
0755: }
0756:
0757: Profile nextProfile = null;
0758: other = (AbstractProfiledObject) super .clone();
0759:
0760: //create deep copy clone of Profiles Hashtable
0761: Hashtable hshProfs = new Hashtable();
0762: Iterator iter = m_profiles.values().iterator();
0763: int nP = 0;
0764:
0765: while (iter.hasNext()) {
0766: nextProfile = (Profile) iter.next();
0767:
0768: Profile profClone = (Profile) nextProfile.clone();
0769: profClone.setProfiledObject(other);
0770: hshProfs.put(profClone.getName(), profClone);
0771: }
0772:
0773: other.m_profiles = new Hashtable(hshProfs);
0774:
0775: //if there's a default profile set it
0776: if (m_profiles.size() > 0) {
0777:
0778: Profile oProf = getProfile();
0779: String sName = oProf.getName();
0780: other.setDefaultProfile(sName);
0781: }
0782:
0783: } catch (DataAccessException da_e) {
0784: throw new IllegalStateException(
0785: "Problem occured during clone"
0786: + da_e.getLocalizedMessage());
0787: } catch (PopulateException pop_e) {
0788: throw new IllegalStateException(
0789: "Problem occured during clone"
0790: + pop_e.getLocalizedMessage());
0791: } catch (InvalidProfileException ip_e) {
0792: throw new IllegalStateException(
0793: "Problem occured during clone"
0794: + ip_e.getLocalizedMessage());
0795: }
0796:
0797: return other;
0798: }
0799:
0800: /* (non-Javadoc)
0801: * @see org.openharmonise.rm.resources.AbstractObject#markAsNew()
0802: */
0803: public void markAsNew() throws PopulateException {
0804: super .markAsNew();
0805:
0806: Profile nextProfile = null;
0807: Iterator iter = null;
0808:
0809: try {
0810: iter = getProfiles().iterator();
0811: } catch (DataAccessException e) {
0812: throw new PopulateException(e.getLocalizedMessage());
0813: }
0814:
0815: while (iter.hasNext()) {
0816: nextProfile = (Profile) iter.next();
0817:
0818: nextProfile.markAsNew();
0819:
0820: }
0821: }
0822:
0823: /* (non-Javadoc)
0824: * @see org.openharmonise.rm.resources.AbstractObject#clear()
0825: */
0826: public void clear() {
0827: super .clear();
0828: m_profiles.clear();
0829: m_sDefaultKey = null;
0830: }
0831:
0832: /*----------------------------------------------------------------------
0833: Protected Functions
0834: -----------------------------------------------------------------------*/
0835:
0836: /* (non-Javadoc)
0837: * @see org.openharmonise.rm.resources.AbstractObject#populateFromResultSetRow(java.sql.ResultSet, org.openharmonise.commons.dsi.dml.SelectStatement)
0838: */
0839: protected void populateFromResultSetRow(ResultSet rs,
0840: SelectStatement select) throws PopulateException {
0841: if (isPopulated() == false) {
0842: super .populateFromResultSetRow(rs, select);
0843: try {
0844: String sTemp = null;
0845: int nTemp = -1;
0846: java.sql.Date dTemp = null;
0847: ColumnRef colref = null;
0848:
0849: colref = Profile.getColumnRef(this , TAG_NAME);
0850:
0851: if (select.containsSelectColumn(colref) == true) {
0852:
0853: String sProfileName = rs.getString(select
0854: .getResultSetIndex(colref));
0855:
0856: if ((sProfileName != null)
0857: && (sProfileName.length() > 0)) {
0858: Profile prof2pop = null;
0859:
0860: if (m_profiles.containsKey(sProfileName) == true) {
0861: prof2pop = (Profile) m_profiles
0862: .get(sProfileName);
0863: } else {
0864: colref = Profile.getColumnRef(this ,
0865: ATTRIB_ID);
0866:
0867: int nProfId = -1;
0868:
0869: if (select.containsSelectColumn(colref) == true) {
0870: nProfId = rs.getInt(select
0871: .getResultSetIndex(colref));
0872: }
0873:
0874: String sProfileClass = Profile.class
0875: .getName();
0876: colref = Profile.getColumnRef(this ,
0877: ATTRIB_TYPE);
0878:
0879: if (select.containsSelectColumn(colref) == true) {
0880: sTemp = rs.getString(select
0881: .getResultSetIndex(colref));
0882:
0883: if (sTemp != null && sTemp.length() > 0) {
0884: sProfileClass = sTemp;
0885: }
0886: }
0887:
0888: //get profile instance
0889: prof2pop = (Profile) Class.forName(
0890: sProfileClass).newInstance();
0891:
0892: //populate profile
0893: prof2pop.setProfiledObject(this );
0894: prof2pop.setDataStoreInterface(m_dsi);
0895: prof2pop.setName(sProfileName);
0896: if (isHistorical() == true) {
0897: prof2pop.setHistorical(true);
0898: }
0899: if (nProfId > 0) {
0900: prof2pop.setId(nProfId);
0901: }
0902:
0903: addProfile(prof2pop);
0904:
0905: }
0906:
0907: AbstractObject ao = (AbstractObject) prof2pop;
0908: ao.populateFromResultSetRow(rs, select);
0909: }
0910:
0911: }
0912:
0913: } catch (DataStoreException ds_e) {
0914: throw new PopulateException(
0915: "Error occured accessing data", ds_e);
0916: } catch (InvalidProfileException da_e) {
0917: throw new PopulateException(
0918: "Error occured adding profile", da_e);
0919: } catch (SQLException sql_e) {
0920: throw new PopulateException(
0921: "Error occured adding profile", sql_e);
0922: } catch (InstantiationException e) {
0923: throw new PopulateException(
0924: "Error occured creating new profile", e);
0925: } catch (IllegalAccessException e) {
0926: throw new PopulateException(
0927: "Error occured creating new profile", e);
0928: } catch (ClassNotFoundException e) {
0929: throw new PopulateException(
0930: "Error occured creating new profile", e);
0931: } catch (InvalidNameException e) {
0932: throw new PopulateException(e);
0933: }
0934: }
0935: }
0936:
0937: /* (non-Javadoc)
0938: * @see org.openharmonise.rm.resources.AbstractEditableObject#saveCoreData()
0939: */
0940: protected void saveCoreData() throws EditException {
0941: try {
0942: if (isChanged() == true) {
0943:
0944: Profile nextProfile = null;
0945: int nNextId = 0;
0946: Iterator iter = m_profiles.values().iterator();
0947: List profiles = new ArrayList();
0948:
0949: while (iter.hasNext()) {
0950: profiles.add((Profile) iter.next());
0951: }
0952:
0953: iter = profiles.iterator();
0954:
0955: while (iter.hasNext()) {
0956: nextProfile = (Profile) iter.next();
0957: nNextId = nextProfile.getId();
0958: nextProfile = nextProfile.save(this );
0959:
0960: //test to see if profile has changed
0961: if (nextProfile.getId() != nNextId) {
0962: // set the new profile at this position
0963: m_profiles.put(nextProfile.getName(),
0964: nextProfile);
0965: }
0966: }
0967:
0968: }
0969: } catch (DataAccessException da_e) {
0970: throw new EditException("Error accessing profile's data:",
0971: da_e);
0972: } catch (ProfileException prof_e) {
0973: throw new EditException("Error saving core data:", prof_e);
0974: }
0975: }
0976:
0977: /* (non-Javadoc)
0978: * @see org.openharmonise.rm.resources.AbstractEditableObject#update()
0979: */
0980: protected void update() throws DataStoreException, EditException {
0981: super .update();
0982:
0983: Profile prof2Remove = null;
0984:
0985: // delete the profiles waiting to be deleted
0986: try {
0987: for (Iterator profiles = m_profiles2Remove.iterator(); profiles
0988: .hasNext();) {
0989: // get the next profile
0990: prof2Remove = (Profile) profiles.next();
0991:
0992: prof2Remove.delete(); // delete the profile
0993: }
0994: } catch (ProfileException pe) {
0995: throw new EditException(pe.getLocalizedMessage());
0996: }
0997:
0998: Profile nextProfile = null;
0999: Iterator iter = m_profiles.values().iterator();
1000:
1001: while (iter.hasNext()) {
1002: nextProfile = (Profile) iter.next();
1003:
1004: try {
1005:
1006: if (nextProfile.isNew() == true) {
1007: nextProfile.save(this );
1008: } else {
1009: nextProfile.update();
1010: }
1011: } catch (PopulateException pop_e) {
1012: throw new DataStoreException(pop_e
1013: .getLocalizedMessage(), pop_e);
1014: } catch (ProfileException prof_e) {
1015: throw new DataStoreException(prof_e
1016: .getLocalizedMessage(), prof_e);
1017: }
1018: }
1019:
1020: // clear the profiles to be removed
1021: m_profiles2Remove.clear();
1022: }
1023:
1024: /* (non-Javadoc)
1025: * @see org.openharmonise.rm.resources.AbstractObject#fullPopulate()
1026: */
1027: protected void fullPopulate() throws PopulateException {
1028: super .fullPopulate();
1029: fillProfiles();
1030: }
1031:
1032: /**
1033: * Fully populates all profiles.
1034: *
1035: * @throws PopulateException if there is an error populating a profile
1036: */
1037: protected void fillProfiles() throws PopulateException {
1038: Profile nextProfile = null;
1039: int nNextId = 0;
1040: Iterator iter = m_profiles.values().iterator();
1041:
1042: while (iter.hasNext()) {
1043: nextProfile = (Profile) iter.next();
1044: try {
1045: nextProfile.fillProfileData();
1046: } catch (ProfileException prof_e) {
1047: throw new PopulateException(prof_e);
1048: }
1049:
1050: }
1051: }
1052:
1053: /**
1054: * Sets whether all profiles are historical.
1055: *
1056: * @param bIsHistorical <code>true</code> of all profiles are to be historical
1057: */
1058: protected void setProfilesHistorical(boolean bIsHistorical) {
1059: Profile nextProfile = null;
1060: int nNextId = 0;
1061: Iterator iter = m_profiles.values().iterator();
1062:
1063: while (iter.hasNext()) {
1064: nextProfile = (Profile) iter.next();
1065: nextProfile.setHistorical(bIsHistorical);
1066: }
1067: }
1068:
1069: /**
1070: * Returns <code>true</code> if object contains a profile of the
1071: * specified name.
1072: *
1073: * @param sName the name of a profile
1074: * @return <code>true</code> if object contains a profile of the
1075: * specified name
1076: */
1077: protected boolean isProfileLoaded(String sName) {
1078: return ((m_profiles != null) && (m_profiles.size() > 0) && m_profiles
1079: .get(sName) != null);
1080: }
1081:
1082: /* (non-Javadoc)
1083: * @see org.openharmonise.rm.resources.AbstractObject#addColumnsToPopulateQuery(org.openharmonise.commons.dsi.dml.SelectStatement, boolean)
1084: */
1085: protected void addColumnsToPopulateQuery(SelectStatement select,
1086: boolean bIsHist) throws DataStoreException {
1087: super .addColumnsToPopulateQuery(select, bIsHist);
1088:
1089: select.addSelectColumn(Profile.getColumnRef(this , TAG_NAME));
1090: select.addSelectColumn(Profile.getColumnRef(this , ATTRIB_ID));
1091: select.addSelectColumn(Profile.getColumnRef(this , ATTRIB_TYPE));
1092: select.addOuterJoinCondition(Profile.getColumnRef(this ,
1093: Profile.ATTRIB_OBJECT_KEY), getInstanceColumnRef(
1094: ATTRIB_KEY, bIsHist));
1095:
1096: //this ensures that only top level profiles are found
1097: select.addWhereCondition(ProfilePropertyInstance
1098: .getColumnRef(this , ProfilePropertyInstance.TAG_VALUE,
1099: isHistorical()), "is", null);
1100: }
1101:
1102: /* (non-Javadoc)
1103: * @see org.openharmonise.rm.resources.AbstractObject#setHistorical(boolean)
1104: */
1105: public void setHistorical(boolean bIsHistorical) {
1106: super .setHistorical(bIsHistorical);
1107:
1108: if (m_profiles != null) {
1109:
1110: // get the iterator
1111: Iterator profilesIter = m_profiles.values().iterator();
1112:
1113: // holds the temporary profile
1114: Profile prof = null;
1115: Iterator propertiesIter = null;
1116:
1117: while (profilesIter.hasNext() == true) {
1118: prof = (Profile) profilesIter.next();
1119: prof.setHistorical(bIsHistorical);
1120: }
1121: }
1122: }
1123:
1124: /* (non-Javadoc)
1125: * @see java.lang.Object#toString()
1126: */
1127: public String toString() {
1128: StringBuffer strbuf = new StringBuffer();
1129: strbuf.append(super .toString());
1130:
1131: Iterator iter = m_profiles.keySet().iterator();
1132:
1133: while (iter.hasNext()) {
1134: String sKey = (String) iter.next();
1135: Profile prof = (Profile) m_profiles.get(sKey);
1136: strbuf.append("\n").append(sKey).append(" - ").append("[")
1137: .append(prof.toString()).append("]");
1138: }
1139:
1140: return strbuf.toString();
1141: }
1142:
1143: /* (non-Javadoc)
1144: * @see org.openharmonise.rm.resources.lifecycle.Editable#changeStatus(org.openharmonise.rm.resources.lifecycle.Status)
1145: */
1146: public Editable changeStatus(Status status) throws EditException {
1147: //check profiles for valid data for approval
1148:
1149: if (isPopulated() == false) {
1150: try {
1151: populateFromDatabase();
1152: } catch (PopulateException e) {
1153: throw new EditException(e.getLocalizedMessage(), e);
1154: }
1155: }
1156:
1157: if (m_bIgnoreProfileRestrictions == false) {
1158: boolean bIsProfilesValid = true;
1159:
1160: Iterator iter = m_profiles.values().iterator();
1161:
1162: //the assumption here is that the object will always have a profile
1163: //obviously if the object has no profile no validity checks will be
1164: //made
1165: while (iter.hasNext() && bIsProfilesValid == true) {
1166: Profile prof = (Profile) iter.next();
1167:
1168: try {
1169: bIsProfilesValid = prof.isValid(this );
1170: } catch (DataAccessException e) {
1171: throw new EditException(e.getLocalizedMessage(), e);
1172: }
1173:
1174: }
1175:
1176: if (bIsProfilesValid == false) {
1177: throw new StatusChangeNotAllowedException(
1178: "Profiles not valid for status change");
1179: }
1180: }
1181:
1182: return super .changeStatus(status);
1183: }
1184:
1185: /**
1186: * Sets whether to allow object to have status approved even if profile
1187: * restrictions have been broken.
1188: *
1189: * @param bIgnore <code>true</code> if profile restrictoins are
1190: * to ignored during a change of status
1191: */
1192: public void ignoreProfileRestrictions(boolean bIgnore) {
1193: m_bIgnoreProfileRestrictions = bIgnore;
1194: }
1195:
1196: }
|