001: /*
002: * The contents of this file are subject to the
003: * Mozilla Public License Version 1.1 (the "License");
004: * you may not use this file except in compliance with the License.
005: * You may obtain a copy of the License at http://www.mozilla.org/MPL/
006: *
007: * Software distributed under the License is distributed on an "AS IS"
008: * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
009: * See the License for the specific language governing rights and
010: * limitations under the License.
011: *
012: * The Initial Developer of the Original Code is Simulacra Media Ltd.
013: * Portions created by Simulacra Media Ltd are Copyright (C) Simulacra Media Ltd, 2004.
014: *
015: * All Rights Reserved.
016: *
017: * Contributor(s):
018: */
019: package org.openharmonise.rm.metadata;
020:
021: import java.util.*;
022: import java.util.logging.*;
023:
024: import org.openharmonise.commons.cache.*;
025: import org.openharmonise.commons.dsi.*;
026: import org.openharmonise.commons.dsi.ddl.*;
027: import org.openharmonise.commons.dsi.dml.*;
028: import org.openharmonise.commons.xml.XMLPrettyPrint;
029: import org.openharmonise.commons.xml.namespace.NamespaceClashException;
030: import org.openharmonise.rm.*;
031: import org.openharmonise.rm.dsi.DatabaseInfo;
032: import org.openharmonise.rm.factory.*;
033: import org.openharmonise.rm.publishing.*;
034: import org.openharmonise.rm.resources.*;
035: import org.openharmonise.rm.resources.metadata.properties.Property;
036: import org.openharmonise.rm.resources.metadata.properties.ranges.ChildObjectRange;
037: import org.openharmonise.rm.resources.publishing.*;
038: import org.w3c.dom.*;
039:
040: /**
041: * A concrete implementation of <code>AbstractPropertyInstance</code> to handle
042: * property instances which contain <code>AbstractChildObject</code> values.
043: *
044: * @author Michael Bell
045: * @version $Revision: 1.5 $
046: *
047: */
048: public class ChildObjectPropertyInstance extends
049: AbstractPropertyInstance implements Publishable {
050:
051: /**
052: * Internal cache of mappings between <code>AbstractChildObject</code>
053: * implementations and their database tables.
054: */
055: private static Map m_childObj_table_mappings = new Hashtable();
056: protected final static String CLMN_OBJECT_ID = "object_id";
057:
058: /**
059: * Logger for this class
060: */
061: private static final Logger m_logger = Logger
062: .getLogger(ChildObjectPropertyInstance.class.getName());
063:
064: /**
065: * Constructs a property instance.
066: */
067: public ChildObjectPropertyInstance() {
068: super ();
069:
070: }
071:
072: /**
073: * Constructs a property instance with a data store interface.
074: *
075: * @param dbint the data store interface
076: */
077: public ChildObjectPropertyInstance(AbstractDataStoreInterface dbint) {
078: super (dbint);
079:
080: }
081:
082: /**
083: * Constructs a property instance with a data store interface and a
084: * reference to the <code>Profile</code> which will contain this instance.
085: *
086: * @param dbintrf the data store interface
087: * @param profile the owner <code>Profile</code>
088: */
089: public ChildObjectPropertyInstance(
090: AbstractDataStoreInterface dbintrf, Profile profile) {
091: super (dbintrf, profile);
092:
093: }
094:
095: /**
096: * Constructs a property instance with a data store interface, a reference
097: * to the <code>Profile</code> which will contain this instance and a
098: * reference to the <code>Property</code> of which this is property instance
099: * is an instance of.
100: *
101: * @param dbintrf the data store interface
102: * @param nPropertyId the id of the <code>Property</code>
103: * @param profile the owner <code>Profile</code>
104: */
105: public ChildObjectPropertyInstance(
106: AbstractDataStoreInterface dbintrf, int nPropertyId,
107: Profile profile) {
108: super (dbintrf, nPropertyId, profile);
109: }
110:
111: /**
112: * Constructs a property instance with a data store interface and referenec
113: * to the <code>Property</code> it is an instance of.
114: *
115: * @param dbintrf the data store interface
116: * @param prop the <code>Property</code> this is an instance of
117: */
118: public ChildObjectPropertyInstance(
119: AbstractDataStoreInterface dbintrf, Property prop) {
120: super (dbintrf, prop);
121: }
122:
123: /**
124: * Constructs a property instance with a data store interface, a
125: * reference to the <code>Profile</code> which will contain this object
126: * and a reference to the <code>Property</code> which this object is an
127: * instance of.
128: *
129: * @param dbintrf the data store interface
130: * @param property the <code>Property</code>
131: * @param profile the owner <code>Profile</code>
132: */
133: public ChildObjectPropertyInstance(
134: AbstractDataStoreInterface dbintrf, Property property,
135: Profile profile) {
136: super (dbintrf, property, profile);
137:
138: }
139:
140: /**
141: * Adds the given <code>AbstractChildObject</code> as a value to this
142: * property instance.
143: *
144: * @param child the new value to add to this property instance
145: *
146: * @throws InvalidPropertyValueException if the value given is invalid
147: */
148: public void addValue(AbstractChildObject child)
149: throws PopulateException {
150: if (child != null && isValidValue(child)) {
151: try {
152: CachePointer ptr = CacheHandler.getInstance(m_dsi)
153: .getCachePointer(child);
154:
155: super .addValue(ptr);
156:
157: } catch (CacheException e) {
158: throw new InvalidPropertyValueException(
159: "Unable to get cache pointer", e);
160: }
161: }
162: }
163:
164: /**
165: * Adds the given <code>AbstractChildObject</code> as a value to this
166: * property instance with the specified id.
167: *
168: * @param child the new value to add to this property instance
169: * @param nId the id to associate with this value
170: *
171: * @throws InvalidPropertyValueException if the value given is invalid
172: */
173: public void addValue(AbstractChildObject child, int nId)
174: throws PopulateException {
175: if (child != null && isValidValue(child)) {
176: try {
177: CachePointer ptr = CacheHandler.getInstance(m_dsi)
178: .getCachePointer(child);
179:
180: super .addValue(ptr, nId);
181: } catch (CacheException e) {
182: throw new InvalidPropertyValueException(
183: "Unable to get cache pointer", e);
184: }
185: }
186:
187: }
188:
189: /**
190: * Removes the specified <code>AbstractChildObject</code> from
191: * this property instance's list of values.
192: *
193: * @param child the value to remove
194: *
195: * @throws InvalidPropertyValueException if the specified value
196: * is an invalid value for this property instance
197: */
198: public void removeValue(AbstractChildObject child)
199: throws InvalidPropertyValueException {
200:
201: try {
202: CachePointer ptr = CacheHandler.getInstance(m_dsi)
203: .getCachePointer(child);
204:
205: super .removeValue(ptr);
206: } catch (CacheException e) {
207: throw new InvalidPropertyValueException(e
208: .getLocalizedMessage(), e);
209: }
210: }
211:
212: /* (non-Javadoc)
213: * @see org.openharmonise.rm.publishing.Publishable#populate(org.w3c.dom.Element, org.openharmonise.rm.publishing.State)
214: */
215: public void populate(Element xmlElement, State state)
216: throws PopulateException {
217: String sTagName = xmlElement.getTagName();
218: Text txt = null;
219:
220: if (sTagName.equals(TAG_PROP_INSTANCE_VALUES) == true) {
221: NodeList nodes = xmlElement.getChildNodes();
222: boolean bChildFound = false;
223:
224: for (int i = 0; i < nodes.getLength(); i++) {
225: if (nodes.item(i).getNodeType() != Node.ELEMENT_NODE) {
226: continue;
227: }
228: Element tmpEl = (Element) nodes.item(i);
229: sTagName = tmpEl.getTagName();
230:
231: if (sTagName.equals(TAG_ATTACH) == true) {
232: NodeList attachNodes = tmpEl.getChildNodes();
233: for (int j = 0; j < attachNodes.getLength(); j++) {
234: if (attachNodes.item(j).getNodeType() != Node.ELEMENT_NODE) {
235: continue;
236: }
237: Element attEl = (Element) attachNodes.item(j);
238: populateChild(attEl, state);
239: }
240: } else if (sTagName.equals(TAG_DETACH) == true) {
241: NodeList detachNodes = tmpEl.getChildNodes();
242: for (int j = 0; j < detachNodes.getLength(); j++) {
243: if (detachNodes.item(j).getNodeType() != Node.ELEMENT_NODE) {
244: continue;
245: }
246: Element attEl = (Element) detachNodes.item(j);
247: populateChild(attEl, state, true);
248: }
249: } else {
250: if (bChildFound == false) {
251: this .clearValues();
252: }
253: populateChild(tmpEl, state);
254: bChildFound = true;
255: }
256: }
257: } else {
258: super .populate(xmlElement, state);
259: }
260: }
261:
262: private void populateChild(Element childEl, State state)
263: throws PopulateException {
264:
265: populateChild(childEl, state, false);
266: }
267:
268: private void populateChild(Element childEl, State state,
269: boolean bRemove) throws PopulateException {
270: try {
271: Publishable pubObj = HarmoniseObjectFactory
272: .instantiatePublishableObject(this .m_dsi, childEl,
273: state);
274:
275: if (pubObj != null) {
276: pubObj.populate(childEl, state);
277: if (bRemove) {
278: removeValue((AbstractChildObject) pubObj);
279: } else {
280: addValue((AbstractChildObject) pubObj);
281: }
282: } else {
283: XMLPrettyPrint xpp = new XMLPrettyPrint();
284:
285: try {
286: throw new PopulateException(xpp.printNode(childEl));
287: } catch (PopulateException e) {
288: m_logger.log(Level.WARNING,
289: e.getLocalizedMessage(), e);
290: } catch (NamespaceClashException e) {
291: m_logger.log(Level.WARNING,
292: e.getLocalizedMessage(), e);
293: }
294: }
295: } catch (InvalidPropertyValueException iv_e) {
296: throw new PopulateException(
297: "Invalid value for PropertyInstance", iv_e);
298: } catch (HarmoniseFactoryException e) {
299: throw new PopulateException(
300: "Problem occured instantiating value", e);
301: } catch (ClassCastException cce) {
302: throw new PopulateException(
303: "Invalid value for PropertyInstance", cce);
304: }
305: }
306:
307: /* (non-Javadoc)
308: * @see org.openharmonise.rm.publishing.Publishable#publish(org.w3c.dom.Element, org.openharmonise.rm.publishing.HarmoniseOutput, org.openharmonise.rm.publishing.State)
309: */
310: public Element publish(Element formEl, HarmoniseOutput xmlDoc,
311: State state) throws PublishException {
312:
313: Element resultEl = null;
314: String sTagname = formEl.getTagName();
315:
316: if (sTagname.equals(TAG_PROP_INSTANCE_VALUES) == true) {
317: resultEl = xmlDoc.createElement(TAG_PROP_INSTANCE_VALUES);
318:
319: if (m_values != null) {
320: NodeList templateNodes = formEl
321: .getElementsByTagName(Template.TAG_TEMPLATE);
322: Element templateEl = (Element) templateNodes.item(0);
323: Template template = null;
324: Element publishTemplateEl = null;
325:
326: int nPageId = -2;
327:
328: if (templateEl != null) {
329: try {
330: template = (Template) HarmoniseObjectFactory
331: .instantiateHarmoniseObject(m_dsi,
332: templateEl, state);
333: NodeList pageNodes = templateEl
334: .getElementsByTagName(WebPage.TAG_PAGE);
335:
336: if (pageNodes.getLength() > 0) {
337: nPageId = Integer
338: .parseInt(((Element) pageNodes
339: .item(0))
340: .getAttribute(AbstractObject.ATTRIB_ID));
341: }
342: } catch (HarmoniseFactoryException e) {
343: throw new PublishException(e
344: .getLocalizedMessage(), e);
345: }
346: }
347:
348: if (template != null) {
349: try {
350: publishTemplateEl = template
351: .getTemplateRootElement();
352: } catch (DataAccessException e) {
353: throw new PublishException(e
354: .getLocalizedMessage(), e);
355: }
356: } else {
357: //if there isn't a template, create a simple one
358: //to publish the object name only
359: publishTemplateEl = xmlDoc
360: .createElement(AbstractObject.TAG_HARMONISE_OBJECT);
361: Element nameEl = xmlDoc
362: .createElement(AbstractObject.TAG_NAME);
363: publishTemplateEl.appendChild(nameEl);
364: Element displayNameEl = xmlDoc
365: .createElement(AbstractChildObject.TAG_DISPLAY_NAME);
366: publishTemplateEl.appendChild(displayNameEl);
367: }
368:
369: Text txt = null;
370: for (int j = 0; j < m_values.size(); j++) {
371: try {
372: AbstractChildObject tmpChild = (AbstractChildObject) ((CachePointer) m_values
373: .get(j)).getObject();
374:
375: Element childEl = null;
376:
377: childEl = tmpChild.publish(publishTemplateEl,
378: xmlDoc, state);
379:
380: if (childEl != null) {
381: resultEl.appendChild(childEl);
382: }
383:
384: } catch (CacheException e) {
385: throw new PublishException(e);
386: }
387:
388: }
389: if (nPageId > 0) {
390: xmlDoc.addPageIdToLinkNode(state.getLoggedInUser(),
391: resultEl, nPageId);
392: }
393: }
394: } else {
395: resultEl = super .publish(formEl, xmlDoc, state);
396: }
397:
398: if (resultEl == null) {
399: resultEl = xmlDoc.createElement(TAG_ERROR);
400: resultEl.appendChild(xmlDoc
401: .createTextNode("Problem publishing " + sTagname));
402: }
403:
404: return resultEl;
405: }
406:
407: /* (non-Javadoc)
408: * @see org.openharmonise.rm.publishing.Publishable#publish(org.openharmonise.rm.resources.publishing.Template, org.openharmonise.rm.publishing.HarmoniseOutput, org.openharmonise.rm.publishing.State)
409: */
410: public Element publish(Template template, HarmoniseOutput xmlDoc,
411: State state) throws PublishException {
412: return super .publish(template, xmlDoc, state);
413: }
414:
415: /* (non-Javadoc)
416: * @see org.openharmonise.rm.metadata.AbstractPropertyInstance#setDBTable(org.openharmonise.rm.metadata.Profile)
417: */
418: protected void setDBTable(Profile profile) {
419: //get table extension
420:
421: try {
422: Property prop = getProperty();
423:
424: if (prop != null) {
425:
426: try {
427:
428: ChildObjectRange range = (ChildObjectRange) getProperty()
429: .getRange();
430:
431: AbstractChildObject child = null;
432:
433: if (m_profile != null) {
434: child = (AbstractChildObject) m_profile
435: .getProfiledObject();
436: }
437:
438: String sClassname = range
439: .getChildObjectValueClassName(child);
440:
441: m_sDataTable = getDBTableName(profile, sClassname);
442: } catch (DataStoreException e) {
443: throw new IllegalStateException(
444: "Property had inappropriate range object for this property instance");
445: } catch (DataAccessException e) {
446: throw new IllegalStateException(
447: "Property had inappropriate range object for this property instance");
448: }
449: }
450: } catch (DataAccessException e) {
451: throw new IllegalStateException(e.getLocalizedMessage());
452: }
453: }
454:
455: /* (non-Javadoc)
456: * @see org.openharmonise.rm.metadata.AbstractPropertyInstance#match(org.openharmonise.rm.metadata.AbstractPropertyInstance)
457: */
458: public boolean match(AbstractPropertyInstance propInst)
459: throws ProfileException {
460: boolean bMatch = false;
461:
462: if (propInst instanceof ChildObjectPropertyInstance) {
463: List vals = getValues();
464: List otherVals = propInst.getValues();
465:
466: Iterator this Iter = vals.iterator();
467:
468: if ((m_sOperator.equals("=") && vals.size() == otherVals
469: .size())
470: || m_sOperator.equalsIgnoreCase("contains")) {
471:
472: while (this Iter.hasNext()) {
473: AbstractChildObject child = (AbstractChildObject) this Iter
474: .next();
475:
476: if (otherVals.contains(child) == false) {
477: bMatch = false;
478: break;
479: } else if (bMatch == false) {
480: bMatch = true;
481: }
482:
483: }
484: }
485:
486: }
487: return bMatch;
488: }
489:
490: /*-------------------------------------------------------------------------------------
491: Protected Methods
492: --------------------------------------------------------------------------------------*/
493:
494: /* (non-Javadoc)
495: * @see org.openharmonise.rm.metadata.AbstractPropertyInstance#getColumnForData()
496: */
497: protected ColumnRef getColumnForData() throws DataStoreException {
498: return getInstanceColumnRef(TAG_VALUE, isHistorical());
499: }
500:
501: /* (non-Javadoc)
502: * @see org.openharmonise.rm.metadata.AbstractPropertyInstance#getValueToStoreForValue(java.lang.Object)
503: */
504: protected Object getValueToStoreForValue(Object val)
505: throws ProfileException {
506: Integer intVal = null;
507:
508: CachePointer ptr = (CachePointer) val;
509: int nChildId = Integer.parseInt((String) ptr.getKey());
510:
511: if (nChildId > 0) {
512: intVal = new Integer(nChildId);
513: } else {
514: throw new InvalidPropertyInstanceException(
515: "Child object value with invalid id - 0");
516: }
517:
518: return intVal;
519: }
520:
521: /* (non-Javadoc)
522: * @see org.openharmonise.rm.dsi.DataStoreObject#getInstanceJoinConditions(java.lang.String, boolean)
523: */
524: public JoinConditions getInstanceJoinConditions(String sObjectTag,
525: boolean bIsOuter) throws DataStoreException {
526: return null;
527: }
528:
529: /* (non-Javadoc)
530: * @see org.openharmonise.rm.dsi.DataStoreObject#getInstanceColumnRef(java.lang.String, boolean)
531: */
532: public ColumnRef getInstanceColumnRef(String sColumn,
533: boolean bIsHist) throws DataStoreException {
534: ColumnRef returnColRef = null;
535: String sDBTable = getDBTableName();
536:
537: if (sColumn.equals(TAG_VALUE) == true
538: || sColumn.equals(CLMN_OBJECT_ID) == true) {
539: returnColRef = new ColumnRef(sDBTable, CLMN_OBJECT_ID,
540: ColumnRef.NUMBER);
541: }
542:
543: if (returnColRef != null) {
544: return returnColRef;
545: } else {
546: return super .getInstanceColumnRef(sColumn, bIsHist);
547: }
548: }
549:
550: /* (non-Javadoc)
551: * @see org.openharmonise.rm.dsi.DataStoreObject#processResultSet(org.openharmonise.commons.dsi.CachedResultSet, org.openharmonise.commons.dsi.dml.SelectStatement)
552: */
553: public List processResultSet(CachedResultSet resultSet,
554: SelectStatement select) {
555: // do nothing as this isn't implemented in Profile
556: return null;
557: }
558:
559: /* (non-Javadoc)
560: * @see org.openharmonise.rm.dsi.DataStoreObject#processResultSet(org.openharmonise.commons.dsi.CachedResultSet, org.openharmonise.commons.dsi.dml.SelectStatement, int)
561: */
562: public List processResultSet(CachedResultSet resultSet,
563: SelectStatement select, int limit) {
564: // do nothing as this isn't implemented in Profile
565: return null;
566: }
567:
568: /**
569: * Returns the database table for the property instance which will be
570: * attached to the specified <code>Profile</code> and contain values
571: * of the type specified by the given class name.
572: *
573: * The table name is determined by the profile database table name
574: * and the type of <code>AbstractChildObject</code>.
575: *
576: * @param profile the owning <code>Profile</code>
577: * @param sClassname the class name of the
578: * <code>AbstractChildObject</code> value for the property instance
579: * @return the database table for the property instance
580: *
581: * @throws DataStoreException if there is an error obtaining the database
582: * table name for the given <code>AbstractChildObject</code> class name
583: */
584: public static String getDBTableName(Profile profile,
585: String sClassname) throws DataStoreException {
586: StringBuffer sDataTable = new StringBuffer();
587:
588: String sExt = (String) m_childObj_table_mappings
589: .get(sClassname);
590:
591: if (sExt == null) {
592: String sTable = DatabaseInfo.getInstance().getTableName(
593: sClassname);
594: sExt = "_" + sTable;
595: m_childObj_table_mappings.put(sClassname, sExt);
596: }
597:
598: if (profile.isHistorical() == true) {
599: AbstractProfiledObject profObj = profile
600: .getProfiledObject();
601: sDataTable.append(profObj.getDBTableName()).append(
602: Profile.EXT_PROFILE).append(sExt).append(EXT_HIST);
603: } else {
604: sDataTable.append(profile.getDBTableName()).append(sExt);
605: }
606:
607: return sDataTable.toString();
608: }
609:
610: /**
611: * Returns the name of the property instance data base table
612: * for holding <code>AbstractChildObject</code> value references from
613: * the given table name and the parent profile.
614: *
615: * The table name is determined by the profile database table name
616: * and the given table name.
617: *
618: * The given table name must be the table name associated to a
619: * <code>AbstractChildObject</code> such as <code>Document</code>,
620: * <code>User</code>, etc.
621: *
622: * @param profile the owner <code>Profile</code>
623: * @param sTable the name of the table associated to a
624: * <code>AbstractChildObject</code>
625: * @return the name of the property instance data base table
626: */
627: public static String constructDBTableName(Profile profile,
628: String sTable) {
629: StringBuffer sDataTable = new StringBuffer();
630:
631: String sExt = "_" + sTable;
632:
633: if (profile.isHistorical() == true) {
634: AbstractProfiledObject profObj = profile
635: .getProfiledObject();
636: sDataTable.append(profObj.getDBTableName()).append(
637: Profile.EXT_PROFILE).append(sExt).append(EXT_HIST);
638: } else {
639: sDataTable.append(profile.getDBTableName()).append(sExt);
640: }
641:
642: return sDataTable.toString();
643: }
644:
645: /* (non-Javadoc)
646: * @see org.openharmonise.rm.dsi.DataStoreObject#getDBTableName()
647: */
648: public String getDBTableName() {
649: if (m_sDataTable == null) {
650: try {
651:
652: ChildObjectRange range = (ChildObjectRange) getProperty()
653: .getRange();
654:
655: AbstractChildObject child = null;
656:
657: if (m_profile != null) {
658: child = (AbstractChildObject) m_profile
659: .getProfiledObject();
660: }
661:
662: String sClassname = range
663: .getChildObjectValueClassName(child);
664: m_sDataTable = getDBTableName(m_profile, sClassname);
665:
666: } catch (DataStoreException e) {
667: throw new IllegalStateException(
668: "Property had inappropriate range object for this property instance");
669: } catch (DataAccessException e) {
670: throw new IllegalStateException(
671: "Property had inappropriate range object for this property instance");
672: }
673: }
674:
675: return m_sDataTable;
676: }
677:
678: /**
679: * Returns <code>true</code> if the child is a valid value for this
680: * property instance, otherwise <code>false</code>.
681: *
682: * Note: If the child is found not to exist and is an existing value it will
683: * be removed from the database.
684: *
685: * @param child the potential value
686: * @return <code>true</code> if the child is a valid value
687: * @throws InvalidPropertyValueException if the object doesn't exist
688: * or there was an error determining the status of the object
689: */
690: private boolean isValidValue(AbstractChildObject child)
691: throws InvalidPropertyValueException {
692: boolean bIsValid = true;
693:
694: if (child.getId() > 0) {
695: try {
696: if (childExists(child) == true) {
697: bIsValid = child.isLiveVersion();
698: } else {
699: bIsValid = false;
700: }
701:
702: } catch (DataAccessException e) {
703: throw new InvalidPropertyValueException(
704: "Couldn't determine status of child object", e);
705: } catch (DataStoreException e) {
706: throw new InvalidPropertyValueException(
707: "Child doesn't exit and had trouble removing it",
708: e);
709: }
710:
711: if (bIsValid == false) {
712: throw new InvalidPropertyValueException(
713: "Child object must be live to add as value");
714: }
715: } else {
716: bIsValid = false;
717: }
718:
719: return bIsValid;
720: }
721:
722: /* (non-Javadoc)
723: * @see org.openharmonise.rm.metadata.AbstractPropertyInstance#getValue()
724: */
725: public Object getValue() {
726: AbstractChildObject child = null;
727: try {
728: child = (AbstractChildObject) ((CachePointer) super
729: .getValue()).getObject();
730: } catch (CacheException e) {
731: m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
732: }
733:
734: return child;
735: }
736:
737: /* (non-Javadoc)
738: * @see org.openharmonise.rm.metadata.AbstractPropertyInstance#getValue(int)
739: */
740: public Object getValue(int nIndex) {
741: AbstractChildObject child = null;
742: try {
743: CachePointer ptr = (CachePointer) super .getValue(nIndex);
744: child = (AbstractChildObject) ptr.getObject();
745: if (childExists(child) == false) {
746: child = null;
747: }
748: } catch (CacheException e) {
749: m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
750: } catch (DataStoreException e) {
751: m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
752: }
753:
754: return child;
755: }
756:
757: /* (non-Javadoc)
758: * @see org.openharmonise.rm.metadata.AbstractPropertyInstance#getValues()
759: */
760: public List getValues() {
761: List result = new ArrayList();
762: List ptrs = super .getValues();
763:
764: Iterator iter = ptrs.iterator();
765:
766: while (iter.hasNext()) {
767: Object obj = iter.next();
768:
769: CachePointer ptr = (CachePointer) obj;
770: try {
771: AbstractChildObject child = (AbstractChildObject) ptr
772: .getObject();
773: //add child if it still exists otherwise get rid of it
774: if (childExists(child) == true) {
775: result.add(child);
776: }
777:
778: } catch (CacheException e) {
779: m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
780: } catch (DataStoreException e) {
781: m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
782: }
783: }
784:
785: return result;
786: }
787:
788: /* (non-Javadoc)
789: * @see org.openharmonise.rm.metadata.AbstractPropertyInstance#setValues(java.util.List)
790: */
791: public void setValues(List values)
792: throws InvalidPropertyValueException {
793: List ptrs = new ArrayList();
794:
795: Iterator iter = values.iterator();
796:
797: try {
798: while (iter.hasNext()) {
799: Object tmpObj = iter.next();
800: if (tmpObj instanceof AbstractChildObject) {
801: AbstractChildObject child = (AbstractChildObject) tmpObj;
802: ptrs.add(CacheHandler.getInstance(m_dsi)
803: .getCachePointer(child));
804: } else if (tmpObj instanceof CachePointer) {
805: ptrs.add(tmpObj);
806: }
807:
808: }
809: } catch (CacheException e) {
810: m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
811: throw new InvalidPropertyValueException(e);
812: }
813:
814: super .setValues(ptrs);
815: }
816:
817: /**
818: * Returns <code>true</code> if child exists, otherwise, if we're in the
819: * process of populating the object, then remove the reference from
820: * the database.
821: *
822: * @param child the child object
823: * @return <code>true</code> if child exists
824: * @throws DataStoreException if there is an error removing the child
825: * from the database
826: */
827: private boolean childExists(AbstractChildObject child)
828: throws DataStoreException {
829: boolean bExists = child.exists();
830:
831: if (bExists == false && isPopulated() == false) {
832: removeChildReferences(child);
833: }
834:
835: return bExists;
836: }
837:
838: /**
839: * Removes the reference to child from the property instance database
840: * table, used to discard invalid references.
841: *
842: * @param child the child whose reference is to be removed
843: * @throws DataStoreException if there is an error deleting data from
844: * the database
845: */
846: protected void removeChildReferences(AbstractChildObject child)
847: throws DataStoreException {
848: int nIndex = -1;
849: int i = 0;
850:
851: Iterator iter = m_values.iterator();
852: boolean bFound = false;
853: while (iter.hasNext() && bFound == false) {
854: CachePointer ptr = (CachePointer) iter.next();
855:
856: if (ptr.getKey().equals(String.valueOf(child.getId()))) {
857: nIndex = i;
858: bFound = true;
859: }
860:
861: i++;
862: }
863:
864: if (bFound == true && m_valueIds.size() > nIndex) {
865: DeleteStatement delete = new DeleteStatement();
866:
867: delete.addWhereCondition(getColumnForData(), "=", child
868: .getId());
869:
870: delete.addWhereCondition(getInstanceColumnRef(CLMN_ID,
871: isHistorical()), "=", ((Integer) m_valueIds
872: .get(nIndex)).intValue());
873:
874: m_dsi.execute(delete);
875:
876: if (m_values.size() > nIndex) {
877: m_values.remove(nIndex);
878: }
879: if (m_valueIds.size() > nIndex) {
880: m_valueIds.remove(nIndex);
881: }
882: }
883:
884: }
885:
886: /**
887: * Creates table for property instances associated to the specified
888: * profile table and with the given table name.
889: *
890: * @param dsi the data store interface
891: * @param sProfileTable the profile table name
892: * @param sTableName the new table name
893: * @throws DataStoreException if an error occurs creating the table
894: */
895: public static void generateTable(AbstractDataStoreInterface dsi,
896: String sProfileTable, String sTableName)
897: throws DataStoreException {
898:
899: TableDefinition tblDef = new TableDefinition(sTableName);
900:
901: tblDef.addColumn(CLMN_ID, true, ColumnDefinition.NUMBER);
902: ColumnDefinition profRef = new ColumnDefinition(
903: CLMN_PROFILE_ID, ColumnDefinition.NUMBER);
904: profRef.addForeignKey(sProfileTable);
905: tblDef.addColumn(profRef);
906: tblDef.addColumn(CLMN_PROPERTY_ID, ColumnDefinition.NUMBER);
907: tblDef.addColumn(CLMN_OBJECT_ID, ColumnDefinition.NUMBER);
908: tblDef.addColumn(CLMN_VERSION_COMMENT, ColumnDefinition.TEXT,
909: true);
910:
911: dsi.createTable(tblDef);
912: }
913:
914: /**
915: * Returns the name of the property instance table for objects of
916: * type <i>domainClass</i> which have relationships to objects
917: * of type <i>valueClass</i>.
918: *
919: * @param domainClass the class name of the profile object
920: * @param valueClass the class name of the objects which will be values of the property instance
921: * @param bIsHist <code>true</code> if the table is historical
922: * @return the name of the property instance table
923: * @throws DataAccessException if an error occurs constructing the
924: * table name
925: */
926: public static String getDBTableName(String domainClass,
927: String valueClass, boolean bIsHist)
928: throws DataAccessException {
929: StringBuffer str = new StringBuffer();
930: try {
931: DatabaseInfo dbinf = DatabaseInfo.getInstance();
932: str.append(dbinf.getTableName(domainClass));
933: str.append(Profile.EXT_PROFILE);
934: str.append("_");
935: str.append(dbinf.getTableName(valueClass));
936:
937: if (bIsHist == true) {
938: str.append(Profile.EXT_HIST);
939: }
940: } catch (DataStoreException e) {
941: throw new DataAccessException(e);
942: }
943:
944: return str.toString();
945: }
946:
947: /**
948: * Creates the table required to hold property instances for the profiled
949: * object of type <i>domainClass</i> and with values of type
950: * <i>valueClass</i>
951: *
952: * @param m_dsi the data store interface
953: * @param domainClass the class name of the profiled object
954: * @param valueClass the class name of the values of the property instance
955: * @param bIsHist <code>true</code> if the table is historical
956: * @throws DataStoreException if there is an error creating the new
957: * database table
958: * @throws DataAccessException if there is an error constructing
959: * the details of the new table
960: */
961: public static void createTable(AbstractDataStoreInterface dsi,
962: String domainClass, String valueClass, boolean bIsHist)
963: throws DataAccessException, DataStoreException {
964: generateTable(dsi, Profile.getTableName(domainClass, bIsHist),
965: getDBTableName(domainClass, valueClass, bIsHist));
966: }
967:
968: }
|