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