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.metadata.properties.domains;
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.dsi.dml.functions.*;
0028: import org.openharmonise.commons.xml.XMLUtils;
0029: import org.openharmonise.rm.*;
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.Property;
0035: import org.openharmonise.rm.resources.publishing.Template;
0036: import org.w3c.dom.*;
0037:
0038: /**
0039: * This class represents a property domain which can be associated to
0040: * a <code>Property</code> can apply to within Harmonise. A
0041: * property domain defines the set of objects that may have an instance
0042: * of the associated property. The domain may be restricted by object type, path
0043: * and content type.
0044: *
0045: * @author Michael Bell
0046: * @version $Revision: 1.3 $
0047: *
0048: */
0049: public class Domain implements Publishable, Cloneable {
0050:
0051: /**
0052: * Path restriction XML tag name
0053: */
0054: public String TAG_PATHRESTRICTION = "PathRestriction";
0055:
0056: /**
0057: * <code>int</code> constant for representing an unbounded value
0058: */
0059: public static final int UNBOUNDED = -1;
0060:
0061: //XML constants
0062: /**
0063: * Domain tag name
0064: */
0065: public static final String TAG_DOMAIN = "Domain";
0066:
0067: /**
0068: * Domain object tag name
0069: */
0070: public static final String TAG_DOMAIN_OBJECT = "DomainObject";
0071:
0072: /**
0073: * Domain details tag name
0074: */
0075: public static final String TAG_DOMAIN_DETAILS = "DomainDetails";
0076: /**
0077: * Domain details tag name
0078: */
0079: public static final String TAG_PATH = "Path";
0080: /**
0081: * Domain details tag name
0082: */
0083: public static final String TAG_CONTENT_RESTRICTIONS = "ContentRestrictions";
0084: /**
0085: * Minimum occurance attribute name
0086: */
0087: public static final String ATTRIB_MIN_OCCURS = "minOccurs";
0088:
0089: /**
0090: * Maximum occurance attribute name
0091: */
0092: public static final String ATTRIB_MAX_OCCURS = "maxOccurs";
0093:
0094: /**
0095: * Depth attribute name
0096: */
0097: public static final String ATTRIB_DEPTH = "depth";
0098:
0099: //DB constants
0100: /**
0101: * Domain id database sequence name
0102: */
0103: public static final String SEQ_DOMAIN = "seq_property_domain";
0104:
0105: /**
0106: * Domain database table name
0107: */
0108: public static final String TBL_NAME = "property_domain";
0109:
0110: /**
0111: * Domain details database column name
0112: */
0113: public static final String TBL_DOMAIN_DETAILS = "domain_details";
0114:
0115: /**
0116: * Domain content restrictions database table name
0117: */
0118: public static final String TBL_DOMAIN_CONTENT_RESTRICTIONS = "domain_content_details";
0119:
0120: /**
0121: * Domain id database column name
0122: */
0123: public static final String CLMN_DOMAIN_ID = "id";
0124:
0125: /**
0126: * Domain id database column name in the domain detail table
0127: */
0128: public static final String CLMN_DETAILS_DOMAIN_ID = "domain_id";
0129:
0130: /**
0131: * Content type database column name
0132: */
0133: public static final String CLMN_CONTENT_TYPE = "content_type";
0134:
0135: /**
0136: * Domain object database column name
0137: */
0138: public static final String CLMN_DOMAIN_OBJECT = "domain_object";
0139:
0140: /**
0141: * Domain details database column name.
0142: */
0143: public static final String CLMN_DOMAIN_DETAILS = "domain_details";
0144:
0145: /**
0146: * Property key database column name
0147: */
0148: public static final String CLMN_PROPERTY_KEY = "property_key";
0149:
0150: /**
0151: * Minimum occurance database column name
0152: */
0153: public static final String CLMN_MIN_OCCURS = "minOccurs";
0154:
0155: /**
0156: * Maximum occurance databse column name
0157: */
0158: public static final String CLMN_MAX_OCCURS = "maxOccurs";
0159:
0160: /**
0161: * Depth database column name
0162: */
0163: public static final String CLMN_DEPTH = "depth";
0164:
0165: /**
0166: * Map of child class to parent classes. Used to cache info.
0167: */
0168: public static Map m_child_parent_mappings = new Hashtable();
0169:
0170: /**
0171: * Id of this domain
0172: */
0173: private int m_nId = -1;
0174:
0175: /**
0176: * Class name for objects in this domain
0177: */
0178: private String m_sObjectName = null;
0179:
0180: /**
0181: * List of domain details. Specifies the paths to the parent
0182: * objects which are the ancestors of all objects included in this
0183: * domain
0184: */
0185: private List m_details = null;
0186:
0187: /**
0188: * List of content restrictions, mime types, for this domain. For example,
0189: * a domain may specify only resources which are 'image/jpeg'
0190: */
0191: private List m_contentRestrictions = null;
0192:
0193: /**
0194: * Minimum occurance of the property associated to this domain on a resource
0195: * in this domain.
0196: */
0197: private int m_nMinOccurs = 0;
0198:
0199: /**
0200: * Maximum occurance of the property associated to this domain on a resource
0201: * in this domain.
0202: *
0203: * Note: A value of -1 signifies an unbounded limit
0204: */
0205: private int m_nMaxOccurs = -1;
0206:
0207: /**
0208: * <code>boolean</code> indicating whether the list of domain details has been
0209: * populated.
0210: */
0211: private boolean m_bIsDetailsPopulated = false;
0212:
0213: /**
0214: * <code>boolean</code> indicating whether the list of content restrictions
0215: * has been populated.
0216: */
0217: private boolean m_bIsContentRestrictPopulated = false;
0218:
0219: /**
0220: * <code>boolean</code> indicating whether this domain is a historical version
0221: */
0222: private boolean m_bIsHistorical = false;
0223:
0224: /**
0225: * Data store interface for this domain
0226: */
0227: private AbstractDataStoreInterface m_dsi = null;
0228:
0229: /**
0230: * The depth restriction from the collections defined by the domain details
0231: * that determine the scope of this domain
0232: *
0233: */
0234: private int m_nDepth = -1;
0235:
0236: /**
0237: * <code>boolean</code> indicating whether this domain has been changed since
0238: * being populated from the database
0239: */
0240: private boolean m_bIsChanged = false;
0241:
0242: /**
0243: * Logger for this class
0244: */
0245: private static final Logger m_logger = Logger
0246: .getLogger(Domain.class.getName());
0247:
0248: /**
0249: * Constructs a <code>Domain</code> with no details and no interface to the
0250: * database.
0251: *
0252: */
0253: public Domain() {
0254: }
0255:
0256: /**
0257: * Constructs a <code>Domain</code> with an interface to the database.
0258: *
0259: * @param dsi the data store interface
0260: */
0261: public Domain(AbstractDataStoreInterface dsi) {
0262: m_dsi = dsi;
0263: }
0264:
0265: /**
0266: * Constructs a <code>Domain</code> with an interface to the database with a
0267: * class name restriction.
0268: *
0269: * @param dsi the data store interface
0270: * @param sClassName the class name restriction
0271: */
0272: public Domain(AbstractDataStoreInterface dsi, String sClassName) {
0273: m_dsi = dsi;
0274: m_sObjectName = sClassName;
0275: }
0276:
0277: /**
0278: * Constructs a known <code>Domain</code> from an id.
0279: *
0280: * @param dsi the data store interface
0281: * @param nId the domain id
0282: *
0283: */
0284: public Domain(AbstractDataStoreInterface dsi, int nId) {
0285: m_dsi = dsi;
0286: m_nId = nId;
0287: }
0288:
0289: /**
0290: * Marks this domain as new.
0291: *
0292: */
0293: public void markAsNew() {
0294: m_nId = -1;
0295: }
0296:
0297: /**
0298: * Returns the id of this domain.
0299: *
0300: * @return the id of this domain
0301: */
0302: public int getId() {
0303: return m_nId;
0304: }
0305:
0306: /**
0307: * Sets the id of this domain.
0308: *
0309: * @param nId the id of this domain
0310: */
0311: public void setId(int nId) {
0312: m_nId = nId;
0313: }
0314:
0315: /**
0316: * Returns the depth restiction on this domain.
0317: *
0318: * @return the depth restiction on this domain
0319: */
0320: public int getDepth() {
0321: return m_nDepth;
0322: }
0323:
0324: /**
0325: * Sets the depth of this domain.
0326: *
0327: * @param nId the depth of this domain
0328: */
0329: public void setDepth(int nDepth) {
0330: m_nDepth = nDepth;
0331: }
0332:
0333: /**
0334: * Returns the name of the <code>Class</code> restriction for this domain.
0335: *
0336: * @return the name of the <code>Class</code> restriction for this domain
0337: */
0338: public String getDomainClass() {
0339: return m_sObjectName;
0340: }
0341:
0342: /**
0343: * Sets the <code>Class</code> restriction for this domain.
0344: *
0345: * @param the name of the <code>Class</code> restriction for this domain
0346: */
0347: public void setDomainClass(String objectName) {
0348: this .m_sObjectName = objectName;
0349: }
0350:
0351: /**
0352: * Returns the list of path restrictions for this domain.
0353: *
0354: * @return the list of path restrictions for this domain.
0355: * @throws DataAccessException if an error occurs populating
0356: * the data from the database
0357: */
0358: public List getDetails() throws DataAccessException {
0359: if (m_bIsDetailsPopulated == false) {
0360: try {
0361: populateDetails();
0362: } catch (DataStoreException e) {
0363: throw new DataAccessException(
0364: "Error populating details", e);
0365: }
0366: }
0367:
0368: try {
0369: List detailsToRemove = new ArrayList();
0370:
0371: ListIterator iter = m_details.listIterator();
0372:
0373: String domainClassName = getDomainClass();
0374: String parentClassName = domainClassName;
0375:
0376: Class domainClass = Class.forName(domainClassName);
0377:
0378: if (AbstractParentObject.class
0379: .isAssignableFrom(domainClass) == false) {
0380:
0381: parentClassName = (String) m_child_parent_mappings
0382: .get(domainClass);
0383:
0384: if (parentClassName == null) {
0385: parentClassName = ((AbstractChildObject) domainClass
0386: .newInstance()).getParentObjectClassName();
0387: m_child_parent_mappings.put(domainClass,
0388: parentClassName);
0389: }
0390:
0391: }
0392:
0393: while (iter.hasNext()) {
0394: String sDetail = (String) iter.next();
0395: AbstractObject obj = HarmoniseObjectFactory
0396: .instantiateHarmoniseObject(m_dsi,
0397: parentClassName, sDetail);
0398:
0399: if (obj == null || obj.exists() == false) {
0400: detailsToRemove.add(sDetail);
0401: iter.remove();
0402: }
0403: }
0404:
0405: if (detailsToRemove.size() > 0) {
0406: DeleteStatement delete = new DeleteStatement();
0407:
0408: delete.addWhereCondition(getDetailsColumnRef(
0409: CLMN_DOMAIN_DETAILS, m_bIsHistorical), "IN",
0410: detailsToRemove);
0411:
0412: m_dsi.execute(delete);
0413: }
0414: } catch (HarmoniseFactoryException e) {
0415: throw new DataAccessException(e);
0416: } catch (DataStoreException e) {
0417: throw new DataAccessException(e);
0418: } catch (ClassNotFoundException e) {
0419: throw new DataAccessException(e);
0420: } catch (InstantiationException e) {
0421: throw new DataAccessException(e);
0422: } catch (IllegalAccessException e) {
0423: throw new DataAccessException(e);
0424: }
0425:
0426: return m_details;
0427: }
0428:
0429: /**
0430: * Adds a path restriction to this domain.
0431: *
0432: * @param sDetails the path restriction to add
0433: * @throws if an error occurs populating this domain
0434: */
0435: public void addDetails(String sDetails) throws PopulateException {
0436: if (m_bIsDetailsPopulated == false) {
0437: try {
0438: populateDetails();
0439: } catch (DataStoreException e) {
0440: throw new PopulateException("Error populating details",
0441: e);
0442: }
0443: }
0444:
0445: if (m_details.contains(sDetails) == false) {
0446: m_details.add(sDetails);
0447: m_bIsChanged = true;
0448: }
0449: }
0450:
0451: /**
0452: * Returns <code>true</code> if this domain has changed since being
0453: * populated from the database.
0454: *
0455: * @return <code>true</code> if this domain has changed
0456: */
0457: public boolean isChanged() {
0458: return m_bIsChanged;
0459: }
0460:
0461: /**
0462: * Returns the list of content restrictions on this domain.
0463: *
0464: * @return the list of content restrictions on this domain
0465: * @throws DataAccessException if an error occurs populating this
0466: * domain
0467: */
0468: public List getContentRestrictions() throws DataAccessException {
0469: if (m_bIsContentRestrictPopulated == false) {
0470: try {
0471: populateContentRestrictions();
0472: } catch (DataStoreException e) {
0473: throw new DataAccessException(
0474: "Error populating details", e);
0475: }
0476: }
0477:
0478: return this .m_contentRestrictions;
0479: }
0480:
0481: /**
0482: * Adds a content type restriction to this domain.
0483: *
0484: * @param sDetails the content type restriction to add
0485: * @throws PopulateException if an error occurs populating this object
0486: */
0487: public void addContentTypeRestriction(String sContentType)
0488: throws PopulateException {
0489: if (m_bIsDetailsPopulated == false) {
0490: try {
0491: populateContentRestrictions();
0492: } catch (DataStoreException e) {
0493: throw new PopulateException("Error populating details",
0494: e);
0495: }
0496: }
0497:
0498: if (m_contentRestrictions.contains(sContentType) == false) {
0499: m_contentRestrictions.add(sContentType);
0500: m_bIsChanged = true;
0501: }
0502:
0503: }
0504:
0505: /**
0506: * Populates this domain with content restrictions from the DB.
0507: *
0508: * @throws DataStoreException if an error occurs quering the database
0509: */
0510: private void populateContentRestrictions()
0511: throws DataStoreException {
0512: ResultSet rs = null;
0513:
0514: if (m_bIsContentRestrictPopulated == false) {
0515:
0516: if (m_contentRestrictions == null) {
0517: m_contentRestrictions = new Vector();
0518: }
0519:
0520: SelectStatement select = new SelectStatement();
0521:
0522: select.addSelectColumn(getContentRestrictionsColumnRef(
0523: CLMN_CONTENT_TYPE, m_bIsHistorical));
0524:
0525: select.addWhereCondition(getContentRestrictionsColumnRef(
0526: CLMN_DETAILS_DOMAIN_ID, m_bIsHistorical), "=",
0527: this .m_nId);
0528:
0529: rs = m_dsi.execute(select);
0530:
0531: try {
0532: while (rs.next()) {
0533: String sDetail = rs.getString(1);
0534:
0535: m_contentRestrictions.add(sDetail);
0536: }
0537: } catch (SQLException e) {
0538: throw new DataStoreException(
0539: "Error populating domain details", e);
0540: } finally {
0541: if (rs != null) {
0542: try {
0543: rs.close();
0544: } catch (SQLException e1) {
0545: throw new DataStoreException(
0546: "Error occured closing result set", e1);
0547: }
0548: }
0549: }
0550:
0551: m_bIsContentRestrictPopulated = true;
0552: }
0553:
0554: }
0555:
0556: /**
0557: * Returns the minimum occurance limit for the property on this domain.
0558: *
0559: * @return the minimum occurance limit for the property on this domain
0560: */
0561: public int getMinOccurs() {
0562: return m_nMinOccurs;
0563: }
0564:
0565: /**
0566: * Returns the maximum occurance limit for the property on this domain.
0567: *
0568: * Note: A value of -1 signifies an unbounded limit
0569: *
0570: * @return the maximum occurance limit for the property on this domain
0571: */
0572: public int getMaxOccurs() {
0573: return m_nMaxOccurs;
0574: }
0575:
0576: /**
0577: * Sets the minimum occurance limit for the property on this domain.
0578: *
0579: * @param nMinOccurs the minimum occurance limit
0580: */
0581: public void setMinOccurs(int nMinOccurs) {
0582: m_nMinOccurs = nMinOccurs;
0583: }
0584:
0585: /**
0586: * Sets the maximum occurance limit for the property on this domain.
0587: *
0588: * @param nMinOccurs the maximum occurance limit
0589: */
0590: public void setMaxOccurs(int nMaxOccurs) {
0591: m_nMaxOccurs = nMaxOccurs;
0592: }
0593:
0594: /**
0595: * Sets whether this domain is historical.
0596: *
0597: * @param bIsHist <code>true</code> if this domain is a historical version,
0598: * otherwise <code>false</code>
0599: */
0600: public void setHistorical(boolean bIsHist) {
0601: m_bIsHistorical = bIsHist;
0602: }
0603:
0604: /* (non-Javadoc)
0605: * @see org.openharmonise.rm.publishing.Publishable#publish(org.openharmonise.rm.resources.publishing.Template, org.openharmonise.rm.publishing.HarmoniseOutput, org.openharmonise.rm.publishing.State)
0606: */
0607: public Element publish(Template template, HarmoniseOutput output,
0608: State state) throws PublishException {
0609: Element resultEl = null;
0610:
0611: try {
0612: resultEl = publish(template.getTemplateRootElement(),
0613: output, state);
0614: } catch (DataAccessException e) {
0615: throw new PublishException(e);
0616: }
0617:
0618: return resultEl;
0619: }
0620:
0621: /* (non-Javadoc)
0622: * @see org.openharmonise.rm.publishing.Publishable#publish(org.w3c.dom.Element, org.openharmonise.rm.publishing.HarmoniseOutput, org.openharmonise.rm.publishing.State)
0623: */
0624: public Element publish(Element topEl, HarmoniseOutput output,
0625: State state) throws PublishException {
0626: Element docEl = null;
0627: NodeList nodes = null;
0628: Text txt = null;
0629: String sTagName = topEl.getTagName();
0630:
0631: try {
0632:
0633: if (topEl.getTagName().equals(getTagName())) {
0634: docEl = output.createElement(getTagName());
0635:
0636: if (m_nMinOccurs > 0) {
0637: docEl.setAttribute(ATTRIB_MIN_OCCURS, String
0638: .valueOf(m_nMinOccurs));
0639: }
0640:
0641: if (m_nMaxOccurs > 0) {
0642: docEl.setAttribute(ATTRIB_MAX_OCCURS, String
0643: .valueOf(m_nMaxOccurs));
0644: }
0645:
0646: nodes = topEl.getChildNodes();
0647: } else if (sTagName.equals(TAG_DOMAIN_DETAILS)) {
0648: docEl = output.createElement(sTagName);
0649:
0650: if (m_bIsDetailsPopulated == false) {
0651: populateDetails();
0652: }
0653:
0654: Iterator iter = m_details.iterator();
0655:
0656: while (iter.hasNext()) {
0657: String sDetail = (String) iter.next();
0658: Element pathEl = output.createElement(TAG_PATH);
0659: txt = output.createTextNode(sDetail);
0660: pathEl.appendChild(txt);
0661: docEl.appendChild(pathEl);
0662: }
0663: } else if (sTagName.equals(TAG_CONTENT_RESTRICTIONS)) {
0664: docEl = output.createElement(sTagName);
0665: if (m_bIsContentRestrictPopulated == false) {
0666: populateContentRestrictions();
0667: }
0668: Iterator iter = m_contentRestrictions.iterator();
0669: while (iter.hasNext()) {
0670: String sDetail = (String) iter.next();
0671: Element pathEl = output.createElement(TAG_PATH);
0672: txt = output.createTextNode(sDetail);
0673: pathEl.appendChild(txt);
0674: docEl.appendChild(pathEl);
0675: }
0676: } else if (sTagName.equals(TAG_DOMAIN_OBJECT)) {
0677: docEl = output.createElement(sTagName);
0678: txt = output.createTextNode(getDomainClass());
0679: docEl.appendChild(txt);
0680: }
0681:
0682: // recurse through the children if there are any
0683: Element formEl;
0684: Element el;
0685:
0686: if (nodes != null) {
0687: for (int i = 0; i < nodes.getLength(); i++) {
0688: if (nodes.item(i).getNodeType() != Node.ELEMENT_NODE) {
0689: continue;
0690: }
0691:
0692: formEl = (Element) nodes.item(i);
0693: el = publish(formEl, output, state);
0694:
0695: if (el != null) {
0696: docEl.appendChild(el);
0697: }
0698: }
0699: }
0700:
0701: } catch (DataStoreException e) {
0702: throw new PublishException(e);
0703: }
0704:
0705: return docEl;
0706: }
0707:
0708: /* (non-Javadoc)
0709: * @see org.openharmonise.rm.publishing.Publishable#populate(org.w3c.dom.Element, org.openharmonise.rm.publishing.State)
0710: */
0711: public void populate(Element xmlElement, State state)
0712: throws PopulateException {
0713: String sTagName = xmlElement.getTagName();
0714: Text txt = null;
0715: String sTemp = null;
0716:
0717: if (sTagName.equals(getTagName()) == true) {
0718:
0719: String sMinOccurs = xmlElement
0720: .getAttribute(ATTRIB_MIN_OCCURS);
0721:
0722: if (sMinOccurs != null && sMinOccurs.length() > 0) {
0723: m_nMinOccurs = Integer.parseInt(sMinOccurs);
0724: }
0725:
0726: String sMaxOccurs = xmlElement
0727: .getAttribute(ATTRIB_MAX_OCCURS);
0728:
0729: if (sMaxOccurs != null && sMaxOccurs.length() > 0) {
0730: m_nMaxOccurs = Integer.parseInt(sMaxOccurs);
0731: }
0732:
0733: NodeList nodes = xmlElement.getChildNodes();
0734:
0735: for (int i = 0; i < nodes.getLength(); i++) {
0736: if (nodes.item(i).getNodeType() != Node.ELEMENT_NODE) {
0737: continue;
0738: }
0739:
0740: Element el = (Element) nodes.item(i);
0741: populate(el, state);
0742: }
0743: } else if (sTagName.equals(TAG_DOMAIN_OBJECT)) {
0744: NodeList nodes = xmlElement.getChildNodes();
0745:
0746: for (int i = 0; i < nodes.getLength(); i++) {
0747: Node node = nodes.item(i);
0748:
0749: if (node.getNodeType() == Node.TEXT_NODE) {
0750: txt = (Text) node;
0751: String sVal = txt.getNodeValue().trim();
0752:
0753: if (sVal.length() > 0) {
0754: setDomainClass(sVal);
0755: break;
0756: }
0757:
0758: } else if (node.getNodeType() == Node.ELEMENT_NODE) {
0759: try {
0760: String sClassname = HarmoniseObjectFactory
0761: .getClassName(m_dsi, (Element) node);
0762: setDomainClass(sClassname);
0763: break;
0764: } catch (HarmoniseFactoryException e) {
0765: throw new PopulateException(e);
0766: }
0767: }
0768: }
0769:
0770: } else if (sTagName.equals(TAG_DOMAIN_DETAILS)) {
0771:
0772: List nodes = XMLUtils.getChildrenByName(xmlElement,
0773: TAG_PATHRESTRICTION);
0774:
0775: for (Iterator iter = nodes.iterator(); iter.hasNext();) {
0776: Element pathEl = (Element) iter.next();
0777: txt = (Text) pathEl.getFirstChild();
0778: addDetails(txt.getNodeValue());
0779: }
0780:
0781: }
0782:
0783: }
0784:
0785: /**
0786: * Returns a <code>List</code> of <code>Property</code> definitions which can be applied
0787: * to objects of the specified <code>Class</code>.
0788: *
0789: * @param dsi the data store interface
0790: * @param clss the <code>Class</code>
0791: * @return a <code>List</code> of <code>Property</code> objects
0792: * @throws DataAccessException if an error occurs querying the data store
0793: */
0794: static public List getAvailableProperties(
0795: AbstractDataStoreInterface dsi, Class clss)
0796: throws DataAccessException {
0797: return getAvailableProperties(dsi, clss, (String) null);
0798: }
0799:
0800: /**
0801: * Returns a <code>List</code> of <code>Property</code> definitions which can be applied
0802: * to the object of the specified <code>Class</code> and path.
0803: *
0804: * @param dsi the data store interface
0805: * @param clss the <code>Class</code>
0806: * @param sPath the path of an object of the specified <code>Class</code>
0807: * @return a <code>List</code> of <code>Property</code> objects
0808: * @throws DataAccessException if an error occurs querying the data store
0809: */
0810: static public List getAvailableProperties(
0811: AbstractDataStoreInterface dsi, Class clss, String sPath)
0812: throws DataAccessException {
0813: Vector result = new Vector();
0814: ResultSet rs = null;
0815: SelectStatement select = new SelectStatement();
0816:
0817: try {
0818: select
0819: .addSelectColumn(AbstractObject.getColumnRef(
0820: Property.class.getName(),
0821: AbstractObject.ATTRIB_ID));
0822: select.addSelectColumn(AbstractObject.getColumnRef(
0823: Property.class.getName(),
0824: AbstractObject.ATTRIB_TYPE));
0825:
0826: ColumnRef colDomDetails = new ColumnRef(TBL_DOMAIN_DETAILS,
0827: CLMN_DOMAIN_DETAILS, ColumnRef.TEXT);
0828:
0829: select.addSelectColumn(colDomDetails);
0830:
0831: select.addJoinCondition(AbstractObject
0832: .getColumnRef(Property.class.getName(),
0833: AbstractObject.ATTRIB_KEY), new ColumnRef(
0834: TBL_NAME, CLMN_PROPERTY_KEY, ColumnRef.NUMBER));
0835:
0836: select.addJoinCondition(getDetailsColumnRef(
0837: CLMN_DETAILS_DOMAIN_ID, false), getColumnRef(
0838: CLMN_DOMAIN_ID, false));
0839:
0840: select.addWhereCondition(new ColumnRef(TBL_NAME,
0841: CLMN_DOMAIN_OBJECT, ColumnRef.TEXT), "=", clss
0842: .getName());
0843:
0844: if (sPath != null) {
0845: Substring substr = new Substring(sPath, new Integer(1),
0846: new Length(colDomDetails));
0847:
0848: select.addWhereCondition(colDomDetails, "=", substr);
0849: }
0850:
0851: } catch (DataStoreException e) {
0852: throw new DataAccessException(
0853: "Error occured building query", e);
0854: }
0855:
0856: try {
0857:
0858: rs = dsi.execute(select);
0859:
0860: while (rs.next()) {
0861: int nPropId = rs.getInt(1);
0862: String sPropType = rs.getString(2);
0863:
0864: Property prop = (org.openharmonise.rm.resources.metadata.properties.Property) HarmoniseObjectFactory
0865: .instantiateHarmoniseObject(dsi, sPropType,
0866: nPropId);
0867:
0868: result.add(prop);
0869:
0870: }
0871: } catch (HarmoniseFactoryException e) {
0872: throw new DataAccessException(
0873: "Error occured getting property from factory", e);
0874: } catch (DataStoreException e) {
0875: throw new DataAccessException(
0876: "Error occured executing query", e);
0877: } catch (SQLException e) {
0878: throw new DataAccessException(
0879: "Error occured executing query", e);
0880: } finally {
0881: if (rs != null) {
0882: try {
0883: rs.close();
0884: } catch (SQLException e) {
0885: m_logger.log(Level.WARNING,
0886: e.getLocalizedMessage(), e);
0887: }
0888: }
0889: }
0890:
0891: return result;
0892: }
0893:
0894: /**
0895: * Returns a <code>List</code> of <code>Property</code> definitions which can be applied
0896: * to the objects of the specified <code>Class</code> and paths.
0897: *
0898: * @param dsi the data store interface
0899: * @param clss the <code>Class</code>
0900: * @param paths the list of paths
0901: * @return a <code>List</code> of <code>Property</code> objects
0902: * @throws DataAccessException if an error occurs querying the data store
0903: */
0904: static public List getAvailableProperties(
0905: AbstractDataStoreInterface dsi, Class clss, List paths)
0906: throws DataAccessException {
0907: Vector result = new Vector();
0908: ResultSet rs = null;
0909: SelectStatement select = new SelectStatement();
0910:
0911: try {
0912: select
0913: .addSelectColumn(AbstractObject.getColumnRef(
0914: Property.class.getName(),
0915: AbstractObject.ATTRIB_ID));
0916: select.addSelectColumn(AbstractObject.getColumnRef(
0917: Property.class.getName(),
0918: AbstractObject.ATTRIB_TYPE));
0919:
0920: ColumnRef colDomDetails = new ColumnRef(TBL_DOMAIN_DETAILS,
0921: CLMN_DOMAIN_DETAILS, ColumnRef.TEXT);
0922:
0923: select.addSelectColumn(colDomDetails);
0924:
0925: select.addJoinCondition(AbstractObject
0926: .getColumnRef(Property.class.getName(),
0927: AbstractObject.ATTRIB_KEY), new ColumnRef(
0928: TBL_NAME, CLMN_PROPERTY_KEY, ColumnRef.NUMBER));
0929:
0930: select.addJoinCondition(getDetailsColumnRef(
0931: CLMN_DETAILS_DOMAIN_ID, false), getColumnRef(
0932: CLMN_DOMAIN_ID, false));
0933:
0934: select.addWhereCondition(new ColumnRef(TBL_NAME,
0935: CLMN_DOMAIN_OBJECT, ColumnRef.TEXT), "=", clss
0936: .getName());
0937:
0938: if (paths != null) {
0939:
0940: if (paths.size() == 1) {
0941: Substring substr = new Substring((String) paths
0942: .get(0), new Integer(1), new Length(
0943: colDomDetails));
0944:
0945: select
0946: .addWhereCondition(colDomDetails, "=",
0947: substr);
0948:
0949: } else if (paths.size() > 1) {
0950: WhereConditionGroup wheres = new WhereConditionGroup();
0951: wheres.setStringingOperator("or");
0952:
0953: Iterator iter = paths.iterator();
0954:
0955: while (iter.hasNext()) {
0956: String sPath = (String) iter.next();
0957:
0958: Substring substr = new Substring(sPath,
0959: new Integer(1), new Length(
0960: colDomDetails));
0961: wheres.addCondition(colDomDetails, "=", substr);
0962:
0963: }
0964: select.addWhereCondition(wheres);
0965: }
0966:
0967: }
0968:
0969: } catch (DataStoreException e) {
0970: throw new DataAccessException(
0971: "Error occured building query", e);
0972: }
0973:
0974: try {
0975:
0976: rs = dsi.execute(select);
0977:
0978: while (rs.next()) {
0979: int nPropId = rs.getInt(1);
0980: String sPropType = rs.getString(2);
0981: Property prop = (org.openharmonise.rm.resources.metadata.properties.Property) HarmoniseObjectFactory
0982: .instantiateHarmoniseObject(dsi, sPropType,
0983: nPropId);
0984:
0985: result.add(prop);
0986: }
0987: } catch (HarmoniseFactoryException e) {
0988: throw new DataAccessException(
0989: "Error occured getting property from factory", e);
0990: } catch (DataStoreException e) {
0991: throw new DataAccessException(
0992: "Error occured executing query", e);
0993: } catch (SQLException e) {
0994: throw new DataAccessException(
0995: "Error occured executing query", e);
0996: } finally {
0997: if (rs != null) {
0998: try {
0999: rs.close();
1000: } catch (SQLException e) {
1001: m_logger.log(Level.WARNING,
1002: e.getLocalizedMessage(), e);
1003: }
1004: }
1005: }
1006:
1007: return result;
1008: }
1009:
1010: /**
1011: * Returns a <code>List</code> of <code>Property</code> objects which are allowed
1012: * to be applied to the specified <code>AbstractProfiledObject</code>.
1013: *
1014: * @param dsi the data store interface
1015: * @param profObj the profiled object
1016: * @return a applicable <code>List</code> of <code>Property</code> objects
1017: * @throws DataAccessException if an error occurs querying the data store
1018: */
1019: static public List getAvailableProperties(
1020: AbstractDataStoreInterface dsi,
1021: AbstractProfiledObject profObj) throws DataAccessException {
1022: List result = null;
1023: if (profObj instanceof AbstractChildObject) {
1024: result = getAvailableProperties(dsi, profObj.getClass(),
1025: ((AbstractChildObject) profObj).getAllFullPaths());
1026: } else {
1027: result = getAvailableProperties(dsi, profObj.getClass());
1028: }
1029:
1030: return result;
1031: }
1032:
1033: /* (non-Javadoc)
1034: * @see org.openharmonise.rm.publishing.Publishable#getTagName()
1035: */
1036: public String getTagName() {
1037: return TAG_DOMAIN;
1038: }
1039:
1040: /* (non-Javadoc)
1041: * @see java.lang.Object#equals(java.lang.Object)
1042: */
1043: public boolean equals(Object obj) {
1044: boolean bResult = false;
1045:
1046: if (obj instanceof Domain) {
1047: Domain domain = (Domain) obj;
1048:
1049: if (this == domain) {
1050: bResult = true;
1051: } else {
1052: try {
1053: if (this .m_bIsContentRestrictPopulated == false) {
1054: this .populateContentRestrictions();
1055: }
1056: if (this .m_bIsDetailsPopulated == false) {
1057: this .populateDetails();
1058: }
1059:
1060: if (m_nDepth == domain.getDepth()) {
1061: if (m_nMaxOccurs == domain.getMaxOccurs()) {
1062: if (m_nMinOccurs == domain.getMinOccurs()) {
1063: if (m_sObjectName.equals(domain
1064: .getDomainClass())) {
1065: if (m_contentRestrictions
1066: .equals(domain
1067: .getContentRestrictions())) {
1068: if (m_details.equals(domain
1069: .getDetails())) {
1070: bResult = true;
1071: }
1072: }
1073: }
1074: }
1075: }
1076: }
1077:
1078: } catch (DataStoreException e) {
1079: m_logger.log(Level.WARNING,
1080: e.getLocalizedMessage(), e);
1081: } catch (DataAccessException e) {
1082: m_logger.log(Level.WARNING,
1083: e.getLocalizedMessage(), e);
1084: }
1085:
1086: }
1087:
1088: }
1089:
1090: return bResult;
1091: }
1092:
1093: /**
1094: * Saves the domain data for this property to the database.
1095: *
1096: * @param prop the <code>Property</code> assocaited to this domain
1097: * @throws EditException if an error occurs saving this domain to the
1098: * database
1099: */
1100: public void save(Property prop) throws EditException {
1101: try {
1102: InsertStatement insert = new InsertStatement();
1103:
1104: if (m_nId < 0) {
1105: m_nId = m_dsi.getSequenceNextValue(SEQ_DOMAIN);
1106: }
1107:
1108: insert.addColumnValue(getColumnRef(CLMN_DOMAIN_ID,
1109: m_bIsHistorical), m_nId);
1110:
1111: insert.addColumnValue(getColumnRef(
1112: Domain.CLMN_PROPERTY_KEY, m_bIsHistorical), prop
1113: .getKey());
1114: insert.addColumnValue(getColumnRef(
1115: Domain.CLMN_DOMAIN_OBJECT, m_bIsHistorical),
1116: this .m_sObjectName);
1117:
1118: insert.addColumnValue(getColumnRef(Domain.CLMN_MIN_OCCURS,
1119: m_bIsHistorical), this .m_nMinOccurs);
1120:
1121: insert.addColumnValue(getColumnRef(Domain.CLMN_MAX_OCCURS,
1122: m_bIsHistorical), this .m_nMaxOccurs);
1123:
1124: m_dsi.execute(insert);
1125:
1126: if (m_details != null) {
1127:
1128: Iterator iter = m_details.iterator();
1129:
1130: while (iter.hasNext()) {
1131: String sDetail = (String) iter.next();
1132:
1133: insert.clear();
1134:
1135: insert.addColumnValue(getDetailsColumnRef(
1136: Domain.CLMN_DETAILS_DOMAIN_ID,
1137: m_bIsHistorical), m_nId);
1138:
1139: insert.addColumnValue(
1140: getDetailsColumnRef(
1141: Domain.CLMN_DOMAIN_DETAILS,
1142: m_bIsHistorical), sDetail);
1143:
1144: m_dsi.execute(insert);
1145: }
1146: }
1147:
1148: if (m_contentRestrictions != null) {
1149:
1150: Iterator iter = m_contentRestrictions.iterator();
1151:
1152: while (iter.hasNext()) {
1153: String contentType = (String) iter.next();
1154:
1155: insert.clear();
1156:
1157: insert.addColumnValue(
1158: getContentRestrictionsColumnRef(
1159: Domain.CLMN_DETAILS_DOMAIN_ID,
1160: m_bIsHistorical), m_nId);
1161:
1162: insert.addColumnValue(
1163: getContentRestrictionsColumnRef(
1164: Domain.CLMN_CONTENT_TYPE,
1165: m_bIsHistorical), contentType);
1166:
1167: m_dsi.execute(insert);
1168: }
1169: }
1170: } catch (DataAccessException e) {
1171: throw new EditException("Error saving domain", e);
1172: } catch (DataStoreException e) {
1173: throw new EditException("Error saving domain", e);
1174: } catch (SQLException e) {
1175: throw new EditException("Error saving domain", e);
1176: }
1177: }
1178:
1179: /**
1180: * Deletes this domain from the database.
1181: *
1182: * @throws EditException if an error occurs deleting this domain from
1183: * the database
1184: */
1185: public void delete() throws EditException {
1186: try {
1187: DeleteStatement delete = new DeleteStatement();
1188:
1189: delete.addWhereCondition(getDetailsColumnRef(
1190: Domain.CLMN_DETAILS_DOMAIN_ID, m_bIsHistorical),
1191: "=", m_nId);
1192:
1193: m_dsi.execute(delete);
1194:
1195: delete.clear();
1196:
1197: delete.addWhereCondition(this
1198: .getContentRestrictionsColumnRef(
1199: CLMN_DETAILS_DOMAIN_ID,
1200: this .m_bIsHistorical), "=", m_nId);
1201:
1202: m_dsi.execute(delete);
1203:
1204: delete.clear();
1205:
1206: delete.addWhereCondition(getColumnRef(CLMN_DOMAIN_ID,
1207: this .m_bIsHistorical), "=", m_nId);
1208:
1209: m_dsi.execute(delete);
1210:
1211: } catch (DataStoreException e) {
1212: throw new EditException("Error deleting domain", e);
1213: }
1214: }
1215:
1216: /**
1217: * Populates the restrictions for this domain from the database.
1218: *
1219: * @throws DataStoreException if an error occurs querying the database
1220: */
1221: private synchronized void populateDetails()
1222: throws DataStoreException {
1223: if (m_bIsDetailsPopulated == false) {
1224:
1225: if (m_details == null) {
1226: m_details = new Vector();
1227: }
1228:
1229: SelectStatement select = new SelectStatement();
1230:
1231: select.addSelectColumn(getDetailsColumnRef(
1232: CLMN_DOMAIN_DETAILS, m_bIsHistorical));
1233:
1234: select.addWhereCondition(getDetailsColumnRef(
1235: CLMN_DETAILS_DOMAIN_ID, m_bIsHistorical), "=",
1236: this .m_nId);
1237:
1238: ResultSet rs = m_dsi.execute(select);
1239:
1240: try {
1241: while (rs.next()) {
1242: String sDetail = rs.getString(1);
1243:
1244: m_details.add(sDetail);
1245: }
1246: } catch (SQLException e) {
1247: throw new DataStoreException(
1248: "Error populating domain details", e);
1249: } finally {
1250: if (rs != null) {
1251: try {
1252: rs.close();
1253: } catch (SQLException e1) {
1254: throw new DataStoreException(
1255: "Error occured closing result set:"
1256: + e1.getLocalizedMessage());
1257: }
1258: }
1259: }
1260:
1261: m_bIsDetailsPopulated = true;
1262: }
1263: }
1264:
1265: /**
1266: * Returns the appropriate <code>ColumnRef</code> for the given column name
1267: * from the <code>Domain</code> domain details database table.
1268: *
1269: * @param sCol the column name
1270: * @param bIsHist <code>true</code> if the column references the historical
1271: * database table
1272: * @return the appropriate <code>ColumnRef</code>
1273: * @throws DataStoreException if the referenced column is invalid
1274: */
1275: protected static ColumnRef getDetailsColumnRef(String sCol,
1276: boolean bIsHist) throws DataStoreException {
1277: String sTable = Domain.CLMN_DOMAIN_DETAILS;
1278: ColumnRef colref = null;
1279:
1280: if (bIsHist == true) {
1281: sTable = sTable + AbstractObject.EXT_HIST;
1282: }
1283:
1284: if (sCol.equals(Domain.CLMN_DOMAIN_DETAILS) == true) {
1285: colref = new ColumnRef(sTable, sCol, ColumnRef.TEXT);
1286: } else if (sCol.equals(Domain.CLMN_DETAILS_DOMAIN_ID) == true) {
1287: colref = new ColumnRef(sTable, sCol, ColumnRef.NUMBER);
1288: } else {
1289: throw new InvalidColumnReferenceException();
1290: }
1291:
1292: return colref;
1293: }
1294:
1295: /**
1296: * Returns the appropriate <code>ColumnRef</code> for the given column name
1297: * from the <code>Domain</code> content restrictions database table.
1298: *
1299: * @param sCol the column name
1300: * @param bIsHist <code>true</code> if the column references the historical
1301: * @return the appropriate <code>ColumnRef</code>
1302: * @throws DataStoreException if the referenced column is invalid
1303: */
1304: private ColumnRef getContentRestrictionsColumnRef(String sCol,
1305: boolean bIsHist) throws DataStoreException {
1306: String sTable = Domain.TBL_DOMAIN_CONTENT_RESTRICTIONS;
1307: ColumnRef colref = null;
1308:
1309: if (bIsHist == true) {
1310: sTable = sTable + AbstractObject.EXT_HIST;
1311: }
1312:
1313: if (sCol.equals(Domain.CLMN_CONTENT_TYPE) == true) {
1314: colref = new ColumnRef(sTable, sCol, ColumnRef.TEXT);
1315: } else if (sCol.equals(Domain.CLMN_DETAILS_DOMAIN_ID) == true) {
1316: colref = new ColumnRef(sTable, sCol, ColumnRef.NUMBER);
1317: } else {
1318: throw new InvalidColumnReferenceException();
1319: }
1320:
1321: return colref;
1322: }
1323:
1324: /**
1325: * Returns the appropriate <code>ColumnRef</code> for the given column name
1326: * from the <code>Domain</code> database table.
1327: *
1328: * @param sCol the column name
1329: * @param bIsHist <code>true</code> if the column references the historical
1330: * @return the appropriate <code>ColumnRef</code>
1331: * @throws DataStoreException if the referenced column is invalid
1332: */
1333: protected static ColumnRef getColumnRef(String sCol, boolean bIsHist)
1334: throws DataStoreException {
1335: String sTable = Domain.TBL_NAME;
1336: ColumnRef colref = null;
1337:
1338: if (bIsHist == true) {
1339: sTable = sTable + AbstractObject.EXT_HIST;
1340: }
1341:
1342: if (sCol.equals(Domain.CLMN_DOMAIN_DETAILS) == true
1343: || sCol.equals(Domain.CLMN_DOMAIN_OBJECT) == true) {
1344: colref = new ColumnRef(sTable, sCol, ColumnRef.TEXT);
1345: } else if (sCol.equals(Domain.CLMN_PROPERTY_KEY) == true) {
1346: colref = new ColumnRef(sTable, sCol, ColumnRef.NUMBER);
1347: } else if (sCol.equals(Domain.CLMN_MIN_OCCURS) == true) {
1348: colref = new ColumnRef(sTable, sCol, ColumnRef.NUMBER);
1349: } else if (sCol.equals(Domain.CLMN_MAX_OCCURS) == true) {
1350: colref = new ColumnRef(sTable, sCol, ColumnRef.NUMBER);
1351: } else if (sCol.equals(Domain.CLMN_DEPTH) == true) {
1352: colref = new ColumnRef(sTable, sCol, ColumnRef.NUMBER);
1353: } else if (sCol.equals(Domain.CLMN_DOMAIN_ID) == true) {
1354: colref = new ColumnRef(sTable, sCol, ColumnRef.NUMBER);
1355: } else {
1356: throw new InvalidColumnReferenceException();
1357: }
1358:
1359: return colref;
1360: }
1361:
1362: /**
1363: * Returns <code>true</code> if the specified object is a member of this
1364: * domain and therefore can have an instance of the <code>Property</code>
1365: * associated to this domain applied to it, otherwise <code>false</code>.
1366: *
1367: * @param obj the profiled object
1368: * @return <code>true</code> if the specified object is a member of this domain
1369: */
1370: public boolean isValid(AbstractProfiledObject obj)
1371: throws DataAccessException {
1372: boolean bIsValid = true;
1373:
1374: if (obj.getClass().getName().equals(getDomainClass()) == true) {
1375: if (obj instanceof AbstractChildObject) {
1376: AbstractChildObject child = (AbstractChildObject) obj;
1377: List details = getDetails();
1378: String sChildPath = child.getPath();
1379:
1380: //if there are domain details and the child has
1381: //a parent then check object path
1382: if (details.size() > 0 && sChildPath != null
1383: && sChildPath.length() > 0) {
1384:
1385: bIsValid = false;
1386:
1387: Iterator iter = details.iterator();
1388:
1389: while (iter.hasNext()) {
1390: String sPath = (String) iter.next();
1391:
1392: if (sChildPath.startsWith(sPath)) {
1393: bIsValid = true;
1394: }
1395: }
1396: }
1397:
1398: }
1399: } else {
1400: bIsValid = false;
1401: }
1402:
1403: return bIsValid;
1404: }
1405:
1406: /* (non-Javadoc)
1407: * @see java.lang.Object#clone()
1408: */
1409: public Object clone() throws CloneNotSupportedException {
1410: try {
1411: populateContentRestrictions();
1412: populateDetails();
1413:
1414: Domain domain = (Domain) super .clone();
1415: domain.m_details = (List) ((Vector) m_details).clone();
1416: domain.m_contentRestrictions = (List) ((Vector) m_contentRestrictions)
1417: .clone();
1418:
1419: return domain;
1420: } catch (CloneNotSupportedException e) {
1421: throw new IllegalStateException("Clone failed:"
1422: + e.getLocalizedMessage());
1423: } catch (DataStoreException e) {
1424: throw new IllegalStateException("Clone failed:"
1425: + e.getLocalizedMessage());
1426: }
1427: }
1428:
1429: }
|