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.resources.metadata.properties.ranges;
020:
021: import java.util.*;
022: import java.util.logging.*;
023:
024: import org.openharmonise.commons.dsi.*;
025: import org.openharmonise.rm.*;
026: import org.openharmonise.rm.dsi.DataStoreInterfaceFactory;
027: import org.openharmonise.rm.factory.*;
028: import org.openharmonise.rm.metadata.ChildObjectPropertyInstance;
029: import org.openharmonise.rm.publishing.*;
030: import org.openharmonise.rm.resources.*;
031: import org.openharmonise.rm.resources.publishing.Template;
032: import org.w3c.dom.*;
033:
034: /**
035: * Class which represents a <code>Property</code> range which is
036: * restricted to <code>AbstractChildObject</code> values defined by an
037: * absolute path.
038: *
039: * @author Michael Bell
040: * @version $Revision: 1.2 $
041: */
042: public class AbsoluteChildObjectRange extends AbstractRange implements
043: ChildObjectRange, Publishable {
044:
045: /**
046: * Absolute child object range XML tag name
047: */
048: public final static String TAG_ABSOLUTECHILDOBJECT_RANGE = "AbsoluteChildObjectRange";
049:
050: /**
051: * The available values XML element name
052: */
053: public static final String TAG_AVAILABLEVALUES = "AvailableValues";
054:
055: /**
056: * The list of paths which specify the parent objects which define
057: * the collection of allowable values for this property range
058: */
059: private List m_parent_restrictions = null;
060:
061: /**
062: * The separator used to separate values in the string which is
063: * saved to the database representing the restrictions on this range
064: */
065: static final private String SEPARATOR = "|";
066:
067: private static Logger m_logger = Logger
068: .getLogger(AbsoluteChildObjectRange.class.getName());
069:
070: /**
071: * Constructs a new <code>AbsoluteChildObjectRange</code>.
072: *
073: */
074: public AbsoluteChildObjectRange() {
075: super ();
076: }
077:
078: /**
079: * Constructs an <code>AbsoluteChildObjectRange</code> with the specified
080: * class type and path restrictions.
081: *
082: * @param sObjClassName the class name of objects within this range
083: * @param sDetails the <code>String</code> representation of the path
084: * restrictions for objects within this range.
085: */
086: public AbsoluteChildObjectRange(String sObjClassName,
087: String sDetails) {
088: super (sObjClassName, sDetails);
089: }
090:
091: /**
092: * Constructs an <code>AbsoluteChildObjectRange</code> with the specified
093: * class type restriction.
094: *
095: * @param sObjClassName the class name of objects within this range
096: */
097: public AbsoluteChildObjectRange(String sObjClassName) {
098: super (sObjClassName);
099: }
100:
101: /**
102: * Constructs an <code>AbsoluteChildObjectRange</code> with the specified
103: * class type and parent object restrictions.
104: *
105: * @param sObjClassName the class name of objects within this range
106: * @param parent the parent object which defines the path restriction
107: * for objects within this range
108: * @throws DataAccessException
109: */
110: public AbsoluteChildObjectRange(String sObjClassName,
111: AbstractParentObject parent) throws DataAccessException {
112: super (sObjClassName, parent.getFullPath());
113: }
114:
115: /* (non-Javadoc)
116: * @see org.openharmonise.rm.resources.metadata.properties.ranges.Range#isValid(java.lang.Object)
117: */
118: public boolean isValid(Object obj) {
119: boolean bIsValid = false;
120:
121: if (obj instanceof AbstractChildObject) {
122:
123: try {
124: Class clss = Class.forName(m_sObjectClassName);
125:
126: if (clss.isInstance(obj) == true) {
127: if (m_sDetails == null || m_sDetails.length() == 0) {
128: bIsValid = true;
129: } else {
130: AbstractChildObject child = (AbstractChildObject) obj;
131:
132: Iterator iter = getAllowedParents().iterator();
133:
134: while (iter.hasNext() && bIsValid == false) {
135: String sPath = (String) iter.next();
136: bIsValid = child.getPath()
137: .startsWith(sPath);
138: }
139:
140: }
141: }
142: } catch (DataAccessException e) {
143: //if we can't get the path from the child it's probably not valid
144: m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
145: bIsValid = false;
146: } catch (ClassNotFoundException e) {
147: //if class is not found it is definitely not valid
148: m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
149: bIsValid = false;
150: }
151:
152: }
153:
154: return bIsValid;
155: }
156:
157: /**
158: * Returns a list of available <code>AbstractChildObject</code> instances this
159: * range defines.
160: *
161: * @return a list of available <code>AbstractChildObject</code> instances this
162: * range defines
163: * @throws DataAccessException if an error occurs obtaining the instances
164: */
165: public List getAvailableValues() throws DataAccessException {
166: Vector result = new Vector();
167: try {
168: AbstractDataStoreInterface dsi = DataStoreInterfaceFactory
169: .getDataStoreInterface();
170:
171: String sParentClassName = AbstractChildObject
172: .getParentObjectClassName(m_sObjectClassName);
173:
174: Iterator iter = getAllowedParents().iterator();
175:
176: while (iter.hasNext()) {
177: String sPath = (String) iter.next();
178:
179: AbstractParentObject parent = (AbstractParentObject) HarmoniseObjectFactory
180: .instantiateHarmoniseObject(dsi,
181: sParentClassName, sPath);
182:
183: addAllChildObjectsToList(result, parent);
184:
185: }
186:
187: } catch (HarmoniseFactoryException e) {
188: throw new DataAccessException(
189: "Error occured getting parent from factory", e);
190: } catch (DataStoreException e) {
191: throw new DataAccessException(
192: "Error occured getting datastoreinterface", e);
193: }
194:
195: return result;
196: }
197:
198: /* (non-Javadoc)
199: * @see org.openharmonise.rm.publishing.Publishable#publish(org.w3c.dom.Element, org.openharmonise.rm.publishing.HarmoniseOutput, org.openharmonise.rm.publishing.State)
200: */
201: public Element publish(Element topEl, HarmoniseOutput output,
202: State state) throws PublishException {
203: Element el = null;
204:
205: if (topEl.getTagName().equals(TAG_AVAILABLEVALUES) == true) {
206: el = output.createElement(TAG_AVAILABLEVALUES);
207:
208: try {
209: AbstractDataStoreInterface dsi = DataStoreInterfaceFactory
210: .getDataStoreInterface();
211:
212: NodeList templates = topEl
213: .getElementsByTagName(Template.TAG_TEMPLATE);
214:
215: if (templates.getLength() > 0) {
216: Element templateEl = (Element) templates.item(0);
217:
218: Template template = (Template) HarmoniseObjectFactory
219: .instantiateHarmoniseObject(dsi,
220: templateEl, state);
221:
222: List values = getAvailableValues();
223:
224: Iterator iter = values.iterator();
225:
226: while (iter.hasNext()) {
227: Publishable val = (Publishable) iter.next();
228:
229: el.appendChild(val.publish(template, output,
230: state));
231: }
232: }
233: } catch (HarmoniseFactoryException e) {
234: throw new PublishException(
235: "Error occured getting template from factory",
236: e);
237: } catch (DataAccessException e) {
238: throw new PublishException(
239: "Error occured getting available values", e);
240: } catch (DataStoreException e) {
241: throw new PublishException(
242: "Error occured getting data store interface", e);
243: }
244:
245: } else {
246: el = super .publish(topEl, output, state);
247: }
248:
249: return el;
250: }
251:
252: /*----------------------------------------------------------------------------
253: Private Methods
254: -----------------------------------------------------------------------------*/
255:
256: /**
257: * Adds all the non <code>AbstractParentObject</code> <code>AbstractChildObject</code>
258: * objects of the given <code>AbstractParentObject</code> to the given <code>List</code>.
259: *
260: * @param result the list which will hold the child objects
261: * @param parent the parent object whose descendants will be added to the
262: *
263: * @throws DataAccessException if there is an error getting the children of
264: * the given parent object
265: */
266: protected void addAllChildObjectsToList(List result,
267: AbstractParentObject parent) throws DataAccessException {
268: Iterator iter = parent.getChildren().iterator();
269:
270: while (iter.hasNext()) {
271: AbstractChildObject child = (AbstractChildObject) iter
272: .next();
273:
274: if (isValid(child)) {
275: result.add(child);
276: }
277:
278: if (child instanceof AbstractParentObject) {
279: addAllChildObjectsToList(result,
280: (AbstractParentObject) child);
281: }
282: }
283: }
284:
285: /* (non-Javadoc)
286: * @see java.lang.Object#equals(java.lang.Object)
287: */
288: public boolean equals(Object obj) {
289: boolean bResult = false;
290:
291: if (obj instanceof AbsoluteChildObjectRange) {
292: bResult = super .equals(obj);
293: }
294:
295: return bResult;
296: }
297:
298: /**
299: * Returns a list of parent objects which define the path restrictions
300: * for this range.
301: *
302: * @return a list of parent objects which define the path restrictions
303: * for this range
304: * @throws DataAccessException
305: */
306: public List getAllowedParents() throws DataAccessException {
307: validateAllowedParents();
308:
309: List allowedParent = new ArrayList();
310:
311: if (m_parent_restrictions != null) {
312: allowedParent.addAll(m_parent_restrictions);
313: }
314:
315: return allowedParent;
316: }
317:
318: /**
319: * Sets the list of path restrictions which determine the members of this
320: * range.
321: *
322: * @param allowedParents list of path restrictions
323: */
324: public void setAllowedParents(List allowedParents) {
325: if ((m_parent_restrictions == null && allowedParents != null)
326: || m_parent_restrictions.equals(allowedParents) == false) {
327: m_parent_restrictions = new ArrayList(allowedParents);
328: isChanged(true);
329: }
330: }
331:
332: /**
333: * Adds the specified path restriction to the list of path restrictions.
334: *
335: * @param sPath the new path restriction
336: */
337: public void addAllowedParent(String sPath) {
338: if (m_parent_restrictions == null) {
339: m_parent_restrictions = new ArrayList();
340: }
341:
342: if (m_parent_restrictions.contains(sPath) == false) {
343: m_parent_restrictions.add(sPath);
344: isChanged(true);
345: }
346:
347: }
348:
349: /* (non-Javadoc)
350: * @see org.openharmonise.rm.resources.metadata.properties.ranges.Range#getDetails()
351: */
352: public String getDetails() {
353: if (isChanged()) {
354: StringBuffer strbuf = new StringBuffer();
355: if (m_parent_restrictions != null) {
356: try {
357: validateAllowedParents();
358: } catch (DataAccessException e) {
359: m_logger.log(Level.WARNING,
360: e.getLocalizedMessage(), e);
361: }
362: Iterator iter = m_parent_restrictions.iterator();
363:
364: while (iter.hasNext()) {
365: String sPath = (String) iter.next();
366: strbuf.append(sPath);
367:
368: if (iter.hasNext()) {
369: strbuf.append(SEPARATOR);
370: }
371: }
372:
373: }
374: super .setDetails(strbuf.toString());
375: }
376:
377: return super .getDetails();
378: }
379:
380: /* (non-Javadoc)
381: * @see org.openharmonise.rm.resources.metadata.properties.ranges.Range#setDetails(java.lang.String)
382: */
383: public void setDetails(String sDetails) {
384: if (m_parent_restrictions == null) {
385: m_parent_restrictions = new ArrayList();
386: }
387:
388: if (sDetails != null) {
389: StringTokenizer tokenizer = new StringTokenizer(sDetails,
390: SEPARATOR);
391:
392: int i = 0;
393: int nTmp = 0;
394: while (tokenizer.hasMoreTokens()) {
395: String token = tokenizer.nextToken();
396:
397: if (token != null && token.length() > 0) {
398: m_parent_restrictions.add(token);
399: }
400: }
401: }
402: super .setDetails(sDetails);
403: }
404:
405: /**
406: * Sets the object type restriction for this range.
407: *
408: * @param sClassname the class name of the objects within this range
409: */
410: public void setObjectRestriction(String sClassname) {
411: if ((m_sObjectClassName == null && sClassname != null)
412: || m_sObjectClassName.equals(sClassname) == false) {
413: m_sObjectClassName = sClassname;
414: isChanged(true);
415: }
416:
417: }
418:
419: /* (non-Javadoc)
420: * @see org.openharmonise.rm.resources.metadata.properties.ranges.ChildObjectRange#getChildObjectValueClassName(org.openharmonise.rm.resources.AbstractChildObject)
421: */
422: public String getChildObjectValueClassName(AbstractChildObject child) {
423: return getObject();
424: }
425:
426: /* (non-Javadoc)
427: * @see org.openharmonise.rm.resources.metadata.properties.ranges.Range#getPropertyInstanceClass()
428: */
429: public Class getPropertyInstanceClass()
430: throws ClassNotFoundException {
431:
432: return ChildObjectPropertyInstance.class;
433: }
434:
435: /* (non-Javadoc)
436: * @see org.openharmonise.rm.publishing.Publishable#getTagName()
437: */
438: public String getTagName() {
439: return TAG_ABSOLUTECHILDOBJECT_RANGE;
440: }
441:
442: /* (non-Javadoc)
443: * @see org.openharmonise.rm.publishing.Publishable#populate(org.w3c.dom.Element, org.openharmonise.rm.publishing.State)
444: */
445: public void populate(Element xmlElement, State state)
446: throws PopulateException {
447: String sTagname = xmlElement.getTagName();
448:
449: if (sTagname.equals(TAG_PATH_RESTRICTION)) {
450: String sPath = xmlElement.getFirstChild().getNodeValue();
451: addAllowedParent(sPath);
452: } else {
453: super .populate(xmlElement, state);
454: }
455:
456: }
457:
458: /* (non-Javadoc)
459: * @see org.openharmonise.rm.resources.metadata.properties.ranges.ChildObjectRange#getChildObjectValueClassName(java.lang.Class)
460: */
461: public String getChildObjectValueClassName(Class clss) {
462: return getObject();
463: }
464:
465: private void validateAllowedParents() throws DataAccessException {
466: if (m_parent_restrictions != null && m_sObjectClassName != null) {
467: try {
468: AbstractDataStoreInterface dsi = DataStoreInterfaceFactory
469: .getDataStoreInterface();
470: ListIterator iter = m_parent_restrictions
471: .listIterator();
472: String sParentClassName = AbstractChildObject
473: .getParentObjectClassName(m_sObjectClassName);
474:
475: if (sParentClassName != null) {
476: while (iter.hasNext()) {
477: String sPath = (String) iter.next();
478:
479: AbstractObject obj = HarmoniseObjectFactory
480: .instantiateHarmoniseObject(dsi,
481: sParentClassName, sPath);
482:
483: if (obj == null || obj.exists() == false) {
484: iter.remove();
485: }
486: }
487: }
488:
489: } catch (HarmoniseFactoryException e) {
490: throw new DataAccessException(e);
491: } catch (DataStoreException e) {
492: throw new DataAccessException(e);
493: }
494: }
495: }
496:
497: }
|