001: // THIS SOFTWARE IS PROVIDED BY SOFTARIS PTY.LTD. AND OTHER METABOSS
002: // CONTRIBUTORS ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
003: // BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
004: // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SOFTARIS PTY.LTD.
005: // OR OTHER METABOSS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
006: // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
007: // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
008: // OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
009: // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
010: // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
011: // EVEN IF SOFTARIS PTY.LTD. OR OTHER METABOSS CONTRIBUTORS ARE ADVISED OF THE
012: // POSSIBILITY OF SUCH DAMAGE.
013: //
014: // Copyright 2000-2005 © Softaris Pty.Ltd. All Rights Reserved.
015: package com.metaboss.sdlctools.models.impl.metabossmodel;
016:
017: import java.util.ArrayList;
018: import java.util.Collection;
019: import java.util.Collections;
020: import java.util.HashMap;
021: import java.util.HashSet;
022: import java.util.Iterator;
023: import java.util.List;
024: import java.util.Map;
025: import java.util.Set;
026: import java.util.regex.Matcher;
027: import java.util.regex.Pattern;
028:
029: import javax.jmi.model.AggregationKindEnum;
030: import javax.jmi.model.AssociationEnd;
031: import javax.jmi.model.Feature;
032: import javax.jmi.model.MofClass;
033: import javax.jmi.model.Reference;
034: import javax.jmi.reflect.ConstraintViolationException;
035: import javax.jmi.reflect.RefObject;
036: import javax.naming.Context;
037: import javax.naming.InitialContext;
038: import javax.naming.NamingException;
039:
040: import org.apache.commons.logging.Log;
041: import org.apache.commons.logging.LogFactory;
042: import org.netbeans.mdr.handlers.InstanceHandler;
043: import org.netbeans.mdr.storagemodel.StorableObject;
044:
045: import com.metaboss.sdlctools.models.ModelAssistant;
046: import com.metaboss.sdlctools.models.ModelRepository;
047: import com.metaboss.sdlctools.models.ModelRepositoryRuntimeException;
048: import com.metaboss.sdlctools.models.metabossmodel.ModelElement;
049: import com.metaboss.sdlctools.models.metabossmodel.ModelElementAttachment;
050: import com.metaboss.sdlctools.models.metabossmodel.datadictionarymodel.Property;
051:
052: public abstract class ModelElementImpl extends InstanceHandler
053: implements ModelElement {
054: // Commons Logging instance.
055: private static final Log sLogger = LogFactory
056: .getLog(ModelElementImpl.class);
057:
058: // This class keeps type information, so we do not have to generate it every time
059: private static class TypeInformation {
060: private String mTypeName;
061: private Set mParentTypes; // Types (Metaclasses) of all possible containers - can be used in RefObject.refIsInstanceOf()
062: private List mParentReferences;// References to all possible containers
063: private List mContainedCollectionsReferences; // References to all contained collections
064: private List mContainedReferences; // References to all contained objects
065: private List mAllReferences; // All references
066: }
067:
068: // The model repository interface accessible by all derived implementations
069: private static ModelRepository sModelRepository;
070: // Map of type information per MofObject
071: private static Map sTypeInfoMap = new HashMap();
072: // Type information of the instance
073: private TypeInformation mTypeInformation = null;
074: // Element name pattern
075: private static Pattern sNamePattern = Pattern
076: .compile("[a-zA-Z](( )|([\\w]))*");
077: private String mLastVerifiedName = null; // Cashe of the last good name -until name has changed there is no need to verify it
078:
079: // Required constructor
080: protected ModelElementImpl(StorableObject storable) {
081: super (storable);
082: // Obtain the object type information if necessary
083: MofClass lMetaObject = (MofClass) refMetaObject();
084: if ((mTypeInformation = (TypeInformation) sTypeInfoMap
085: .get(lMetaObject)) == null) {
086: mTypeInformation = new TypeInformation();
087: mTypeInformation.mTypeName = (String) lMetaObject
088: .refGetValue("name");
089: mTypeInformation.mParentTypes = new HashSet();
090: mTypeInformation.mParentReferences = new ArrayList();
091: mTypeInformation.mContainedCollectionsReferences = new ArrayList();
092: mTypeInformation.mContainedReferences = new ArrayList();
093: mTypeInformation.mAllReferences = new ArrayList();
094: // Find out the reference name in parent and multiplicity of the association if multiplicty is one - we do not need instance name
095: // Collect contents for the type and all supertypes
096: List lAllContents = new ArrayList();
097: lAllContents.addAll(lMetaObject.getContents());
098: for (Iterator lSupertypesIterator = lMetaObject
099: .allSupertypes().iterator(); lSupertypesIterator
100: .hasNext();)
101: lAllContents.addAll(((MofClass) lSupertypesIterator
102: .next()).getContents());
103: for (Iterator lAllContentsIterator = lAllContents
104: .iterator(); lAllContentsIterator.hasNext();) {
105: Feature lFeature = (Feature) lAllContentsIterator
106: .next();
107: if (lFeature instanceof Reference) {
108: Reference lReference = (Reference) lFeature;
109: mTypeInformation.mAllReferences.add(lReference);
110: AssociationEnd lReferencedEnd = lReference
111: .getReferencedEnd();
112: if (lReferencedEnd.getAggregation().equals(
113: AggregationKindEnum.COMPOSITE)) {
114: mTypeInformation.mParentReferences
115: .add(lReference);
116: mTypeInformation.mParentTypes
117: .add((MofClass) lReferencedEnd
118: .getType());
119: } else {
120: AssociationEnd lExposedEnd = lReference
121: .getExposedEnd();
122: if (lExposedEnd.getAggregation().equals(
123: AggregationKindEnum.COMPOSITE)) {
124: mTypeInformation.mContainedReferences
125: .add(lReference);
126: if (lReferencedEnd.getMultiplicity()
127: .getUpper() != 1)
128: mTypeInformation.mContainedCollectionsReferences
129: .add(lReference);
130: }
131: }
132: }
133: }
134: sTypeInfoMap.put(lMetaObject, mTypeInformation);
135: }
136:
137: // // Immediately set the default name, so model element can be referenceable immediately
138: // String lTypeName = (String)refMetaObject().refGetValue("name");
139: // Collection lAllInstancesCollection = refClass().refAllOfClass();
140: // int lCollectionSize = lAllInstancesCollection.size();
141: // // Last element in the collection is ours and it should not be checked
142: // // as this usually throws DebugException (probably due tothe object not being fully created at the time
143: // for (int i = 0; ; i++)
144: // {
145: // Iterator lCollectionIterator = lAllInstancesCollection.iterator();
146: // String lProposedName = "New" + lTypeName + ((i > 0) ? Integer.toString(i) : "");
147: // boolean lFoundSameName = false;
148: // for (int j = 0; j < (lCollectionSize-1); j++)
149: // {
150: // ModelElement lModelElement = (ModelElement)lCollectionIterator.next();
151: // if (lProposedName.equals(lModelElement.getName()))
152: // {
153: // lFoundSameName = true;
154: // break;
155: // }
156: // }
157: // if (!lFoundSameName)
158: // {
159: // // No match found for the name. It can be used
160: // setName(lProposedName);
161: // break;
162: // }
163: // }
164: }
165:
166: // Verify certain constraints
167: protected Collection _verify(Collection pViolations) {
168: // First call superclass
169: Collection lViolations = super ._verify(pViolations);
170:
171: // Constraint #1 - name must start from letter and only consist of letters, numbers and underscores
172: {
173: String lName = getName();
174: // Use cache pattern to speed things up
175: if (mLastVerifiedName == null
176: || mLastVerifiedName.equals(lName) == false) {
177: Matcher lMatcher = sNamePattern.matcher(lName);
178: if (!lMatcher.matches()) {
179: mLastVerifiedName = null;
180: lViolations
181: .add(new ConstraintViolationException(
182: this ,
183: refMetaObject(),
184: "Value of the Name attribute must begin with letter and followed by mixture of letters, digits, spaces and underscores. Value '"
185: + lName
186: + "' is not acceptable."));
187: } else {
188: mLastVerifiedName = lName;
189: }
190: }
191: }
192: // Constraint #2 - contents in collection must have unique name
193: {
194: for (Iterator lContainedCollectionsReferencesIterator = mTypeInformation.mContainedCollectionsReferences
195: .iterator(); lContainedCollectionsReferencesIterator
196: .hasNext();) {
197: Reference lContainedCollectionReference = (Reference) lContainedCollectionsReferencesIterator
198: .next();
199: Set lContentNames = new HashSet();
200: for (Iterator lConentsIterator = ((Collection) refGetValue(lContainedCollectionReference))
201: .iterator(); lConentsIterator.hasNext();) {
202: ModelElementImpl lContainedElement = (ModelElementImpl) lConentsIterator
203: .next();
204: if (lContainedElement instanceof Property) {
205: String lContentKey = ((Property) lContainedElement)
206: .getKey();
207: if (lContentNames.contains(lContentKey))
208: lViolations
209: .add(new ConstraintViolationException(
210: lContainedElement,
211: lContainedElement
212: .refMetaObject(),
213: "Key of the property element must be unque within its container. Value '"
214: + ((Property) lContainedElement)
215: .getKey()
216: + "' is not acceptable."));
217: else
218: lContentNames.add(lContentKey);
219: } else {
220: String lContentKey = lContainedElement
221: .getName();
222: if (lContentNames.contains(lContentKey))
223: lViolations
224: .add(new ConstraintViolationException(
225: lContainedElement,
226: lContainedElement
227: .refMetaObject(),
228: "Name of the model element must be unque within its parent model element. Value '"
229: + lContainedElement
230: .getName()
231: + "' is not acceptable."));
232: else
233: lContentNames.add(lContentKey);
234: }
235: }
236: }
237: }
238: return lViolations;
239: }
240:
241: // Returns the model repository this object belongs to
242: protected ModelRepository getModelRepository() {
243: // Obtain the model repository instance if necessary
244: if (sModelRepository == null) {
245: try {
246: // Create model repository to use
247: Context lContext = new InitialContext();
248: sModelRepository = (ModelRepository) lContext
249: .lookup(ModelRepository.COMPONENT_URL);
250: } catch (NamingException e) {
251: throw new ModelRepositoryRuntimeException(
252: "Unable to obtain an instance of the ModelRepository",
253: e);
254: }
255: }
256: return sModelRepository;
257: }
258:
259: // This helper method is used internally in the implementation to quickly find meta object of the reference to parent
260: private Reference getReferenceToParent() {
261: for (Iterator lParentReferencesIter = mTypeInformation.mParentReferences
262: .iterator(); lParentReferencesIter.hasNext();) {
263: Reference lParentReference = (Reference) lParentReferencesIter
264: .next();
265: // Have potential parent, see if this is the one we have got
266: RefObject lPotentialParent = (RefObject) refGetValue(lParentReference);
267: if (lPotentialParent != null)
268: return lParentReference;
269: }
270: return null;
271: }
272:
273: // Implement custom method, which generates the reference for the element
274: // reference is a path along containment chain where every model element
275: // on the chain represented by token : /ReferenceName[InstanceName - only if reference is plural].
276: // For example /Enterprise[HatMaker]/systems[Crm]/domains[Main] refers to the
277: // Domain with the name Main contained in System with the name Crm etc, etc, etc
278: public String getRef() {
279: Reference lParentReference = getReferenceToParent();
280: if (lParentReference == null) {
281: // Our instance is a top instance in the hierarchy - we have to use type name.
282: return mTypeInformation.mTypeName;
283: } else {
284: // Found metadata regarding parent link. Use it
285: AssociationEnd lExposedEnd = lParentReference
286: .getExposedEnd();
287: StringBuffer lRefBuffer = new StringBuffer(
288: ((ModelElement) refGetValue(lParentReference))
289: .getRef());
290: lRefBuffer.append("/");
291: lRefBuffer.append(lExposedEnd.getName());
292: if (lExposedEnd.getMultiplicity().getUpper() != 1) {
293: lRefBuffer.append("[");
294: lRefBuffer.append(getName());
295: lRefBuffer.append("]");
296: }
297: return lRefBuffer.toString();
298: }
299: }
300:
301: /**
302: * @param pAttachmentName
303: * @return ModelElementAttachment with specified name or throws exception if none found
304: */
305: public ModelElementAttachment getAttachment(String pAttachmentName) {
306: ModelElementAttachment lFoundAttachment = findAttachment(pAttachmentName);
307: // Throw exception if nothing found
308: if (lFoundAttachment == null)
309: throw new IllegalArgumentException(
310: "Unable to locate Attachment named '"
311: + pAttachmentName
312: + "' in ModelElement. ModelElementRef: "
313: + getRef());
314: return lFoundAttachment;
315: }
316:
317: /**
318: * @param pAttachmentName
319: * @return ModelElementAttachment with specified name or null if none found
320: */
321: public ModelElementAttachment findAttachment(String pAttachmentName) {
322: Collection lAttachments = getAttachments();
323: if (!lAttachments.isEmpty()) {
324: for (Iterator lAttachmentsIterator = lAttachments
325: .iterator(); lAttachmentsIterator.hasNext();) {
326: ModelElementAttachment lAttachment = (ModelElementAttachment) lAttachmentsIterator
327: .next();
328: if (lAttachment.getName().equals(pAttachmentName))
329: return lAttachment;
330: }
331: }
332: return null;
333: }
334:
335: /** @return Collection of elements directly owned by this element */
336: public Collection getContents() {
337: Set lAllContents = new HashSet();
338: for (Iterator lContainmentReferencesIter = mTypeInformation.mContainedReferences
339: .iterator(); lContainmentReferencesIter.hasNext();) {
340: Reference lReference = (Reference) lContainmentReferencesIter
341: .next();
342: AssociationEnd lReferencedEnd = lReference
343: .getReferencedEnd();
344: if (lReferencedEnd.getMultiplicity().getUpper() != 1) {
345: // This is the collection
346: Collection lReferencedObjectsCollection = (Collection) refGetValue(lReference);
347: if (!lReferencedObjectsCollection.isEmpty())
348: lAllContents.addAll(lReferencedObjectsCollection);
349: } else {
350: RefObject lReferencedObject = (RefObject) refGetValue(lReference);
351: if (lReferencedObject != null)
352: lAllContents.add(lReferencedObject);
353: }
354: }
355: return Collections.unmodifiableCollection(lAllContents);
356: }
357:
358: /** @return Collection of elements directly or indirectly owned by this element */
359: public Collection getCombinedContents() {
360: List lCombinedContents = new ArrayList();
361: getCombinedContents(lCombinedContents);
362: return Collections.unmodifiableCollection(lCombinedContents);
363: }
364:
365: /** Helper. Populates combined contents of this element into the given list */
366: private void getCombinedContents(List pCombinedContentsList) {
367: for (Iterator lContentsIterator = getContents().iterator(); lContentsIterator
368: .hasNext();) {
369: ModelElementImpl lContainedElement = (ModelElementImpl) lContentsIterator
370: .next();
371: pCombinedContentsList.add(lContainedElement);
372: lContainedElement
373: .getCombinedContents(pCombinedContentsList);
374: }
375: }
376:
377: /** @return Collection of elements directly referenced by this element */
378: public Collection getReferencedElements() {
379: Set lAllReferences = new HashSet();
380: for (Iterator lAllReferencesIter = mTypeInformation.mAllReferences
381: .iterator(); lAllReferencesIter.hasNext();) {
382: Reference lReference = (Reference) lAllReferencesIter
383: .next();
384: AssociationEnd lReferencedEnd = lReference
385: .getReferencedEnd();
386: if (lReferencedEnd.getMultiplicity().getUpper() != 1) {
387: // This is the collection
388: Collection lReferencedObjectsCollection = (Collection) refGetValue(lReference);
389: if (!lReferencedObjectsCollection.isEmpty())
390: lAllReferences.addAll(lReferencedObjectsCollection);
391: } else {
392: RefObject lReferencedObject = (RefObject) refGetValue(lReference);
393: if (lReferencedObject != null)
394: lAllReferences.add(lReferencedObject);
395: }
396: }
397: return Collections.unmodifiableCollection(lAllReferences);
398: }
399:
400: /** @return true if this element is contained inside the given container */
401: public boolean isContainedWithin(ModelElement pContainerElement) {
402: for (RefObject lContainer = (RefObject) refImmediateComposite(); lContainer != null; lContainer = (RefObject) lContainer
403: .refImmediateComposite()) {
404: if (pContainerElement.equals(lContainer))
405: return true;
406: }
407: return false;
408: }
409:
410: /** @return true if this element may contain given element at any level */
411: public boolean mayContainWithin(ModelElement pModelElement) {
412: Set lAlreadyTestedTypesCache = new HashSet();
413: return mayContainWithin(pModelElement, lAlreadyTestedTypesCache);
414: }
415:
416: /** @return true if this element may contain given element as the immediate child */
417: public boolean mayContain(ModelElement pModelElement) {
418: MofClass lMetaClass = (MofClass) refMetaObject();
419: for (Iterator lPossibleParentsIterator = ((ModelElementImpl) pModelElement).mTypeInformation.mParentTypes
420: .iterator(); lPossibleParentsIterator.hasNext();) {
421: MofClass lPossibleParentMetaObject = (MofClass) lPossibleParentsIterator
422: .next();
423: if (refIsInstanceOf(lPossibleParentMetaObject, true))
424: return true; // Yes this object may contain given element
425: }
426: return false; // No, this object may not contain given element
427: }
428:
429: /** Helper. Returns true if this element may contain given element at any level. */
430: private boolean mayContainWithin(ModelElement pModelElement,
431: Set pAlreadyTestedTypesCache) {
432: MofClass lMetaClass = (MofClass) refMetaObject();
433: if (!pAlreadyTestedTypesCache.contains(lMetaClass)) {
434: for (Iterator lPossibleParentsIterator = ((ModelElementImpl) pModelElement).mTypeInformation.mParentTypes
435: .iterator(); lPossibleParentsIterator.hasNext();) {
436: MofClass lPossibleParentMetaObject = (MofClass) lPossibleParentsIterator
437: .next();
438: if (refIsInstanceOf(lPossibleParentMetaObject, true))
439: return true; // Yes this object may contain given element
440: }
441: // There is no point in testing instances of the same type - remember this fact
442: pAlreadyTestedTypesCache.add(lMetaClass);
443: }
444: // Now get contents and test them
445: for (Iterator lContentsIterator = getContents().iterator(); lContentsIterator
446: .hasNext();) {
447: if (((ModelElementImpl) lContentsIterator.next())
448: .mayContainWithin(pModelElement,
449: pAlreadyTestedTypesCache))
450: return true;
451: }
452: return false;
453: }
454:
455: /** @return true if this element is derived from other elements of the model (i.e. owned by some sort of model assistant) */
456: public boolean isDerived() {
457: String lOwnerIdentifier = getOwnerIdentifier();
458: return (lOwnerIdentifier != null && lOwnerIdentifier
459: .startsWith(ModelAssistant.OWNER_IDENTIFIER_PRREFIX));
460: }
461: }
|