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.lang.reflect.InvocationTargetException;
0022: import java.sql.*;
0023: import java.text.SimpleDateFormat;
0024: import java.util.*;
0025: import java.util.Date;
0026: import java.util.logging.*;
0027:
0028: import org.openharmonise.commons.cache.*;
0029: import org.openharmonise.commons.dsi.*;
0030: import org.openharmonise.commons.dsi.dml.*;
0031: import org.openharmonise.rm.*;
0032: import org.openharmonise.rm.commands.InvalidCommandException;
0033: import org.openharmonise.rm.dsi.*;
0034: import org.openharmonise.rm.factory.*;
0035: import org.openharmonise.rm.publishing.*;
0036: import org.openharmonise.rm.resources.lifecycle.*;
0037: import org.openharmonise.rm.resources.publishing.*;
0038: import org.openharmonise.rm.resources.users.User;
0039: import org.openharmonise.rm.search.Search;
0040: import org.openharmonise.rm.security.authorization.AuthorizationValidator;
0041: import org.w3c.dom.*;
0042:
0043: /**
0044: * Abstract class that provides the necessary functionality for objects
0045: * which can be children in a parent-child relationship within Harmonise.
0046: *
0047: *
0048: * @author Michael Bell
0049: * @version $Revision: 1.7.2.1 $
0050: *
0051: */
0052: public abstract class AbstractChildObject extends
0053: AbstractProfiledObject implements Editable, Publishable,
0054: DataStoreObject, Cloneable {
0055:
0056: //XML constants
0057:
0058: /**
0059: * Name of XML attribute which specifies whether a parent object is the
0060: * default parent
0061: */
0062: public static final String ATTRIB_DEFAULT = "default";
0063:
0064: /**
0065: * Name of XML attribute which determines whether all parent objects
0066: * should be published
0067: */
0068: public static final String ATTRIB_SHOWALL = "showAll";
0069:
0070: /**
0071: * Path tag name
0072: */
0073: public static final String TAG_PATH = "Path";
0074:
0075: /**
0076: * Group tag name
0077: */
0078: public static final String TAG_GROUP = "Group";
0079:
0080: //DB constants
0081: /**
0082: * Relationship table default link column name
0083: */
0084: protected static final String CLMN_DEFAULT_LINK = "default_link";
0085:
0086: /**
0087: * Relationship table path column name
0088: */
0089: protected static final String CLMN_PATH = "path";
0090:
0091: /**
0092: * Relationship table parent key column name
0093: */
0094: protected static final String CLMN_PARENT_KEY = "parent_key";
0095:
0096: /**
0097: * Relationship table child key column name
0098: */
0099: protected static final String CLMN_CHILD_KEY = "child_key";
0100:
0101: /**
0102: * Relationship table date column name
0103: */
0104: protected static final String CLMN_DATE = "date";
0105:
0106: /**
0107: * String used for composing relationship table names.
0108: *
0109: * Note: the pattern for relationship table names is
0110: * 'parentObj.getTableName() + JOIN_TO + childObj.getTableName()'
0111: */
0112: public static final String JOIN_TO = "_2_";
0113:
0114: /**
0115: * Archive timestamp format, used in composing archived child names in
0116: * the case of a duplicate name
0117: */
0118: public static final String ARCHIVE_TIMESTAMP_FORMAT = "yyyy-MM-dd_HH-mm";
0119:
0120: /**
0121: * Constant value for default attribute when insantiating object
0122: * with XML, specifically this value indicates that the parent
0123: * object should be added as the default parent
0124: */
0125: protected static final String IS_DEFAULT_GROUP = "1";
0126:
0127: /**
0128: * Map of child class to parent classes. Used to cache info.
0129: */
0130: protected static Map m_child_parent_mappings = new Hashtable();
0131:
0132: /**
0133: * <code>Map</code> of parents of this child object
0134: */
0135: protected Map m_groups = null;
0136:
0137: /**
0138: * The list of parent objects to save on the next <code>save()</code>
0139: * operation
0140: */
0141: protected List m_groups_to_save;
0142:
0143: /**
0144: * The identifier of the default parent
0145: */
0146: protected int m_defaultGroup = -1;
0147:
0148: /**
0149: * The name of the class that may act as parent to this object
0150: */
0151: protected String m_sGroupClass = null;
0152:
0153: /**
0154: * The <code>boolean</code> flag which indicates whether this object has
0155: * populated it's <code>Map</code> of parents
0156: */
0157: protected boolean m_bIsGroupsPopulated = false;
0158:
0159: /**
0160: * The path of this object.
0161: *
0162: * Note: this is only used if the object is historical, otherwise the
0163: * path is built on the fly from it's current relationships
0164: */
0165: protected String m_sPath = null;
0166:
0167: //separator constant
0168: /**
0169: * The Harmonise path-separator character
0170: */
0171: public static final String separator = "/";
0172:
0173: /**
0174: * Logger for this class
0175: */
0176: private static final Logger m_logger = Logger
0177: .getLogger(AbstractChildObject.class.getName());
0178:
0179: //initialiser block
0180: {
0181: m_sGroupClass = getParentObjectClassName();
0182: m_groups = new HashMap();
0183: m_groups_to_save = new Vector();
0184: }
0185:
0186: /**
0187: * Constructs a new or anonymous instance without an interface
0188: * to the database.
0189: */
0190: public AbstractChildObject() {
0191: super ();
0192: }
0193:
0194: /**
0195: * Constructor for a new or anonymous instance.
0196: *
0197: * @param dbintrf the data store interface
0198: */
0199: public AbstractChildObject(AbstractDataStoreInterface dbintrf) {
0200: super (dbintrf);
0201: }
0202:
0203: /**
0204: * Standard constructor for an existing resource,
0205: * registering an <code>AbstractDataStoreInterface</code> to use
0206: * with all database communications.
0207: *
0208: * @param dbintrf the interface to the database
0209: * @param nId the id of the object
0210: */
0211: public AbstractChildObject(AbstractDataStoreInterface dbintrf,
0212: int nId) {
0213: super (dbintrf, nId);
0214: }
0215:
0216: /**
0217: * Standard constructor for an existing resource which may be historical.
0218: *
0219: * @param dbintrf the interface to the database
0220: * @param nId the id of the object
0221: * @param nKey the unique key of the resource
0222: * @param bIsHist <code>true</code> if the object is historical
0223: */
0224: public AbstractChildObject(AbstractDataStoreInterface dbintrf,
0225: int nId, int nKey, boolean bIsHist) {
0226: super (dbintrf, nId, nKey, bIsHist);
0227: }
0228:
0229: /* (non-Javadoc)
0230: * @see org.openharmonise.rm.resources.AbstractObject#markAsNew()
0231: */
0232: public void markAsNew() throws PopulateException {
0233: super .markAsNew();
0234: m_groups_to_save = new Vector(m_groups.values());
0235: }
0236:
0237: /* (non-Javadoc)
0238: * @see java.lang.Object#clone()
0239: */
0240: public Object clone() {
0241: try {
0242: if (m_bIsPopulated == false) {
0243: populateFromDatabase();
0244: }
0245:
0246: AbstractChildObject other = (AbstractChildObject) super
0247: .clone();
0248:
0249: if (m_groups != null) {
0250: other.m_groups = new HashMap(m_groups);
0251: }
0252:
0253: return other;
0254: } catch (PopulateException e) {
0255: m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
0256:
0257: return null;
0258: }
0259: }
0260:
0261: /* (non-Javadoc)
0262: * @see org.openharmonise.rm.resources.AbstractObject#clear()
0263: */
0264: public void clear() {
0265: //break ties from group object to this object
0266: Collection parent_groups = m_groups.values();
0267:
0268: Iterator iter = parent_groups.iterator();
0269:
0270: while (iter.hasNext() == true) {
0271: CachePointer ptr = (CachePointer) iter.next();
0272:
0273: try {
0274: if (this instanceof AbstractParentObject) {
0275: ((AbstractParentObject) ptr.getObject())
0276: .clearChildren();
0277: } else {
0278: ((AbstractParentObject) ptr.getObject())
0279: .clearChildren();
0280: }
0281: } catch (CacheException e) {
0282: throw new IllegalStateException(
0283: "Problem occured getting object from the cache:"
0284: + e.getLocalizedMessage());
0285: }
0286: }
0287:
0288: super .clear();
0289: m_groups.clear();
0290: m_groups_to_save.clear();
0291: m_defaultGroup = -1;
0292: m_bIsGroupsPopulated = false;
0293: }
0294:
0295: /**
0296: * Returns the 'real' parent of this child object.
0297: *
0298: * <p>Note: Real can be understood to mean
0299: * the default or main parent of this child.</p>
0300: *
0301: * @return the 'real' parent of this child object.
0302: * @throws DataAccessException if an error occurs populating this object
0303: * or accessing it's live version
0304: */
0305: public AbstractParentObject getRealParent()
0306: throws DataAccessException {
0307: AbstractParentObject defGroup = null;
0308:
0309: if (isLiveVersion() == true
0310: || (getLiveVersion() == null && isHistorical() == false)) {
0311:
0312: if (m_bIsGroupsPopulated == false) {
0313:
0314: try {
0315: populateGroupsFromDatabase();
0316: } catch (PopulateException e) {
0317: throw new DataAccessException(
0318: "Error occured accessing parents", e);
0319: }
0320: }
0321:
0322: if (m_defaultGroup > 0) {
0323: CachePointer ptr = (CachePointer) m_groups.get(String
0324: .valueOf(m_defaultGroup));
0325:
0326: if (ptr != null) {
0327: try {
0328: defGroup = (AbstractParentObject) ptr
0329: .getObject();
0330: } catch (CacheException e) {
0331: throw new DataAccessException(
0332: "Error occured getting parent", e);
0333: }
0334: }
0335:
0336: if ((defGroup == null) && (m_groups.size() > 0)) {
0337: defGroup = (AbstractParentObject) getParents().get(
0338: 0);
0339: }
0340: }
0341: } else if (isHistorical() == true && getLiveVersion() == null) {
0342:
0343: //need to account for the fact that the parent collection
0344: //itself may be historical so, we drill up to get a live
0345: //collection somewhere in the hierarchy and then drill
0346: //back down to find the desired collection
0347:
0348: String sTmpPath = m_sPath;
0349: Stack pathStack = new Stack();
0350: AbstractParentObject tmpParent = null;
0351:
0352: while (defGroup == null && sTmpPath != null
0353: && sTmpPath.length() > 1) {
0354:
0355: if (tmpParent == null) {
0356: try {
0357: tmpParent = (AbstractParentObject) HarmoniseObjectFactory
0358: .instantiateHarmoniseObject(m_dsi,
0359: getParentObjectClassName(),
0360: sTmpPath);
0361: } catch (HarmoniseFactoryException e) {
0362: throw new DataAccessException(e);
0363: }
0364: }
0365:
0366: if (tmpParent == null) {
0367: int nLastSlashIndex = sTmpPath
0368: .lastIndexOf(separator);
0369: sTmpPath = sTmpPath.substring(0, nLastSlashIndex);
0370: nLastSlashIndex = sTmpPath.lastIndexOf(separator);
0371: String sName = sTmpPath.substring(
0372: nLastSlashIndex + 1, sTmpPath.length());
0373: pathStack.push(sName);
0374: } else if (pathStack.size() == 0) {
0375: defGroup = tmpParent;
0376: } else {
0377: String sName = (String) pathStack.pop();
0378: tmpParent = (AbstractParentObject) tmpParent
0379: .getArchivedChildByName(sName);
0380: }
0381: }
0382:
0383: } else {
0384: defGroup = ((AbstractChildObject) getLiveVersion())
0385: .getRealParent();
0386: }
0387:
0388: return defGroup;
0389: }
0390:
0391: /**
0392: * Returns <code>true</code> if the specified <code>AbstractParentObject</code>
0393: * is the 'real' parent of this child object.
0394: *
0395: * @param obj the parent object
0396: * @return <code>true</code> if the specified <code>AbstractParentObject</code>
0397: * is the 'real' parent of this child object.
0398: * @throws DataAccessException if an error occurs accessing the real parent
0399: */
0400: public boolean isRealParent(AbstractParentObject obj)
0401: throws DataAccessException {
0402: boolean isDefault = false;
0403: AbstractParentObject defObj = getRealParent();
0404:
0405: if ((defObj != null) && (defObj.getId() == obj.getId())) {
0406: isDefault = true;
0407: }
0408:
0409: return isDefault;
0410: }
0411:
0412: /**
0413: * Returns the path string which specifies the default location in the
0414: * hierarchy of parent-child relationships of this object.
0415: *
0416: * @return the path string which specifies the default location
0417: * @throws DataAccessException if an error occurs accessing the real
0418: * parent
0419: */
0420: public String getPath() throws DataAccessException {
0421: String sPath = null;
0422:
0423: if (isPopulated() == false) {
0424: try {
0425: populateFromDatabase();
0426: } catch (PopulateException e) {
0427: throw new DataAccessException(
0428: "Error populating object:", e);
0429: }
0430: }
0431:
0432: if (isHistorical() == true) {
0433: sPath = m_sPath;
0434: } else {
0435: AbstractParentObject parent = getRealParent();
0436:
0437: if (parent != null) {
0438: sPath = parent.getFullPath();
0439: }
0440: }
0441:
0442: return sPath;
0443: }
0444:
0445: /**
0446: * Returns the complete path string, which includes the name of this
0447: * object, which specifies the default location in the hierarchy of
0448: * parent-child relationships of this object.
0449: *
0450: * @return the complete path string of this object
0451: * @throws DataAccessException if an error occurs getting the main path
0452: * information
0453: */
0454: public String getFullPath() throws DataAccessException {
0455: StringBuffer sFullPath = new StringBuffer();
0456:
0457: sFullPath.append(getPath());
0458:
0459: //add seperator if necessary
0460: if (sFullPath.length() > 1) {
0461: sFullPath.append(separator);
0462: }
0463:
0464: sFullPath.append(getName());
0465:
0466: return sFullPath.toString();
0467: }
0468:
0469: /**
0470: * Returns a list of of all the paths to this child object.
0471: *
0472: * @return a list of of all the paths to this child object
0473: * @throws DataAccessException if an error occurs building any
0474: * of the paths
0475: */
0476: public List getAllPaths() throws DataAccessException {
0477: ArrayList paths = new ArrayList();
0478:
0479: List parents = getParents();
0480:
0481: if (isHistorical() == false && parents.size() > 0) {
0482: Iterator iter = parents.iterator();
0483:
0484: while (iter.hasNext()) {
0485: AbstractChildObject child = (AbstractChildObject) iter
0486: .next();
0487: paths.addAll(child.getAllFullPaths());
0488: }
0489: } else {
0490: paths.add(getPath());
0491: }
0492:
0493: return paths;
0494: }
0495:
0496: /**
0497: * Returns a list of all possible full paths for this child.
0498: *
0499: * @return a list of all possible full paths for this child
0500: * @throws DataAccessException if an error occurs building any
0501: * of the paths
0502: */
0503: public List getAllFullPaths() throws DataAccessException {
0504: ArrayList paths = new ArrayList();
0505:
0506: List parents = getParents();
0507:
0508: if (isHistorical() == false && parents.size() > 0) {
0509: Iterator iter = parents.iterator();
0510:
0511: while (iter.hasNext()) {
0512: AbstractChildObject child = (AbstractChildObject) iter
0513: .next();
0514:
0515: List childPaths = child.getAllFullPaths();
0516:
0517: Iterator pathIter = childPaths.iterator();
0518:
0519: while (pathIter.hasNext()) {
0520: String path = (String) pathIter.next();
0521: StringBuffer sFullPath = new StringBuffer();
0522: sFullPath.append(path).append(separator).append(
0523: m_sName);
0524: paths.add(sFullPath.toString());
0525: }
0526: }
0527:
0528: } else {
0529: paths.add(getFullPath());
0530: }
0531:
0532: return paths;
0533: }
0534:
0535: /**
0536: * Returns a list of all this child's parent objects.
0537: *
0538: * @return a list of all this child's parent objects.
0539: * @throws DataAccessException if an error occurs populating the
0540: * parent objects
0541: */
0542: public List getParents() throws DataAccessException {
0543: List groups = new Vector();
0544: if (isLiveVersion() == true || getLiveVersion() == null) {
0545: if (this .m_bIsGroupsPopulated == false) {
0546: try {
0547: this .populateGroupsFromDatabase();
0548: } catch (PopulateException e) {
0549: throw new DataAccessException(e
0550: .getLocalizedMessage(), e);
0551: }
0552: }
0553:
0554: Iterator iter = m_groups.values().iterator();
0555:
0556: while (iter.hasNext()) {
0557: CachePointer ptr = (CachePointer) iter.next();
0558:
0559: try {
0560: groups.add(ptr.getObject());
0561: } catch (CacheException e) {
0562: throw new DataAccessException(
0563: "Error occured getting object from cache",
0564: e);
0565: }
0566: }
0567: } else {
0568: AbstractChildObject live = (AbstractChildObject) getLiveVersion();
0569:
0570: if (live != null && live != this ) {
0571: groups = live.getParents();
0572: }
0573:
0574: }
0575:
0576: return groups;
0577: }
0578:
0579: /* (non-Javadoc)
0580: * @see org.openharmonise.rm.publishing.Publishable#populate(org.w3c.dom.Element, org.openharmonise.rm.publishing.State)
0581: */
0582: public void populate(Element xmlElement, State state)
0583: throws PopulateException {
0584: String sTagName = xmlElement.getTagName();
0585:
0586: if (sTagName.equals(TAG_GROUP)) {
0587: NodeList nodes = xmlElement.getChildNodes();
0588:
0589: for (int i = 0; i < nodes.getLength(); i++) {
0590: if (nodes.item(i).getNodeType() == Node.ELEMENT_NODE) {
0591: Element node = (Element) nodes.item(i);
0592:
0593: try {
0594:
0595: AbstractParentObject grpObj = (AbstractParentObject) HarmoniseObjectFactory
0596: .instantiatePublishableObject(
0597: this .m_dsi, node, state);
0598: try {
0599: if (this .isLiveVersion() == false) {
0600: acquireEditWriteLock();
0601: User user = state.getLoggedInUser();
0602: if (user == null) {
0603: throw new PopulateException(
0604: "Unable to process object without without specifying a user");
0605: }
0606: try {
0607: boolean bIsAvailable = AuthorizationValidator
0608: .isCommandAvailable(
0609: user,
0610: (AbstractEditableObject) this ,
0611: "Save");
0612: if (bIsAvailable == false) {
0613: throw new PopulateException(
0614: "Save is not authorised for this object");
0615: }
0616: } catch (org.openharmonise.rm.security.authorization.AuthorizationException e) {
0617: throw new PopulateException(
0618: "There was an authorisation problem"
0619: + this .getClass(),
0620: e);
0621: }
0622: save();
0623: releaseEditWriteLock();
0624: }
0625: } catch (Exception e) {
0626: throw new PopulateException(
0627: "There was a problem saving this object",
0628: e);
0629: }
0630: if (node.getAttribute(ATTRIB_DEFAULT).equals(
0631: IS_DEFAULT_GROUP)) {
0632: AbstractParentObject parent = getRealParent();
0633: if (parent != null) {
0634: parent.acquireEditWriteLock();
0635: parent.removeChild(this );
0636: parent.saveNonCoreData();
0637: parent.releaseEditWriteLock();
0638: }
0639: grpObj.acquireEditWriteLock();
0640: grpObj.addChild(this );
0641: grpObj.saveNonCoreData();
0642: grpObj.releaseEditWriteLock();
0643: } else {
0644: grpObj.acquireEditWriteLock();
0645: grpObj.addChild(this , true);
0646: grpObj.saveNonCoreData();
0647: grpObj.releaseEditWriteLock();
0648: }
0649: } catch (InvalidChildException ig_e) {
0650: throw new PopulateException("Invalid child",
0651: ig_e);
0652: } catch (HarmoniseFactoryException f_e) {
0653: throw new PopulateException(
0654: "Invalid parent for object", f_e);
0655: } catch (DataAccessException e) {
0656: throw new PopulateException(
0657: "There was a problem populating parent",
0658: e);
0659: } catch (EditException e) {
0660: throw new PopulateException(
0661: "There was a problem editing", e);
0662: }
0663: }
0664: }
0665: } else {
0666: super .populate(xmlElement, state);
0667: }
0668: }
0669:
0670: /* (non-Javadoc)
0671: * @see org.openharmonise.rm.resources.AbstractObject#getColumnRef(java.lang.String, java.lang.String, boolean)
0672: */
0673: public static ColumnRef getColumnRef(String sClassname,
0674: String sColumn, boolean bHist) throws DataStoreException {
0675: ColumnRef returnColRef = null;
0676: String sTable = getTableName(sClassname, bHist);
0677:
0678: return AbstractChildObject.getObjectColumnRef(sTable, sColumn);
0679: }
0680:
0681: /* (non-Javadoc)
0682: * @see org.openharmonise.rm.dsi.DataStoreObject#getInstanceColumnRef(java.lang.String, boolean)
0683: */
0684: public ColumnRef getInstanceColumnRef(String sColumn,
0685: boolean bIsHist) throws DataStoreException {
0686: String sDBTable = getTableName(bIsHist);
0687:
0688: if (bIsHist == false
0689: && (sColumn.equals(CLMN_PATH) == true || sColumn
0690: .equals(TAG_PATH) == true)) {
0691: throw new InvalidColumnReferenceException(
0692: "Path only valid for historical objects");
0693: }
0694:
0695: return getObjectColumnRef(sDBTable, sColumn);
0696: }
0697:
0698: /* (non-Javadoc)
0699: * @see org.openharmonise.rm.resources.AbstractObject#getObjectColumnRef(java.lang.String, java.lang.String)
0700: */
0701: public static ColumnRef getObjectColumnRef(String sTable,
0702: String sColumn) throws DataStoreException {
0703: ColumnRef returnColRef = null;
0704:
0705: if (sColumn.equals(ATTRIB_DEFAULT) == true
0706: || sColumn.equals(CLMN_DEFAULT_LINK) == true) {
0707: returnColRef = new ColumnRef(sTable, CLMN_DEFAULT_LINK,
0708: ColumnRef.NUMBER);
0709: } else if (sColumn.equals(CLMN_PATH) == true
0710: || sColumn.equals(TAG_PATH) == true) {
0711: returnColRef = new ColumnRef(sTable, CLMN_PATH,
0712: ColumnRef.TEXT);
0713: }
0714:
0715: if (returnColRef != null) {
0716: return returnColRef;
0717: } else {
0718: return AbstractEditableObject.getObjectColumnRef(sTable,
0719: sColumn);
0720: }
0721: }
0722:
0723: /* (non-Javadoc)
0724: * @see org.openharmonise.rm.publishing.Publishable#publish(org.w3c.dom.Element, org.openharmonise.rm.publishing.HarmoniseOutput, org.openharmonise.rm.publishing.State)
0725: */
0726: public org.w3c.dom.Element publish(Element topEl,
0727: HarmoniseOutput xmlDoc, State state)
0728: throws PublishException {
0729: Element docEl = null;
0730: NodeList nodes = null;
0731: Text txt = null;
0732: String sTagName = topEl.getTagName();
0733:
0734: if (sTagName.equals(TAG_GROUP)) {
0735: docEl = xmlDoc.createElement(TAG_GROUP);
0736:
0737: NodeList nlChildren = topEl.getChildNodes();
0738: Node nTemp = null;
0739:
0740: for (int j = 0; j < nlChildren.getLength(); j++) {
0741: nTemp = nlChildren.item(j);
0742:
0743: if (nTemp.getNodeType() != Node.ELEMENT_NODE) {
0744: continue;
0745: } else if (nTemp.getNodeName().equals(
0746: Template.TAG_TEMPLATE)) {
0747: if (m_bIsGroupsPopulated == false) {
0748: try {
0749:
0750: populateGroupsFromDatabase();
0751: } catch (PopulateException pop_e) {
0752: throw new PublishException(
0753: "Error occured populating parents:"
0754: + pop_e
0755: .getLocalizedMessage());
0756: }
0757: }
0758:
0759: if (m_groups.isEmpty() == false) {
0760: Template grpTemplate = null;
0761: try {
0762: grpTemplate = (Template) HarmoniseObjectFactory
0763: .instantiateHarmoniseObject(
0764: m_dsi,
0765: Template.class.getName(),
0766: Integer
0767: .parseInt(((Element) nTemp)
0768: .getAttribute(AbstractObject.ATTRIB_ID)));
0769: } catch (NumberFormatException e) {
0770: throw new PublishException(e);
0771: } catch (HarmoniseFactoryException e) {
0772: throw new PublishException(e);
0773: }
0774: int nPageId = -1;
0775:
0776: NodeList pageNodes = ((Element) nTemp)
0777: .getElementsByTagName(WebPage.TAG_PAGE);
0778:
0779: if (pageNodes.getLength() > 0) {
0780: nPageId = Integer
0781: .parseInt(((Element) pageNodes
0782: .item(0))
0783: .getAttribute(AbstractObject.ATTRIB_ID));
0784: }
0785:
0786: if (grpTemplate == null) {
0787: throw new PublishException(
0788: "No template supplied.");
0789: }
0790:
0791: if (topEl
0792: .hasAttribute(AbstractChildObject.ATTRIB_SHOWALL)) {
0793: try {
0794:
0795: List groups = getParents();
0796:
0797: for (int i = 0; i < groups.size(); i++) {
0798: Publishable pObj = (Publishable) groups
0799: .get(i);
0800: Element grpEl = pObj.publish(
0801: grpTemplate, xmlDoc, state);
0802:
0803: if (((AbstractObject) pObj).getId() == this .m_defaultGroup) {
0804: grpEl
0805: .setAttribute(
0806: AbstractChildObject.ATTRIB_DEFAULT,
0807: "true");
0808: }
0809:
0810: if (nPageId > 0) {
0811: xmlDoc
0812: .addPageIdToLinkNode(
0813: state
0814: .getLoggedInUser(),
0815: grpEl, nPageId);
0816: }
0817:
0818: docEl.appendChild(grpEl);
0819: }
0820: } catch (DataAccessException da_e) {
0821: throw new PublishException(
0822: "Error occured accessing parents:"
0823: + da_e
0824: .getLocalizedMessage());
0825: }
0826: } else {
0827: try {
0828:
0829: Element grpEl = ((Publishable) getRealParent())
0830: .publish(grpTemplate, xmlDoc,
0831: state);
0832:
0833: if (nPageId > 0) {
0834: xmlDoc.addPageIdToLinkNode(state
0835: .getLoggedInUser(), grpEl,
0836: nPageId);
0837: }
0838:
0839: docEl.appendChild(grpEl);
0840: } catch (DataAccessException da_e) {
0841: throw new PublishException(
0842: "Error occured getting parent of object:"
0843: + da_e
0844: .getLocalizedMessage());
0845: }
0846: }
0847: }
0848: } else if (nTemp.getNodeName().equals(
0849: TAG_AVAILABLEOPTIONS)) {
0850: Element elAvOpt = xmlDoc
0851: .createElement(TAG_AVAILABLEOPTIONS);
0852:
0853: NodeList nlList = ((Element) nTemp)
0854: .getElementsByTagName(Search.TAG_LIST);
0855:
0856: if (nlList.getLength() > 0) {
0857: Element elList = (Element) nlList.item(0);
0858: try {
0859:
0860: Publishable list = HarmoniseObjectFactory
0861: .instantiatePublishableObject(
0862: this .m_dsi, elList, state);
0863:
0864: elAvOpt.appendChild(((Search) list)
0865: .publish(elList, xmlDoc, state));
0866: } catch (HarmoniseFactoryException e) {
0867: throw new PublishException(
0868: "Error instantiating list:"
0869: + e.getLocalizedMessage());
0870: }
0871: } else {
0872: throw new PublishException(
0873: "No other implementation for available options");
0874: }
0875:
0876: docEl.appendChild(elAvOpt);
0877: }
0878: }
0879: } else if (sTagName.equals(TAG_PATH)) {
0880: try {
0881:
0882: docEl = xmlDoc.createElement(TAG_PATH);
0883: txt = xmlDoc.createTextNode(getPath());
0884: docEl.appendChild(txt);
0885: } catch (DataAccessException da_e) {
0886: throw new PublishException(
0887: "Error occured getting path:"
0888: + da_e.getLocalizedMessage());
0889: }
0890: } else {
0891: // if we don't know about the tag, pass it up
0892: docEl = super .publish(topEl, xmlDoc, state);
0893: }
0894:
0895: // recurse through the children if there are any
0896: Element formEl;
0897: Element el;
0898:
0899: if (nodes != null) {
0900: for (int i = 0; i < nodes.getLength(); i++) {
0901: if (nodes.item(i).getNodeType() != Node.ELEMENT_NODE) {
0902: continue;
0903: }
0904:
0905: formEl = (Element) nodes.item(i);
0906: el = publish(formEl, xmlDoc, state);
0907:
0908: if (el != null) {
0909: try {
0910: docEl.appendChild(el);
0911: } catch (org.w3c.dom.DOMException e) {
0912: throw new PublishException(el.getTagName()
0913: + ":" + e.getMessage());
0914: }
0915: }
0916: }
0917: }
0918:
0919: return docEl;
0920: }
0921:
0922: /* (non-Javadoc)
0923: * @see org.openharmonise.rm.resources.AbstractObject#isChanged()
0924: */
0925: public boolean isChanged() throws DataAccessException {
0926: boolean bReturn = super .isChanged();
0927:
0928: if (m_bIsGroupsPopulated == false && bReturn == false) {
0929:
0930: try {
0931: populateGroupsFromDatabase();
0932: } catch (PopulateException e) {
0933: throw new DataAccessException(
0934: "Error occured while populating parents:"
0935: + e.getLocalizedMessage());
0936: }
0937:
0938: bReturn = (m_groups_to_save.size() > 0);
0939: }
0940:
0941: return bReturn;
0942: }
0943:
0944: /*----------------------------------------------------------------------------
0945: Protected Methods
0946: -----------------------------------------------------------------------------*/
0947:
0948: /* (non-Javadoc)
0949: * @see org.openharmonise.rm.resources.AbstractEditableObject#delete(boolean)
0950: */
0951: protected void delete(boolean bDeleteHist)
0952: throws DataStoreException, DataAccessException,
0953: EditException, PopulateException {
0954: //ensure groups are populated
0955: if (m_bIsGroupsPopulated == false) {
0956: populateGroupsFromDatabase();
0957: }
0958:
0959: //loop through groups and remove child from each group
0960: Iterator iter = m_groups.values().iterator();
0961:
0962: while (iter.hasNext()) {
0963: try {
0964: AbstractParentObject parent = (AbstractParentObject) ((CachePointer) iter
0965: .next()).getObject();
0966:
0967: parent.removeChild(this );
0968:
0969: parent.saveNonCoreData();
0970: } catch (CacheException e) {
0971: throw new EditException(
0972: "Error occurred getting object from cache:", e);
0973: }
0974: }
0975:
0976: super .delete(bDeleteHist);
0977: }
0978:
0979: /* (non-Javadoc)
0980: * @see org.openharmonise.rm.resources.AbstractEditableObject#saveCoreData()
0981: */
0982: protected void saveCoreData() throws EditException {
0983:
0984: updateParents();
0985:
0986: super .saveCoreData();
0987: }
0988:
0989: /* (non-Javadoc)
0990: * @see org.openharmonise.rm.resources.AbstractEditableObject#update()
0991: */
0992: protected void update() throws EditException, DataStoreException {
0993: super .update();
0994:
0995: updateParents();
0996:
0997: }
0998:
0999: /**
1000: * Updates all parents if this child object has added itself
1001: * to any parent objects, only necessary if <code>populate</code>
1002: * has been called.
1003: *
1004: * @throws EditException if an error occurs adding this child to a parent
1005: */
1006: protected void updateParents() throws EditException {
1007: if (m_groups_to_save.isEmpty() == false) {
1008: Iterator iter = m_groups_to_save.iterator();
1009:
1010: while (iter.hasNext()) {
1011: try {
1012: AbstractParentObject parent = (AbstractParentObject) ((CachePointer) iter
1013: .next()).getObject();
1014:
1015: parent.saveNonCoreData();
1016: } catch (CacheException e) {
1017: throw new EditException(
1018: "Error occurred getting object from cache:",
1019: e);
1020: }
1021: }
1022:
1023: m_groups_to_save.clear();
1024: }
1025: }
1026:
1027: /* (non-Javadoc)
1028: * @see org.openharmonise.rm.resources.AbstractObject#fullPopulate()
1029: */
1030: protected void fullPopulate() throws PopulateException {
1031: if (m_bIsGroupsPopulated == false) {
1032: populateGroupsFromDatabase();
1033: }
1034:
1035: super .fullPopulate();
1036: }
1037:
1038: /**
1039: * Populates this object's store of parents from database.
1040: *
1041: * @throws PopulateException if an error occurs populating this object
1042: */
1043: protected void populateGroupsFromDatabase()
1044: throws PopulateException {
1045: if (m_bIsPopulated == false) {
1046: populateFromDatabase();
1047: }
1048:
1049: if (this .m_bIsGroupsPopulated == true) {
1050: return;
1051: }
1052:
1053: if (m_groups == null) {
1054: m_groups = new HashMap();
1055: }
1056:
1057: if (this .m_nId != AbstractObject.NOTDBSAVED_ID) {
1058: SelectStatement select = new SelectStatement();
1059:
1060: ColumnRef typeColref;
1061: ColumnRef idColref;
1062: ColumnRef defaultColref;
1063: try {
1064: idColref = AbstractObject.getColumnRef(
1065: getParentObjectClassName(), ATTRIB_ID);
1066: defaultColref = getParentChildJoinColumnRef(ATTRIB_DEFAULT);
1067: getInstanceColumnRef(
1068: AbstractChildObject.ATTRIB_DEFAULT, false);
1069: typeColref = AbstractObject.getColumnRef(
1070: getParentObjectClassName(), ATTRIB_TYPE);
1071:
1072: select.addSelectColumn(idColref); //1
1073: select.addSelectColumn(defaultColref); //2
1074: select.addSelectColumn(typeColref); //3
1075:
1076: Collection coreRefs = AbstractParentObject
1077: .getCoreColumnRefs(this
1078: .getParentObjectClassName());
1079: Iterator iter = coreRefs.iterator();
1080:
1081: while (iter.hasNext() == true) {
1082: select.addSelectColumn((ColumnRef) iter.next());
1083: }
1084:
1085: // key in the group table
1086: ColumnRef joinColumn1 = AbstractObject.getColumnRef(
1087: getParentObjectClassName(),
1088: AbstractObject.ATTRIB_KEY);
1089:
1090: // key for the group in the join table
1091: ColumnRef joinColumn2 = getParentChildJoinColumnRef(TAG_GROUP);
1092: select.addJoinCondition(joinColumn1, joinColumn2);
1093:
1094: ColumnRef whereColumn = getParentChildJoinColumnRef(AbstractParentObject.TAG_CHILDREN);
1095:
1096: select
1097: .addWhereCondition(whereColumn, "=",
1098: m_nObjectKey);
1099: } catch (DataStoreException ds_e) {
1100: throw new PopulateException(
1101: "Error occured building query:", ds_e);
1102: }
1103:
1104: ResultSet rs = null;
1105:
1106: try {
1107:
1108: rs = m_dsi.execute(select);
1109:
1110: while (rs.next()) {
1111: int nId = rs.getInt(idColref.getColumn());
1112:
1113: AbstractParentObject tmpDSO = (AbstractParentObject) HarmoniseObjectFactory
1114: .instantiatePublishableObject(this .m_dsi,
1115: rs
1116: .getString(typeColref
1117: .getColumn()), nId);
1118:
1119: addEditEventListener(tmpDSO);
1120:
1121: try {
1122: CachePointer pointer = CacheHandler
1123: .getInstance(m_dsi).getCachePointer(
1124: tmpDSO);
1125:
1126: if (tmpDSO.isPopulated() == false) {
1127: tmpDSO.populateFromResultSetRow(rs, select);
1128: }
1129:
1130: m_groups.put(String.valueOf(nId), pointer);
1131:
1132: if (rs.getBoolean(defaultColref.getColumn()) == true) {
1133: this .m_defaultGroup = nId;
1134: }
1135: } catch (CacheException e1) {
1136: throw new PopulateException(
1137: "Had problems getting pointer from cache",
1138: e1);
1139: }
1140: }
1141:
1142: m_bIsGroupsPopulated = true;
1143: } catch (SQLException e) {
1144: throw new PopulateException(
1145: "Error occured processing query", e);
1146: } catch (HarmoniseFactoryException e) {
1147: throw new PopulateException(
1148: "Error instantiatiing new parent object", e);
1149: } catch (DataStoreException e) {
1150: throw new PopulateException(
1151: "Error occured processing query", e);
1152: } finally {
1153: if (rs != null) {
1154: try {
1155: rs.close();
1156: } catch (SQLException sql_e) {
1157: throw new PopulateException(
1158: "Error occured closing result set",
1159: sql_e);
1160: }
1161: }
1162: }
1163: }
1164: }
1165:
1166: /**
1167: * Creates an <code>AbstractParentObject</code> from the specified path.
1168: *
1169: * @param sFullPath the path describing the location of the parent object
1170: * @return the parent object
1171: * @throws EditException if an error occurs creating the object
1172: */
1173: protected AbstractParentObject createGroupFromPath(String sFullPath)
1174: throws EditException {
1175: AbstractParentObject group = null;
1176: ResultSet rs = null;
1177:
1178: String sGroupName = sFullPath.substring(sFullPath
1179: .lastIndexOf('/') + 1);
1180: String sPath = sFullPath.substring(0, sFullPath
1181: .lastIndexOf('/'));
1182:
1183: //first try get group from the factory, i.e. from live table
1184: try {
1185: group = (AbstractParentObject) HarmoniseObjectFactory
1186: .instantiateHarmoniseObject(m_dsi, this
1187: .getParentObjectClassName(), sFullPath);
1188: } catch (HarmoniseFactoryException e) {
1189: throw new EditException(
1190: "Error occured getting object from factory", e);
1191: }
1192:
1193: // if we didn't find it, look in history
1194: if (group == null) {
1195: Class groupClass;
1196: try {
1197: // create an archived version of the group to use to find archived groups
1198: groupClass = Class.forName(getParentObjectClassName());
1199: Class[] paramTypesHistory = {
1200: AbstractDataStoreInterface.class, boolean.class };
1201: java.lang.reflect.Constructor ctorHistory = groupClass
1202: .getConstructor(paramTypesHistory);
1203: Object[] paramsHistory = { m_dsi, new Boolean(true) };
1204: AbstractParentObject archivedGroupObject = (AbstractParentObject) ctorHistory
1205: .newInstance(paramsHistory);
1206:
1207: // get all the constructors we need
1208: Class[] paramTypes = {
1209: AbstractDataStoreInterface.class, int.class,
1210: boolean.class };
1211: java.lang.reflect.Constructor ctorExists = groupClass
1212: .getConstructor(paramTypes);
1213:
1214: // find the group in history
1215: SelectStatement select = new SelectStatement();
1216: select.addSelectColumn(archivedGroupObject
1217: .getInstanceColumnRef(AbstractObject.ATTRIB_ID,
1218: false));
1219: select.addSelectColumn(archivedGroupObject
1220: .getInstanceColumnRef(
1221: AbstractObject.ATTRIB_KEY, false));
1222: select.addWhereCondition(archivedGroupObject
1223: .getInstanceColumnRef(CLMN_PATH, false), "=",
1224: sPath);
1225: select.addWhereCondition(archivedGroupObject
1226: .getInstanceColumnRef(TAG_NAME, false), "=",
1227: sGroupName);
1228:
1229: rs = m_dsi.execute(select);
1230:
1231: if (rs.next()) {
1232: Object[] params = { m_dsi,
1233: new Integer(rs.getInt(1)),
1234: new Boolean(true) };
1235: group = (AbstractParentObject) ctorExists
1236: .newInstance(params);
1237: group.setKey(rs.getInt(2));
1238:
1239: AbstractChildObject reactivated = (AbstractChildObject) group
1240: .reactivate();
1241:
1242: AbstractParentObject parent = createGroupFromPath(sPath);
1243:
1244: parent.acquireEditWriteLock();
1245: try {
1246: parent.addChild(reactivated);
1247:
1248: parent.saveNonCoreData();
1249: } finally {
1250: parent.releaseEditWriteLock();
1251: }
1252: }
1253:
1254: rs.close();
1255: } catch (SecurityException e1) {
1256: throw new EditException("Security exception", e1);
1257: } catch (IllegalArgumentException e1) {
1258: throw new EditException("IllegalArgumentException", e1);
1259: } catch (InvalidChildException e1) {
1260: throw new EditException("InvalidGroupException", e1);
1261: } catch (PopulateException e1) {
1262: throw new EditException("PopulateException", e1);
1263: } catch (ClassNotFoundException e1) {
1264: throw new EditException("ClassNotFoundException", e1);
1265: } catch (NoSuchMethodException e1) {
1266: throw new EditException("NoSuchMethodException", e1);
1267: } catch (InstantiationException e1) {
1268: throw new EditException("InstantiationException", e1);
1269: } catch (IllegalAccessException e1) {
1270: throw new EditException("IllegalAccessException", e1);
1271: } catch (InvocationTargetException e1) {
1272: throw new EditException("InvocationTargetException", e1);
1273: } catch (DataStoreException e1) {
1274: throw new EditException("DataStoreException", e1);
1275: } catch (SQLException e1) {
1276: throw new EditException("SQLException", e1);
1277: }
1278:
1279: // if we still haven't found it, it doesn't exist anywhere,
1280: // create a new one with the same name
1281: if (group == null) {
1282: try {
1283: Class[] dsiParamTypes = { AbstractDataStoreInterface.class };
1284: java.lang.reflect.Constructor ctorNew = groupClass
1285: .getConstructor(dsiParamTypes);
1286: Object[] params = { m_dsi };
1287: group = (AbstractParentObject) ctorNew
1288: .newInstance(params);
1289:
1290: group.setName(sGroupName);
1291:
1292: // save and approve it
1293: group.save();
1294:
1295: AbstractParentObject parent = createGroupFromPath(sPath);
1296:
1297: parent.acquireEditWriteLock();
1298: try {
1299: parent.addChild(group);
1300:
1301: parent.save();
1302: } finally {
1303: parent.releaseEditWriteLock();
1304: }
1305:
1306: group.changeStatus(Status.APPROVED);
1307: } catch (SecurityException e2) {
1308: throw new EditException("Security exception:"
1309: + e2.getLocalizedMessage());
1310: } catch (IllegalArgumentException e2) {
1311: throw new EditException("IllegalArgumentException:"
1312: + e2.getLocalizedMessage());
1313: } catch (InvalidChildException e2) {
1314: throw new EditException("InvalidGroupException:"
1315: + e2.getLocalizedMessage());
1316: } catch (PopulateException e2) {
1317: throw new EditException("PopulateException:"
1318: + e2.getLocalizedMessage());
1319: } catch (NoSuchMethodException e2) {
1320: throw new EditException("NoSuchMethodException:"
1321: + e2.getLocalizedMessage());
1322: } catch (InstantiationException e2) {
1323: throw new EditException("InstantiationException:"
1324: + e2.getLocalizedMessage());
1325: } catch (IllegalAccessException e2) {
1326: throw new EditException("IllegalAccessException:"
1327: + e2.getLocalizedMessage());
1328: } catch (InvocationTargetException e2) {
1329: throw new EditException(
1330: "InvocationTargetException:"
1331: + e2.getLocalizedMessage());
1332: } catch (InvalidNameException e) {
1333: throw new EditException(
1334: "InvocationTargetException:"
1335: + e.getLocalizedMessage());
1336: }
1337: }
1338: }
1339:
1340: return group;
1341: }
1342:
1343: /* (non-Javadoc)
1344: * @see org.openharmonise.rm.resources.AbstractEditableObject#addDataToSave(org.openharmonise.commons.dsi.dml.InsertStatement)
1345: */
1346: protected void addDataToSave(InsertStatement insert)
1347: throws DataStoreException {
1348:
1349: if (isHistorical() == true) {
1350: try {
1351: insert.addColumnValue(this .getInstanceColumnRef(
1352: TAG_PATH, true), getPath());
1353: } catch (DataAccessException e) {
1354: throw new DataStoreException(
1355: "Error occured getting path", e);
1356: }
1357: }
1358:
1359: super .addDataToSave(insert);
1360: }
1361:
1362: /**
1363: * Returns the column reference for a column in the parent-child
1364: * relationship table.
1365: *
1366: * @param sCol the column, tag or attribute name
1367: * @return the corresponding column reference
1368: * @throws DataStoreException if an error occurs getting the column reference
1369: * @throws InvalidColumnReferenceException if the given column name is
1370: * invalid
1371: */
1372: protected ColumnRef getParentChildJoinColumnRef(String sCol)
1373: throws DataStoreException {
1374: ColumnRef colref = null;
1375:
1376: String sGroupTableName = null;
1377:
1378: sGroupTableName = DatabaseInfo.getInstance().getTableName(
1379: getParentObjectClassName());
1380:
1381: StringBuffer sbuf = new StringBuffer(sGroupTableName).append(
1382: JOIN_TO).append(getDBTableName());
1383:
1384: String sTable = sbuf.toString();
1385:
1386: if (sCol.equals(CLMN_CHILD_KEY) == true
1387: || sCol.equals(AbstractParentObject.TAG_CHILDREN)) {
1388: colref = new ColumnRef(sTable, CLMN_CHILD_KEY,
1389: ColumnRef.NUMBER);
1390: } else if (sCol.equals(CLMN_PARENT_KEY) == true
1391: || sCol.equals(TAG_GROUP) == true) {
1392: colref = new ColumnRef(sTable, CLMN_PARENT_KEY,
1393: ColumnRef.NUMBER);
1394: } else if (sCol.equals(CLMN_DATE) == true) {
1395: colref = new ColumnRef(sTable, CLMN_DATE, ColumnRef.DATE);
1396: } else if (sCol.equals(CLMN_DEFAULT_LINK) == true
1397: || sCol.equals(ATTRIB_DEFAULT) == true) {
1398: colref = new ColumnRef(sTable, CLMN_DEFAULT_LINK,
1399: ColumnRef.NUMBER);
1400: }
1401:
1402: if (colref == null) {
1403: throw new InvalidColumnReferenceException();
1404: }
1405:
1406: return colref;
1407: }
1408:
1409: /**
1410: * Adds the specified parent object to this child's list of parents
1411: *
1412: * @param group the new parent object
1413: * @throws PopulateException if there is an erorr populating the list of
1414: * parent objects
1415: */
1416: protected void addParent(AbstractParentObject group)
1417: throws PopulateException {
1418: if (this .m_bIsGroupsPopulated == false) {
1419: populateGroupsFromDatabase();
1420: }
1421:
1422: try {
1423: CachePointer ptr = CacheHandler.getInstance(m_dsi)
1424: .getCachePointer(group);
1425:
1426: if (m_groups.containsValue(group) == false) {
1427: m_groups.put(String.valueOf(group.getId()), ptr);
1428: }
1429: } catch (CacheException e) {
1430: throw new PopulateException("cache pointer problem", e);
1431: }
1432: }
1433:
1434: /**
1435: * Removes the specified parent object from this child's list of parents.
1436: *
1437: * @param group the parent object to remove
1438: * @throws PopulateException if there is an erorr populating the list of
1439: * parent objects
1440: */
1441: protected void removeParent(AbstractParentObject group)
1442: throws PopulateException {
1443: if (this .m_bIsGroupsPopulated == false) {
1444: this .populateGroupsFromDatabase();
1445: }
1446:
1447: String sKey = String.valueOf(group.getId());
1448:
1449: if (m_groups.containsKey(sKey) == true) {
1450: m_groups.remove(m_groups.get(sKey));
1451: }
1452: }
1453:
1454: /**
1455: * Returns the name of the class that may act as parent to this object.
1456: *
1457: * @return the name of the class that may act as parent to this object
1458: */
1459: abstract public String getParentObjectClassName();
1460:
1461: /**
1462: * Adds and sets the given parent object as the 'real'/default
1463: * parent of this child object.
1464: *
1465: * @param group the default parent object
1466: * @throws PopulateException if there is an error adding this
1467: * parent object
1468: */
1469: protected void setRealParent(AbstractParentObject group)
1470: throws PopulateException {
1471:
1472: int nId = group.getId();
1473: String sId = String.valueOf(nId);
1474:
1475: addParent(group);
1476:
1477: m_defaultGroup = nId;
1478: }
1479:
1480: /* (non-Javadoc)
1481: * @see org.openharmonise.rm.resources.lifecycle.Editable#changeStatus(org.openharmonise.rm.resources.lifecycle.Status)
1482: */
1483: public Editable changeStatus(Status status) throws EditException {
1484:
1485: Editable result = null;
1486:
1487: try {
1488: if (getStatus() == Status.UNAPPROVED
1489: && status == Status.APPROVED) {
1490: AbstractChildObject live = (AbstractChildObject) this
1491: .getLiveVersion();
1492:
1493: if (live != null) {
1494:
1495: List parents = live.getParents();
1496: AbstractParentObject realParent = live
1497: .getRealParent();
1498:
1499: //get index position in parent collections
1500: Map posMap = new Hashtable();
1501:
1502: Iterator parentIter = parents.iterator();
1503:
1504: while (parentIter.hasNext()) {
1505: AbstractParentObject tmpParent = (AbstractParentObject) parentIter
1506: .next();
1507: posMap.put(tmpParent, new Integer(tmpParent
1508: .indexOf(live)));
1509: }
1510:
1511: result = super .changeStatus(status);
1512:
1513: Iterator iter = parents.iterator();
1514:
1515: while (iter.hasNext()) {
1516: AbstractParentObject tmpParent = (AbstractParentObject) iter
1517: .next();
1518: int nPos = ((Integer) posMap.get(tmpParent))
1519: .intValue();
1520:
1521: tmpParent.acquireEditWriteLock();
1522: try {
1523: if (tmpParent.equals(realParent) == true) {
1524: tmpParent.addChild(nPos, this );
1525: } else {
1526: tmpParent.addChild(nPos, this , true);
1527: }
1528:
1529: tmpParent.saveNonCoreData();
1530: } finally {
1531: tmpParent.releaseEditWriteLock();
1532: }
1533: }
1534: } else {
1535: result = super .changeStatus(status);
1536: }
1537:
1538: } else {
1539: result = super .changeStatus(status);
1540: }
1541: } catch (DataAccessException e) {
1542: throw new EditException(e.getLocalizedMessage(), e);
1543: } catch (InvalidChildException e) {
1544: throw new EditException(e.getLocalizedMessage(), e);
1545: } catch (PopulateException e) {
1546: throw new EditException(e.getLocalizedMessage(), e);
1547: }
1548:
1549: return result;
1550: }
1551:
1552: /* (non-Javadoc)
1553: * @see org.openharmonise.rm.resources.lifecycle.Editable#archive()
1554: */
1555: public Editable archive() throws EditException {
1556: try {
1557: AbstractParentObject parent = getRealParent();
1558:
1559: if (parent != null
1560: && parent.getArchivedChildByName(m_sName) != null) {
1561:
1562: Date now = new Date();
1563: SimpleDateFormat format = new SimpleDateFormat(
1564: ARCHIVE_TIMESTAMP_FORMAT);
1565:
1566: StringBuffer sbuf = new StringBuffer();
1567:
1568: sbuf.append(m_sName).append("_").append(
1569: format.format(now));
1570:
1571: m_sName = sbuf.toString();
1572: }
1573:
1574: m_sPath = getPath();
1575: } catch (DataAccessException e) {
1576: throw new EditException(e.getLocalizedMessage(), e);
1577: }
1578:
1579: return super .archive();
1580: }
1581:
1582: /* (non-Javadoc)
1583: * @see org.openharmonise.rm.resources.AbstractObject#addColumnsToPopulateQuery(org.openharmonise.commons.dsi.dml.SelectStatement, boolean)
1584: */
1585: protected void addColumnsToPopulateQuery(SelectStatement select,
1586: boolean bIsHist) throws DataStoreException {
1587: if (isHistorical() == true) {
1588: select
1589: .addSelectColumn(getInstanceColumnRef(TAG_PATH,
1590: true));
1591: }
1592: super .addColumnsToPopulateQuery(select, bIsHist);
1593: }
1594:
1595: /* (non-Javadoc)
1596: * @see org.openharmonise.rm.resources.AbstractObject#populateFromResultSetRow(java.sql.ResultSet, org.openharmonise.commons.dsi.dml.SelectStatement)
1597: */
1598: protected void populateFromResultSetRow(ResultSet rs,
1599: SelectStatement select) throws PopulateException {
1600: if (isHistorical() == true) {
1601: try {
1602: ColumnRef pathRef = getInstanceColumnRef(TAG_PATH, true);
1603:
1604: if (select.containsSelectColumn(pathRef) == true) {
1605: m_sPath = rs.getString(select
1606: .getResultSetIndex(pathRef));
1607: }
1608: } catch (DataStoreException e) {
1609: throw new PopulateException(e.getLocalizedMessage(), e);
1610: } catch (SQLException e) {
1611: throw new PopulateException(e.getLocalizedMessage(), e);
1612: }
1613: }
1614: super .populateFromResultSetRow(rs, select);
1615: }
1616:
1617: /* (non-Javadoc)
1618: * @see org.openharmonise.rm.resources.lifecycle.Editable#reactivate()
1619: */
1620: public Editable reactivate() throws EditException {
1621:
1622: AbstractParentObject parent = null;
1623:
1624: try {
1625: if (getLiveVersion() == null) {
1626: parent = getRealParent();
1627: }
1628: } catch (DataAccessException e) {
1629: throw new EditException(e.getLocalizedMessage(), e);
1630: }
1631:
1632: AbstractChildObject child = (AbstractChildObject) super
1633: .reactivate();
1634:
1635: try {
1636: if (parent != null) {
1637: parent.acquireEditWriteLock();
1638: try {
1639: parent.addChild(child);
1640: parent.saveNonCoreData();
1641: } finally {
1642: parent.releaseEditWriteLock();
1643: }
1644: }
1645: } catch (InvalidChildException e) {
1646: throw new EditException(e.getLocalizedMessage(), e);
1647: } catch (PopulateException e) {
1648: throw new EditException(e.getLocalizedMessage(), e);
1649: }
1650:
1651: return child;
1652: }
1653:
1654: /**
1655: * Returns the class name of parent object for the given
1656: * child object of type <i>sChildClassname</i>.
1657: *
1658: * @param sChildClassname the child object class name
1659: * @return the class name of parent object
1660: * @throws DataAccessException if an error occurs
1661: */
1662: static public String getParentObjectClassName(String sChildClassname)
1663: throws DataAccessException {
1664:
1665: String sParentClassName = (String) m_child_parent_mappings
1666: .get(sChildClassname);
1667:
1668: try {
1669: if (sParentClassName == null) {
1670: Class clss = Class.forName(sChildClassname);
1671:
1672: if (AbstractChildObject.class.isAssignableFrom(clss)) {
1673:
1674: AbstractChildObject child = (AbstractChildObject) clss
1675: .newInstance();
1676:
1677: sParentClassName = child.getParentObjectClassName();
1678: m_child_parent_mappings.put(sChildClassname,
1679: sParentClassName);
1680: }
1681: }
1682: } catch (InstantiationException e) {
1683: throw new DataAccessException(e);
1684: } catch (IllegalAccessException e) {
1685: throw new DataAccessException(e);
1686: } catch (ClassNotFoundException e) {
1687: throw new DataAccessException(e);
1688: }
1689:
1690: return sParentClassName;
1691: }
1692:
1693: }
|