001: package org.andromda.metafacades.emf.uml2;
002:
003: import java.util.ArrayList;
004: import java.util.Collection;
005: import java.util.Iterator;
006: import java.util.LinkedHashMap;
007: import java.util.LinkedList;
008: import java.util.List;
009: import java.util.Map;
010: import java.util.Set;
011:
012: import org.andromda.core.common.ExceptionUtils;
013: import org.andromda.core.metafacade.MetafacadeConstants;
014: import org.andromda.metafacades.uml.ClassifierFacade;
015: import org.andromda.metafacades.uml.UMLProfile;
016: import org.apache.commons.collections.CollectionUtils;
017: import org.apache.commons.collections.Predicate;
018: import org.apache.commons.collections.Transformer;
019: import org.apache.commons.lang.StringUtils;
020: import org.apache.log4j.Logger;
021: import org.eclipse.emf.common.util.EList;
022: import org.eclipse.emf.common.util.TreeIterator;
023: import org.eclipse.emf.ecore.EObject;
024: import org.eclipse.emf.ecore.EcorePackage;
025: import org.eclipse.emf.ecore.resource.Resource;
026: import org.eclipse.emf.ecore.resource.ResourceSet;
027: import org.eclipse.emf.ecore.util.EcoreUtil;
028: import org.eclipse.uml2.Association;
029: import org.eclipse.uml2.Classifier;
030: import org.eclipse.uml2.Comment;
031: import org.eclipse.uml2.Element;
032: import org.eclipse.uml2.EnumerationLiteral;
033: import org.eclipse.uml2.Generalization;
034: import org.eclipse.uml2.InstanceSpecification;
035: import org.eclipse.uml2.LiteralInteger;
036: import org.eclipse.uml2.LiteralString;
037: import org.eclipse.uml2.LiteralUnlimitedNatural;
038: import org.eclipse.uml2.Model;
039: import org.eclipse.uml2.MultiplicityElement;
040: import org.eclipse.uml2.NamedElement;
041: import org.eclipse.uml2.Namespace;
042: import org.eclipse.uml2.Operation;
043: import org.eclipse.uml2.Package;
044: import org.eclipse.uml2.Parameter;
045: import org.eclipse.uml2.Profile;
046: import org.eclipse.uml2.Property;
047: import org.eclipse.uml2.Slot;
048: import org.eclipse.uml2.Stereotype;
049: import org.eclipse.uml2.Type;
050: import org.eclipse.uml2.TypedElement;
051: import org.eclipse.uml2.UML2Package;
052: import org.eclipse.uml2.ValueSpecification;
053: import org.eclipse.uml2.util.UML2Resource;
054: import org.eclipse.uml2.util.UML2Util;
055:
056: /**
057: * Contains utilities for the Eclipse/UML2 metafacades.
058: *
059: * @author Steve Jerman
060: * @author Chad Brandon
061: * @author Wouter Zoons
062: */
063: public class UmlUtilities {
064: /**
065: * The logger instance.
066: */
067: private static Logger logger = Logger.getLogger(UmlUtilities.class);
068:
069: /**
070: * A transformer which transforms:
071: * <ul>
072: * <li>each property in an attribute or an association end</li>
073: * <li>each slot in an attribute link or a link end</li>
074: * <li>each instance specification in an object instance or a link instance</li>
075: * </ul>
076: * This is needed because UML2 is an API in which there is no conceptual difference between
077: * fundamentally different elements (see list above); which makes it harder to map to metafacades
078: * geared towards UML 1.4
079: */
080: protected static final Transformer ELEMENT_TRANSFORMER = new Transformer() {
081: public Object transform(Object element) {
082: final Object transformedObject;
083:
084: if (element instanceof Property) {
085: final Property property = (Property) element;
086:
087: if (property instanceof AssociationEnd
088: || property instanceof Attribute) {
089: transformedObject = property;
090: } else if (property.getAssociation() != null) {
091: transformedObject = new AssociationEndImpl(property);
092: } else {
093: transformedObject = new AttributeImpl(property);
094: }
095: } else if (element instanceof Slot) {
096: final Slot slot = (Slot) element;
097:
098: if (slot instanceof LinkEnd
099: || slot instanceof AttributeLink) {
100: transformedObject = slot;
101: } else if (this .transform(slot.getDefiningFeature()) instanceof Attribute) {
102: transformedObject = new AttributeLinkImpl(slot);
103: } else {
104: transformedObject = new LinkEndImpl(slot);
105: }
106: } else if (element instanceof InstanceSpecification) {
107: final InstanceSpecification instanceSpecification = (InstanceSpecification) element;
108:
109: if (instanceSpecification instanceof LinkInstance
110: || instanceSpecification instanceof ObjectInstance
111: || instanceSpecification instanceof EnumerationLiteral) {
112: transformedObject = instanceSpecification;
113: } else if (!instanceSpecification.getClassifiers()
114: .isEmpty()
115: && instanceSpecification.getClassifiers()
116: .iterator().next() instanceof org.eclipse.uml2.Class) {
117: transformedObject = new ObjectInstanceImpl(
118: instanceSpecification);
119: } else {
120: transformedObject = new LinkInstanceImpl(
121: instanceSpecification);
122: }
123: } else {
124: transformedObject = element;
125: }
126:
127: return transformedObject;
128: }
129: };
130:
131: /**
132: * List all meta objects instances of a given meta class It's a way to
133: * achieve refAllOfType method in a JMI implementation. Please take care of the
134: * fact that properties are not transformed here.
135: *
136: * @param metaClass The meta class we're looking for its instances
137: * @param model The model where we're searching
138: * @return a list of objects owned by model, instance of metaClass
139: */
140: public static List getAllMetaObjectsInstanceOf(
141: final java.lang.Class metaClass, final Model model) {
142: LinkedList metaObjects = new LinkedList();
143: for (Iterator it = model.eAllContents(); it.hasNext();) {
144: Object metaObject = it.next();
145: if (metaClass.isInstance(metaObject)) {
146: metaObjects.add(metaObject);
147: }
148: }
149: if (logger.isDebugEnabled()) {
150: logger.debug("getAllMetaObjectsInstanceOf class: "
151: + metaClass + ". Found: " + metaObjects.size());
152: }
153: return metaObjects;
154: }
155:
156: /**
157: * Get the comments for a UML Element. This will be a string with each
158: * comment separated by a 2 newlines.
159: *
160: * @param element
161: * @return concatenated string
162: */
163: public static String getComment(final Element element) {
164: String commentString = "";
165: EList comments = element.getOwnedComments();
166:
167: for (Iterator iterator = comments.iterator(); iterator
168: .hasNext();) {
169: final Comment comment = (Comment) iterator.next();
170: if (!commentString.equalsIgnoreCase("")) {
171: commentString = commentString + "\n\n";
172: }
173: commentString = commentString.concat(comment.getBody());
174: }
175: return cleanText(commentString);
176: }
177:
178: /**
179: * Gets rid of all excess whitespace.
180: *
181: * @param text the text from which to remove the white space.
182: * @return the cleaned text.
183: */
184: public static String cleanText(String text) {
185: text = text.replaceAll("[\\t\\n]*", "");
186: text = text.replaceAll("\\s+", " ");
187:
188: return text;
189: }
190:
191: /**
192: * Retrieves the name of the type for the given <code>element</code>.
193: *
194: * @param element the element for which to retrieve the type.
195: * @return the type name.
196: * @deprecated - it is not used. Do we need to keep it ?
197: */
198: public static String getType(final TypedElement element) {
199: final Type elementType = element.getType();
200: String type = elementType.getName();
201: if (type != null && type.trim().length() > 0) {
202: if (element instanceof MultiplicityElement) {
203: MultiplicityElement multiplicity = (MultiplicityElement) element;
204: if (multiplicity.isMultivalued()) {
205: type = type + "[";
206: if (multiplicity.getLower() > 0) {
207: type = type + multiplicity.getLower() + "..";
208: }
209: if (multiplicity.getUpper() == -1) {
210: type = type + "*]";
211: } else {
212: type = type + multiplicity.getUpper() + "]";
213: }
214: }
215: }
216: }
217: return type;
218: }
219:
220: /**
221: * Gets a collection containing all of the attributes for this
222: * class/interface. Superclass properties will included if
223: * <code>follow</code> is true. Overridden properties will be omitted.
224: *
225: * @param umlClassifier the UML class instance from which to retrieve all properties
226: * @param follow whether or not the inheritance hierarchy should be followed
227: * @return all retrieved attributes.
228: */
229: public static List getAttributes(final Classifier umlClassifier,
230: final boolean follow) {
231: final Map attributeMap = new LinkedHashMap(); // preserve ordering
232: final List members = new ArrayList(umlClassifier
233: .getOwnedMembers());
234:
235: if (follow) {
236: members.addAll(umlClassifier.getInheritedMembers());
237: }
238:
239: for (final Iterator memberIterator = members.iterator(); memberIterator
240: .hasNext();) {
241: final Object nextCandidate = memberIterator.next();
242: if (nextCandidate instanceof Property) {
243: final Property property = (Property) nextCandidate;
244:
245: if (property.getAssociation() == null) {
246: if (logger.isDebugEnabled()) {
247: logger.debug("Attribute found for "
248: + umlClassifier.getName() + ": "
249: + property.getName());
250: if (attributeMap
251: .containsKey(property.getName())) {
252: logger
253: .warn("An attribute with this name has already been registered, overriding: "
254: + property.getName());
255: }
256: }
257:
258: // property represents an association end
259: attributeMap.put(property.getName(), property);
260: }
261: }
262: }
263:
264: final List attributeList = new ArrayList(attributeMap.values());
265: CollectionUtils.transform(attributeList, ELEMENT_TRANSFORMER);
266: return attributeList;
267: }
268:
269: /**
270: * Returns <code>true</code> if the given association end's type is an ancestor of the classifier, or just the
271: * argument classifier if follow is <code>false</code>.
272: *
273: * @param property this method returns false if this argument is not an association end
274: */
275: public static boolean isAssociationEndAttachedToType(
276: final Classifier classifier, final Property property,
277: final boolean follow) {
278: boolean attachedToType = false;
279:
280: if (property.getAssociation() != null) {
281: attachedToType = classifier.equals(property.getType());
282:
283: if (follow && !attachedToType) {
284: final List parents = classifier.getGenerals();
285: for (int i = 0; i < parents.size() && !attachedToType; i++) {
286: if (parents.get(i) instanceof Classifier) {
287: final Classifier parent = (Classifier) parents
288: .get(i);
289: attachedToType = isAssociationEndAttachedToType(
290: parent, property, follow);
291: }
292: }
293: }
294: }
295:
296: return attachedToType;
297: }
298:
299: /**
300: * Gets a collection containing all of the associationEnds for this
301: * class/interface. Superclass properties will be included if
302: * <code>follow</code> is true. Overridden properties will be omitted.
303: * <p/>
304: * cejeanne: Changed the way association end are found.
305: *
306: * @param classifier the UML class instance from which to retrieve all properties
307: * @param follow whether or not the inheritance hierarchy should be followed
308: * @return all retrieved attributes.
309: */
310: public static List getAssociationEnds(final Classifier classifier,
311: final boolean follow) {
312: final List associationEnds = new ArrayList();
313: final List allProperties = getAllMetaObjectsInstanceOf(
314: Property.class, classifier.getModel());
315:
316: for (final Iterator propertyIterator = allProperties.iterator(); propertyIterator
317: .hasNext();) {
318: final Property property = (Property) propertyIterator
319: .next();
320:
321: // only treat association ends, ignore attributes
322: if (property.getAssociation() != null
323: && isAssociationEndAttachedToType(classifier,
324: property, follow)) {
325: associationEnds.add(property);
326: }
327: }
328:
329: CollectionUtils.transform(associationEnds, ELEMENT_TRANSFORMER);
330: return associationEnds;
331: }
332:
333: /**
334: * Returns <code>true</code> if and only if the given operation would have an identical signature.
335: * This means:
336: * <ul>
337: * <li>the same name</li>
338: * <li>the same number of parameters</li>
339: * <li>matching parameter types (in that very same order)</li>
340: * </ul>
341: */
342: public static boolean isSameSignature(final Operation first,
343: final Operation second) {
344: boolean sameSignature = true;
345:
346: // test name
347: if (isEqual(first.getName(), second.getName())) {
348: final List firstParameters = first.getOwnedParameters();
349: final List secondParameters = second.getOwnedParameters();
350:
351: // test number of parameters
352: if (firstParameters.size() == secondParameters.size()) {
353: for (int i = 0; i < firstParameters.size()
354: && sameSignature; i++) {
355: final Parameter firstParameter = (Parameter) firstParameters
356: .get(i);
357: final Parameter secondParameter = (Parameter) secondParameters
358: .get(i);
359:
360: // test each parameter's type
361: sameSignature = isEqual(firstParameter.getType(),
362: secondParameter.getType());
363: }
364: } else {
365: sameSignature = false;
366: }
367: } else {
368: sameSignature = false;
369: }
370:
371: return sameSignature;
372: }
373:
374: /**
375: * Returns <code>true</code> if and only if both arguments are equal, this method handles potential
376: * incoming <code>null</code> values.
377: */
378: private static boolean isEqual(Object first, Object second) {
379: return first == null ? second == null : first.equals(second);
380: }
381:
382: /**
383: * Retrieves all specializations of the given <code>classifier</code>
384: * instance.
385: *
386: * @param classifier the classifier from which to retrieve the specializations.
387: * @return all specializations.
388: */
389: public static List getSpecializations(final Classifier classifier) {
390: final List specials = new ArrayList();
391: for (final TreeIterator iterator = EcoreUtil.getRootContainer(
392: classifier).eAllContents(); iterator.hasNext();) {
393: final EObject object = (EObject) iterator.next();
394: if (object instanceof Generalization) {
395: final Generalization generalization = (Generalization) object;
396: if (generalization.getGeneral().equals(classifier)) {
397: specials.add(generalization.getSpecific());
398: }
399: iterator.prune();
400: }
401: }
402: return specials;
403: }
404:
405: /**
406: * Retrieves the names of the stereotypes for the given <code>element</code>
407: *
408: * @param element the element for which to retrieve the stereotypes.
409: * @return all stereotype names
410: */
411: public static List getStereotypeNames(final Element element) {
412: final Collection stereotypes = element.getAppliedStereotypes();
413: final List names = new ArrayList();
414: if (stereotypes != null) {
415: for (final Iterator iterator = stereotypes.iterator(); iterator
416: .hasNext();) {
417: final Stereotype stereotype = (Stereotype) iterator
418: .next();
419: names.add(stereotype.getName());
420: }
421: }
422: return names;
423: }
424:
425: /**
426: * Indicates whether or not the given <code>element</code> contains a
427: * stereotype with the given <code>stereotypeName</code>.
428: *
429: * @param element the element instance.
430: * @param stereotypeName the name of the stereotype
431: * @return true/false
432: */
433: public static boolean containsStereotype(final Element element,
434: final String stereotypeName) {
435: Collection stereotypes = element.getAppliedStereotypes();
436:
437: boolean hasStereotype = StringUtils.isNotBlank(stereotypeName)
438: && stereotypes != null && !stereotypes.isEmpty();
439:
440: if (hasStereotype) {
441: class StereotypeFilter implements Predicate {
442: public boolean evaluate(Object object) {
443: boolean valid;
444: Stereotype stereotype = (Stereotype) object;
445: String name = StringUtils.trimToEmpty(stereotype
446: .getName());
447: valid = stereotypeName.equals(name);
448: for (Iterator itStereo = stereotype.allParents()
449: .iterator(); !valid && itStereo.hasNext();) {
450: Stereotype currentStereotype = (Stereotype) itStereo
451: .next();
452: valid = StringUtils.trimToEmpty(
453: currentStereotype.getName()).equals(
454: stereotypeName);
455: }
456: return valid;
457: }
458: }
459: hasStereotype = CollectionUtils.find(stereotypes,
460: new StereotypeFilter()) != null;
461: }
462: if (logger.isDebugEnabled()) {
463: if (element instanceof NamedElement) {
464: logger.debug(((NamedElement) element)
465: .getQualifiedName()
466: + " has stereotype <<"
467: + stereotypeName
468: + ">> : " + hasStereotype);
469: } else {
470: logger.debug(element.toString() + " has stereotype <<"
471: + stereotypeName + ">> : " + hasStereotype);
472: }
473: }
474: return hasStereotype;
475: }
476:
477: /**
478: * @deprecated old way to handle tag values
479: * Note: The uml profile defines it as "AndroMdaTags" and not "AndroMDATags"
480: * Stores the tagged values that may be applied to an element.
481: */
482: private static final String TAGGED_VALUES_STEREOTYPE = "AndroMdaTags";
483:
484: /**
485: * Retrieves the TagDefinitions for the given element.
486: *
487: * @param element the element from which to retrieve the tagged values.
488: * @return the collection of {@link TagDefinition} instances.
489: */
490: public static Collection getTaggedValue(final NamedElement element) {
491: if (logger.isDebugEnabled()) {
492: logger.debug("Searching Tagged Values for "
493: + element.getName());
494: }
495: final Collection tags = new ArrayList();
496: final Collection stereotypes = element.getAppliedStereotypes();
497: for (Iterator stereoIt = stereotypes.iterator(); stereoIt
498: .hasNext();) {
499: Stereotype stereo = (Stereotype) stereoIt.next();
500: if (stereo.getName().equals(TAGGED_VALUES_STEREOTYPE)) {
501: List tagNames = (List) element.getValue(stereo,
502: "TagName");
503: List tagValues = (List) element.getValue(stereo,
504: "TagValue");
505: for (int ctr = 0; ctr < tagValues.size(); ctr++) {
506: tags.add(new TagDefinitionImpl(tagNames.get(ctr)
507: .toString(), tagValues.get(ctr)));
508: }
509: } else if (element.hasValue(stereo, "value")) {
510: final Object value = element.getValue(stereo, "value");
511: tags
512: .add(new TagDefinitionImpl(stereo.getName(),
513: value));
514: } else {
515: for (Iterator tvIt = getAttributes(stereo, true)
516: .iterator(); tvIt.hasNext();) {
517: Property tagProperty = (Property) tvIt.next();
518: String tagName = tagProperty.getName();
519: if (!tagName.startsWith("base$")) {
520: if (element.hasValue(stereo, tagName)) {
521: // Obtain its value
522: Object tagValue = element.getValue(stereo,
523: tagName);
524: if (tagValue instanceof Collection) {
525: Collection tagValues = (Collection) tagValue;
526: if (!tagValues.isEmpty()) {
527: Collection tagValuesInString = CollectionUtils
528: .collect(tagValues,
529: new Transformer() {
530: public Object transform(
531: Object object) {
532: return getTagValueAsString(object);
533: }
534: });
535: TagDefinition tagDefinition = new TagDefinitionImpl(
536: tagName, tagValuesInString);
537: tags.add(tagDefinition);
538: }
539: } else {
540: TagDefinition tagDefinition = new TagDefinitionImpl(
541: tagName,
542: getTagValueAsString(tagValue));
543: tags.add(tagDefinition);
544: }
545: }
546: }
547: }
548: }
549: }
550:
551: if (logger.isDebugEnabled()) {
552: logger.debug("Found " + tags.size() + " tagged values for "
553: + element.getName());
554: }
555:
556: return tags;
557: }
558:
559: /**
560: * The toString() method isn't suitable to transform the values of tagValue as String.
561: * @param tagValue
562: * @return the tag value as a string.
563: */
564: static String getTagValueAsString(Object tagValue) {
565: String valueAsString = null;
566: if (tagValue != null) {
567: valueAsString = tagValue.toString();
568: if (tagValue instanceof ValueSpecification) {
569: ValueSpecification literal = (ValueSpecification) tagValue;
570: valueAsString = literal.stringValue();
571: } else if (tagValue instanceof InstanceSpecification) {
572: InstanceSpecification instance = (InstanceSpecification) tagValue;
573: valueAsString = instance.getName();
574: }
575: }
576: return valueAsString;
577: }
578:
579: /**
580: * Attempts to find the applied stereotype with the given name on the given
581: * <code>element</code>. First tries to find it with the fully qualified
582: * name, and then tries it with just the name.
583: *
584: * @param name
585: * the name of the stereotype
586: * @return the found stereotype or null if not found.
587: */
588: public static Stereotype findAppliedStereotype(
589: final Element element, final String name) {
590: Stereotype foundStereotype = element.getAppliedStereotype(name);
591: if (foundStereotype == null) {
592: final Set stereotypes = element.getAppliedStereotypes();
593: if (stereotypes != null) {
594: for (final Iterator iterator = stereotypes.iterator(); iterator
595: .hasNext();) {
596: final Stereotype stereotype = (Stereotype) iterator
597: .next();
598: if (stereotype.getName().equals(name)) {
599: foundStereotype = stereotype;
600: break;
601: }
602: }
603: }
604: }
605: return foundStereotype;
606: }
607:
608: /**
609: * Attempts to find the applicable stereotype with the given name on the
610: * given <code>element</code>. First tries to find it with the fully
611: * qualified name, and then tries it with just the name.
612: *
613: * @param name the name of the stereotype
614: * @return the found stereotype or null if not found.
615: */
616: public static Stereotype findApplicableStereotype(
617: final Element element, final String name) {
618: Stereotype foundStereotype = element
619: .getApplicableStereotype(name);
620: if (foundStereotype == null) {
621: final Set stereotypes = element.getApplicableStereotypes();
622: if (stereotypes != null) {
623: for (final Iterator iterator = stereotypes.iterator(); iterator
624: .hasNext();) {
625: final Stereotype stereotype = (Stereotype) iterator
626: .next();
627: if (stereotype.getName().equals(name)) {
628: foundStereotype = stereotype;
629: break;
630: }
631: }
632: }
633: }
634: return foundStereotype;
635: }
636:
637: /**
638: * Retrieves the serial version UID by reading the tagged value
639: * {@link UMLProfile#TAGGEDVALUE_SERIALVERSION_UID} of the
640: * <code>classifier</code>.
641: *
642: * @param classifier the classifier to be inspected.
643: * @return the serial version UID of the classifier. Returns
644: * <code>null</code> if the tagged value cannot be found.
645: */
646: static String getSerialVersionUID(final ClassifierFacade classifier) {
647: ExceptionUtils.checkNull("classifer", classifier);
648: String serialVersionString = (String) classifier
649: .findTaggedValue(UMLProfile.TAGGEDVALUE_SERIALVERSION_UID);
650: return StringUtils.trimToNull(serialVersionString);
651: }
652:
653: /**
654: * Gets the opposite end of the given <code>associationEnd</code> if the
655: * property is indeed an association end, otherwise returns null.
656: *
657: * @param associationEnd the association end from which to retrieve the opposite end.
658: * @return the opposite association end or null.
659: */
660: static AssociationEnd getOppositeAssociationEnd(
661: final Property associationEnd) {
662: Object opposite = null;
663: Association association = associationEnd.getAssociation();
664:
665: if (association != null) {
666: Collection ends = association.getMemberEnds();
667: for (final Iterator endIterator = ends.iterator(); endIterator
668: .hasNext();) {
669: final Object end = endIterator.next();
670: if (end != null && !associationEnd.equals(end)) {
671: opposite = end;
672: break;
673: }
674: }
675: }
676:
677: return new AssociationEndImpl((Property) opposite);
678: }
679:
680: /**
681: * Finds and returns the first model element having the given
682: * <code>name</code> in the <code>modelPackage</code>, returns
683: * <code>null</code> if not found.
684: *
685: * @return the found model element.
686: */
687: static Object findByPredicate(final ResourceSet resourceSet,
688: final Predicate pred) {
689: Object modelElement = null;
690: for (final Iterator iterator = resourceSet.getResources()
691: .iterator(); iterator.hasNext() && modelElement == null;) {
692: final Resource resource = (Resource) iterator.next();
693: final Package model = (Package) EcoreUtil.getObjectByType(
694: resource.getContents(), UML2Package.eINSTANCE
695: .getPackage());
696: if (model != null) {
697: for (final TreeIterator elementIterator = model
698: .eAllContents(); elementIterator.hasNext()
699: && modelElement == null;) {
700: final Object object = elementIterator.next();
701: if (pred.evaluate(object)) {
702: modelElement = object;
703: }
704: }
705: }
706: }
707:
708: return modelElement;
709: }
710:
711: /**
712: * Find the Model of a ressource (UML2 Model)
713: */
714: public static Model findModel(final UML2Resource resource) {
715: Model model = (Model) EcoreUtil.getObjectByType(resource
716: .getContents(), EcorePackage.eINSTANCE.getEObject());
717: if (logger.isDebugEnabled()) {
718: logger.debug("Model found: " + model);
719: }
720: return model;
721: }
722:
723: /**
724: * Constructs the package name for the given <code>metaObject</code>,
725: * seperating the package name by the given <code>separator</code>.
726: *
727: * @param metaObject the Model Element
728: * @param separator the PSM namespace separator, ignored if <code>modelName</code> is <code>true</code>
729: * @param modelName true/false on whether or not to get the model package name
730: * instead of the PSM package name.
731: * @return the package name.
732: */
733: static String getPackageName(final NamedElement metaObject,
734: final String separator, final boolean modelName) {
735: final StringBuffer buffer = new StringBuffer();
736:
737: final String usedSeparator = modelName ? MetafacadeConstants.NAMESPACE_SCOPE_OPERATOR
738: : separator;
739:
740: for (Namespace namespace = metaObject.getNamespace(); namespace != null; namespace = namespace
741: .getNamespace()) {
742: if (namespace instanceof Package
743: && !(namespace instanceof Model)
744: && !(namespace instanceof Profile)) {
745: if (buffer.length() != 0) {
746: buffer.insert(0, usedSeparator);
747: }
748:
749: buffer.insert(0, namespace.getName());
750: }
751: }
752: String packageName = buffer.toString();
753: if (modelName && StringUtils.isNotBlank(packageName)) {
754: packageName = StringUtils.replace(packageName, separator,
755: MetafacadeConstants.NAMESPACE_SCOPE_OPERATOR);
756: }
757:
758: return packageName;
759: }
760:
761: /**
762: * Returns the package name of the closest ancestor that is an instance of <code>NamedElement</code>. If no such
763: * ancestor exists the empty String is returned.
764: * <p/>
765: * If the argument would be an instance of <code>NamedElement</code> then this method returns that object's
766: * package name.
767: *
768: * @see #getPackageName(org.eclipse.uml2.NamedElement, String, boolean)
769: */
770: static String getPackageName(final Element metaObject,
771: final String separator, final boolean modelName) {
772: final String packageName;
773:
774: if (metaObject instanceof NamedElement) {
775: packageName = getPackageName((NamedElement) metaObject,
776: separator, modelName);
777: } else if (metaObject.getOwner() == null) {
778: packageName = "";
779: } else {
780: packageName = getPackageName(metaObject.getOwner(),
781: separator, modelName);
782: }
783:
784: return packageName;
785: }
786:
787: /**
788: * Finds and returns the first model element having the given
789: * <code>name</code> in the <code>modelPackage</code>, returns
790: * <code>null</code> if not found.
791: *
792: * @param rs the resource set to search in
793: * @param name the name to find.
794: * @return the found model element.
795: */
796: static Object findByName(final ResourceSet rs, final String name) {
797: Object modelElement = null;
798: if (StringUtils.isNotBlank(name)) {
799: modelElement = findByPredicate(rs, new Predicate() {
800: public boolean evaluate(final Object object) {
801: if (object instanceof NamedElement) {
802: return StringUtils.trimToEmpty(
803: ((NamedElement) object).getName())
804: .equals(name);
805: }
806: return false;
807: }
808: });
809: }
810: return modelElement;
811: }
812:
813: /**
814: * Finds a given model element in the model having the specified
815: * <code>fullyQualifiedName</code>. If the model element can <strong>NOT
816: * </strong> be found, <code>null</code> will be returned instead.
817: *
818: * @param rs the resource set to search in
819: * @param fullyQualifiedName the fully qualified name of the element to search for.
820: * @param separator the PSM separator used for qualifying the name (example ".").
821: * @param modelName a flag indicating whether or not a search shall be performed
822: * using the fully qualified model name or fully qualified PSM
823: * name.
824: * @return the found model element
825: */
826: static Object findByFullyQualifiedName(final ResourceSet rs,
827: final String fullyQualifiedName, final String separator,
828: final boolean modelName) {
829: Object modelElement;
830: modelElement = findByPredicate(rs, new Predicate() {
831: public boolean evaluate(final Object object) {
832: if (object instanceof NamedElement) {
833: NamedElement element = (NamedElement) object;
834: StringBuffer fullName = new StringBuffer(
835: getPackageName(element, separator,
836: modelName));
837: String name = element.getName();
838: if (StringUtils.isNotBlank(name)) {
839: String namespaceSeparator = MetafacadeConstants.NAMESPACE_SCOPE_OPERATOR;
840: if (!modelName) {
841: namespaceSeparator = separator;
842: }
843: fullName.append(namespaceSeparator);
844: fullName.append(name);
845: }
846: return fullName.toString().equals(
847: fullyQualifiedName);
848: }
849: return false;
850: }
851: });
852: return modelElement;
853: }
854:
855: /**
856: * Multiplicity can be expressed as Value. String, integer... This method
857: * parse it. MD11.5 uses string, and RSM integers.
858: *
859: * @param multValue a ValueSpecification, which need to be parsed
860: * @return the parsed intrger
861: */
862: static int parseMultiplicity(final ValueSpecification multValue) {
863: int value = 1;
864: if (multValue != null) {
865: if (multValue instanceof LiteralInteger) {
866: LiteralInteger litInt = (LiteralInteger) multValue;
867: value = litInt.getValue();
868: } else if (multValue instanceof LiteralUnlimitedNatural) {
869: LiteralUnlimitedNatural litInt = (LiteralUnlimitedNatural) multValue;
870: value = litInt.getValue();
871: }
872:
873: else if (multValue instanceof LiteralString) {
874: LiteralString litStr = (LiteralString) multValue;
875: String multString = litStr.getValue();
876: if (multString.equals("*")) {
877: value = MultiplicityElement.UNLIMITED_UPPER_BOUND;
878: } else {
879: value = Integer.parseInt(multString);
880: }
881: } else {
882: logger
883: .error("Unable to parse this value as multiplicity: "
884: + multValue);
885: }
886: }
887: if (logger.isDebugEnabled()) {
888: logger.debug("Parsing multiplicity: intValue = " + value
889: + " value: " + multValue);
890: }
891: return value;
892: }
893:
894: /**
895: * There is an issue with EMF / XMI about tag value name (there should not be any @ or . inside)
896: * This method checks whether <code>tagValueName</code> can be seen as <code>requestedName</code>.
897: * <li>We compare them either:
898: * without name transformation
899: * removing initial '@' and replacing '.' by '_' (rsm / emf-uml2 profile)
900: * EMF normalization (for MD11.5 export)
901: *
902: * @param requestedName
903: * @param tagValueName
904: */
905: public static boolean doesTagValueNameMatch(String requestedName,
906: String tagValueName) {
907: boolean result = requestedName.equals(tagValueName);
908: if (!result && requestedName.startsWith("@")) {
909: // let's try rsm guess
910: String rsmName = requestedName.substring(1);
911: rsmName = rsmName.replace('.', '_');
912: result = rsmName.equals(tagValueName);
913: if (!result) {
914: // let's try emf normalization
915: String emfName = EMFNormalizer
916: .getEMFName(requestedName);
917: result = emfName.equals(tagValueName);
918: }
919: }
920: return result;
921: }
922:
923: // hack to use a protected method
924: private static class EMFNormalizer extends UML2Util {
925: public static String getEMFName(String name) {
926: return getValidIdentifier(name);
927: }
928: }
929: }
|