1 package org.andromda.metafacades.emf.uml22;
2
3 import java.util.ArrayList;
4 import java.util.Collection;
5 import java.util.Collections;
6 import java.util.Comparator;
7 import java.util.HashMap;
8 import java.util.Iterator;
9 import java.util.LinkedHashMap;
10 import java.util.LinkedHashSet;
11 import java.util.List;
12 import java.util.Map;
13 import java.util.Set;
14 import org.andromda.core.common.ExceptionUtils;
15 import org.andromda.core.metafacade.MetafacadeConstants;
16 import org.andromda.metafacades.uml.ClassifierFacade;
17 import org.andromda.metafacades.uml.UMLProfile;
18 import org.apache.commons.collections.CollectionUtils;
19 import org.apache.commons.collections.Predicate;
20 import org.apache.commons.collections.Transformer;
21 import org.apache.commons.lang.StringUtils;
22 import org.apache.log4j.Logger;
23 import org.eclipse.emf.common.util.EList;
24 import org.eclipse.emf.common.util.TreeIterator;
25 import org.eclipse.emf.ecore.EObject;
26 import org.eclipse.emf.ecore.EcorePackage;
27 import org.eclipse.emf.ecore.resource.Resource;
28 import org.eclipse.emf.ecore.resource.ResourceSet;
29 import org.eclipse.emf.ecore.util.EcoreUtil;
30 import org.eclipse.uml2.common.util.UML2Util;
31 import org.eclipse.uml2.uml.Association;
32 import org.eclipse.uml2.uml.Classifier;
33 import org.eclipse.uml2.uml.Comment;
34 import org.eclipse.uml2.uml.Element;
35 import org.eclipse.uml2.uml.EnumerationLiteral;
36 import org.eclipse.uml2.uml.Generalization;
37 import org.eclipse.uml2.uml.InstanceSpecification;
38 import org.eclipse.uml2.uml.LiteralInteger;
39 import org.eclipse.uml2.uml.LiteralString;
40 import org.eclipse.uml2.uml.LiteralUnlimitedNatural;
41 import org.eclipse.uml2.uml.Model;
42 import org.eclipse.uml2.uml.NamedElement;
43 import org.eclipse.uml2.uml.Namespace;
44 import org.eclipse.uml2.uml.OpaqueExpression;
45 import org.eclipse.uml2.uml.Operation;
46 import org.eclipse.uml2.uml.Package;
47 import org.eclipse.uml2.uml.Parameter;
48 import org.eclipse.uml2.uml.Profile;
49 import org.eclipse.uml2.uml.Property;
50 import org.eclipse.uml2.uml.Slot;
51 import org.eclipse.uml2.uml.Stereotype;
52 import org.eclipse.uml2.uml.UMLPackage;
53 import org.eclipse.uml2.uml.ValueSpecification;
54 import org.eclipse.uml2.uml.resource.UMLResource;
55
56 /**
57 * Contains utilities for the Eclipse/UML2 metafacades.
58 *
59 * @author Steve Jerman
60 * @author Chad Brandon
61 * @author Wouter Zoons
62 * @author Bob Fields
63 */
64 public class UmlUtilities
65 {
66 /**
67 * The logger instance.
68 */
69 private static final Logger LOGGER = Logger.getLogger(UmlUtilities.class);
70
71 private static List<Package> models = new ArrayList<Package>();
72
73 /**
74 * Utility method to return ALL loaded models, populated by RepositoryFacade
75 * @return models
76 */
77 public static List<Package> getModels()
78 {
79 return UmlUtilities.models;
80 }
81
82 /**
83 * @param resources
84 */
85 public static void setModels(final List<Package> resources)
86 {
87 models = Collections.synchronizedList(resources);
88 }
89
90 /**
91 * @param resource
92 */
93 public static void addModel(final Package resource)
94 {
95 models.add(resource);
96 }
97
98 /**
99 * @param resource
100 */
101 public static void removeModel(final Package resource)
102 {
103 models.remove(resource);
104 }
105
106 /**
107 * A transformer which transforms:
108 * <ul>
109 * <li>each property in an attribute or an association end to AssociationEnd or Attribute</li>
110 * <li>each slot in an attribute link or a link end to LinkEnd or AttributeLink</li>
111 * <li>each instance specification in an object instance or a link instance</li>
112 * </ul>
113 * This is needed because UML2 is an API in which there is no conceptual difference between
114 * fundamentally different elements (see list above); which makes it harder to map to metafacades
115 * geared towards UML 1.4
116 */
117 protected static final Transformer ELEMENT_TRANSFORMER =
118 new Transformer()
119 {
120 public Object transform(final Object element)
121 {
122 final Object transformedObject;
123
124 if (element instanceof Property)
125 {
126 final Property property = (Property)element;
127 if (property instanceof AssociationEnd || property instanceof Attribute)
128 {
129 transformedObject = property;
130 }
131 else if (property.getAssociation() == null)
132 {
133 transformedObject = new AttributeImpl(property);
134 }
135 else
136 {
137 transformedObject = new AssociationEndImpl(property);
138 }
139 if (LOGGER.isDebugEnabled() && property.getName() != null && !property.getName().startsWith("andromda"))
140 {
141 LOGGER.debug("UMLUtilities.transform " + property.getName() + " "
142 + property.getType().getName() + " " + property + " " + transformedObject);
143 }
144 }
145 else if (element instanceof Slot)
146 {
147 final Slot slot = (Slot)element;
148
149 // TODO: This mixes uml2 types and metafacade types, uml2 cannot be instanceof mf type
150 if (slot instanceof LinkEnd || slot instanceof AttributeLink)
151 {
152 transformedObject = slot;
153 }
154 else if (this.transform(slot.getDefiningFeature()) instanceof Attribute)
155 {
156 transformedObject = new AttributeLinkImpl(slot);
157 }
158 else
159 {
160 transformedObject = new LinkEndImpl(slot);
161 }
162 }
163 else if (element instanceof InstanceSpecification)
164 {
165 final InstanceSpecification instanceSpecification = (InstanceSpecification)element;
166
167 if (instanceSpecification instanceof LinkInstance ||
168 instanceSpecification instanceof ObjectInstance ||
169 instanceSpecification instanceof EnumerationLiteral)
170 {
171 transformedObject = instanceSpecification;
172 }
173 else if (!instanceSpecification.getClassifiers().isEmpty() &&
174 instanceSpecification.getClassifiers().iterator().next() instanceof org.eclipse.uml2.uml.Class)
175 {
176 transformedObject = new ObjectInstanceImpl(instanceSpecification);
177 }
178 else
179 {
180 transformedObject = new LinkInstanceImpl(instanceSpecification);
181 }
182 }
183 else
184 {
185 transformedObject = element;
186 }
187
188 return transformedObject;
189 }
190 };
191
192 private static final Map<String,List<EObject>> ALL_META_OBJECTS_CACHE =
193 Collections.synchronizedMap(new HashMap<String,List<EObject>>());
194
195 /**
196 * List all meta objects instances of a given meta class It's a way to
197 * achieve refAllOfType method in a JMI implementation. Please take care of the
198 * fact that properties are not transformed here.
199 *
200 * @param metaClass The meta class we're looking for its instances
201 * @param models The models where we're searching
202 * @return a list of objects owned by model, instance of metaClass
203 */
204 public static List<? extends EObject> getAllMetaObjectsInstanceOf(
205 final Class metaClass,
206 final List<Package> models)
207 {
208 if (metaClass==null)
209 {
210 return new ArrayList<EObject>();
211 }
212 List<EObject> metaObjects = ALL_META_OBJECTS_CACHE.get(metaClass.getCanonicalName());
213 if (metaObjects == null)
214 {
215 metaObjects = new ArrayList<EObject>();
216
217 for (final Package model : models)
218 {
219 if (model!=null)
220 {
221 //for (Object metaObject : model.eAllContents())
222 for (final Iterator<EObject> it = model.eAllContents(); it.hasNext();)
223 {
224 final EObject metaObject = it.next();
225 if (metaClass.isInstance(metaObject))
226 {
227 metaObjects.add(metaObject);
228 if (LOGGER.isDebugEnabled())
229 {
230 LOGGER.debug("getAllMetaObjectsInstanceOf class: " + metaClass.getCanonicalName() + " " + metaClass.getClass() + " Found: " + metaObject.getClass());
231 }
232 }
233 }
234 }
235 }
236 }
237
238 if (LOGGER.isDebugEnabled())
239 {
240 LOGGER.debug("getAllMetaObjectsInstanceOf class: " + metaClass.getCanonicalName() + ' ' + metaClass.getClass() + " Found: " + metaObjects.size());
241 }
242 ALL_META_OBJECTS_CACHE.put(metaClass.getCanonicalName(), metaObjects);
243
244 return metaObjects;
245 }
246
247 /**
248 * List all meta objects instances of a given meta class It's a way to
249 * achieve refAllOfType method in a JMI implementation. Please take care of the
250 * fact that properties are not transformed here.
251 *
252 * @param metaClass The meta class we're looking for its instances
253 * @param model The model where we're searching
254 * @return a list of objects owned by model, instance of metaClass
255 */
256 private static List getAllMetaObjectsInstanceOf(
257 final Class metaClass,
258 final Package model)
259 {
260 if (metaClass==null)
261 {
262 return new ArrayList<EObject>();
263 }
264 final List<EObject> metaObjects = new ArrayList<EObject>();
265
266 if (model!=null)
267 {
268 //for (Object metaObject : model.eAllContents())
269 for (final Iterator<EObject> it = model.eAllContents(); it.hasNext();)
270 {
271 final EObject metaObject = it.next();
272 if (metaClass.isInstance(metaObject))
273 {
274 metaObjects.add(metaObject);
275 }
276 }
277 }
278
279 return metaObjects;
280 }
281
282 /**
283 * This clears the meta objects cache. Even though this
284 * isn't the "cleanest" way to handle things, we need this
285 * for performance reasons (getAllMetaObjectsInstanceOf is WAY
286 * to slow otherwise).
287 */
288 public static void clearAllMetaObjectsCache()
289 {
290 ALL_META_OBJECTS_CACHE.clear();
291 }
292
293 /**
294 * Get the comments for a UML Element. This will be a string with each
295 * comment separated by a 2 newlines.
296 *
297 * @param element
298 * @return concatenated string
299 */
300 public static String getComment(final Element element)
301 {
302 if (element==null)
303 {
304 return null;
305 }
306 final StringBuilder commentString = new StringBuilder();
307 final Collection<Comment> comments = element.getOwnedComments();
308
309 for (final Comment comment : comments)
310 {
311 if (commentString.length()>0)
312 {
313 commentString.append("\n\n");
314 }
315 commentString.append(comment.getBody());
316 }
317 return cleanText(commentString.toString());
318 }
319
320 /**
321 * Gets rid of all excess whitespace.
322 *
323 * @param text the text from which to remove the white space.
324 * @return the cleaned text.
325 */
326 public static String cleanText(String text)
327 {
328 if (StringUtils.isBlank(text))
329 {
330 return text;
331 }
332 text =
333 text.replaceAll(
334 "[\\t\\n]*",
335 "");
336 text =
337 text.replaceAll(
338 "\\s+",
339 " ");
340
341 return text;
342 }
343
344 /**
345 * returns all owned properties of the given classifier with the right type:
346 * attribute if <code>isAssociation</code> is false and association end
347 * otherwise.
348 *
349 * @param classifier the classifier to inspect.
350 * @param follow whether to follow inheritance hierarchy upward.
351 * @param isAssociation Retrieve only AssociationEnd properties.
352 * @return all owned properties of the given classifier with the right type.
353 */
354 public static List<Property> getOwnedProperty(
355 final Classifier classifier,
356 final boolean follow,
357 final boolean isAssociation)
358 {
359 if (classifier==null)
360 {
361 return new ArrayList<Property>();
362 }
363 final Map<String, Property> attributeMap = new LinkedHashMap<String, Property>(); // preserve ordering
364 final List<NamedElement> members = new ArrayList<NamedElement>(classifier.getOwnedMembers());
365
366 if (follow)
367 {
368 members.addAll(classifier.getInheritedMembers());
369 }
370
371 for (NamedElement nextCandidate : members)
372 {
373 if (nextCandidate instanceof Property)
374 {
375 final Property property = (Property)nextCandidate;
376 /*if (attributeMap.containsKey(property.getName()))
377 {
378 logger.warn(
379 "Attribute with this name has already been registered on " +
380 classifier.getQualifiedName() + ": " + property.getName());
381 }*/
382
383 if (isAssociation && property.getAssociation() != null)
384 {
385 /*if (LOGGER.isDebugEnabled())
386 {
387 LOGGER.debug("Association found for " + classifier.getName() + ": " + property.getName());
388 }*/
389 // property represents an association end
390 attributeMap.put(
391 property.getName(),
392 property);
393 }
394 else if (!isAssociation && property.getAssociation() == null)
395 {
396 /*if (LOGGER.isDebugEnabled())
397 {
398 LOGGER.debug("Attribute found for " + classifier.getName() + ": " + property.getName());
399 }*/
400 // property represents an attribute
401 attributeMap.put(
402 property.getName(),
403 property);
404 }
405 }
406 }
407
408 return new ArrayList<Property>(attributeMap.values());
409 }
410
411 /**
412 * Gets a collection containing all of the attributes for this
413 * class/interface. Superclass properties will included if
414 * <code>follow</code> is true. Overridden properties will be omitted.
415 *
416 * @param classifier the UML class instance from which to retrieve all properties
417 * @param follow whether or not the inheritance hierarchy should be followed upward
418 * @return all retrieved attributes. No associations or enumerations.
419 */
420 public static List<Property> getAttributes(
421 final Classifier classifier,
422 final boolean follow)
423 {
424 final List<Property> attributeList = getOwnedProperty(classifier, follow, false);
425 CollectionUtils.transform(
426 attributeList,
427 ELEMENT_TRANSFORMER);
428 //Collections.sort(attributeList, new PropertyComparator());
429 if (LOGGER.isDebugEnabled())
430 {
431 for (Property property : attributeList)
432 {
433 if (!classifier.getQualifiedName().startsWith("andromda") && LOGGER.isDebugEnabled())
434 {
435 LOGGER.debug("UMLUtilities.getAttributes " + classifier.getQualifiedName()
436 + " " + property.getName() + " " + property.getType().getName());
437 }
438 }
439 }
440 return attributeList;
441 }
442
443 /**
444 * Returns <code>true</code> if the given association end's type is an ancestor of the classifier, or just the
445 * argument classifier if follow is <code>false</code>.
446 * @param classifier
447 * @param property this method returns false if this argument is not an association end
448 * @param follow
449 * @return isAssociationEndAttachedToType((Classifier)parent, property, follow)
450 */
451 public static boolean isAssociationEndAttachedToType(
452 final Classifier classifier,
453 final Property property,
454 final boolean follow)
455 {
456 boolean attachedToType = false;
457
458 if (property.getAssociation() != null)
459 {
460 attachedToType = classifier.equals(property.getType());
461 if (follow && !attachedToType)
462 {
463
464 for (Classifier parent : classifier.getGenerals())
465 {
466 //if (parent instanceof Classifier)
467 //{
468 attachedToType =
469 isAssociationEndAttachedToType(
470 parent,
471 property,
472 follow);
473 //}
474 }
475 }
476 if (LOGGER.isDebugEnabled() && attachedToType)
477 {
478 LOGGER.debug("isAssociationEndAttachedToType " + classifier.getQualifiedName() + ' ' + property + ' ' + property.getQualifiedName() + ' ' + property.getAssociation() + ' ' + property.getAssociationEnd() + ' ' + attachedToType);
479 }
480 }
481 return attachedToType;
482 }
483
484 /**
485 * Gets a collection containing all of the associationEnds for this
486 * class/interface. Superclass properties will be included if
487 * <code>follow</code> is true. Overridden properties will be omitted.
488 * Finds all Property classes in model and iterates through to see which are of type classifier.
489 * <p/>
490 * cejeanne: Changed the way association ends are found.
491 *
492 * @param classifier the UML class instance from which to retrieve all properties
493 * @param follow whether or not the inheritance hierarchy should be followed
494 * @return all retrieved attributes.
495 */
496 public static List<Property> getAssociationEnds(
497 final Classifier classifier,
498 final boolean follow)
499 {
500 final Set<Property> associationEnds = new LinkedHashSet<Property>();
501 if (classifier==null)
502 {
503 return Collections.emptyList();
504 }
505 associationEnds.addAll(getOwnedProperty(classifier, follow, true));
506 CollectionUtils.transform(associationEnds, new Transformer()
507 {
508 public Object transform(final Object input) {
509 return getOppositeProperty((Property)input);
510 }
511 });
512 // TODO: Iterate through all referenced models, not just the model containing this classifier.
513 // TODO: UML2 bug? getModel returns null because UMLUtil.getOwningElement getBaseElement(owner.eContainer()) changes owningElement to null
514 final Package modelPackage = UmlUtilities.findModel(classifier);
515 /*if (modelPackage==null)
516 {
517 logger.error(classifier + " getModel was null: " + classifier.getOwner() + " " + classifier.getQualifiedName());
518 Element classifierOwner = classifier.getOwner();
519 Element owner = null;
520 while (classifierOwner!=null)
521 {
522 owner = classifierOwner;
523 classifierOwner = owner.getOwner();
524 }
525 // Find the last owner in the chain... Top level package.
526 modelPackage = (Package) owner;
527 }*/
528 final List<Property> allProperties = getAllMetaObjectsInstanceOf(
529 Property.class,
530 modelPackage);
531 if (LOGGER.isDebugEnabled())
532 {
533 LOGGER.debug("getAssociationEnds " + classifier.getQualifiedName() + ": getAllMetaObjectsInstanceOf=" + allProperties.size());
534 }
535
536 for (Property property : allProperties)
537 {
538 // only treat association ends, ignore attributes
539 if (property.getAssociation() != null && isAssociationEndAttachedToType(
540 classifier,
541 property,
542 follow))
543 {
544 /*int ownedSize = property.getAssociation().getOwnedEnds().size();
545 if (ownedSize==1)
546 {
547 associationEnds.add(property.getAssociation().getOwnedEnds().get(0));
548 logger.debug("getAssociationEnds " + classifier.getQualifiedName() + ": addedOwnedAssociationEnd " + property + " " + property.getType() + " " + property.getAssociation() + " AssociationEnd=" + property.getAssociationEnd() + " Qualifiers=" + property.getQualifiers() + " Opposite=" + property.getOpposite());
549 }
550 else if (ownedSize==0 || ownedSize>1)
551 {
552 logger.error("associationEnds ownedEnds=" + ownedSize);
553 }
554 else
555 {*/
556 // TODO: associationEnds always show up as non-navigable because the association property (not the end) is added.
557 associationEnds.add(property);
558 if (LOGGER.isDebugEnabled())
559 {
560 LOGGER.debug("getAssociationEnds " + classifier.getQualifiedName() + ": addedAssociation " + property + ' ' + property.getType() + ' ' + property.getAssociation() + " AssociationEnd=" + property.getAssociationEnd() + " OwnedEnds=" + property.getAssociation().getOwnedEnds() + " Qualifiers=" + property.getQualifiers() + " Navigable=" + property.isNavigable());
561 }
562 /* }*/
563 }
564 }
565
566 CollectionUtils.transform(
567 associationEnds,
568 ELEMENT_TRANSFORMER);
569 return new ArrayList<Property>(associationEnds);
570 }
571
572 /**
573 * Returns <code>true</code> if and only if the given operation would have an identical signature.
574 * This means:
575 * <ul>
576 * <li>the same name</li>
577 * <li>the same number of parameters</li>
578 * <li>matching parameter types (in that very same order)</li>
579 * </ul>
580 * @param first
581 * @param second
582 * @return isEqual(firstParameter.getType(), secondParameter.getType())
583 */
584 public static boolean isSameSignature(
585 final Operation first,
586 final Operation second)
587 {
588 boolean sameSignature = true;
589
590 // test name
591 if (isEqual(
592 first.getName(),
593 second.getName()))
594 {
595 final List<Parameter> firstParameters = first.getOwnedParameters();
596 final List<Parameter> secondParameters = second.getOwnedParameters();
597
598 // test number of parameters
599 if (firstParameters.size() == secondParameters.size())
600 {
601 for (int i = 0; i < firstParameters.size() && sameSignature; i++)
602 {
603 final Parameter firstParameter = firstParameters.get(i);
604 final Parameter secondParameter = secondParameters.get(i);
605
606 // test each parameter's type
607 sameSignature =
608 isEqual(
609 firstParameter.getType(),
610 secondParameter.getType());
611 }
612 }
613 else
614 {
615 sameSignature = false;
616 }
617 }
618 else
619 {
620 sameSignature = false;
621 }
622
623 return sameSignature;
624 }
625
626 /**
627 * Returns <code>true</code> if and only if both arguments are equal, this method handles potential
628 * incoming <code>null</code> values.
629 */
630 private static boolean isEqual(
631 final Object first,
632 final Object second)
633 {
634 return first == null ? second == null : first.equals(second);
635 }
636
637 /**
638 * Retrieves all specializations of the given <code>classifier</code>
639 * instance.
640 *
641 * @param classifier the classifier from which to retrieve the specializations.
642 * @return all specializations.
643 */
644 public static List<Classifier> getSpecializations(final Classifier classifier)
645 {
646 final List<Classifier> specials = new ArrayList<Classifier>();
647 if (classifier==null)
648 {
649 return specials;
650 }
651 /*for(DirectedRelationship gen :
652 classifier.getTargetDirectedRelationships(UMLPackage.eINSTANCE.getGeneralization()))
653 {
654 for(Element elt : gen.getSources())
655 {
656 if (elt instanceof Classifier)
657 specials.add((Classifier)elt);
658 }
659 }*/
660
661 for (final TreeIterator<EObject> iterator = EcoreUtil.getRootContainer(classifier).eAllContents(); iterator.hasNext();)
662 {
663 final EObject object = iterator.next();
664 if (object instanceof Generalization)
665 {
666 final Generalization generalization = (Generalization)object;
667 if (generalization.getGeneral().equals(classifier))
668 {
669 specials.add(generalization.getSpecific());
670 }
671 iterator.prune();
672 }
673 }
674 return specials;
675 }
676
677 /**
678 * Retrieves the names of the stereotypes for the given <code>element</code>
679 *
680 * @param element the element for which to retrieve the stereotypes.
681 * @return all stereotype names
682 */
683 public static List<String> getStereotypeNames(final Element element)
684 {
685 final List<String> names = new ArrayList<String>();
686 if (element==null)
687 {
688 return names;
689 }
690 final Collection<Stereotype> stereotypes = element.getAppliedStereotypes();
691 if (stereotypes != null)
692 {
693 for (Stereotype stereotype : stereotypes)
694 {
695 names.add(stereotype.getName());
696 }
697 }
698 return names;
699 }
700
701 /**
702 * Indicates whether or not the given <code>element</code> contains a
703 * stereotype with the given <code>stereotypeName</code>.
704 *
705 * @param element the element instance.
706 * @param stereotypeName the name of the stereotype
707 * @return true/false
708 */
709 public static boolean containsStereotype(
710 final Element element,
711 final String stereotypeName)
712 {
713 if (element==null || StringUtils.isBlank(stereotypeName))
714 {
715 return false;
716 }
717 final Collection<Stereotype> stereotypes = element.getAppliedStereotypes();
718
719 boolean hasStereotype = StringUtils.isNotBlank(stereotypeName) && stereotypes != null &&
720 !stereotypes.isEmpty();
721
722 if (hasStereotype)
723 {
724 class StereotypeFilter
725 implements Predicate
726 {
727 public boolean evaluate(final Object object)
728 {
729 boolean valid;
730 final Stereotype stereotype = (Stereotype)object;
731 final String name = StringUtils.trimToEmpty(stereotype.getName());
732 valid = stereotypeName.equalsIgnoreCase(name);
733 for (Classifier itStereo : stereotype.allParents())
734 {
735 valid = valid || StringUtils.trimToEmpty(itStereo.getName()).equalsIgnoreCase(stereotypeName);
736 }
737 return valid;
738 }
739 }
740 hasStereotype =
741 CollectionUtils.find(
742 stereotypes,
743 new StereotypeFilter()) != null;
744 }
745 if (LOGGER.isDebugEnabled() && hasStereotype)
746 {
747 if (element instanceof NamedElement)
748 {
749 LOGGER.debug(
750 ((NamedElement)element).getQualifiedName() + " has stereotype <<" + stereotypeName + ">> : " +
751 hasStereotype);
752 }
753 else
754 {
755 LOGGER.debug(element.toString() + " has stereotype <<" + stereotypeName + ">> : " + hasStereotype);
756 }
757 }
758 return hasStereotype;
759 }
760
761 /**
762 * @deprecated old way to handle tag values
763 * Note: The uml profile defines it as "AndroMdaTags" and not "AndroMDATags"
764 * Stores the tagged values that may be applied to an element.
765 */
766 @Deprecated
767 private static final String TAGGED_VALUES_STEREOTYPE = "AndroMdaTags";
768
769 /**
770 * Retrieves the TagDefinitions for the given element.
771 *
772 * @param element the element from which to retrieve the tagged values.
773 * @return the collection of {@link TagDefinition} instances.
774 */
775 public static Collection<TagDefinition> getTaggedValue(final Element element)
776 {
777 final Collection<TagDefinition> tags = new ArrayList<TagDefinition>();
778 if (element==null)
779 {
780 return tags;
781 }
782 String elementName = "";
783
784 if (element instanceof NamedElement)
785 {
786 elementName = ((NamedElement)element).getName();
787 }
788 else
789 {
790 elementName = element.toString();
791 }
792
793 /*if (logger.isDebugEnabled())
794 {
795 logger.debug("Searching Tagged Values for " + elementName);
796 }*/
797 final Collection<Stereotype> stereotypes = element.getAppliedStereotypes();
798 for (final Stereotype stereo : stereotypes)
799 {
800 if (TAGGED_VALUES_STEREOTYPE.equals(stereo.getName()))
801 {
802 final List tagNames = (List)element.getValue(
803 stereo,
804 "TagName");
805 final List tagValues = (List)element.getValue(
806 stereo,
807 "TagValue");
808 for (int ctr = 0; ctr < tagValues.size(); ctr++)
809 {
810 tags.add(new TagDefinitionImpl(
811 tagNames.get(ctr).toString(),
812 tagValues.get(ctr)));
813 }
814 }
815 else if (element.hasValue(
816 stereo,
817 "value"))
818 {
819 final Object value = element.getValue(
820 stereo,
821 "value");
822 tags.add(new TagDefinitionImpl(
823 stereo.getName(),
824 value));
825 }
826 else
827 {
828 for (final Property tagProperty : getAttributes(stereo, true))
829 {
830 final String tagName = tagProperty.getName();
831 // Some metafacades depend on an actual returned value. hasValue returns nothing if taggedValue=default for the attribute.
832 if (!tagName.startsWith("base$") && element.hasValue(stereo, tagName))
833 {
834 // Obtain its value
835 final Object tagValue = element.getValue(stereo, tagName);
836 if (tagValue instanceof Collection)
837 {
838 final Collection tagValues = (Collection)tagValue;
839 if (!tagValues.isEmpty())
840 {
841 final Collection tagValuesInString =
842 CollectionUtils.collect(
843 tagValues,
844 new Transformer()
845 {
846 public Object transform(final Object object)
847 {
848 return getTagValueAsString(object);
849 }
850 });
851 final TagDefinition tagDefinition = new TagDefinitionImpl(tagName, tagValuesInString);
852 tags.add(tagDefinition);
853 }
854 }
855 else
856 {
857 final String tagString = getTagValueAsString(tagValue);
858 if (!StringUtils.isBlank(tagString) && !"default".equalsIgnoreCase(tagString))
859 {
860 final TagDefinition tagDefinition =
861 new TagDefinitionImpl(tagName, tagString);
862 tags.add(tagDefinition);
863 }
864 }
865 }
866 }
867 }
868 }
869
870 if (LOGGER.isDebugEnabled() && !tags.isEmpty())
871 {
872 LOGGER.debug("Found " + tags.size() + " tagged values for " + elementName);
873 }
874
875 return tags;
876 }
877
878 /**
879 * The toString() method isn't suitable to transform the values of tagValue as String.
880 * @param tagValue
881 * @return the tag value as a string.
882 */
883 static String getTagValueAsString(final Object tagValue)
884 {
885 String valueAsString = null;
886 if (tagValue != null)
887 {
888 valueAsString = tagValue.toString();
889 if (tagValue instanceof ValueSpecification)
890 {
891 final ValueSpecification literal = (ValueSpecification)tagValue;
892 valueAsString = literal.stringValue();
893 }
894 else if (tagValue instanceof NamedElement)
895 {
896 final NamedElement instance = (NamedElement)tagValue;
897 valueAsString = instance.getName();
898 }
899 }
900 return valueAsString;
901 }
902
903 /**
904 * Attempts to find the applied stereotype with the given name on the given
905 * <code>element</code>. First tries to find it with the fully qualified
906 * name, and then tries it with just the name.
907 * @param element
908 * @param name
909 * the name of the stereotype
910 * @return the found stereotype or null if not found.
911 */
912 public static Stereotype findAppliedStereotype(
913 final Element element,
914 final String name)
915 {
916 if (element==null || StringUtils.isBlank(name))
917 {
918 return null;
919 }
920 Stereotype foundStereotype = element.getAppliedStereotype(name);
921 if (foundStereotype == null)
922 {
923 final EList<Stereotype> stereotypes = element.getAppliedStereotypes();
924 if (stereotypes != null)
925 {
926 for (Stereotype stereotype : stereotypes)
927 {
928 if (stereotype.getName().equals(name))
929 {
930 foundStereotype = stereotype;
931 break;
932 }
933 }
934 }
935 }
936 return foundStereotype;
937 }
938
939 /**
940 * Attempts to find the applicable stereotype with the given name on the
941 * given <code>element</code>. First tries to find it with the fully
942 * qualified name, and then tries it with just the name.
943 * @param element
944 * @param name the name of the stereotype
945 * @return the found stereotype or null if not found.
946 */
947 public static Stereotype findApplicableStereotype(
948 final Element element,
949 final String name)
950 {
951 if (element==null || StringUtils.isBlank(name))
952 {
953 return null;
954 }
955 Stereotype foundStereotype = element.getApplicableStereotype(name);
956 if (foundStereotype == null)
957 {
958 final EList<Stereotype> stereotypes = element.getApplicableStereotypes();
959 if (stereotypes != null)
960 {
961 for (Stereotype stereotype : stereotypes)
962 {
963 if (stereotype.getName().equals(name))
964 {
965 foundStereotype = stereotype;
966 break;
967 }
968 }
969 }
970 }
971 return foundStereotype;
972 }
973
974 /**
975 * Retrieves the serial version UID by reading the tagged value
976 * {@link UMLProfile#TAGGEDVALUE_SERIALVERSION_UID} of the
977 * <code>classifier</code>.
978 *
979 * @param classifier the classifier to be inspected.
980 * @return the serial version UID of the classifier. Returns
981 * <code>null</code> if the tagged value cannot be found.
982 */
983 static String getSerialVersionUID(final ClassifierFacade classifier)
984 {
985 ExceptionUtils.checkNull(
986 "classifer",
987 classifier);
988 final String serialVersionString = (String)classifier.findTaggedValue(UMLProfile.TAGGEDVALUE_SERIALVERSION_UID);
989 return StringUtils.trimToNull(serialVersionString);
990 }
991
992 /**
993 * Gets the opposite end of the given <code>associationEnd</code> if the
994 * property is indeed an association end, otherwise returns null.
995 *
996 * @param associationEnd the association end from which to retrieve the opposite end.
997 * @return the opposite association end or null.
998 */
999 public static Property getOppositeProperty(final Property associationEnd)
1000 {
1001 if (associationEnd==null)
1002 {
1003 return null;
1004 }
1005 Property opposite = associationEnd.getOpposite();
1006 if (opposite == null)
1007 {
1008 final Association association = associationEnd.getAssociation();
1009 if (association != null)
1010 {
1011 final Collection<Property> ends = association.getMemberEnds();
1012 for (final Property end : ends)
1013 {
1014 if (end != null && !associationEnd.equals(end))
1015 {
1016 opposite = end;
1017 break;
1018 }
1019 }
1020 }
1021 }
1022 return opposite;
1023 }
1024
1025
1026 /**
1027 * Gets the opposite end of the given <code>associationEnd</code> if the
1028 * property is indeed an association end, otherwise returns null.
1029 *
1030 * @param associationEnd the association end from which to retrieve the opposite end.
1031 * @return the opposite association end or null.
1032 */
1033 public static AssociationEnd getOppositeAssociationEnd(final Property associationEnd)
1034 {
1035 if (associationEnd==null)
1036 {
1037 return null;
1038 }
1039 return new AssociationEndImpl(getOppositeProperty(associationEnd));
1040 }
1041
1042 /**
1043 * Finds and returns the first model element having the given
1044 * <code>name</code> in the <code>modelPackage</code>, returns
1045 * <code>null</code> if not found.
1046 * @param resourceSet
1047 * @param pred
1048 *
1049 * @return the found model element.
1050 */
1051 public static Object findByPredicate(
1052 final ResourceSet resourceSet,
1053 final Predicate pred)
1054 {
1055 Object modelElement = null;
1056 if (resourceSet==null || pred==null)
1057 {
1058 return modelElement;
1059 }
1060 for (Resource resource : resourceSet.getResources())
1061 {
1062 final Package model =
1063 (Package)EcoreUtil.getObjectByType(
1064 resource.getContents(),
1065 UMLPackage.eINSTANCE.getPackage());
1066 if (model != null)
1067 {
1068 for (final TreeIterator<EObject> elementIterator = model.eAllContents();
1069 elementIterator.hasNext() && modelElement == null;)
1070 {
1071 final Object object = elementIterator.next();
1072 if (pred.evaluate(object))
1073 {
1074 modelElement = object;
1075 }
1076 }
1077 }
1078 if (modelElement != null)
1079 {
1080 break;
1081 }
1082 }
1083
1084 return modelElement;
1085 }
1086
1087 /**
1088 * Find the Model of a resource (UML2 Model)
1089 * @param resource
1090 * @return (Model)EcoreUtil.getObjectByType(resource.getContents(), EcorePackage.eINSTANCE.getEObject())
1091 */
1092 public static Package findModel(final UMLResource resource)
1093 {
1094 if (resource==null)
1095 {
1096 return null;
1097 }
1098 final Package model = (Package)EcoreUtil.getObjectByType(
1099 resource.getContents(),
1100 EcorePackage.eINSTANCE.getEObject());
1101 if (model==null)
1102 {
1103 LOGGER.error("getModel was null: " + resource);
1104 }
1105 else if (LOGGER.isDebugEnabled())
1106 {
1107 LOGGER.debug("Model found: " + model);
1108 }
1109 return model;
1110 }
1111
1112 /**
1113 * Find the Model of a resource (UML2 Model)
1114 * @param element
1115 * @return (Model)EcoreUtil.getObjectByType(resource.getContents(), EcorePackage.eINSTANCE.getEObject())
1116 */
1117 public static Package findModel(final Element element)
1118 {
1119 if (element==null)
1120 {
1121 return null;
1122 }
1123 Package modelPackage = element.getModel();
1124 if (modelPackage==null)
1125 {
1126 if (LOGGER.isDebugEnabled())
1127 {
1128 LOGGER.error("getModel was null: " + element + " OWNER: " + element.getOwner());
1129 }
1130 Element classifierOwner = element.getOwner();
1131 Element owner = null;
1132 while (classifierOwner!=null)
1133 {
1134 owner = classifierOwner;
1135 classifierOwner = owner.getOwner();
1136 }
1137 // Find the last owner in the chain... Top level package.
1138 modelPackage = (Package) owner;
1139 }
1140 return modelPackage;
1141 }
1142
1143 /**
1144 * Constructs the package name for the given <code>metaObject</code>,
1145 * separating the package name by the given <code>separator</code>.
1146 *
1147 * @param metaObject the Model Element
1148 * @param separator the PSM namespace separator, ignored if <code>modelName</code> is <code>true</code>
1149 * @param modelName true/false on whether or not to get the model package name
1150 * instead of the PSM package name.
1151 * @return the package name.
1152 */
1153 public static String getPackageName(
1154 final NamedElement metaObject,
1155 final String separator,
1156 final boolean modelName)
1157 {
1158 if (metaObject==null || StringUtils.isBlank(separator))
1159 {
1160 return null;
1161 }
1162 final StringBuilder buffer = new StringBuilder();
1163
1164 final String usedSeparator = modelName ? MetafacadeConstants.NAMESPACE_SCOPE_OPERATOR : separator;
1165
1166 for (Namespace namespace = metaObject.getNamespace(); namespace != null;
1167 namespace = namespace.getNamespace())
1168 {
1169 if (namespace instanceof Package && !(namespace instanceof Model) && !(namespace instanceof Profile))
1170 {
1171 if (buffer.length() != 0)
1172 {
1173 buffer.insert(
1174 0,
1175 usedSeparator);
1176 }
1177
1178 buffer.insert(
1179 0,
1180 namespace.getName());
1181 }
1182 }
1183 String packageName = buffer.toString();
1184 /* // TODO Remove Model Name from the package hierarchy
1185 if (StringUtils.isBlank(packageName))
1186 {
1187 packageName =
1188 getPackageName(
1189 metaObject.getOwner(),
1190 separator,
1191 modelName);
1192 }
1193 if (StringUtils.isBlank(packageName) && metaObject instanceof Classifier)
1194 {
1195 packageName = ((Classifier)metaObject).getPackage().getQualifiedName();
1196 }
1197 // Allow for empty namespace - new after UML2 v3
1198 if (StringUtils.isBlank(packageName))
1199 {
1200 Package modelPackage = metaObject.getModel();
1201 String name = metaObject.getNearestPackage().getQualifiedName();
1202 if (modelPackage instanceof Model)
1203 {
1204 // Remove model name from the front of Package Name string
1205 String model = modelPackage.getName();
1206 if (model != null && name.indexOf(model) > -1 && (name.length() >= model.length() + separator.length() + 1))
1207 {
1208 packageName = name.substring(model.length() + separator.length() + 1);
1209 }
1210 }
1211 }*/
1212 if (modelName && StringUtils.isNotBlank(packageName))
1213 {
1214 packageName =
1215 StringUtils.replace(
1216 packageName,
1217 separator,
1218 MetafacadeConstants.NAMESPACE_SCOPE_OPERATOR);
1219 }
1220
1221 return packageName;
1222 }
1223
1224 /**
1225 * Returns the package name of the closest ancestor that is an instance of <code>NamedElement</code>. If no such
1226 * ancestor exists the empty String is returned.
1227 * <p/>
1228 * If the argument would be an instance of <code>NamedElement</code> then this method returns that object's
1229 * package name.
1230 * @param metaObject
1231 * @param separator
1232 * @param modelName
1233 * @return packageName
1234 *
1235 * @see #getPackageName(org.eclipse.uml2.uml.NamedElement, String, boolean)
1236 */
1237 public static String getPackageName(
1238 final Element metaObject,
1239 final String separator,
1240 final boolean modelName)
1241 {
1242 if (metaObject==null || StringUtils.isBlank(separator))
1243 {
1244 return null;
1245 }
1246 String packageName = null;
1247
1248 if (metaObject instanceof NamedElement)
1249 {
1250 packageName =
1251 getPackageName(
1252 (NamedElement)metaObject,
1253 separator,
1254 modelName);
1255 }
1256 else if (metaObject.getOwner() == null)
1257 {
1258 packageName = "";
1259 }
1260 else
1261 {
1262 packageName =
1263 getPackageName(
1264 metaObject.getOwner(),
1265 separator,
1266 modelName);
1267 }
1268 /* if (StringUtils.isBlank(packageName))
1269 {
1270 packageName =
1271 getPackageName(
1272 metaObject.getOwner(),
1273 separator,
1274 modelName);
1275 }
1276 // TODO Remove model name from the front of the FQ package name
1277 if (StringUtils.isBlank(packageName) && metaObject instanceof Classifier)
1278 {
1279 packageName = ((Classifier)metaObject).getPackage().getQualifiedName();
1280 }
1281 if (StringUtils.isBlank(packageName))
1282 {
1283 packageName = metaObject.getNearestPackage().getQualifiedName();
1284 }*/
1285
1286 return packageName;
1287 }
1288
1289 /**
1290 * Returns the fully-qualified name of the model element by iterating up through the getOwner hierarchy.
1291 * @param metaObject
1292 * @param separator
1293 * @param modelName
1294 * @return packageName
1295 */
1296 public static String getFullyQualifiedName(
1297 final Element metaObject,
1298 final String separator,
1299 final boolean modelName)
1300 {
1301 if (metaObject==null || StringUtils.isBlank(separator) || !(metaObject instanceof NamedElement))
1302 {
1303 return "";
1304 }
1305 final NamedElement element = (NamedElement)metaObject;
1306 String name = element.getName();
1307 Element owner = element.getOwner();
1308 String ownerName = null;
1309
1310 while (owner != null)
1311 {
1312 // Don't add the top level model name(s) to the FQN, unless the model is a Package.
1313 if (owner instanceof NamedElement && !(owner instanceof Model) && !(owner instanceof Profile))
1314 {
1315 ownerName = ((NamedElement)owner).getName();
1316 name = ownerName + separator + name;
1317 }
1318 owner = owner.getOwner();
1319 }
1320 /*// remove the top level model name, so that mapping works correctly...
1321 if (ownerName != null)
1322 {
1323 name = name.substring(ownerName.length() + separator.length());
1324 }*/
1325
1326 return name;
1327 }
1328
1329 /**
1330 * Finds and returns the first model element having the given
1331 * <code>name</code> in the <code>modelPackage</code>, returns
1332 * <code>null</code> if not found.
1333 *
1334 * @param rs the resource set to search in
1335 * @param name the name to find.
1336 * @return the found model element.
1337 */
1338 public static Object findByName(
1339 final ResourceSet rs,
1340 final String name)
1341 {
1342 if (rs==null || StringUtils.isBlank(name))
1343 {
1344 return null;
1345 }
1346 Object modelElement = null;
1347 if (StringUtils.isNotBlank(name))
1348 {
1349 modelElement =
1350 findByPredicate(
1351 rs,
1352 new Predicate()
1353 {
1354 public boolean evaluate(final Object object)
1355 {
1356 if (object instanceof NamedElement)
1357 {
1358 return StringUtils.trimToEmpty(((NamedElement)object).getName()).equals(name);
1359 }
1360 return false;
1361 }
1362 });
1363 }
1364 return modelElement;
1365 }
1366
1367 /**
1368 * Finds a given model element in the model having the specified
1369 * <code>fullyQualifiedName</code>. If the model element can <strong>NOT
1370 * </strong> be found, <code>null</code> will be returned instead.
1371 *
1372 * @param resourceSet the resource set to search in
1373 * @param fullyQualifiedName the fully qualified name of the element to search for.
1374 * @param separator the PSM separator used for qualifying the name (example ".").
1375 * @param modelName a flag indicating whether or not a search shall be performed
1376 * using the fully qualified model name or fully qualified PSM
1377 * name.
1378 * @return the found model element
1379 */
1380 public static Object findByFullyQualifiedName(
1381 final ResourceSet resourceSet,
1382 final String fullyQualifiedName,
1383 final String separator,
1384 final boolean modelName)
1385 {
1386 if (resourceSet==null || StringUtils.isBlank(fullyQualifiedName) || StringUtils.isBlank(separator))
1387 {
1388 return null;
1389 }
1390 Object modelElement;
1391 modelElement =
1392 findByPredicate(
1393 resourceSet,
1394 new Predicate()
1395 {
1396 public boolean evaluate(final Object object)
1397 {
1398 if (object instanceof NamedElement)
1399 {
1400 final NamedElement element = (NamedElement)object;
1401 final StringBuilder fullName = new StringBuilder(getPackageName(
1402 element,
1403 separator,
1404 modelName));
1405 final String name = element.getName();
1406 if (StringUtils.isNotBlank(name))
1407 {
1408 String namespaceSeparator = MetafacadeConstants.NAMESPACE_SCOPE_OPERATOR;
1409 if (!modelName)
1410 {
1411 namespaceSeparator = separator;
1412 }
1413 fullName.append(namespaceSeparator);
1414 fullName.append(name);
1415 }
1416 return fullName.toString().equals(fullyQualifiedName);
1417 }
1418 return false;
1419 }
1420 });
1421 return modelElement;
1422 }
1423
1424 /**
1425 * Multiplicity can be expressed as Value. String, integer... This method
1426 * parses it. MD11.5 uses string, and RSM integers.
1427 *
1428 * @param multValue a ValueSpecification, which needs to be parsed
1429 * @param type ClassifierFacade type used to determine default lower multiplicity (primitive=1, wrapped=0)
1430 * @param defaultMultiplicity from ClassifierFacadeLogic.getConfiguredProperty(UMLMetafacadeProperties.DEFAULT_MULTIPLICITY)
1431 * @return the parsed integer. Defaults to 1.
1432 */
1433 public static int parseLowerMultiplicity(final ValueSpecification multValue, final ClassifierFacade type, final String defaultMultiplicity)
1434 {
1435 int value = 1;
1436 if (multValue == null)
1437 {
1438 if (type.isWrappedPrimitive())
1439 {
1440 value = 0;
1441 }
1442 else if (!type.isPrimitive())
1443 {
1444 if (StringUtils.isNotBlank(defaultMultiplicity) && (defaultMultiplicity.charAt(0) == '0'))
1445 {
1446 value = 0;
1447 }
1448 else
1449 {
1450 value = 1;
1451 }
1452 }
1453 // Defaults to 1 if a Primitive
1454 }
1455 else
1456 {
1457 value = parseMultiplicity(multValue, Integer.parseInt(defaultMultiplicity));
1458 }
1459 return value;
1460 }
1461
1462 /**
1463 * Multiplicity can be expressed as Value. String, integer... This method
1464 * parses it. MD11.5 uses string, and RSM integers.
1465 *
1466 * @param multValue a ValueSpecification, which needs to be parsed
1467 * @param defaultValue when null: 1 for upper multiplicity, 0 for lower multiplicity.
1468 * @return the parsed integer. Defaults to 1.
1469 */
1470 public static int parseMultiplicity(final ValueSpecification multValue, final int defaultValue)
1471 {
1472 int value = defaultValue;
1473 if (multValue != null)
1474 {
1475 if (multValue instanceof LiteralInteger)
1476 {
1477 final LiteralInteger litInt = (LiteralInteger)multValue;
1478 value = litInt.getValue();
1479 }
1480 else if (multValue instanceof LiteralUnlimitedNatural)
1481 {
1482 final LiteralUnlimitedNatural litInt = (LiteralUnlimitedNatural)multValue;
1483 value = litInt.getValue();
1484 }
1485
1486 else if (multValue instanceof LiteralString)
1487 {
1488 final LiteralString litStr = (LiteralString)multValue;
1489 final String multString = litStr.getValue();
1490 if ("*".equals(multString))
1491 {
1492 value = LiteralUnlimitedNatural.UNLIMITED;
1493 }
1494 else
1495 {
1496 value = Integer.parseInt(multString);
1497 }
1498 }
1499 else
1500 {
1501 // Construct a String with the named element and default value
1502 String multString = multValue.toString();
1503 String forValue = "";
1504 // property owns the upper/lower value OpaqueExpression which owns the multiplicity value body
1505 final Element element = multValue.getOwner();
1506 if (element instanceof Property)
1507 {
1508 final Property property = (Property)element;
1509 forValue = " in property " + property.getQualifiedName();
1510 }
1511 if (multValue instanceof OpaqueExpression)
1512 {
1513 final OpaqueExpression expression = (OpaqueExpression)multValue;
1514 final EList<String> bodies = expression.getBodies();
1515 if (bodies != null && !bodies.isEmpty())
1516 {
1517 multString = bodies.get(0);
1518 }
1519 }
1520 LOGGER.error("Invalid multiplicity value" + forValue + ", using default " + defaultValue + ": " + multString);
1521 }
1522 }
1523 /*if (logger.isDebugEnabled())
1524 {
1525 logger.debug("Parsing multiplicity: intValue = " + value + " value: " + multValue);
1526 }*/
1527 return value;
1528 }
1529
1530 /**
1531 * There is an issue with EMF / XMI about tag value name (there should not be any @ or . inside)
1532 * This method checks whether <code>tagValueName</code> can be seen as <code>requestedName</code>.
1533 * <li>We compare them either:
1534 * without name transformation
1535 * removing initial '@' and replacing '.' by '_' (rsm / emf-uml2 profile)
1536 * replacing initial '@' with '_' and removing '.' (EMF Normalization, RSM migration of MD 9.5 profiles)
1537 * EMF normalization (for MD11.5 export)
1538 *
1539 * @param requestedName
1540 * @param tagValueName
1541 * @return Equals
1542 */
1543 public static boolean doesTagValueNameMatch(
1544 final String requestedName,
1545 final String tagValueName)
1546 {
1547 if (StringUtils.isBlank(requestedName) || StringUtils.isBlank(tagValueName))
1548 {
1549 return false;
1550 }
1551 boolean result = requestedName.equals(tagValueName);
1552 if (!result)
1553 {
1554 if (requestedName.charAt(0) == '@')
1555 {
1556 // let's try rsm guess
1557 String rsmName = requestedName.substring(1);
1558 rsmName =
1559 rsmName.replace(
1560 '.',
1561 '_');
1562 result = rsmName.equals(tagValueName);
1563 if (!result)
1564 {
1565 // let's try emf normalization
1566 final String emfName = EMFNormalizer.getEMFName(requestedName);
1567 result = emfName.equals(tagValueName);
1568 }
1569 /*}
1570 if (!result && tagValueName.startsWith("@"))
1571 {
1572 // let's try rsm guess
1573 String rsmName = tagValueName.substring(1);
1574 rsmName =
1575 rsmName.replace(
1576 '.',
1577 '_');
1578 result = requestedName.equals(rsmName);
1579 if (!result)
1580 {
1581 // let's try emf normalization
1582 String emfName = EMFNormalizer.getEMFName(tagValueName);
1583 result = requestedName.equals(emfName);
1584 }
1585 }*/
1586 // RSM converts @andromda.value to _andromdavalue when upgrading MD 9.5 profile
1587 if (!result)
1588 {
1589 rsmName =
1590 '_' + StringUtils.remove(requestedName.substring(1), '.');
1591 result = rsmName.equals(tagValueName);
1592 }
1593 }
1594 else
1595 {
1596 // MD converts to _andromdavalue when exporting to EMF UML2 (v2.x) XMI and
1597 // the requestValue uses andromda_value
1598 final String emfName = '_' + StringUtils.remove(requestedName, '_');
1599 result = emfName.equals(tagValueName);
1600 }
1601 }
1602 return result;
1603 }
1604
1605 // hack to use a protected method
1606 private static class EMFNormalizer
1607 extends UML2Util
1608 {
1609 public static String getEMFName(final String name)
1610 {
1611 return getValidJavaIdentifier(name);
1612 }
1613 }
1614
1615 // Sort Attributes and AssociationEnds
1616 @SuppressWarnings("unused")
1617 private static class PropertyComparator implements Comparator<Property>
1618 {
1619 private static final long serialVersionUID = 1L;
1620 public int compare(final Property property1, final Property property2)
1621 {
1622 return property1.getName().compareTo(property2.getName());
1623 }
1624 }
1625 }