View Javadoc

1   package org.andromda.cartridges.meta.metafacades;
2   
3   import java.util.ArrayList;
4   import java.util.Collection;
5   import java.util.Collections;
6   import java.util.Comparator;
7   import java.util.HashMap;
8   import java.util.Iterator;
9   import java.util.LinkedHashSet;
10  import java.util.List;
11  import java.util.Map;
12  import java.util.Set;
13  
14  import org.andromda.cartridges.meta.MetaProfile;
15  import org.andromda.core.metafacade.MetafacadeException;
16  import org.andromda.metafacades.uml.AssociationEndFacade;
17  import org.andromda.metafacades.uml.AttributeFacade;
18  import org.andromda.metafacades.uml.ClassifierFacade;
19  import org.andromda.metafacades.uml.DependencyFacade;
20  import org.andromda.metafacades.uml.GeneralizationFacade;
21  import org.andromda.metafacades.uml.ModelElementFacade;
22  import org.andromda.metafacades.uml.OperationFacade;
23  import org.apache.commons.collections.CollectionUtils;
24  import org.apache.commons.collections.Predicate;
25  import org.apache.commons.collections.Transformer;
26  import org.apache.commons.lang.ObjectUtils;
27  import org.apache.commons.lang.StringUtils;
28  
29  
30  /***
31   * Metaclass facade implementation.
32   *
33   * @see org.andromda.cartridges.meta.metafacades.Metafacade
34   */
35  public class MetafacadeLogicImpl
36      extends MetafacadeLogic
37  {
38      /***
39       * This defines the metamodel version package name (i.e.
40       * org.andromda.metafacades.uml14, org.andromda.metafacades.um20, etc) used
41       * by this cartridge to create the generated impl package name, if left
42       * empty then the impl package will be the same as the metafacade package
43       * (therefore we default to an empty name)
44       */
45      private static final String METAMODEL_VERSION_PACKAGE = "metamodelVersionPackage";
46      private Map featureMap = null;
47  
48      public MetafacadeLogicImpl(
49          java.lang.Object metaObject,
50          String context)
51      {
52          super(metaObject, context);
53      }
54  
55      /***
56       * Returns the class tagged with <<metaclass>>> that is
57       * connected to the metaobject via a dependency. If no metaclass is directly
58       * connected, the method walks up the supertype hierarchy.
59       *
60       * @return the metaclass object
61       */
62      protected Object handleGetMetaclass()
63      {
64          // delegate to recursive method
65          return getMetaclass(this);
66      }
67  
68      /***
69       * Returns the class tagged with <<metaclass>> that is connected
70       * to cl via a dependency.
71       *
72       * @param cl the source classifier
73       * @return the metaclass object
74       */
75      private ClassifierFacade getMetaclass(ClassifierFacade classifier)
76      {
77          for (final Iterator iter = classifier.getSourceDependencies().iterator(); iter.hasNext();)
78          {
79              DependencyFacade dep = (DependencyFacade)iter.next();
80              ClassifierFacade target = (ClassifierFacade)dep.getTargetElement();
81              Collection stereotypes = target.getStereotypeNames();
82              if ((stereotypes != null) && (stereotypes.size() > 0))
83              {
84                  String stereotypeName = (String)stereotypes.iterator().next();
85                  if (stereotypeName.equals(MetaProfile.STEREOTYPE_METACLASS))
86                  {
87                      return target;
88                  }
89              }
90          }
91  
92          ClassifierFacade superclass = (ClassifierFacade)classifier.getGeneralization();
93          return (superclass != null) ? getMetaclass(superclass) : null;
94      }
95  
96      /***
97       * @see org.andromda.cartridges.meta.metafacades.MetafacadeFacade#isMetaclassDirectDependency()
98       */
99      protected boolean handleIsMetaclassDirectDependency()
100     {
101         boolean isMetaClassDirectDependency = false;
102         Collection dependencies = this.getSourceDependencies();
103         if ((dependencies != null) && !dependencies.isEmpty())
104         {
105             // there should be only one.
106             DependencyFacade dependency = (DependencyFacade)dependencies.iterator().next();
107             if (dependency != null)
108             {
109                 ModelElementFacade targetElement = dependency.getTargetElement();
110                 if (targetElement != null)
111                 {
112                     isMetaClassDirectDependency = targetElement.hasStereotype(MetaProfile.STEREOTYPE_METACLASS);
113                 }
114             }
115         }
116         return isMetaClassDirectDependency;
117     }
118 
119     /***
120      * @see org.andromda.cartridges.meta.metafacades.MetafacadeFacade#getLogicName()
121      */
122     protected String handleGetLogicName()
123     {
124         return this.getName() + "Logic";
125     }
126 
127     /***
128      * @see org.andromda.cartridges.meta.metafacades.MetafacadeFacade#getLogicImplName()
129      */
130     protected String handleGetLogicImplName()
131     {
132         return this.getName() + "LogicImpl";
133     }
134 
135     /***
136      * @see org.andromda.cartridges.meta.metafacades.MetafacadeFacade#getFullyQualifiedLogicImplName()
137      */
138     protected String handleGetFullyQualifiedLogicImplName()
139     {
140         return this.getMetafacadeSupportClassName(this.getLogicImplName());
141     }
142 
143     /***
144      * @see org.andromda.cartridges.meta.metafacades.MetafacadeFacade#getFullyQualifiedLogicName()
145      */
146     protected String handleGetFullyQualifiedLogicName()
147     {
148         return this.getMetafacadeSupportClassName(this.getLogicName());
149     }
150 
151     /***
152      * @see org.andromda.cartridges.meta.metafacades.MetafacadeFacade#getLogicFile(java.lang.String)
153      */
154     protected String handleGetLogicFile()
155     {
156         return this.getFullyQualifiedLogicName().replace('.', '/') + ".java";
157     }
158 
159     /***
160      * Gets the metamodel version package name (i.e.
161      * org.andromda.metafacades.uml14, org.andromda.metafacades.um20, etc) used
162      * by this cartridge to create the generated impl package name, if left
163      * empty then the impl package will be the same as the metafacade package
164      * (therefore we default to an empty name)
165      */
166     private String getMetaModelVersionPackage()
167     {
168         return ObjectUtils.toString(this.getConfiguredProperty(METAMODEL_VERSION_PACKAGE));
169     }
170 
171     /***
172      * @see org.andromda.cartridges.meta.metafacades.MetafacadeFacade#getLogicPackageName(java.lang.String)
173      */
174     protected String handleGetLogicPackageName()
175     {
176         String packageName = this.getMetaModelVersionPackage();
177         if</strong> (StringUtils.isEmpty(packageName))
178         {
179             packageName = this.getPackageName();
180         }
181         return</strong> packageName;
182     }
183 
184     /***
185      * @see org.andromda.cartridges.meta.metafacades.MetafacadeFacade#getLogicImplFile(java.lang.String)
186      */
187     protected String handleGetLogicImplFile()
188     {
189         return this.getFullyQualifiedLogicImplName().replace('.', '/') + ".java";
190     }
191 
192     /***
193      * Creates a metafacade support class name from the given
194      * <code>metamodelVersionPackage</code> (i.e. the package for the specific
195      * meta model version). Support classes are the 'Logic' classes.
196      *
197      * @param metamodelVersionPackage the version of the meta model
198      * @param the name of the class to append to the package.
199      * @return the new metafacade support class name.
200      */
201     private String getMetafacadeSupportClassName(String name)
202     {
203         StringBuffer fullyQualifiedName = new StringBuffer(this.getLogicPackageName());
204         if (StringUtils.isNotBlank(fullyQualifiedName.toString()))
205         {
206             fullyQualifiedName.append(".");
207             fullyQualifiedName.append(name);
208         }
209         return fullyQualifiedName.toString();
210     }
211 
212     /***
213      * @see org.andromda.cartridges.meta.metafacades.MetafacadeFacadeLogic#handleGetMethodDataForPSM(org.andromda.metafacades.uml.ClassifierFacade)
214      */
215     protected Collection handleGetMethodDataForPSM(ClassifierFacade facade)
216     {
217         return this.getMethodDataForPSM(facade, true);
218     }
219 
220     /***
221      * @see org.andromda.cartridges.meta.metafacades.MetafacadeFacade#getMethodDataForPSM()
222      */
223     protected Collection handleGetMethodDataForPSM()
224     {
225         return this.getMethodDataForPSM(null, false);
226     }
227 
228     /***
229      * @see org.andromda.cartridges.meta.metafacades.MetafacadeFacade#getMethodDataForPSM(boolean)
230      */
231     private final Collection getMethodDataForPSM(
232         final ClassifierFacade facade,
233         final boolean includeSuperclasses)
234     {
235         try
236         {
237             final Set declarationSet = new LinkedHashSet();
238             if (this.featureMap == null)
239             {
240                 this.featureMap = new HashMap();
241                 if (includeSuperclasses && this.getGeneralizations() != null)
242                 {
243                     for (final Iterator iterator = this.getGeneralizations().iterator(); iterator.hasNext();)
244                     {
245                         final Map methodDataMap = new HashMap();
246                         final ClassifierFacade metafacade = (ClassifierFacade)iterator.next();
247                         for (ClassifierFacade classifier = metafacade; classifier instanceof Metafacade;
248                              classifier = (ClassifierFacade)classifier.getGeneralization())
249                         {
250                             this.getAllFeatures(methodDataMap, declarationSet, (Metafacade)classifier);
251                         }
252                         this.featureMap.put(
253                             metafacade,
254                             methodDataMap.values());
255                     }
256                 }
257             }
258             final List result = new ArrayList();
259             if (this.featureMap != null)
260             {
261                 Collection features = (Collection)this.featureMap.get(facade);
262                 if (features != null)
263                 {
264                     result.addAll(features);
265                 }
266             }
267             if (!includeSuperclasses)
268             {
269                 final Map methodDataMap = new HashMap();
270                 this.getAllFeatures(methodDataMap, declarationSet, this);
271                 result.addAll(methodDataMap.values());
272             }
273             Collections.sort(result);
274             return result;
275         }
276         catch (Throwable th)
277         {
278             throw new RuntimeException(th);
279         }
280     }
281 
282     private final void getAllFeatures(
283         final Map methodDataMap,
284         final Set declarationSet,
285         final Metafacade facade)
286     {
287         try
288         {
289             final String methodVisibility = "public";
290             final String indendation = "    * ";
291             final String fullyQualifiedName = facade.getFullyQualifiedName();
292 
293             // translate UML attributes and association ends to getter methods
294             for (final Iterator iterator = facade.getProperties().iterator(); iterator.hasNext();)
295             {
296                 final ModelElementFacade property = (ModelElementFacade)iterator.next();
297                 MethodData method = null;
298                 if (property instanceof AttributeFacade)
299                 {
300                     final AttributeFacade attribute = (AttributeFacade)property;
301                     method =
302                         new MethodData(
303                             fullyQualifiedName,
304                             methodVisibility,
305                             false,
306                             attribute.getGetterSetterTypeName(),
307                             attribute.getGetterName(),
308                             attribute.getDocumentation(indendation));
309                 }
310                 else
311                 {
312                     final AssociationEndFacade association = (AssociationEndFacade)property;
313                     method =
314                         new MethodData(
315                             fullyQualifiedName,
316                             methodVisibility,
317                             false,
318                             association.getGetterSetterTypeName(),
319                             association.getGetterName(),
320                             association.getDocumentation(indendation));
321                 }
322                 final String declaration = method.buildMethodDeclaration(true);
323 
324                 // don't add the new method data if we already have the 
325                 // declaration from a previous generalization.
326                 if (!declarationSet.contains(declaration))
327                 {
328                     methodDataMap.put(
329                         method.buildCharacteristicKey(),
330                         method);
331                     declarationSet.add(declaration);
332                 }
333             }
334 
335             // translate UML operations to methods
336             for (final Iterator iterator = facade.getOperations().iterator(); iterator.hasNext();)
337             {
338                 final OperationFacade operation = (OperationFacade)iterator.next();
339                 final UMLOperationData method = new UMLOperationData(fullyQualifiedName, operation);
340 
341                 // don't add the new method data if we already have the 
342                 // declaration from a previous generalization.
343                 final String declaration = method.buildMethodDeclaration(true);
344                 if (!declarationSet.contains(declaration))
345                 {
346                     methodDataMap.put(
347                         method.buildCharacteristicKey(),
348                         method);
349                     declarationSet.add(declaration);
350                 }
351             }
352         }
353         catch (final Throwable throwable)
354         {
355             logger.error(throwable);
356             throw new MetafacadeException(throwable);
357         }
358     }
359 
360     /***
361      * @see org.andromda.cartridges.meta.metafacades.MetafacadeFacade#isRequiresInheritanceDelegatation()
362      */
363     protected boolean handleIsRequiresInheritanceDelegatation()
364     {
365         boolean requiresInheritanceDelegation = false;
366         final ModelElementFacade superMetafacade = this.getGeneralization();
367         if (superMetafacade != null)
368         {
369             requiresInheritanceDelegation =
370                 !superMetafacade.getPackageName().equals(this.getPackageName()) ||
371                 (this.getGeneralizations().size() > 1);
372         }
373         return requiresInheritanceDelegation;
374     }
375 
376     /***
377      * @see org.andromda.cartridges.meta.metafacades.MetafacadeFacade#isConstructorRequiresMetaclassCast()
378      */
379     protected boolean handleIsConstructorRequiresMetaclassCast()
380     {
381         boolean requiresCast = false;
382         final Metafacade superMetafacade = (Metafacade)this.getGeneralization();
383         if (superMetafacade != null)
384         {
385             requiresCast = superMetafacade.isMetaclassDirectDependency() && !this.isRequiresInheritanceDelegatation();
386         }
387         return requiresCast;
388     }
389 
390     /***
391      * @see org.andromda.metafacades.uml.GeneralizableElementFacade#getGeneralizations()
392      */
393     public Collection getGeneralizations()
394     {
395         final List generalizations = new ArrayList(super.getGeneralizationLinks());
396         Collections.sort(
397             generalizations,
398             new GeneralizationPrecedenceComparator());
399         CollectionUtils.transform(
400             generalizations,
401             new Transformer()
402             {
403                 public Object transform(final Object object)
404                 {
405                     return ((GeneralizationFacade)object).getParent();
406                 }
407             });
408         CollectionUtils.filter(generalizations,
409             new Predicate()
410             {
411                 public boolean evaluate(final Object object)
412                 {
413                     return object instanceof Metafacade;
414                 }
415             });
416         return generalizations;
417     }
418 
419     /***
420      * @see org.andromda.cartridges.meta.metafacades.MetafacadeFacade#getGeneralizationCount()
421      */
422     protected int handleGetGeneralizationCount()
423     {
424         int count = 0;
425         final Collection generalizations = this.getGeneralizations();
426         if (generalizations != null)
427         {
428             count = generalizations.size();
429         }
430         return count;
431     }
432 
433     /***
434      * Used to sort metafacade generalizations by precedence.
435      */
436     static final class GeneralizationPrecedenceComparator
437         implements Comparator
438     {
439         public int compare(
440             Object objectA,
441             Object objectB)
442         {
443             MetafacadeGeneralization a = (MetafacadeGeneralization)objectA;
444             MetafacadeGeneralization b = (MetafacadeGeneralization)objectB;
445             return a.getPrecedence().compareTo(b.getPrecedence());
446         }
447     }
448 
449     /***
450      * @see org.andromda.cartridges.meta.metafacades.MetafacadeLogic#getAllParents()
451      */
452     protected Collection handleGetAllParents()
453     {
454         Set allParents = new LinkedHashSet();
455         final Collection parents = this.getGeneralizations();
456         allParents.addAll(parents);
457         for (final Iterator iterator = parents.iterator(); iterator.hasNext();)
458         {
459             final Object object = iterator.next();
460             if (object instanceof Metafacade)
461             {
462                 final Metafacade metafacade = (Metafacade)object;
463                 allParents.addAll(metafacade.getAllParents());    
464             }
465         }
466         return allParents;
467     }
468 }