View Javadoc
1   package org.andromda.cartridges.ejb3.metafacades;
2   
3   import java.util.ArrayList;
4   import java.util.Collection;
5   import java.util.Iterator;
6   import java.util.List;
7   import org.andromda.cartridges.ejb3.EJB3Globals;
8   import org.andromda.cartridges.ejb3.EJB3Profile;
9   import org.andromda.core.common.ExceptionUtils;
10  import org.andromda.metafacades.uml.AttributeFacade;
11  import org.andromda.metafacades.uml.ClassifierFacade;
12  import org.andromda.metafacades.uml.EntityMetafacadeUtils;
13  import org.andromda.metafacades.uml.ModelElementFacade;
14  import org.andromda.metafacades.uml.OperationFacade;
15  import org.andromda.metafacades.uml.UMLProfile;
16  import org.apache.commons.collections.CollectionUtils;
17  import org.apache.commons.collections.Predicate;
18  import org.apache.commons.lang.StringUtils;
19  
20  /**
21   * Contains utilities for use with EJB metafacades.
22   *
23   * @author Chad Brandon
24   * @author Vance Karimi
25   */
26  class EJB3MetafacadeUtils
27  {
28      /**
29       * Gets all create methods for the given <code>classifier</code>.
30       *
31       * @param classifier The classifier from which to retries the create methods
32       * @param follow if true, all super type create methods are also retrieved
33       * @return collection of create methods found.
34       */
35      static Collection<OperationFacade> getCreateMethods(
36              ClassifierFacade classifier,
37              boolean follow)
38      {
39          ExceptionUtils.checkNull("classifer", classifier);
40          Collection<OperationFacade> retval = new ArrayList<OperationFacade>();
41          ClassifierFacade entity = classifier;
42          do
43          {
44              for (final OperationFacade op : entity.getOperations())
45              {
46                  if (op.hasStereotype(EJB3Profile.STEREOTYPE_CREATE_METHOD))
47                  {
48                      retval.add(op);
49                  }
50              }
51              if (follow)
52              {
53                  entity = (ClassifierFacade)entity.getGeneralization();
54              }
55          }
56          while (follow && entity != null);
57          return retval;
58      }
59  
60      /**
61       * Gets the interface name for the passed in <code>classifier</code>. Returns 'LocalHome' if the mode element has
62       * the entity stereotype, returns 'Home' otherwise.
63       * @param classifier
64       * @return the interface name.
65       */
66      static String getHomeInterfaceName(ClassifierFacade classifier)
67      {
68          ExceptionUtils.checkNull("classifer", classifier);
69          String homeInterfaceName;
70          if (classifier.hasStereotype(UMLProfile.STEREOTYPE_ENTITY))
71          {
72              homeInterfaceName = classifier.getName() + "LocalHome";
73          }
74          else
75          {
76              homeInterfaceName = classifier.getName() + "Home";
77          }
78          return homeInterfaceName;
79      }
80  
81      /**
82       * Gets the view type for the passed in <code>classifier</code>. If no
83       * view type can be retrieved from the <code>classifier</code>, then the
84       * <code>defaultViewType</code> is returned.
85       *
86       * If session ejb pojo then checks the ejb tagged value and if there is
87       * no value defined, returns 'remote'.
88       *
89       * @param classifier The classifier to lookup the view type tagged value
90       * @param defaultViewType The default view type if one is not found
91       * @return String the view type name.
92       */
93      static String getViewType(
94              ClassifierFacade classifier,
95              String defaultViewType)
96      {
97          ExceptionUtils.checkNull("classifer", classifier);
98          String viewType = (String)classifier.findTaggedValue(EJB3Profile.TAGGEDVALUE_EJB_VIEWTYPE);
99          if (StringUtils.isBlank(viewType))
100         {
101             if (classifier.hasStereotype(EJB3Profile.STEREOTYPE_SERVICE))
102             {
103                 // if the view type wasn't found, search all super classes
104                 if (StringUtils.isBlank(viewType))
105                 {
106                     viewType = (String)CollectionUtils.find(
107                             classifier.getAllGeneralizations(),
108                             new Predicate()
109                             {
110                                 public boolean evaluate(Object object)
111                                 {
112                                     return ((ModelElementFacade)object).findTaggedValue(
113                                             EJB3Profile.TAGGEDVALUE_EJB_VIEWTYPE) != null;
114                                 }
115                             });
116                 }
117                 if (StringUtils.isBlank(viewType))
118                 {
119                     viewType = (StringUtils.isNotBlank(defaultViewType) ?
120                             defaultViewType : EJB3Globals.VIEW_TYPE_REMOTE);
121                 }
122             }
123         }
124         return viewType.toLowerCase();
125     }
126 
127     /**
128      * Gets all the inherited instance attributes, excluding the instance attributes directory from this
129      * <code>classifier</code>.
130      *
131      * @param classifier the ClassifierFacade from which to retrieve the inherited attributes.
132      * @return a list of ordered attributes.
133      */
134     static List<AttributeFacade> getInheritedInstanceAttributes(ClassifierFacade classifier)
135     {
136         ExceptionUtils.checkNull("classifer", classifier);
137         ClassifierFacade current = (ClassifierFacade)classifier.getGeneralization();
138         if (current == null)
139         {
140             return new ArrayList<AttributeFacade>();
141         }
142         List<AttributeFacade> retval = getInheritedInstanceAttributes(current);
143 
144         if (current.getInstanceAttributes() != null)
145         {
146             retval.addAll(current.getInstanceAttributes());
147         }
148         return retval;
149     }
150 
151     /**
152      * Gets all instance attributes including those instance attributes belonging to the
153      * <code>classifier</code> and any inherited ones.
154      *
155      * @param classifier the ClassifierFacade from which to retrieve the instance attributes.
156      * @return the list of all instance attributes.
157      */
158     static List<AttributeFacade> getAllInstanceAttributes(ClassifierFacade classifier)
159     {
160         ExceptionUtils.checkNull("classifer", classifier);
161         List<AttributeFacade> retval = getInheritedInstanceAttributes(classifier);
162         retval.addAll(classifier.getInstanceAttributes());
163         return retval;
164     }
165 
166     /**
167      * Gets all environment entries for the specified <code>classifier</code>. If <code>follow</code> is true, then a
168      * search up the inheritance hierarchy will be performed and all super type environment entries will also be
169      * retrieved.
170      *
171      * @param classifier the classifier from which to retrieve the env-entries
172      * @param follow     true/false on whether or not to 'follow' the inheritance hierarchy when retrieving the
173      *                   env-entries.
174      * @return the collection of environment entries
175      */
176     static Collection<AttributeFacade> getEnvironmentEntries(
177             ClassifierFacade classifier,
178             boolean follow)
179     {
180         ExceptionUtils.checkNull("classifer", classifier);
181 
182         Collection<AttributeFacade> attributes = classifier.getStaticAttributes();
183 
184         if (follow)
185         {
186             for (classifier = (ClassifierFacade)classifier.getGeneralization();
187                  classifier != null; classifier = (ClassifierFacade)classifier.getGeneralization())
188             {
189                 attributes.addAll(classifier.getStaticAttributes());
190             }
191         }
192 
193         CollectionUtils.filter(attributes, new Predicate()
194         {
195             public boolean evaluate(Object object)
196             {
197                 return ((AttributeFacade)object).hasStereotype(EJB3Profile.STEREOTYPE_ENV_ENTRY);
198             }
199         });
200 
201         return attributes;
202     }
203 
204     /**
205      * Returns the transaction type for the specified <code>classifier</code>.
206      *
207      * @param classifier the classifier from which to retrieve the transaction type.
208      * @param defaultTransactionType the default transaction type if no tagged value is specified.
209      * @return the transaction type as a String.
210      */
211     static String getTransactionType(ClassifierFacade classifier, String defaultTransactionType)
212     {
213         ExceptionUtils.checkNull("classifer", classifier);
214 
215         String transactionType = (String)classifier.findTaggedValue(EJB3Profile.TAGGEDVALUE_EJB_TRANSACTION_TYPE);
216         if (StringUtils.isNotBlank(transactionType))
217         {
218             transactionType = convertTransactionType(transactionType);
219         }
220         else
221         {
222             transactionType = defaultTransactionType;
223         }
224         return transactionType;
225     }
226 
227     /**
228      * Convert the transaction type from lower casing to upper casing.
229      * This maintains reusable tagged value enumeration from EJB
230      * implementation.
231      *
232      * @param transType
233      * @return transactionType
234      */
235     static String convertTransactionType(String transType)
236     {
237         ExceptionUtils.checkNull("transType", transType);
238 
239         String type = null;
240         if (StringUtils.equalsIgnoreCase(transType, EJB3Globals.TRANSACTION_TYPE_MANDATORY))
241         {
242             type = "MANDATORY";
243         }
244         else if (StringUtils.equalsIgnoreCase(transType, EJB3Globals.TRANSACTION_TYPE_NEVER))
245         {
246             type = "NEVER";
247         }
248         else if (StringUtils.equalsIgnoreCase(transType, EJB3Globals.TRANSACTION_TYPE_NOT_SUPPORTED))
249         {
250             type = "NOT_SUPPORTED";
251         }
252         else if (StringUtils.equalsIgnoreCase(transType, EJB3Globals.TRANSACTION_TYPE_REQUIRED))
253         {
254             type = "REQUIRED";
255         }
256         else if (StringUtils.equalsIgnoreCase(transType, EJB3Globals.TRANSACTION_TYPE_REQUIRES_NEW))
257         {
258             type = "REQUIRES_NEW";
259         }
260         else if (StringUtils.equalsIgnoreCase(transType, EJB3Globals.TRANSACTION_TYPE_SUPPORTS))
261         {
262             type = "SUPPORTS";
263         }
264         return type;
265     }
266 
267     /**
268      * Gets all constants for the specified <code>classifier</code>.
269      * If <code>follow</code> is true, then a search up
270      * the inheritance hierarchy will be performed and all super
271      * type constants will also be retrieved.
272      *
273      * @param classifier the classifier from which to retrieve the constants
274      * @param follow     true/false on whether or not to 'follow' the inheritance hierarchy when retrieving the
275      *                   constants.
276      * @return the collection of environment entries
277      */
278     static Collection<AttributeFacade> getConstants(
279             ClassifierFacade classifier,
280             boolean follow)
281     {
282         ExceptionUtils.checkNull("classifer", classifier);
283 
284         Collection<AttributeFacade> attributes = classifier.getStaticAttributes();
285 
286         if (follow)
287         {
288             for (classifier = (ClassifierFacade)classifier.getGeneralization();
289                  classifier != null; classifier = (ClassifierFacade)classifier.getGeneralization())
290             {
291                 attributes.addAll(classifier.getStaticAttributes());
292             }
293         }
294 
295         CollectionUtils.filter(attributes, new Predicate()
296         {
297             public boolean evaluate(Object object)
298             {
299                 return !((AttributeFacade)object).hasStereotype(EJB3Profile.STEREOTYPE_ENV_ENTRY);
300             }
301         });
302 
303         return attributes;
304     }
305 
306     /**
307      * Returns true/false based on whether or not synthetic or auto generated create methods should be allowed.
308      *
309      * @param classifier The entity or session bean.
310      * @return true/false
311      */
312     static boolean allowSyntheticCreateMethod(ClassifierFacade classifier)
313     {
314         ExceptionUtils.checkNull("classifer", classifier);
315         return !classifier.isAbstract() && classifier.findTaggedValue(
316                 EJB3Profile.TAGGEDVALUE_EJB_NO_SYNTHETIC_CREATE_METHOD) == null;
317     }
318 
319     /**
320      * Creates a fully qualified name from the given <code>packageName</code>,
321      * <code>name</code>, and <code>suffix</code>.
322      *
323      * @param packageName the name of the model element package.
324      * @param name the name of the model element.
325      * @param suffix the suffix to append.
326      * @return the new fully qualified name.
327      */
328     static String getFullyQualifiedName(
329         String packageName,
330         String name,
331         String suffix)
332     {
333         StringBuilder fullyQualifiedName = new StringBuilder(StringUtils.trimToEmpty(packageName));
334         if (StringUtils.isNotBlank(packageName))
335         {
336             fullyQualifiedName.append('.');
337         }
338         fullyQualifiedName.append(StringUtils.trimToEmpty(name));
339         fullyQualifiedName.append(StringUtils.trimToEmpty(suffix));
340         return fullyQualifiedName.toString();
341     }
342 
343     /**
344      * Returns true if the Seam stereotype is modeled on the class.
345      *
346      * @param classifier The classifier to lookup if the stereotype is modeled
347      * @return True is stereotype exists, false otherwise
348      */
349     static boolean isSeamComponent(ClassifierFacade classifier)
350     {
351         boolean isSeamComponent = false;
352         if (classifier.hasStereotype(EJB3Profile.STEREOTYPE_SEAM_COMPONENT))
353         {
354             isSeamComponent = true;
355         }
356         return isSeamComponent;
357     }
358 
359     /**
360      * Gets the Seam component scope type for Entity and Session beans.
361      * If no scope has been specified:
362      *     If the Classifier is a stateless session bean, then returns STATELESS
363      *     If the Classifier is an entity or stateful session bean, then returns CONVERSATION
364      *
365      * @param classifier The classifier to lookup the scope type tagged value
366      * @param stateless Whether the classifier is a stateless session bean
367      * @return The scope type as a String
368      */
369     static String getSeamComponentScopeType(ClassifierFacade classifier, boolean stateless)
370     {
371         ExceptionUtils.checkNull("classifer", classifier);
372         String scopeType = (String)classifier.findTaggedValue(EJB3Profile.TAGGEDVALUE_SEAM_SCOPE_TYPE);
373         if (StringUtils.isBlank(scopeType))
374         {
375             if (stateless)
376             {
377                 scopeType = EJB3Globals.SEAM_COMPONENT_SCOPE_STATELESS;
378             }
379             else
380             {
381                 scopeType = EJB3Globals.SEAM_COMPONENT_SCOPE_CONVERSATION;
382             }
383         }
384         return scopeType;
385     }
386 
387     /**
388      * Returns the Seam component name.  Can override using tagged value, otherwise just the
389      * class name.
390      *
391      * @param classifier The classifier to get the tagged value or the name from.
392      * @return The Seam component name
393      */
394     static String getSeamComponentName(ClassifierFacade classifier)
395     {
396         ExceptionUtils.checkNull("classifer", classifier);
397         String componentName = (String)classifier.findTaggedValue(EJB3Profile.TAGGEDVALUE_SEAM_COMPONENT_NAME);
398         if (StringUtils.isBlank(componentName))
399         {
400             componentName = StringUtils.uncapitalize(classifier.getName());
401         }
402         return componentName;
403     }
404 
405     /**
406      * Builds an annotation parameter line
407      * @param parameters The parameters
408      * @return The parameter line
409      */
410     static String buildAnnotationParameters(Collection<String> parameters)
411     {
412         StringBuilder buf = new StringBuilder();
413         if(!parameters.isEmpty())
414         {
415             buf.append("(");
416             Iterator it = parameters.iterator();
417             while(it.hasNext())
418             {
419                 String option = (String) it.next();
420                 buf.append(option);
421                 if(it.hasNext())
422                 {
423                     buf.append(", ");
424                 }
425             }
426             buf.append(")");
427             return buf.toString();
428         }
429         else
430         {
431             return null;
432         }
433     }
434 
435     /**
436      * Builds a multi valued parameter string
437      * @param name The name of the parameter
438      * @param values The values for the parameters
439      * @return The parameter string
440      */
441     static String buildAnnotationMultivalueParameter(String name, Collection<String> values)
442     {
443         return buildAnnotationMultivalueParameter(name, values, true);
444     }
445 
446     /**
447      * Builds a multi valued parameter string
448      * @param name The name of the parameter
449      * @param values The values for the parameters
450      * @param areStrings If the values are strings then surround with " sign
451      * @return The parameter string
452      */
453     static String buildAnnotationMultivalueParameter(String name, Collection<String> values, boolean areStrings)
454     {
455         return buildAnnotationMultivalueParameter(name, values, areStrings, null);
456     }
457 
458     /**
459      * Builds a multi option string
460      * Builds a multi valued parameter string
461      * @param name The name of the parameter
462      * @param values The values for the parameters
463      * @param areStrings If the values are strings then surround with " sign
464      * @param suffix Any suffix to add to the values
465      * @return The parameter string
466      */
467     static String buildAnnotationMultivalueParameter(String name, Collection<String> values, boolean areStrings, String suffix)
468     {
469         if(values.isEmpty())
470         {
471             return null;
472         }
473         else
474         {
475             StringBuilder buf = new StringBuilder();
476             buf.append(name + " = {");
477 
478             Iterator it = values.iterator();
479             while(it.hasNext())
480             {
481                 String parameter = (String) it.next();
482                 if(areStrings)
483                 {
484                     buf.append("\"");
485                 }
486                 buf.append(parameter);
487                 if((suffix != null) && !parameter.endsWith(suffix))
488                 {
489                     buf.append(suffix);
490                 }
491                 if(areStrings)
492                 {
493                     buf.append("\"");
494                 }
495                 if(it.hasNext())
496                 {
497                     buf.append(", ");
498                 }
499             }
500             buf.append("}");
501             return buf.toString();
502         }
503     }
504 
505     /**
506      * Gets the SQL name. (i.e. column name, table name, etc.). If it can't find
507      * the corresponding tagged value with the specified <code>name</code>,
508      * then it uses the element name by default and just returns that.
509      *
510      * @param prefix the optional prefix to add to the sql name (i.e. table name
511      *        prefix, etc.).
512      * @param element from which to retrieve the SQL name.
513      * @param name the name of the tagged value.
514      * @param nameMaxLength if this is not null, then the name returned will be
515      *        trimmed to this length (if it happens to be longer).
516      * @param suffix the optional suffix to add to the sql name (i.e. foreign
517      *        key suffix, etc.)
518      * @param separator character used to separate words
519      * @param shortenSqlNameMethod The method used to shorten the name, i.e. removeVowels
520      * @return the SQL name as a String.
521      */
522     public static String getSqlNameFromTaggedValue(
523         String prefix,
524         final EJB3AssociationFacade element,
525         String name,
526         final Short nameMaxLength,
527         String suffix,
528         final Object separator,
529         final Object shortenSqlNameMethod)
530     {
531         if (element != null)
532         {
533             Object value = element.findTaggedValue(name);
534             StringBuilder buffer = new StringBuilder(StringUtils.trimToEmpty((String)value));
535             if (StringUtils.isBlank(buffer.toString()))
536             {
537                 // if we can't find the tagValue then use the
538                 // element name for the name
539                 buffer = new StringBuilder(
540                         EntityMetafacadeUtils.toSqlName(
541                             element.getName(),
542                             separator));
543 
544                 suffix = StringUtils.trimToEmpty(suffix);
545                 prefix = StringUtils.trimToEmpty(prefix);
546                 if (nameMaxLength != null)
547                 {
548                     final short maxLength = (short)(nameMaxLength.shortValue() - suffix.length() - prefix.length());
549                     buffer =
550                         new StringBuilder(
551                             EntityMetafacadeUtils.ensureMaximumNameLength(
552                                 buffer.toString(),
553                                 new Short(maxLength),
554                                 (String)shortenSqlNameMethod));
555                 }
556                 if (StringUtils.isNotBlank(prefix))
557                 {
558                     buffer.insert(
559                         0,
560                         prefix);
561                 }
562                 if (StringUtils.isNotBlank(suffix))
563                 {
564                     buffer.append(suffix);
565                 }
566             }
567             name = buffer.toString();
568         }
569         return name;
570     }
571 }