View Javadoc
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.HashMap;
7   import java.util.Iterator;
8   import java.util.List;
9   import java.util.Map;
10  import java.util.regex.Pattern;
11  import org.andromda.core.metafacade.MetafacadeConstants;
12  import org.andromda.metafacades.uml.BindingFacade;
13  import org.andromda.metafacades.uml.ConstraintFacade;
14  import org.andromda.metafacades.uml.ModelElementFacade;
15  import org.andromda.metafacades.uml.NameMasker;
16  import org.andromda.metafacades.uml.RedefinableTemplateSignatureFacade;
17  import org.andromda.metafacades.uml.TaggedValueFacade;
18  import org.andromda.metafacades.uml.TemplateArgumentFacade;
19  import org.andromda.metafacades.uml.TemplateParameterFacade;
20  import org.andromda.metafacades.uml.TypeMappings;
21  import org.andromda.metafacades.uml.UMLMetafacadeProperties;
22  import org.andromda.metafacades.uml.UMLMetafacadeUtils;
23  import org.andromda.metafacades.uml.UMLProfile;
24  import org.andromda.translation.ocl.ExpressionKinds;
25  import org.andromda.utils.StringUtilsHelper;
26  import org.apache.commons.collections.CollectionUtils;
27  import org.apache.commons.collections.Predicate;
28  import org.apache.commons.lang.BooleanUtils;
29  import org.apache.commons.lang.ObjectUtils;
30  import org.apache.commons.lang.StringUtils;
31  import org.apache.commons.lang.SystemUtils;
32  import org.apache.log4j.Logger;
33  import org.eclipse.emf.ecore.resource.Resource;
34  import org.eclipse.emf.ecore.xmi.XMLResource;
35  import org.eclipse.emf.ecore.xmi.impl.XMIHelperImpl;
36  import org.eclipse.uml2.uml.Abstraction;
37  import org.eclipse.uml2.uml.Comment;
38  import org.eclipse.uml2.uml.Constraint;
39  import org.eclipse.uml2.uml.Dependency;
40  import org.eclipse.uml2.uml.Deployment;
41  import org.eclipse.uml2.uml.DirectedRelationship;
42  import org.eclipse.uml2.uml.Element;
43  import org.eclipse.uml2.uml.Manifestation;
44  import org.eclipse.uml2.uml.NamedElement;
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.Property;
49  import org.eclipse.uml2.uml.Realization;
50  import org.eclipse.uml2.uml.StateMachine;
51  import org.eclipse.uml2.uml.Stereotype;
52  import org.eclipse.uml2.uml.Substitution;
53  import org.eclipse.uml2.uml.TemplateBinding;
54  import org.eclipse.uml2.uml.TemplateParameter;
55  import org.eclipse.uml2.uml.TemplateSignature;
56  import org.eclipse.uml2.uml.TemplateableElement;
57  import org.eclipse.uml2.uml.Usage;
58  import org.eclipse.uml2.uml.VisibilityKind;
59  
60  /**
61   * MetafacadeLogic implementation for
62   * org.andromda.metafacades.uml.ModelElementFacade.
63   *
64   * @see org.andromda.metafacades.uml.ModelElementFacade
65   * @author Bob Fields
66   */
67  public class ModelElementFacadeLogicImpl
68      extends ModelElementFacadeLogic
69  {
70      private static final long serialVersionUID = 34L;
71      /**
72       * Helps to get the xmi:id value from the model
73       */
74      static XMIHelperImpl xmiHelper = new XMIHelperImpl();
75  
76      /**
77       * @param metaObjectIn
78       * @param context
79       */
80      public ModelElementFacadeLogicImpl(
81          final Element metaObjectIn,
82          final String context)
83      {
84          super(metaObjectIn, context);
85      }
86  
87      /**
88       * The logger instance.
89       */
90      private static final Logger LOGGER = Logger.getLogger(ModelElementFacadeLogicImpl.class);
91  
92      /**
93       * @see org.andromda.metafacades.uml.ModelElementFacade#getVisibility()
94       */
95      @Override
96      protected String handleGetVisibility()
97      {
98          if (this.metaObject instanceof NamedElement)
99          {
100             final NamedElement element = (NamedElement)this.metaObject;
101             final VisibilityKind kind = element.getVisibility();
102             String visibility = null;
103             if (kind.equals(VisibilityKind.PUBLIC_LITERAL))
104             {
105                 visibility = "public";
106             }
107             else if (kind.equals(VisibilityKind.PRIVATE_LITERAL))
108             {
109                 visibility = "private";
110             }
111             else if (kind.equals(VisibilityKind.PROTECTED_LITERAL))
112             {
113                 visibility = "protected";
114             }
115             else if (kind.equals(VisibilityKind.PACKAGE_LITERAL))
116             {
117                 // So that we can use $attribute.visibility without having to remove the 'package' qualifier
118                 //visibility = "package";
119                 visibility = "";
120             }
121             else
122             {
123                 visibility = "public";
124             }
125             final TypeMappings languageMappings = this.handleGetLanguageMappings();
126             if (languageMappings != null)
127             {
128                 visibility = languageMappings.getTo(visibility);
129             }
130             // Attribute and Associations change visibility from private to public, instead of throwing an error. Get/Set should still be public.
131             return visibility;
132         }
133         return null;
134     }
135 
136     /**
137      * @see org.andromda.metafacades.uml.ModelElementFacade#getPackagePath()
138      */
139     @Override
140     protected String handleGetPackagePath()
141     {
142         return StringUtils.replace(
143             this.handleGetPackageName(),
144             String.valueOf(this.getConfiguredProperty(UMLMetafacadeProperties.NAMESPACE_SEPARATOR)),
145             "/");
146     }
147 
148     /**
149      * @see org.andromda.metafacades.uml.ModelElementFacade#getName()
150      */
151     @Override
152     protected String handleGetName()
153     {
154         // In UML2, model elements need not have a name,
155         // only when they are an instance of NamedElement.
156         if (this.metaObject instanceof NamedElement)
157         {
158             final NamedElement namedElement = (NamedElement) this.metaObject;
159 
160             String nameMask = null;
161             try
162             {
163                 nameMask = String.valueOf(this.getConfiguredProperty(UMLMetafacadeProperties.MODEL_ELEMENT_NAME_MASK));
164             }
165             catch (Exception ignore)
166             {
167                 LOGGER.warn("modelElementNameMask not found in " + this.toString());
168                 nameMask = "none";
169             }
170 
171             return NameMasker.mask(namedElement.getName(), nameMask);
172         }
173         return "";
174     }
175 
176     /**
177      * Gets the appropriate namespace property for retrieve the namespace scope
178      * operation (depending on the given <code>modelName</code> flag.
179      *
180      * @param modelName
181      *            whether or not the scope operation for the model should be
182      *            retrieved as opposed to the mapped scope operator.
183      * @return the scope operator.
184      */
185     private String getNamespaceScope(final boolean modelName)
186     {
187         return modelName
188             ? MetafacadeConstants.NAMESPACE_SCOPE_OPERATOR
189             : ObjectUtils.toString(this.getConfiguredProperty(UMLMetafacadeProperties.NAMESPACE_SEPARATOR));
190     }
191 
192     /**
193      * @see org.andromda.metafacades.uml.ModelElementFacade#getPackageName()
194      */
195     @Override
196     protected String handleGetPackageName()
197     {
198         String packageName = UmlUtilities.getPackageName(this.metaObject, this.getNamespaceScope(false), false);
199 
200         //package names are treated differently so we have to apply the name mask here
201         //since there isn't a packageNameMask, we're using the modelElementNameMask
202         String nameMask = null;
203         try
204         {
205             nameMask = String.valueOf(this.getConfiguredProperty(UMLMetafacadeProperties.MODEL_ELEMENT_NAME_MASK));
206         }
207         catch (Exception ignore)
208         {
209             LOGGER.warn("modelElementNameMask not found in " + this.toString() + " (getPackageName)");
210             nameMask = "none";
211         }
212 
213         return NameMasker.mask(packageName, nameMask);
214     }
215 
216     /**
217      * @see org.andromda.metafacades.uml.ModelElementFacade#getFullyQualifiedName()
218      */
219     @Override
220     protected String handleGetFullyQualifiedName()
221     {
222         return this.handleGetFullyQualifiedName(false);
223     }
224 
225     /**
226      * @see org.andromda.metafacades.uml.ModelElementFacade#getFullyQualifiedNamePath()
227      */
228     @Override
229     protected String handleGetFullyQualifiedNamePath()
230     {
231         return StringUtils.replace(
232             this.handleGetFullyQualifiedName(),
233             String.valueOf(this.getConfiguredProperty(UMLMetafacadeProperties.NAMESPACE_SEPARATOR)),
234             "/");
235     }
236 
237     /**
238      * Gets the array suffix from the configured metafacade properties.
239      *
240      * @return the array suffix.
241      */
242     protected String getArraySuffix()
243     {
244         return String.valueOf(this.getConfiguredProperty(UMLMetafacadeProperties.ARRAY_NAME_SUFFIX));
245     }
246 
247     /**
248      * @see org.andromda.metafacades.uml.ModelElementFacade#getLanguageMappings()
249      */
250     @Override
251     protected org.andromda.metafacades.uml.TypeMappings handleGetLanguageMappings()
252     {
253         final String propertyName = UMLMetafacadeProperties.LANGUAGE_MAPPINGS_URI;
254         final Object property = this.getConfiguredProperty(propertyName);
255         TypeMappings mappings = null;
256         if (String.class.isAssignableFrom(property.getClass()))
257         {
258             final String uri = (String)property;
259             try
260             {
261                 mappings = TypeMappings.getInstance(uri);
262                 mappings.setArraySuffix(this.getArraySuffix());
263                 this.setProperty(
264                     propertyName,
265                     mappings);
266             }
267             catch (Throwable th)
268             {
269                 final String errMsg = "Error getting '" + propertyName + "' --> '" + uri + '\'';
270                 ModelElementFacadeLogicImpl.LOGGER.error(
271                     errMsg,
272                     th);
273 
274                 // don't throw the exception
275             }
276         }
277         else
278         {
279             mappings = (TypeMappings)property;
280         }
281         return mappings;
282     }
283 
284     /**
285      * @return Collection String of org.eclipse.uml2.uml.Stereotype.getName()
286      * @see org.andromda.metafacades.uml.ModelElementFacade#getStereotypeNames()
287      */
288     @Override
289     protected Collection<String> handleGetStereotypeNames()
290     {
291         return UmlUtilities.getStereotypeNames(this.metaObject);
292     }
293 
294     /**
295      * @see org.andromda.metafacades.uml.ModelElementFacade#getId()
296      */
297     @Override
298     protected String handleGetId()
299     {
300         if (this.metaObject == null || this.metaObject.eResource() == null)
301             return null;
302         // From http://www.openarchitectureware.org/forum/viewtopic.php?showtopic=6653
303         Resource xmiResource = this.metaObject.eResource();
304         String rtn = ((XMLResource) xmiResource).getID(this.metaObject);
305         /*if (rtn == null)
306         {
307             // From http://www.eclipse.org/forums/index.php?t=msg&th=130555/
308             rtn = xmiResource.getURIFragment(this.metaObject);
309             if (rtn == null)
310             {
311                 // This always returns null for UML2, but just in case something changes, try anyway
312                 rtn = xmiHelper.getID(this.metaObject);
313             }
314         }*/
315         return rtn;
316     }
317 
318     /**
319      * @return isReservedWord
320      * @see org.andromda.metafacades.uml.ModelElementFacade#isReservedWord()
321      */
322     @Override
323     protected boolean handleIsReservedWord()
324     {
325         return UMLMetafacadeUtils.isReservedWord(this.handleGetName());
326     }
327 
328     /**
329      * @see org.andromda.metafacades.uml.ModelElementFacade#isConstraintsPresent()
330      */
331     @Override
332     protected boolean handleIsConstraintsPresent()
333     {
334         return this.handleGetConstraints() != null && !this.handleGetConstraints().isEmpty();
335     }
336 
337     /**
338      * @see org.andromda.metafacades.uml.ModelElementFacade#findTaggedValue(String)
339      */
340     @Override
341     protected Object handleFindTaggedValue(final String name)
342     {
343         final Collection taggedValues = this.findTaggedValues(name);
344         return taggedValues.isEmpty() ? null : taggedValues.iterator().next();
345     }
346 
347     /**
348      * Assumes no stereotype inheritance
349      *
350      * @see org.andromda.metafacades.uml.ModelElementFacade#hasStereotype(String)
351      */
352     @Override
353     protected boolean handleHasStereotype(final String stereotypeName)
354     {
355         return UmlUtilities.containsStereotype(
356             this.metaObject,
357             stereotypeName);
358     }
359 
360     /**
361      * @see org.andromda.metafacades.uml.ModelElementFacade#getDocumentation(String)
362      */
363     @Override
364     protected String handleGetDocumentation(final String indent)
365     {
366         return this.handleGetDocumentation(
367             indent,
368             100 - indent.length());
369     }
370 
371     /**
372      * @see org.andromda.metafacades.uml.ModelElementFacade#getFullyQualifiedName(boolean)
373      */
374     @Override
375     protected String handleGetFullyQualifiedName(final boolean modelName)
376     {
377         return handleGetBindedFullyQualifiedName(modelName, Collections.<BindingFacade>emptyList());
378     }
379 
380     /**
381      * @see org.andromda.metafacades.uml.ModelElementFacade#getDocumentation(String,
382      *      int)
383      */
384     @Override
385     protected String handleGetDocumentation(
386         final String indent,
387         final int lineLength)
388     {
389         // We really don't want the start/end paragraph returns on the first/last lines. Very annoying. Makes the docs too long with mixed html.
390         // That's the only thing that htmlStyle does: convert each line to <p>line</p>. Not necessary.
391         return this.handleGetDocumentation(
392             indent,
393             lineLength,
394             false);
395     }
396 
397     /**
398      * @see org.andromda.metafacades.uml.ModelElementFacade#hasExactStereotype(String)
399      */
400     @Override
401     protected boolean handleHasExactStereotype(final String stereotypeName)
402     {
403         return this.handleGetStereotypeNames().contains(StringUtils.trimToEmpty(stereotypeName));
404     }
405 
406     /**
407      * @see org.andromda.metafacades.uml.ModelElementFacade#translateConstraint(String,
408      *      String)
409      */
410     @Override
411     protected String handleTranslateConstraint(
412         final String name,
413         final String translation)
414     {
415         String translatedExpression = "";
416         final ConstraintFacade constraint =
417             (ConstraintFacade)CollectionUtils.find(
418                 this.getConstraints(),
419                 new Predicate()
420                 {
421                     public boolean evaluate(final Object object)
422                     {
423                         final ConstraintFacade constraintEval = (ConstraintFacade)object;
424                         return StringUtils.trimToEmpty(constraintEval.getName()).equals(StringUtils.trimToEmpty(name));
425                     }
426                 });
427 
428         if (constraint != null)
429         {
430             translatedExpression = constraint.getTranslation(translation);
431         }
432         return translatedExpression;
433     }
434 
435     /**
436      * Private helper that translates all the expressions contained in the
437      * <code>constraints</code>, and returns an array of the translated
438      * expressions.
439      *
440      * @param constraints
441      *            the constraints to translate
442      * @param translation
443      *            the translation to translate <code>to</code>.
444      * @return String[] the translated expressions, or null if no constraints
445      *         were found
446      */
447     // TODO: Possible covariant of the method 'translateConstraints' defined in the class 'ModelElementFacadeLogic'
448     private String[] translateConstraints(
449         final Collection<ConstraintFacade> constraints,
450         final String translation)
451     {
452         String[] translatedExpressions = null;
453         if (constraints != null && !constraints.isEmpty())
454         {
455             translatedExpressions = new String[constraints.size()];
456             final Iterator<ConstraintFacade> constraintIt = constraints.iterator();
457             for (int ctr = 0; constraintIt.hasNext(); ctr++)
458             {
459                 final ConstraintFacade constraint = constraintIt.next();
460                 translatedExpressions[ctr] = constraint.getTranslation(translation);
461             }
462         }
463         return translatedExpressions;
464     }
465 
466     /**
467      * @see org.andromda.metafacades.uml.ModelElementFacade#translateConstraints(String,
468      *      String)
469      */
470     @Override
471     protected String[] handleTranslateConstraints(
472         final String kind,
473         final String translation)
474     {
475         final Collection<ConstraintFacade> constraints = this.getConstraints();
476         CollectionUtils.filter(
477             constraints,
478             new Predicate()
479             {
480                 public boolean evaluate(final Object object)
481                 {
482                     final ConstraintFacade constraint = (ConstraintFacade)object;
483                     return UMLMetafacadeUtils.isConstraintKind(
484                         constraint.getBody(),
485                         kind);
486                 }
487             });
488         return this.translateConstraints(
489             constraints,
490             translation);
491     }
492 
493     /**
494      * @see org.andromda.metafacades.uml.ModelElementFacade#translateConstraints(String)
495      */
496     @Override
497     protected String[] handleTranslateConstraints(final String translation)
498     {
499         return this.translateConstraints(
500             this.getConstraints(),
501             translation);
502     }
503 
504     /**
505      * @see org.andromda.metafacades.uml.ModelElementFacade#getConstraints(String)
506      */
507     @Override
508     protected Collection<ConstraintFacade> handleGetConstraints(final String kind)
509     {
510         final Collection<ConstraintFacade> constraints = new ArrayList<ConstraintFacade>();
511         for (ConstraintFacade constraint : this.getConstraints())
512         {
513             if ((ExpressionKinds.BODY.equals(kind) && constraint.isBodyExpression()) ||
514                 (ExpressionKinds.DEF.equals(kind) && constraint.isDefinition()) ||
515                 (ExpressionKinds.INV.equals(kind) && constraint.isInvariant()) ||
516                 (ExpressionKinds.PRE.equals(kind) && constraint.isPreCondition()) ||
517                 (ExpressionKinds.POST.equals(kind) && constraint.isPostCondition()))
518             {
519                 constraints.add(constraint);
520             }
521         }
522         return constraints;
523     }
524 
525     /**
526      * @see org.andromda.metafacades.uml.ModelElementFacade#findTaggedValues(String)
527      */
528     @Override
529     protected Collection<Object> handleFindTaggedValues(String name)
530     {
531         final Collection<Object> values = new ArrayList<Object>();
532 
533         // only search a tagged value when it actually has a name
534         if (StringUtils.isNotBlank(name))
535         {
536             // trim the name, we don't want leading/trailing spaces
537             name = StringUtils.trimToEmpty(name);
538 
539             // loop over the tagged values
540             final Collection<TaggedValueFacade> taggedValues = this.getTaggedValues();
541             for (final TaggedValueFacade taggedValue : taggedValues)
542             {
543                 // does this name match the argument tagged value name ?
544                 if (UmlUtilities.doesTagValueNameMatch(name, taggedValue.getName()))
545                 {
546                     // 'tagged values' can have arrays of strings as well as
547                     // strings as values.
548                     /* http://andromda.sourceforge.net/jira/browse/UMLMETA-89
549                     Object value = taggedValue.getValue();
550                     if (value instanceof Collection)
551                     {
552                         values.addAll((Collection) taggedValue.getValue());
553                     }
554                     else
555                     {
556                         values.add(taggedValue.getValue());
557                     } */
558                     //
559                     if (taggedValue.getValues() != null && !taggedValue.getValues().isEmpty())
560                     {
561                         values.addAll(taggedValue.getValues());
562                     }
563                     // If it matches this taggedValue, and taggedValues are unique, no need to check the rest.
564                     break;
565                 }
566             }
567         }
568         return values;
569     }
570 
571     /**
572      * @see org.andromda.metafacades.uml.ModelElementFacade#getDocumentation(String,
573      *      int, boolean)
574      */
575     @Override
576     protected String handleGetDocumentation(
577         final String indent,
578         int lineLength,
579         final boolean htmlStyle)
580     {
581         final StringBuilder documentation = new StringBuilder();
582 
583         if (lineLength < 1)
584         {
585             lineLength = Integer.MAX_VALUE;
586         }
587 
588         final Collection<Comment> comments = this.metaObject.getOwnedComments();
589         if (comments != null && !comments.isEmpty())
590         {
591             for (final Comment comment : comments)
592             {
593                 final String commentString = StringUtils.trimToEmpty(comment.getBody());
594 
595                 // Comment.toString returns org.eclipse.uml2.uml.internal.impl.CommentImpl@95c90f4 (body: )
596                 /*if (StringUtils.isBlank(commentString))
597                 {
598                     commentString = StringUtils.trimToEmpty(comment.toString());
599                 }*/
600                 documentation.append(StringUtils.trimToEmpty(commentString));
601                 documentation.append(SystemUtils.LINE_SEPARATOR);
602             }
603         }
604 
605         // if there still isn't anything, try a tagged value
606         if (StringUtils.isBlank(documentation.toString()))
607         {
608             documentation.append(
609                 StringUtils.trimToEmpty((String)this.findTaggedValue(UMLProfile.TAGGEDVALUE_DOCUMENTATION)));
610         }
611 
612         // For associations, use the type class documentation if association documentation is missing.
613         if (StringUtils.isBlank(documentation.toString())
614         && this instanceof AssociationEndFacadeLogicImpl)
615         {
616             AssociationEndFacadeLogicImpl end = (AssociationEndFacadeLogicImpl)this;
617             documentation.append(end.getType().getDocumentation(""));
618         }
619 
620         // if there still isn't anything, create a todo tag.
621         if (StringUtils.isBlank(documentation.toString())
622         && Boolean.valueOf((String)this.getConfiguredProperty(UMLMetafacadeProperties.TODO_FOR_MISSING_DOCUMENTATION)))
623         {
624             final String todoTag = (String)this.getConfiguredProperty(UMLMetafacadeProperties.TODO_TAG);
625             documentation.append(todoTag).append(": Model Documentation for " + this.handleGetFullyQualifiedName());
626         }
627 
628         return StringUtilsHelper.format(
629             StringUtils.trimToEmpty(documentation.toString()),
630             indent,
631             lineLength,
632             htmlStyle);
633     }
634 
635     /**
636      * If documentation is present, i.e. to add toDoTag or skip a line if not
637      * @return true is documentation comment or Documentation stereotype is present
638      * @see org.andromda.metafacades.uml.ModelElementFacade#isDocumentationPresent()
639      */
640     @Override
641     protected boolean handleIsDocumentationPresent()
642     {
643         boolean rtn = false;
644         final Collection<Comment> comments = this.metaObject.getOwnedComments();
645         if (comments != null && !comments.isEmpty())
646         {
647             for (Comment comment : comments)
648             {
649                 final String commentString = StringUtils.trimToEmpty(comment.getBody());
650 
651                 // if there isn't anything in the body, try the name
652                 if (StringUtils.isNotBlank(commentString))
653                 {
654                     rtn = true;
655                     break;
656                 }
657             }
658         }
659 
660         if (!rtn && StringUtils.isNotBlank((String)this.findTaggedValue(UMLProfile.TAGGEDVALUE_DOCUMENTATION)))
661         {
662             rtn = true;
663         }
664 
665         return rtn;
666     }
667 
668     /**
669      * @see org.andromda.metafacades.uml.ModelElementFacade#getPackageName(boolean)
670      */
671     @Override
672     protected String handleGetPackageName(final boolean modelName)
673     {
674         String packageName = this.handleGetPackageName();
675         if (modelName)
676         {
677             packageName =
678                 StringUtils.replace(
679                     packageName,
680                     ObjectUtils.toString(this.getConfiguredProperty(UMLMetafacadeProperties.NAMESPACE_SEPARATOR)),
681                     MetafacadeConstants.NAMESPACE_SCOPE_OPERATOR);
682         }
683         return packageName;
684     }
685 
686     /**
687      * @see org.andromda.metafacades.uml.ModelElementFacade#getTaggedValues()
688      */
689     @Override
690     protected Collection<TagDefinition> handleGetTaggedValues()
691     {
692         // TODO: UmlUtilities returns TagDefinition, not TaggedValueFacade
693         return UmlUtilities.getTaggedValue(this.metaObject);
694     }
695 
696     /*
697      * @see org.andromda.metafacades.uml.ModelElementFacade#getOwnedElements()
698     protected Collection<Element> handleGetOwnedElements()
699     {
700         return this.metaObject.getOwnedElements();
701     }
702      */
703 
704     /**
705      * @see org.andromda.metafacades.uml.ModelElementFacade#getPackage()
706      */
707     @Override
708     protected Package handleGetPackage()
709     {
710         return this.metaObject.getNearestPackage();
711     }
712 
713     /**
714      * @see org.andromda.metafacades.uml.ModelElementFacade#getRootPackage()
715      */
716     @Override
717     protected Package handleGetRootPackage()
718     {
719         // UML2 Model extends Package, is mapped to a PackageFacade -
720         // RootPackage. Need to map Model to UMLResource, not to modelFacade, in metafacade.xml
721         return UmlUtilities.findModel(this.metaObject);
722     }
723 
724     /**
725      * @see org.andromda.metafacades.uml.ModelElementFacade#getTargetDependencies()
726      */
727     @Override
728     protected Collection<DirectedRelationship> handleGetTargetDependencies()
729     {
730         final List<DirectedRelationship> dependencies = new ArrayList<DirectedRelationship>();
731         dependencies.addAll((Collection<? extends DirectedRelationship>) UmlUtilities.getAllMetaObjectsInstanceOf(
732                 DirectedRelationship.class,
733                 UmlUtilities.getModels()));
734         CollectionUtils.filter(
735             dependencies,
736             new Predicate()
737             {
738                 public boolean evaluate(final Object object)
739                 {
740                     final DirectedRelationship relation = (DirectedRelationship) object;
741                     if(isAUml14Dependency(relation))
742                     {
743                         // we only check first, see dependency facade for more detail.
744                         return ModelElementFacadeLogicImpl.this.metaObject.equals(relation.getTargets().get(0));
745                     }
746                     return false;
747                 }
748             });
749         return dependencies;
750     }
751 
752     /**
753      * @see org.andromda.metafacades.uml.ModelElementFacade#getModel()
754      */
755     @Override
756     protected Resource handleGetModel()
757     {
758         // Be careful here, Model Facade is mapped to resource
759         // TODO map ModelFacade to UML2 Model or Package?
760         Resource resource = this.metaObject.getModel().eResource();
761         if (resource==null)
762         {
763             LOGGER.error("ModelElementFacadeLogicImpl.handleGetModel: " + this.metaObject + " Model: " + this.metaObject.getModel());
764             resource = (Resource) this.metaObject.getModel();
765         }
766         return resource;
767     }
768 
769     /**
770      * @see org.andromda.metafacades.uml.ModelElementFacade#getStereotypes()
771      */
772     @Override
773     protected Collection<Stereotype> handleGetStereotypes()
774     {
775         return this.metaObject.getAppliedStereotypes();
776     }
777 
778     /**
779      * @see org.andromda.metafacades.uml.ModelElementFacade#getConstraints()
780      */
781     @Override
782     protected Collection<Constraint> handleGetConstraints()
783     {
784         final List<Constraint> constraints = new ArrayList<Constraint>();
785         constraints.addAll((Collection<? extends Constraint>) UmlUtilities.getAllMetaObjectsInstanceOf(Constraint.class, UmlUtilities.getModels()));
786 
787         CollectionUtils.filter(
788                 constraints,
789                 new Predicate()
790                 {
791                     public boolean evaluate(final Object object)
792                     {
793                         final Constraint constraint = (Constraint) object;
794                         return constraint.getConstrainedElements().contains(ModelElementFacadeLogicImpl.this.metaObject);
795                     }
796                 });
797         return constraints;
798     }
799 
800     /**
801      * @see org.andromda.metafacades.uml.ModelElementFacade#getSourceDependencies()
802      */
803     @Override
804     protected Collection<DirectedRelationship> handleGetSourceDependencies()
805     {
806         // A more efficient implementation of this would have been to use getClientDependencies() and getTemplateBindings()
807         // But it would have required the same filtering
808         // This way, the code is the "same" as getTargetDependencies
809         final List<DirectedRelationship> dependencies = new ArrayList<DirectedRelationship>();
810         dependencies.addAll((Collection<? extends DirectedRelationship>) UmlUtilities.getAllMetaObjectsInstanceOf(
811                 DirectedRelationship.class, UmlUtilities.getModels()));
812         CollectionUtils.filter(
813             dependencies,
814             new Predicate()
815             {
816                 public boolean evaluate(final Object object)
817                 {
818                     final DirectedRelationship relation = (DirectedRelationship) object;
819                     if(relation != null && isAUml14Dependency(relation) && relation.getSources() != null && !relation.getSources().isEmpty())
820                     {
821                         // we only check first, see dependency facade for more detail.
822                         return ModelElementFacadeLogicImpl.this.metaObject.equals(relation.getSources().get(0));
823                     }
824                     return false;
825                 }
826             });
827         return dependencies;
828     }
829 
830     /**
831      * This function tests if the given relation is a dependency in UML1.4 sense of term.
832      * @param relation The relation to test
833      * @return instanceof Abstraction, Deployment, Manifestation, realization, Substitution, Usage
834      */
835     static boolean isAUml14Dependency(final DirectedRelationship relation)
836     {
837         // this ensure that this relation is either a dependency or a template binding
838         boolean isAUml14Dependency = (relation instanceof Dependency) || (relation instanceof TemplateBinding);
839 
840         // but we don't want subclass of dependency
841         isAUml14Dependency = isAUml14Dependency && !(relation instanceof Abstraction); // present in uml 1.4 (but filter in uml14 facade)
842         isAUml14Dependency = isAUml14Dependency && !(relation instanceof Deployment);
843         //isAUml14Dependency = isAUml14Dependency && !(relation instanceof Implementation);
844         isAUml14Dependency = isAUml14Dependency && !(relation instanceof Manifestation);
845         //isAUml14Dependency = isAUml14Dependency && !(relation instanceof Permission); // present in uml 1.4
846         isAUml14Dependency = isAUml14Dependency && !(relation instanceof Realization);
847         isAUml14Dependency = isAUml14Dependency && !(relation instanceof Substitution);
848         isAUml14Dependency = isAUml14Dependency && !(relation instanceof Usage);// present in uml 1.4
849 
850         return isAUml14Dependency;
851     }
852 
853     /**
854      * @return stateMachine org.eclipse.uml2.uml.StateMachine
855      * @see org.andromda.metafacades.uml.ModelElementFacade#getStateMachineContext()
856      */
857     @Override
858     protected StateMachine handleGetStateMachineContext()
859     {
860         // TODO: What should this method return ?
861         // As I've seen in uml1.4 impl, it should return the statemachine which this element is the context for.
862         // Let's say for UML2: Return the owner if the latter is a StateMachine
863         StateMachine stateMachine = null;
864         final Element owner = this.metaObject.getOwner();
865         if(owner instanceof StateMachine)
866         {
867             stateMachine = (StateMachine) owner;
868         }
869         return stateMachine;
870     }
871 
872     /**
873      * @see org.andromda.core.metafacade.MetafacadeBase#getValidationName()
874      */
875     @Override
876     public String getValidationName()
877     {
878         final StringBuilder validationName = new StringBuilder();
879         final Object separator = MetafacadeConstants.NAMESPACE_SCOPE_OPERATOR;
880         for (NamedElement namespace = (NamedElement)this.metaObject.getOwner(); namespace != null;
881             namespace = (NamedElement)namespace.getOwner())
882         {
883             if (validationName.length() == 0)
884             {
885                 validationName.append(namespace.getName());
886             }
887             else
888             {
889                 validationName.insert(
890                     0,
891                     separator);
892                 validationName.insert(
893                     0,
894                     namespace.getName());
895             }
896         }
897         if (validationName.length() > 0)
898         {
899             validationName.append(separator);
900         }
901         if (StringUtils.isNotBlank(this.handleGetName()))
902         {
903             validationName.append(this.handleGetName());
904         }
905         else
906         {
907             validationName.append(this.getConfiguredProperty(UMLMetafacadeProperties.UNDEFINED_NAME));
908         }
909         return validationName.toString();
910     }
911 
912     /**
913      * @see org.andromda.metafacades.emf.uml22.ModelElementFacadeLogic#handleIsBindingDependenciesPresent()
914      */
915     @Override
916     protected boolean handleIsBindingDependenciesPresent()
917     {
918         final Collection<DirectedRelationship> dependencies = this.handleGetSourceDependencies();
919         CollectionUtils.filter(
920             dependencies,
921             new Predicate()
922             {
923                 public boolean evaluate(final Object object)
924                 {
925                     return object instanceof BindingFacade;
926                 }
927             });
928         return !dependencies.isEmpty();
929     }
930 
931     /**
932      * @see org.andromda.metafacades.emf.uml22.ModelElementFacadeLogic#handleIsTemplateParametersPresent()
933      */
934     @Override
935     protected boolean handleIsTemplateParametersPresent()
936     {
937         final Collection<TemplateParameter> params = this.handleGetTemplateParameters();
938         return params != null && !params.isEmpty();
939     }
940 
941     /**
942      * @see org.andromda.metafacades.emf.uml22.ModelElementFacadeLogic#handleCopyTaggedValues(org.andromda.metafacades.uml.ModelElementFacade)
943      */
944     @Override
945     protected void handleCopyTaggedValues(final ModelElementFacade element)
946     {
947         // TODO What to do with this ?
948     }
949 
950     /**
951      * @see org.andromda.metafacades.emf.uml22.ModelElementFacadeLogic#handleGetTemplateParameter(String)
952      */
953     @Override
954     protected Object handleGetTemplateParameter(String parameterName)
955     {
956         TemplateParameterFacade templateParameter = null;
957         if (StringUtils.isNotBlank(parameterName))
958         {
959             parameterName = StringUtils.trimToEmpty(parameterName);
960             final Collection<TemplateParameterFacade> parameters = this.getTemplateParameters();
961             if (parameters != null && !parameters.isEmpty())
962             {
963                 for (final TemplateParameterFacade currentTemplateParameter : parameters)
964                 {
965                     if (currentTemplateParameter.getParameter() != null)
966                     {
967                         final ModelElementFacade parameter = currentTemplateParameter.getParameter();
968 
969                         // there should not be two template parameters with the same parameter name, but nothing
970                         // prevents the model from allowing that.  So return the first instance if found.
971                         if (parameterName.equals(parameter.getName()))
972                         {
973                             templateParameter = currentTemplateParameter;
974                             break;
975                         }
976                     }
977                 }
978             }
979         }
980 
981         return templateParameter;
982     }
983 
984     /**
985      * @see org.andromda.metafacades.emf.uml22.ModelElementFacadeLogic#handleGetTemplateParameters()
986      */
987     @Override
988     protected Collection<TemplateParameter> handleGetTemplateParameters()
989     {
990         final Collection<TemplateParameter> templateParameters = new ArrayList<TemplateParameter>();
991         if (this.metaObject instanceof TemplateableElement)
992         {
993             final TemplateableElement templateableElement = (TemplateableElement)this.metaObject;
994             final TemplateSignature templateSignature = templateableElement.getOwnedTemplateSignature();
995             if (templateSignature != null)
996             {
997                 templateParameters.addAll(templateSignature.getParameters());
998             }
999         }
1000         return templateParameters;
1001     }
1002 
1003     /**
1004      * @return this.metaObject.getKeywords()
1005      * @see org.andromda.metafacades.uml.ModelElementFacade#getKeywords()
1006      */
1007     @Override
1008     protected Collection<String> handleGetKeywords()
1009     {
1010         return this.metaObject.getKeywords();
1011     }
1012 
1013     /**
1014      * @return element.getLabel()
1015      * @see org.andromda.metafacades.uml.ModelElementFacade#getLabel()
1016      */
1017     @Override
1018     protected String handleGetLabel()
1019     {
1020         final NamedElement element = (NamedElement)this.metaObject;
1021         return element.getLabel();
1022     }
1023 
1024     /**
1025      * @return element.getNamespace()
1026      */
1027     // * @see org.andromda.metafacades.uml.ModelElementFacade#getModelNamespace()
1028     //@Override
1029     protected ModelElementFacade handleGetModelNamespace()
1030     {
1031         final NamedElement element = (NamedElement)this.metaObject;
1032         //return (ModelElementFacade) element.getNamespace();
1033         return (ModelElementFacade)this.shieldedElement(element.getNamespace());
1034     }
1035 
1036     /*
1037      * @return this.metaObject.getOwner()
1038      * @see org.eclipse.uml2.uml.Element#getOwner()
1039     //@Override
1040     protected Element handleGetOwner()
1041     {
1042         return this.metaObject.getOwner();
1043     }
1044      */
1045 
1046     /**
1047      * @return element.getQualifiedName()
1048      * @see org.andromda.metafacades.uml.ModelElementFacade#getQualifiedName()
1049      */
1050     protected String handleGetQualifiedName()
1051     {
1052         final NamedElement element = (NamedElement)this.metaObject;
1053         return element.getQualifiedName();
1054     }
1055 
1056     /**
1057      * @param keywordName
1058      * @return this.metaObject.hasKeyword(keywordName)
1059      * @see org.andromda.metafacades.uml.ModelElementFacade#hasKeyword(String)
1060      */
1061     //@Override
1062     protected boolean handleHasKeyword(final String keywordName)
1063     {
1064         return this.metaObject.hasKeyword(keywordName);
1065     }
1066 
1067     /**
1068      * {@inheritDoc}
1069      */
1070     @Override
1071     protected String handleGetBindedFullyQualifiedName(final ModelElementFacade bindedElement)
1072     {
1073         // This cast is not safe yet, but will be as soon as the filtering will be done
1074         @SuppressWarnings("unchecked")
1075         final Collection<BindingFacade> bindingFacades = new ArrayList(bindedElement.getSourceDependencies());
1076         CollectionUtils.filter(
1077             bindingFacades,
1078             new Predicate()
1079             {
1080                 public boolean evaluate(final Object object)
1081                 {
1082                     return object instanceof BindingFacade;
1083                 }
1084             });
1085         return handleGetBindedFullyQualifiedName(false, bindingFacades);
1086     }
1087 
1088     /**
1089      * <p>
1090      * Returns the fully qualified name of the model element. The fully
1091      * qualified name includes complete package qualified name of the
1092      * underlying model element.  If modelName is true, then the
1093      * original name of the model element (the name contained within
1094      * the model) will be the name returned, otherwise a name from a
1095      * language mapping will be returned. Moreover use the given collection
1096      * of {@link BindingFacade} to bind templates parameters to their actual
1097      * type.
1098      * </p>
1099      * @param modelName boolean
1100      * @param bindingFacades Collection
1101      * @return String
1102      */
1103     private String handleGetBindedFullyQualifiedName(final boolean modelName, final Collection<BindingFacade> bindingFacades)
1104     {
1105         final String metafacadeNamespaceScopeOperator = MetafacadeConstants.NAMESPACE_SCOPE_OPERATOR;
1106         String fullName = StringUtils.trimToEmpty(this.handleGetName());
1107         final String packageName = this.handleGetPackageName(true);
1108         // Don't fully qualify other UML types such as Action, UseCase etc. Some cartridges require package.name as the result
1109         // For Parameter, return Classifier.Operation(name)
1110         if (this.metaObject instanceof Parameter)
1111         {
1112             // Add ClassifierName.operationName(ParameterName)
1113             final Object owner = this.metaObject.getOwner();
1114             if (owner != null && owner instanceof Operation)
1115             {
1116                 final Operation operation = (Operation)owner;
1117                 fullName = operation.getName() + '(' + fullName + ')';
1118                 final Object classifier = operation.getOwner();
1119                 if (classifier != null && classifier instanceof NamedElement)
1120                 {
1121                     fullName = ((NamedElement)classifier).getName() + metafacadeNamespaceScopeOperator + fullName;
1122                 }
1123             }
1124         }
1125         // For Attribute/AssociationEnd, return Classifier.name
1126         else if (this.metaObject instanceof Property || this.metaObject instanceof Operation)
1127         {
1128             final Object classifier = this.metaObject.getOwner();
1129             if (classifier != null && classifier instanceof NamedElement)
1130             {
1131                 fullName = ((NamedElement)classifier).getName() + metafacadeNamespaceScopeOperator + fullName;
1132             }
1133         }
1134         if (StringUtils.isNotBlank(packageName))
1135         {
1136             fullName = packageName + metafacadeNamespaceScopeOperator + fullName;
1137         }
1138         if (!modelName)
1139         {
1140             final TypeMappings languageMappings = this.getLanguageMappings();
1141             if (languageMappings != null)
1142             {
1143                 fullName = StringUtils.trimToEmpty(languageMappings.getTo(fullName));
1144 
1145                 // now replace the metafacade scope operators
1146                 // with the mapped scope operators
1147                 final String namespaceScopeOperator =
1148                     String.valueOf(this.getConfiguredProperty(UMLMetafacadeProperties.NAMESPACE_SEPARATOR));
1149                 fullName = StringUtils.replace(
1150                         fullName,
1151                         metafacadeNamespaceScopeOperator,
1152                         namespaceScopeOperator);
1153             }
1154         }
1155 
1156         if (this.isTemplateParametersPresent() &&
1157             BooleanUtils.toBoolean(
1158                 ObjectUtils.toString(this.getConfiguredProperty(UMLMetafacadeProperties.ENABLE_TEMPLATING))))
1159         {
1160             // Retrieve all template parameters
1161             final Collection<TemplateParameterFacade> templateParameters = this.getTemplateParameters();
1162 
1163             // Construct a map of the TemplateParameterFacade to replace
1164             final Map<TemplateParameterFacade, ModelElementFacade> bindedParameters = new HashMap<TemplateParameterFacade, ModelElementFacade>();
1165             for(final BindingFacade bindingFacade : bindingFacades)
1166             {
1167                 ModelElementFacade targetElement = bindingFacade.getTargetElement();
1168                 if(targetElement instanceof RedefinableTemplateSignatureFacade)
1169                 {
1170                     targetElement = ((RedefinableTemplateSignatureFacade) targetElement).getClassifier();
1171                 }
1172                 if(this.equals(targetElement))
1173                 {
1174                     final Collection<TemplateArgumentFacade> arguments = bindingFacade.getArguments();
1175                     if(arguments.size() != getTemplateParameters().size())
1176                     {
1177                         throw new IllegalStateException("The size of the arguments of the BindingFacace must be equals to the size of the TemplateParameter collection of this element.");
1178                     }
1179 
1180                     final Iterator<TemplateArgumentFacade> templateArgumentsIterator = arguments.iterator();
1181                     for (final TemplateParameterFacade templateParameter : templateParameters)
1182                     {
1183                         bindedParameters.put(templateParameter, templateArgumentsIterator.next().getElement());
1184                     }
1185                 }
1186             }
1187             if(bindedParameters.isEmpty())
1188             {
1189                 for(TemplateParameterFacade templateParameterFacade : templateParameters)
1190                 {
1191                     if (templateParameterFacade != null)
1192                     {
1193                         bindedParameters.put(templateParameterFacade, templateParameterFacade.getParameter());
1194                     }
1195                 }
1196             }
1197 
1198             // we'll be constructing the parameter list in this buffer
1199             // add the name we've constructed so far
1200             final StringBuilder buffer = new StringBuilder(fullName).append('<');
1201 
1202             // loop over the parameters, we are so to have at least one (see
1203             // outer condition)
1204             for (final Iterator<TemplateParameterFacade> parameterIterator = templateParameters.iterator(); parameterIterator.hasNext();)
1205             {
1206                 TemplateParameterFacadeLogicImpl parameter = (TemplateParameterFacadeLogicImpl)parameterIterator.next();
1207                 if (parameter == null)
1208                 {
1209                     ModelElementFacadeLogicImpl.LOGGER.error("TemplateParameter was null");
1210                 }
1211                 if (parameter != null && parameter.getType() != null)
1212                 {
1213                     String typeName = parameter.getType().getFullyQualifiedName();
1214                     /*final ModelElementFacade modelElement = bindedParameters.get(parameterIterator.next());
1215 
1216                     // TODO: UML14 returns ParameterFacade, UML2 returns ModelElementFacade, so types are wrong from fullyQualifiedName
1217                     // Mapping from UML2 should return ParameterFacade, with a getType method.
1218                     // Add TemplateParameterFacade.getType method - need to access this in vsl templates.
1219                     if (modelElement instanceof ParameterFacade)
1220                     {
1221                         buffer.append(((ParameterFacade)modelElement).getType().getFullyQualifiedName());
1222                     }
1223                     else
1224                     {*/
1225                         buffer.append(typeName);
1226                     //}
1227 
1228                     if (parameterIterator.hasNext())
1229                     {
1230                         buffer.append(", ");
1231                     }
1232                 }
1233                 else
1234                 {
1235                     ModelElementFacadeLogicImpl.LOGGER.error(
1236                     ((NamedElement)super.metaObject.getOwner()).getName() + "." + parameter + " parameter type NULL");
1237                 }
1238             }
1239 
1240             // we're finished listing the parameters
1241             buffer.append('>');
1242 
1243             // we have constructed the full name in the buffer
1244             fullName = buffer.toString();
1245         }
1246 
1247         return fullName;
1248     }
1249 
1250     // Valid identifier starts with alphanum or _$ and contains only alphanum or _$ or digits
1251     private static final Pattern IDENTIFIER_PATTERN = Pattern.compile("[a-zA-Z_$][a-zA-Z\\d_$]*");
1252     /**
1253      * Return true if name matches the pattern [a-zA-Z_$][a-zA-Z\\d_$]*
1254      * @see org.andromda.metafacades.emf.uml22.ModelElementFacadeLogic#handleIsValidIdentifierName()
1255      */
1256     @Override
1257     protected boolean handleIsValidIdentifierName()
1258     {
1259         final String name = this.handleGetName();
1260         return IDENTIFIER_PATTERN.matcher(name).matches();
1261     }
1262 }