View Javadoc
1   package org.andromda.metafacades.uml;
2   
3   import java.util.ArrayList;
4   import java.util.Collection;
5   import java.util.Date;
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.Matcher;
11  import java.util.regex.Pattern;
12  import org.andromda.core.metafacade.MetafacadeConstants;
13  import org.apache.commons.collections.CollectionUtils;
14  import org.apache.commons.collections.Predicate;
15  import org.apache.commons.lang.BooleanUtils;
16  import org.apache.commons.lang.ObjectUtils;
17  import org.apache.commons.lang.StringUtils;
18  import org.apache.commons.lang.time.FastDateFormat;
19  import org.apache.log4j.Logger;
20  
21  /**
22   * Contains utilities that are common to the UML metafacades.
23   *
24   * @author Chad Brandon
25   * @author Bob Fields
26   */
27  public class UMLMetafacadeUtils
28  {
29      /**
30       * The logger instance.
31       */
32      private static final Logger logger = Logger.getLogger(UMLMetafacadeUtils.class);
33  
34      /**
35       * Returns true or false depending on whether or not this Classifier or any of its specializations is of the given
36       * type having the specified <code>typeName</code>
37       * @param classifier
38       * @param typeName the name of the type (i.e. datatype::Collection)
39       * @return true/false
40       */
41      public static boolean isType(ClassifierFacade classifier, String typeName)
42      {
43          boolean isType = false;
44          if (classifier != null && typeName != null)
45          {
46              final String type = StringUtils.trimToEmpty(typeName);
47              String name = StringUtils.trimToEmpty(classifier.getFullyQualifiedName(true));
48              isType = name.equals(type);
49              // if this isn't a type defined by typeName, see if we can find any
50              // types that inherit from the type.
51              if (!isType)
52              {
53                  isType = CollectionUtils.find(classifier.getAllGeneralizations(), new Predicate()
54                  {
55                      public boolean evaluate(Object object)
56                      {
57                          String name = StringUtils.trimToEmpty(
58                                  ((ModelElementFacade)object).getFullyQualifiedName(true));
59                          return name.equals(type);
60                      }
61                  }) != null;
62              }
63              if (!isType)
64              {
65                  // Match=true if the classifier name is in a different package than datatype::, i.e. PrimitiveTypes::
66                  // or the name is the same. Allows using Java, UML Standard types instead of AndroMDA types
67                  String lastType = typeName;
68                  if (!StringUtils.isBlank(StringUtils.substringAfterLast(typeName, ":")))
69                  {
70                      lastType = StringUtils.substringAfterLast(typeName, ":");
71                  }
72                  String classifierType = classifier.getFullyQualifiedName();
73                  if (!StringUtils.isBlank(StringUtils.substringAfterLast(classifierType, ":")))
74                  {
75                      classifierType = StringUtils.substringAfterLast(classifierType, ":");
76                  }
77                  // If FQN class name is the same as the mapped implementation Class Name
78                  name = StringUtils.trimToEmpty(classifier.getFullyQualifiedName(true));
79                  // IgnoreCase allows primitive and wrapped types to both return true
80                  if (lastType.equalsIgnoreCase(classifierType)
81                      || lastType.equalsIgnoreCase(name) || lastType.equalsIgnoreCase(classifier.getFullyQualifiedName()))
82                  {
83                      isType = true;
84                  }
85              }
86          }
87          return isType;
88      }
89  
90      // TODO: Move this to an external configuration. Distinguish between Java, C# reserved words.
91      private static List<String> reservedWords = new ArrayList<String>();
92      private static void populateReservedWords()
93      {
94          synchronized (reservedWords)
95          {
96              if (reservedWords.isEmpty())
97              {
98                  reservedWords.add("abstract");
99                  reservedWords.add("as");
100                 reservedWords.add("assert");
101                 reservedWords.add("auto");
102                 reservedWords.add("bool");
103                 reservedWords.add("boolean");
104                 reservedWords.add("break");
105                 reservedWords.add("byte");
106                 reservedWords.add("case");
107                 reservedWords.add("catch");
108                 reservedWords.add("char");
109                 reservedWords.add("checked");
110                 reservedWords.add("class");
111                 reservedWords.add("const");
112                 reservedWords.add("continue");
113                 reservedWords.add("decimal");
114                 reservedWords.add("default");
115                 reservedWords.add("delegate");
116                 reservedWords.add("delete");
117                 reservedWords.add("deprecated");
118                 reservedWords.add("do");
119                 reservedWords.add("double");
120                 reservedWords.add("else");
121                 reservedWords.add("enum");
122                 reservedWords.add("event");
123                 reservedWords.add("explicit");
124                 reservedWords.add("export");
125                 reservedWords.add("extends");
126                 reservedWords.add("extern");
127                 reservedWords.add("false");
128                 reservedWords.add("final");
129                 reservedWords.add("finally");
130                 reservedWords.add("fixed");
131                 reservedWords.add("float");
132                 reservedWords.add("foreach");
133                 reservedWords.add("for");
134                 reservedWords.add("function");
135                 reservedWords.add("goto");
136                 reservedWords.add("if");
137                 reservedWords.add("implements");
138                 reservedWords.add("implicit");
139                 reservedWords.add("import");
140                 reservedWords.add("in");
141                 reservedWords.add("inline");
142                 reservedWords.add("instanceof");
143                 reservedWords.add("int");
144                 reservedWords.add("interface");
145                 reservedWords.add("internal");
146                 reservedWords.add("is");
147                 reservedWords.add("lock");
148                 reservedWords.add("long");
149                 reservedWords.add("namespace");
150                 reservedWords.add("native");
151                 reservedWords.add("new");
152                 reservedWords.add("null");
153                 reservedWords.add("object");
154                 reservedWords.add("operator");
155                 reservedWords.add("out");
156                 reservedWords.add("override");
157                 reservedWords.add("package");
158                 reservedWords.add("params");
159                 reservedWords.add("private");
160                 reservedWords.add("property");
161                 reservedWords.add("protected");
162                 reservedWords.add("public");
163                 reservedWords.add("readonly");
164                 reservedWords.add("ref");
165                 reservedWords.add("register");
166                 reservedWords.add("return");
167                 reservedWords.add("sbyte");
168                 reservedWords.add("sealed");
169                 reservedWords.add("short");
170                 reservedWords.add("signed");
171                 reservedWords.add("sizeof");
172                 reservedWords.add("static");
173                 reservedWords.add("strictfp");
174                 reservedWords.add("shring");
175                 reservedWords.add("struct");
176                 reservedWords.add("super");
177                 reservedWords.add("switch");
178                 reservedWords.add("synchronized");
179                 reservedWords.add("this");
180                 reservedWords.add("thread");
181                 reservedWords.add("throw");
182                 reservedWords.add("throws");
183                 reservedWords.add("transient");
184                 reservedWords.add("true");
185                 reservedWords.add("try");
186                 reservedWords.add("typedef");
187                 reservedWords.add("typeof");
188                 reservedWords.add("uint");
189                 reservedWords.add("ulong");
190                 reservedWords.add("unchecked");
191                 reservedWords.add("union");
192                 reservedWords.add("unsafe");
193                 reservedWords.add("unsigned");
194                 reservedWords.add("ushort");
195                 reservedWords.add("using");
196                 reservedWords.add("virtual");
197                 reservedWords.add("union");
198                 reservedWords.add("unsigned");
199                 reservedWords.add("uuid");
200                 reservedWords.add("var");
201                 reservedWords.add("void");
202                 reservedWords.add("volatile");
203                 reservedWords.add("while");
204             }
205         }
206     }
207 
208     /**
209      * Returns true if the value is a reserved keyword in Java or C#, or cannot be used as a name
210      * @param name the String to check if a keyword
211      * @return true/false
212      */
213     public static boolean isReservedWord(String name)
214     {
215         boolean reserved = false;
216         populateReservedWords();
217         if (StringUtils.isNotBlank(name) && reservedWords.contains(name.toLowerCase()))
218         {
219             reserved = true;
220         }
221         return reserved;
222     }
223 
224     /**
225      * Gets the getter prefix for a getter operation given the <code>type</code>.
226      *
227      * @param type the type from which to determine the prefix.
228      * @return the getter prefix.
229      */
230     public static String getGetterPrefix(final ClassifierFacade type)
231     {
232         return type != null && type.isBooleanType() && type.isPrimitive() ? "is" : "get";
233     }
234 
235     /**
236      * Gets the getter prefix for a getter operation given the <code>type</code>,
237      * taking multiplicity into account for booleans
238      *
239      * @param type the type from which to determine the prefix.
240      * @param lowerBound If > 0 then type is not optional, thus primitive isBoolean()
241      * @return the getter prefix.
242      */
243     public static String getGetterPrefix(final ClassifierFacade type, int lowerBound)
244     {
245         // Automatically converted to primitive type or wrapped type based on lowerBound
246         return type != null && type.isBooleanType() && (lowerBound > 0 || type.isPrimitive()) ? "is" : "get";
247     }
248 
249     /**
250      * Returns true if the passed in constraint <code>expression</code> is of type <code>kind</code>, false otherwise.
251      *
252      * @param expression the expression to check.
253      * @param kind       the constraint kind (i.e. <em>inv</em>,<em>pre</em>, <em>body</em>, etc).
254      * @return true/false
255      */
256     public static boolean isConstraintKind(String expression, String kind)
257     {
258         Pattern pattern = Pattern.compile(".*\\s*" + StringUtils.trimToEmpty(kind) + "\\s*\\w*\\s*:.*", Pattern.DOTALL);
259         Matcher matcher = pattern.matcher(StringUtils.trimToEmpty(expression));
260         return matcher.matches();
261     }
262 
263     // TODO extract the mappings into the configurable metafacade namespace in UMLProfile
264     private static Map<String, String> implCollection = new HashMap<String, String>();
265     /**
266      * Transforms the declared type to implementation type for a declared Collection.
267      * Default: Collection=LinkedList, List=ArrayList, Set=HashSet, SortedSet=TreeSet.
268      * Retains the generics and package in the template declaration, if any
269      *
270      * @param input the declared Collection type to be transformed into an implementation type
271      * @return the Collection implementation declaration.
272      */
273     public static String getImplCollection(final String input)
274     {
275         synchronized (implCollection)
276         {
277             // Populate collection map based on profile.xml settings
278             // TODO Use mapped implementation type instead of model types
279             if (implCollection.isEmpty())
280             {
281                 // Put all mappings into Map, removing the initial 'datatype::'
282                 //implCollection.put("List", "ArrayList");
283                 //implCollection.put("Set", "HashSet");
284                 //implCollection.put("SortedSet", "TreeSet");
285                 //implCollection.put("Map", "HashMap");
286                 //implCollection.put("SortedMap", "TreeMap");
287                 implCollection.put(UMLProfile.COLLECTION_TYPE_NAME.substring(
288                         UMLProfile.COLLECTION_TYPE_NAME.lastIndexOf(':')+1),
289                     UMLProfile.COLLECTION_IMPL_TYPE_NAME.substring(
290                         UMLProfile.COLLECTION_IMPL_TYPE_NAME.lastIndexOf(':')+1));
291                 implCollection.put(UMLProfile.LIST_TYPE_NAME.substring(
292                         UMLProfile.LIST_TYPE_NAME.lastIndexOf(':')+1),
293                     UMLProfile.LIST_IMPL_TYPE_NAME.substring(
294                         UMLProfile.LIST_IMPL_TYPE_NAME.lastIndexOf(':')+1));
295                 implCollection.put(UMLProfile.MAP_TYPE_NAME.substring(
296                         UMLProfile.MAP_TYPE_NAME.lastIndexOf(':')+1),
297                     UMLProfile.MAP_IMPL_TYPE_NAME.substring(
298                         UMLProfile.MAP_IMPL_TYPE_NAME.lastIndexOf(':')+1));
299                 implCollection.put(UMLProfile.ORDERED_MAP_TYPE_NAME.substring(
300                         UMLProfile.ORDERED_MAP_TYPE_NAME.lastIndexOf(':')+1),
301                     UMLProfile.ORDERED_MAP_IMPL_TYPE_NAME.substring(
302                         UMLProfile.ORDERED_MAP_IMPL_TYPE_NAME.lastIndexOf(':')+1));
303                 implCollection.put(UMLProfile.ORDERED_SET_TYPE_NAME.substring(
304                         UMLProfile.ORDERED_SET_TYPE_NAME.lastIndexOf(':')+1),
305                     UMLProfile.ORDERED_SET_IMPL_TYPE_NAME.substring(
306                         UMLProfile.ORDERED_SET_IMPL_TYPE_NAME.lastIndexOf(':')+1));
307                 implCollection.put(UMLProfile.SET_TYPE_NAME.substring(
308                         UMLProfile.SET_TYPE_NAME.lastIndexOf(':')+1),
309                     UMLProfile.SET_IMPL_TYPE_NAME.substring(
310                         UMLProfile.SET_IMPL_TYPE_NAME.lastIndexOf(':')+1));
311             }
312         }
313         String collectionImpl = input;
314         // No transformation if no package on fullyQualifiedName
315         if (input.indexOf('.') > 0)
316         {
317             String collectionType = null;
318             String genericType = null;
319             String pkg = null;
320             if (input.indexOf('<') > 0)
321             {
322                 collectionType = input.substring(0, input.indexOf('<'));
323                 genericType = input.substring(input.indexOf('<'));
324                 if (genericType.startsWith("<? extends "))
325                 {
326                     // Implementation collection type cannot declare 'extends'
327                     genericType = '<' + genericType.substring(11);
328                 }
329             }
330             else
331             {
332                 collectionType = input;
333                 genericType = "";
334             }
335             if (collectionType.indexOf('.') > 0)
336             {
337                 pkg = collectionType.substring(0, collectionType.lastIndexOf('.')+1);
338                 collectionType = collectionType.substring(collectionType.lastIndexOf('.')+1);
339             }
340             else
341             {
342                 pkg = "java.util.";
343                 logger.warn("UMLMetafacadeUtils pkg not found for " + collectionType);
344             }
345             String implType = implCollection.get(collectionType);
346             if (implType == null)
347             {
348                 logger.warn("UMLMetafacadeUtils colectionImpl not found for " + collectionType);
349                 collectionImpl = pkg + "ArrayList" + genericType;
350             }
351             else
352             {
353                 //logger.info("UMLMetafacadeUtils translated from " + collectionType + " to " + implType);
354                 collectionImpl = pkg + implType + genericType;
355             }
356         }
357         return collectionImpl;
358     }
359 
360     /**
361      * Determines if the class/package should be generated. Will not be generated if it has any
362      * stereotypes: documentation, docOnly, Future, Ignore, analysis, perspective,
363      * or any invalid package identifier characters ` ~!@#%^&*()-+={}[]:;<>,?/|
364      * @param mef ModelElementFacade class to check for stereotypes.
365      * @return false if it has any Stereotypes DocOnly, Future, Ignore configured in UMLProfile
366      */
367     public static boolean shouldOutput(ModelElementFacade mef)
368     {
369         boolean rtn = true;
370         if (mef!=null)
371         {
372             try
373             {
374                 PackageFacade pkg = (PackageFacade) mef.getPackage();
375                 if (mef instanceof PackageFacade)
376                 {
377                     pkg = (PackageFacade) mef;
378                 }
379                 if (mef.hasStereotype(UMLProfile.STEREOTYPE_DOC_ONLY) ||
380                     mef.hasStereotype(UMLProfile.STEREOTYPE_FUTURE) ||
381                     mef.hasStereotype(UMLProfile.STEREOTYPE_IGNORE))
382                 {
383                     rtn = false;
384                 }
385                 if (pkg != null &&
386                     ( pkg.hasStereotype(UMLProfile.STEREOTYPE_DOC_ONLY) ||
387                     pkg.hasStereotype(UMLProfile.STEREOTYPE_FUTURE) ||
388                     pkg.hasStereotype(UMLProfile.STEREOTYPE_IGNORE) ||
389                     pkg.hasStereotype("analysis") ||
390                     pkg.hasStereotype("perspective") ||
391                     // Verify package does not have any Java disallowed characters
392                     StringUtils.containsAny(pkg.getName(), " `~!@#%^&*()-+={}[]:;<>,?/|") ||
393                             "PrimitiveTypes".equals(pkg.getName()) ||
394                             "datatype".equals(pkg.getName())))
395                 {
396                     rtn = false;
397                 }
398             }
399             catch (Exception ex)
400             {
401                 // Output=true anyway just in case we want this output
402                 logger.error("UMLMetafacadeUtils.shouldOutput for " + mef.toString() + ' ' + ex.getClass().getName() + ": "+ ex.getMessage());
403             }
404         }
405         return rtn;
406     }
407     /**
408      * Get the classname without the package name and without additional template<> parameters.
409      *
410      * @param facade
411      * @param enableTemplating
412      * @return getNameWithoutPackage
413      */
414     // TODO This should really be a method on ModelElementFacade
415     public static String getClassDeclaration(ModelElementFacade facade, boolean enableTemplating)
416     {
417         return UMLMetafacadeUtils.getClassDeclaration(facade, facade.getName(), enableTemplating);
418     }
419 
420     private static final String namespaceScopeOperator = ".";
421     private static final String COMMA = ", ";
422     private static final String LT = "<";
423     private static final String GT = ">";
424     /**
425      * Get the classname without the package name and without additional template<> parameters.
426      *
427      * @param facade
428      * @param className Class name to use in the class declaration, overrides facade.getName()
429      * @param enableTemplating Whether template declaration should be created.
430      * @return getNameWithoutPackage
431      */
432     // TODO This should really be a method on ModelElementFacade
433     public static String getClassDeclaration(ModelElementFacade facade, String className, boolean enableTemplating)
434     {
435         if (StringUtils.isBlank(className))
436     {
437             className = facade.getName();
438         }
439         String fullName = StringUtils.trimToEmpty(className);
440         final String packageName = facade.getPackageName(true);
441         final String metafacadeNamespaceScopeOperator = MetafacadeConstants.NAMESPACE_SCOPE_OPERATOR;
442         if (StringUtils.isNotBlank(packageName))
443         {
444             fullName = packageName + metafacadeNamespaceScopeOperator + fullName;
445         }
446             final TypeMappings languageMappings = facade.getLanguageMappings();
447             if (languageMappings != null)
448             {
449                 fullName = StringUtils.trimToEmpty(languageMappings.getTo(fullName));
450 
451                 // now replace the metafacade scope operators
452                 // with the mapped scope operators
453                 fullName = StringUtils.replace(
454                         fullName,
455                         metafacadeNamespaceScopeOperator,
456                         namespaceScopeOperator);
457             }
458         // remove the package qualifier
459         if (fullName.indexOf('.')>-1)
460         {
461             fullName = fullName.substring(fullName.lastIndexOf('.')+1);
462         }
463 
464         if (facade.isTemplateParametersPresent() && enableTemplating)
465         {
466             // we'll be constructing the parameter list in this buffer
467             final StringBuilder buffer = new StringBuilder();
468 
469             // add the name we've constructed so far
470             buffer.append(fullName);
471 
472             // start the parameter list
473             buffer.append(LT);
474 
475             // loop over the parameters, we are so to have at least one (see
476             // outer condition)
477             int size = facade.getTemplateParameters().size();
478             int i = 1;
479             for (TemplateParameterFacade parameter : facade.getTemplateParameters())
480             {
481                 if (parameter != null)
482                 {
483                     /*String name = parameter.getValidationName();
484                     if (name==null && parameter.getParameter() != null)
485                     {
486                         name = parameter.getParameter().getName();
487                     }
488                     buffer.append(name);*/
489                     buffer.append(parameter.getName());
490                     if (i < size)
491                     {
492                         buffer.append(COMMA);
493                         i++;
494                     }
495                 }
496             }
497 
498             // we're finished listing the parameters
499             buffer.append(GT);
500 
501             // we have constructed the full name in the buffer
502             fullName = buffer.toString();
503         }
504 
505         return fullName;
506     }
507 
508     private static final String QUESTION = "?";
509     /**
510      * Get the generic template<?, ?> declaration.
511      *
512      * @param facade
513      * @param enableTemplating
514      * @return getGenericTemplate
515      */
516     // TODO This should really be a method on ModelElementFacade
517     public static String getGenericTemplate(ModelElementFacade facade, boolean enableTemplating)
518     {
519         String fullName = "";
520         if (facade != null && facade.isTemplateParametersPresent() && enableTemplating)
521         {
522             // we'll be constructing the parameter list in this buffer
523             final StringBuilder buffer = new StringBuilder();
524 
525             // start the parameter list
526             buffer.append(LT);
527 
528             // loop over the parameters, we are so to have at least one (see
529             // outer condition)
530            for (Iterator<TemplateParameterFacade> parameterIterator =
531                facade.getTemplateParameters().iterator(); parameterIterator.hasNext();)
532            {
533                 parameterIterator.next();
534                 buffer.append(QUESTION);
535                 if (parameterIterator.hasNext())
536                 {
537                     buffer.append(COMMA);
538                 }
539             }
540 
541             // we're finished listing the parameters
542             buffer.append(GT);
543 
544             // we have constructed the full name in the buffer
545             fullName = buffer.toString();
546         }
547 
548         return fullName;
549     }
550 
551     /**
552      * Get the fully-qualified classname without the additional template<> parameters.
553      *
554      * @param facade
555      * @return getFQNameWithoutTemplate
556      */
557     // TODO This should really be a method on ModelElementFacade
558     public static String getFQNameWithoutTemplate(ModelElementFacade facade)
559     {
560         String fullName = StringUtils.trimToEmpty(facade.getName());
561         final String packageName = facade.getPackageName(true);
562         final String metafacadeNamespaceScopeOperator = MetafacadeConstants.NAMESPACE_SCOPE_OPERATOR;
563         if (StringUtils.isNotBlank(packageName))
564         {
565             fullName = packageName + metafacadeNamespaceScopeOperator + fullName;
566         }
567         final TypeMappings languageMappings = facade.getLanguageMappings();
568         if (languageMappings != null)
569         {
570             fullName = StringUtils.trimToEmpty(languageMappings.getTo(fullName));
571             fullName = StringUtils.replace(
572                 fullName,
573                 metafacadeNamespaceScopeOperator,
574                 namespaceScopeOperator);
575         }
576         return fullName;
577     }
578 
579     /**
580      * Returns the number of methods without stereotypes or with SimpleClass stereotype. .
581      * @param mef ModelElementFacade class to check for stereotypes.
582      * @param outletFile Name of output file currently being processed. How do we get this in template?
583      * @param refOutput Should .ref files be output?
584      * @return false if it has any Stereotypes DocOnly, Future, Ignore configured in UMLProfile
585      */
586     public static boolean shouldOutput(ModelElementFacade mef, String outletFile, boolean refOutput)
587     {
588         boolean rtn = true;
589         if (outletFile==null)
590         {
591             return rtn;
592         }
593         if (outletFile.endsWith(".ref") && !refOutput)
594         {
595             rtn = false;
596         }
597         else
598         {
599             rtn = shouldOutput(mef);
600         }
601         return rtn;
602     }
603 
604     /**
605      * Supplies a result for type = <new value>; initialization for all types
606      * @param facade Type to create default object for
607      * @return Constructor String with facade name
608      */
609     public String createConstructor(ModelElementFacade facade)
610     {
611         return createConstructor(facade, false);
612     }
613 
614     /**
615      * Supplies a result for type = <new value>; initialization for all types
616      * @param facade Type to create default object for
617      * @param useMany Return constructor with multiplicity type instead of underlying type
618      * @return Constructor String with facade name
619      */
620     public String createConstructor(ModelElementFacade facade, boolean useMany)
621     {
622         return createConstructor(facade, useMany, null);
623     }
624 
625     /**
626      * Supplies a result for type = <new value>; initialization for all types
627      * @param facade Type to create default object for
628      * @param useMany Return constructor with multiplicity type instead of underlying type
629      * @param parent Object containing this facade, which may have an attribute named dependency to a different type
630      * @return Constructor String with facade name
631      */
632     public String createConstructor(ModelElementFacade facade, boolean useMany, ModelElementFacade parent)
633     {
634         if (facade==null)
635         {
636             return "facade was null";
637         }
638         String rtn = "";
639         String toString = "";
640         ClassifierFacade type = null;
641         String typeName = facade.getFullyQualifiedName();
642         String name = facade.getName();
643         String defaultValue = "";
644         // TODO: Default collection type from properties
645         String collectionType = "java.util.ArrayList";
646         Boolean isMany = null;
647         boolean isEnumeration = false;
648         int maxLength = 9999;
649         /*if (parent != null)
650         {
651             // See if a named dependency exists with the same facadeName
652             for (final DependencyFacade dependency : parent.getSourceDependencies())
653             {
654                 if (dependency.getName().equals(facade.getName()) && dependency instanceof DependencyFacade)
655                 {
656                     facade = ((DependencyFacade)dependency).getTargetElement();
657                     toString = ".toString()";
658                     break;
659                 }
660             }
661         }*/
662         try {
663             if (logger.isDebugEnabled())
664             {
665                 logger.debug("name=" + name + " typeName=" + typeName + " useMany=" + useMany + " facade=" + facade + " parent=" + parent);
666             }
667             // Use persistence or validation annotations to limit the created value length
668             String length = (String)facade.findTaggedValue("andromda_persistence_column_length");
669             if (length != null && length.length()>0 && StringUtils.isNumeric(length))
670             {
671                 maxLength = Integer.parseInt(length);
672             }
673             else
674             {
675                 length = (String)facade.findTaggedValue("andromda_persistence_column_precision");
676                 if (length != null && length.length()>0 && StringUtils.isNumeric(length))
677                 {
678                     maxLength = Integer.parseInt(length);
679                 }
680                 else
681                 {
682                     length = (String)facade.findTaggedValue("andromda_validation_length");
683                     if (length != null && length.length()>0 && StringUtils.isNumeric(length))
684                     {
685                         maxLength = Integer.parseInt(length);
686                     }
687                     else
688                     {
689                         length = (String)facade.findTaggedValue("andromda_validation_precision");
690                         if (length != null && length.length()>0 && StringUtils.isNumeric(length))
691                         {
692                             maxLength = Integer.parseInt(length);
693                         }
694                     }
695                 }
696             }
697             if (facade instanceof ClassifierFacade)
698             {
699                 ClassifierFacade classifier = (ClassifierFacade) facade;
700                 type = classifier;
701                 typeName = classifier.getFullyQualifiedName();
702             }
703             if (facade instanceof AttributeFacade)
704             {
705                 AttributeFacade attr = (AttributeFacade) facade;
706                 defaultValue = attr.getDefaultValue();
707                 type = attr.getType();
708                 if (useMany)
709                 {
710                     typeName = attr.getGetterSetterTypeName();
711                 }
712                 else
713                 {
714                     typeName = type.getFullyQualifiedName();
715                 }
716                 if (attr.getUpper()>1 || attr.getUpper()==-1)
717                 {
718                     isMany = true;
719                 }
720             }
721             else if (facade instanceof ParameterFacade)
722             {
723                 ParameterFacade attr = (ParameterFacade) facade;
724                 defaultValue = attr.getDefaultValue();
725                 type = attr.getType();
726                 typeName = type.getFullyQualifiedName();
727                 if (type.isEnumeration())
728                 {
729                     facade = type;
730                 }
731                 else if (useMany)
732                 {
733                     typeName = collectionType + '<' + type.getFullyQualifiedName() + '>';
734                 }
735                 else
736                 {
737                     typeName = type.getFullyQualifiedName();
738                 }
739                 if (attr.getUpper()>1 || attr.getUpper()==-1)
740                 {
741                     isMany = true;
742                 }
743             }
744             if (facade instanceof AssociationEndFacade)
745             {
746                 AssociationEndFacade attr = (AssociationEndFacade) facade;
747                 type = attr.getType();
748                 if (useMany)
749                 {
750                     typeName = attr.getGetterSetterTypeName();
751                 }
752                 else
753                 {
754                     typeName = type.getFullyQualifiedName();
755                 }
756                 if (attr.getUpper()>1 || attr.getUpper()==-1)
757                 {
758                     isMany = true;
759                 }
760                 facade = attr.getType();
761             }
762             // TODO: Make this work for attribute types other than String.
763             if (parent != null && StringUtils.isEmpty(defaultValue) && ("String".equals(typeName) || "java.lang.String".equals(typeName)))
764             {
765                 // See if a named dependency exists with the same facadeName
766                 for (final DependencyFacade dependency : parent.getSourceDependencies())
767                 {
768                     if (dependency.getName().equals(facade.getName()))
769                     {
770                         facade = dependency.getTargetElement();
771                         // DependencyFacade type comes back empty for UML2::Integer
772                         // Need to get metaObject Name property and verify it is not null.
773                         if (facade instanceof ClassifierFacade)
774                         {
775                             type = (ClassifierFacade) facade;
776                         }
777                         typeName = facade.getFullyQualifiedName();
778                         toString = ".toString()";
779                         if (logger.isDebugEnabled())
780                         {
781                             logger.debug(parent + " " + facade + " = "
782                                     + dependency + " type=" + type + " typeName="
783                                     + typeName);
784                         }
785                         break;
786                     }
787                 }
788             }
789             if (type instanceof EnumerationFacade)
790             {
791                 EnumerationFacade enumer = (EnumerationFacade) type;
792                 //type = enumer.getLiteralType().getFullyQualifiedName();
793                 Collection<AttributeFacade> literals = enumer.getLiterals();
794                 if (StringUtils.isEmpty(defaultValue) && !literals.isEmpty())
795                 {
796                     // Just get the first enumeration literal
797                     Object literal = literals.iterator().next();
798                     if (literal instanceof EnumerationLiteralFacade)
799                     {
800                         EnumerationLiteralFacade enumLiteral = (EnumerationLiteralFacade) literal;
801                         defaultValue = enumLiteral.getValue();
802                     }
803                     else if (literal instanceof AttributeFacade)
804                     {
805                         AttributeFacade attrib = (AttributeFacade) literal;
806                         defaultValue = attrib.getEnumerationValue();
807                         if (defaultValue==null)
808                         {
809                             defaultValue = attrib.getDefaultValue();
810                         }
811                     }
812                     // Literal value is always a String. Remove quotes if part of default (i.e. class attribute).
813                     defaultValue = StringUtils.remove(defaultValue, "\"");
814                     defaultValue = enumer.getFullyQualifiedName() + ".fromValue(\"" + defaultValue + "\")";
815                 }
816                 else
817                 {
818                     defaultValue = enumer.getName() + '.' + defaultValue;
819                 }
820                 isEnumeration = true;
821                 if (logger.isDebugEnabled())
822                 {
823                     logger.debug("EnumerationFacade=" + facade + " type=" + type + " literals=" + literals.size() + " default=" + defaultValue);
824                 }
825             }
826             if (type != null && type.findTaggedValue("andromda_persistence_lob_type")!=null)
827             {
828                 typeName = String.valueOf(type.findTaggedValue("andromda_persistence_lob_type"));
829                 // LOB Types have a different datatype than the underlying declared type
830             }
831             if (useMany && (isMany==null || isMany.booleanValue()) && !typeName.endsWith("[]"))
832             {
833                 typeName = UMLMetafacadeUtils.getImplCollection(typeName);
834                 if (!typeName.startsWith("java.util") && type != null)
835                 {
836                     if (type.equals("java.util.Collection") || typeName.equals("java.util.List"))
837                     {
838                         rtn = "new " + collectionType + "<" + typeName + ">()";
839                     }
840                     else if (typeName.equals("java.util.Set"))
841                     {
842                         rtn = "new java.util.HashSet<" + typeName + ">()";
843                     }
844                     else if (typeName.equals("java.util.Map"))
845                     {
846                         rtn = "new java.util.HashMap<" + typeName + ">()";
847                     }
848                     else
849                     {
850                         rtn = "new " + collectionType + '<' + typeName + ">()";
851                     }
852                 }
853                 else
854                 {
855                     // Assume array or type Collection<type>
856                     rtn = "new " + typeName + "()";
857                 }
858             }
859             else if ("String".equals(typeName) || "java.lang.String".equals(typeName))
860             {
861                 if (defaultValue != null && defaultValue.trim().length() > 0)
862                 {
863                     if (defaultValue.startsWith("\"") || defaultValue.startsWith("'"))
864                     {
865                         defaultValue = defaultValue.substring(1, defaultValue.length()-1);
866                     }
867                     if (defaultValue.endsWith("\"") || defaultValue.endsWith("'"))
868                     {
869                         defaultValue = defaultValue.substring(0, defaultValue.length()-2);
870                     }
871                     if (defaultValue.trim().length() > maxLength)
872                     {
873                         logger.warn("Attribute default for " + facade.getFullyQualifiedName() + " is longer than max column length " + maxLength);
874                         defaultValue = defaultValue.substring(0, maxLength-1);
875                     }
876                 }
877                 rtn = '\"' + (StringUtils.isNotBlank(defaultValue) ? defaultValue : name) + '\"';
878             }
879             else if ("Boolean".equals(typeName) || "java.lang.Boolean".equals(typeName))
880             {
881                 rtn = (StringUtils.isNotBlank(defaultValue) ? "Boolean." + defaultValue.toUpperCase() : "Boolean.TRUE");
882             }
883             else if ("boolean".equals(typeName))
884             {
885                 rtn = (StringUtils.isNotBlank(defaultValue) ? defaultValue : "true");
886             }
887             else if ("int".equals(typeName) || "short".equals(typeName) || "long".equals(typeName)
888                     || "byte".equals(typeName) || "float".equals(typeName) || "double".equals(typeName))
889             {
890                 rtn = (StringUtils.isNotBlank(defaultValue) ? defaultValue : "1");
891             }
892             else if ("java.util.Date".equals(typeName))
893             {
894                 rtn = "new " + typeName + "()";
895             }
896             else if ("java.sql.Timestamp".equals(typeName))
897             {
898                 rtn = "new java.sql.Timestamp(System.currentTimeMillis())";
899             }
900             else if ("java.util.Calendar".equals(typeName))
901             {
902                 rtn = "java.util.Calendar.getInstance()";
903             }
904             else if ("org.joda.time.LocalTime".equals(typeName))
905             {
906                 rtn = "new org.joda.time.LocalTime(1, 1)";
907             }
908             else if ("char".equals(typeName))
909             {
910                 rtn = "'" + (StringUtils.isNotEmpty(defaultValue) ? defaultValue : name.substring(0, 1)) + "'";
911             }
912             else if ("Character".equals(typeName))
913             {
914                 rtn = "new Character('" + (StringUtils.isNotEmpty(defaultValue) ? "new Character(" + defaultValue : name.substring(0, 1)) + "')";
915             }
916             else if ("Byte".equals(typeName) || "java.lang.Byte".equals(typeName))
917             {
918                 rtn = "new Byte(\"" + facade.getName() + "\")";
919             }
920             else if ("Short".equals(typeName) || "java.lang.Short".equals(typeName)
921                     || "Integer".equals(typeName) || "java.lang.Integer".equals(typeName)
922                     || "Long".equals(typeName) || "java.lang.Long".equals(typeName)
923                     || "Float".equals(typeName) || "java.lang.Float".equals(typeName)
924                     || "Double".equals(typeName) || "java.lang.Double".equals(typeName)
925                     || "java.math.BigDecimal".equals(typeName))
926             {
927                 rtn = (!StringUtils.isEmpty(defaultValue) ? typeName + ".valueOf(" + defaultValue + ")" : typeName + ".valueOf(1)");
928             }
929             else if ("java.math.BigInteger".equals(typeName))
930             {
931                 rtn = (!StringUtils.isEmpty(defaultValue) ? "java.math.BigInteger.valueOf(" + defaultValue + ')' : "java.math.BigInteger.valueOf(1)");
932             }
933             else if ("byte[]".equals(typeName))
934             {
935                 rtn = (StringUtils.isNotBlank(defaultValue) ? defaultValue : '\"' + name + '\"') + ".getBytes()";
936             }
937             else if ("char[]".equals(typeName))
938             {
939                 String value = StringUtils.isNotBlank(defaultValue) ? defaultValue : name;
940                 if (!value.startsWith("\""))
941                 {
942                     value = "\"" + value;
943                 }
944                 if (!value.endsWith("\""))
945                 {
946                     value = value + "\"";
947                 }
948                 rtn = value + ".toCharArray()";
949             }
950             else if ("String[]".equals(typeName))
951             {
952                 rtn = "new String[] { " + (StringUtils.isNotBlank(defaultValue) ? defaultValue : '\"' + name + '\"') + " }";
953             }
954             else if (isEnumeration)
955             {
956                 if (useMany)
957                 {
958                     rtn = collectionType + '<' + defaultValue + '>';
959                 }
960                 else
961                 {
962                     rtn = defaultValue;
963                 }
964             }
965             else if (!StringUtils.isEmpty(defaultValue))
966             {
967                 rtn = "new " + typeName + '(' + defaultValue + ')';
968             }
969             else if (type != null && type.hasStereotype("EmbeddedValue"))
970             {
971                 // EmbeddedValue classes will always be abstract with Impl generated classes.
972                 rtn = "new " + typeName + "Impl()";
973             }
974             else if (type instanceof GeneralizableElementFacade)
975             {
976                 // If type has a descendant with name <typeName>Impl, assume typeNameImpl must be instantiated instead of typeName
977                 if (typeName.endsWith("[]"))
978                 {
979                     rtn = "{ new " + typeName.substring(0, typeName.length()-2) + "() }";
980                 }
981                 else
982                 {
983                     rtn = "new " + typeName + "()";
984                 }
985                 //if (facade instanceof ClassifierFacade)
986                 //{
987                     //ClassifierFacade classifier = (ClassifierFacade)facade;
988                     // If type is abstract, choose Impl descendant if exists, or the last descendant
989                     if (type.isAbstract())
990                     {
991                         // Can't instantiate abstract class - pick some descendant
992                         for (GeneralizableElementFacade spec : type.getSpecializations())
993                         {
994                             if (spec.getName().equals(type.getName() + "Impl"))
995                             {
996                                 rtn = '(' + type.getName() + ")new " + typeName + "Impl()";
997                                 break;
998                             }
999                             rtn = '(' + type.getName() + ")new " + spec.getFullyQualifiedName() + "()";
1000                         }
1001                     }
1002                 //}
1003                 GeneralizableElementFacade generalization = (GeneralizableElementFacade)type;
1004                 for (GeneralizableElementFacade spec : generalization.getSpecializations())
1005                 {
1006                     if (spec.getName().equals(type.getName() + "Impl"))
1007                     {
1008                         rtn = '(' + type.getName() + ")new " + spec.getFullyQualifiedName() + "Impl()";
1009                     }
1010                 }
1011             }
1012             else if (typeName.endsWith("[]"))
1013             {
1014                 rtn = "new " + typeName + " { new " + typeName.substring(0, typeName.length()-2) + "() }";
1015             }
1016             else
1017             {
1018                 rtn = "new " + typeName + "()";
1019             }
1020             rtn = StringUtils.replace(rtn, "java.util.Collection", "java.util.ArrayList") + toString;
1021             rtn = StringUtils.replace(rtn, "java.util.Set", "java.util.HashSet") + toString;
1022             if (logger.isDebugEnabled())
1023             {
1024                 logger.debug("facade=" + facade + " facadeName=" + facade.getName() + " type=" + type + " typeName=" + typeName + " name=" + name + " isMany=" + isMany + " defaultValue=" + defaultValue + " rtn=" + rtn);
1025             }
1026         } catch (RuntimeException e) {
1027             logger.error(e + " facade=" + facade + " facadeName=" + facade.getName() + " parent=" + parent + " type=" + type + " typeName=" + typeName + " name=" + name + " isMany=" + isMany + " defaultValue=" + defaultValue);
1028             e.printStackTrace();
1029         }
1030         return rtn;
1031     }
1032 
1033     /**
1034      * TODO Reference this logic from AssociationEnd
1035      * Determine if this association end owns the relationship. i.e. if the associationEnd property
1036      * belonging to the Entity on the opposite end owns the relationship. Based on tagged value,
1037      * multiplicity, aggregation/composition. If all else fails, the longest name owns the
1038      * association, or else the alphabetically first name. One side of a relationship must
1039      * always own the association and be created and deleted first.
1040      * @param associationEnd the association end
1041      * @return true if the associationEnd (property of the entity on the other end) is owned by the entity on the other end
1042      */
1043     public static boolean isOwningEnd(AssociationEndFacade associationEnd)
1044     {
1045         boolean owning = false;
1046         AssociationEndFacade otherEnd = associationEnd.getOtherEnd();
1047         //String assoc = ((Entity)otherEnd.getValidationOwner()).getName() + "." + associationEnd.getName() + " -> " + associationEnd.getType().getName() + " ";
1048         if (BooleanUtils.toBoolean(
1049                 ObjectUtils.toString(otherEnd.findTaggedValue(
1050                     "andromda_persistence_associationEnd_primary"))))
1051         {
1052             owning = true;
1053         }
1054         // See if this end or the other end is tagged as the association owner
1055         else if (BooleanUtils.toBoolean(
1056             ObjectUtils.toString(associationEnd.findTaggedValue(
1057                 "andromda_persistence_associationEnd_primary"))))
1058         {
1059             owning = false;
1060         }
1061         // Navigable side always owns the relationship
1062         else if (associationEnd.isNavigable() && !otherEnd.isNavigable())
1063         {
1064             owning = true;
1065             //LOGGER.info("Owning=true: " + assoc + "nav=" + associationEnd.isNavigable() + " Onav=" + otherEnd.isNavigable());
1066         }
1067         else if (!associationEnd.isNavigable() && otherEnd.isNavigable())
1068         {
1069             owning = false;
1070             //LOGGER.info("Owning=false: " + assoc + "nav=" + associationEnd.isNavigable() + " Onav=" + otherEnd.isNavigable());
1071         }
1072         // Other side: aggregation/composition side does not own the bidirectional relationship
1073         else if (otherEnd.isAggregation() || otherEnd.isComposition())
1074         {
1075             owning = false;
1076             //LOGGER.info("Owning=true: " + assoc + "Oagg=" + otherEnd.isAggregation() + " Ocomp=" + otherEnd.isComposition());
1077         }
1078         else if (associationEnd.isAggregation() || associationEnd.isComposition())
1079         {
1080             owning = true;
1081             //LOGGER.info("Owning=false: " + assoc + "Oagg=" + associationEnd.isAggregation() + " Ocomp=" + otherEnd.isComposition());
1082         }
1083         // The many side of 1:M owns the bidirectional relationship
1084         else if (!associationEnd.isMany() && otherEnd.isMany())
1085         {
1086             owning = true;
1087             //LOGGER.info("Owning=true: " + assoc + "many=" + associationEnd.isMany() + " Omany=" + otherEnd.isMany());
1088         }
1089         // Other side: the many side of 1:M owns the bidirectional relationship if no composition/aggregation
1090         else if (associationEnd.isMany() && !otherEnd.isMany())
1091         {
1092             owning = false;
1093             //LOGGER.info("Owning=false: " + assoc + "many=" + associationEnd.isMany() + " Omany=" + otherEnd.isMany());
1094         }
1095         // The optional side of 1:1 or M:M owns the bidirectional relationship
1096         else if (associationEnd.getLower() > 0 && otherEnd.getLower() == 0)
1097         {
1098             owning = true;
1099             //LOGGER.info("Owning=true: " + assoc + "many=" + associationEnd.isMany() + " Omany=" + otherEnd.isMany());
1100         }
1101         // If bidirectional 1:1 or M:M, choose the side with the longest type name because it typically indicates a composition relationship
1102         /*else if (this.getOtherEnd().getType().getName().length()
1103                 > this.getType().getName().length())*/
1104         else if (associationEnd.getName().length()
1105             < otherEnd.getName().length())
1106         {
1107             owning = (associationEnd.getName().length() < otherEnd.getName().length());
1108             //LOGGER.info("Owning=true: " + assoc + "endLength=" + associationEnd.getName().length() + " Olength=" + otherEnd.getName().length());
1109         }
1110         // If length is the same, alphabetically earliest is the owner
1111         else if (associationEnd.getName().compareTo(
1112             otherEnd.getName()) < 0)
1113         {
1114             owning = (associationEnd.getName().compareTo(otherEnd.getName()) < 0);
1115             //LOGGER.info("Owning=true: " + assoc + "name=" + associationEnd.getName() + " < OName=" + otherEnd.getName());
1116         }
1117         /*LOGGER.info(((Entity)associationEnd.getOtherEnd().getValidationOwner()).getName()
1118             + "." + associationEnd.getName() +" IsOwningEnd=" + owning + " for "
1119             + ((Entity)associationEnd.getOtherEnd().getValidationOwner()).getName()
1120             + " OName=" + otherEnd.getName() + " Aggregation=" + associationEnd.isAggregation()
1121             + " Composition=" + associationEnd.isComposition() + " Navigable=" + associationEnd.isNavigable()
1122             + " !Navigable=" + !otherEnd.isNavigable() + " Many=" + associationEnd.isMany()
1123             + " OMany=" + otherEnd.isMany() + " Upper=" + associationEnd.getUpper()
1124             + " OUpper=" + otherEnd.getUpper() + " OAggregation=" + otherEnd.isAggregation()
1125             + " OComposition=" + otherEnd.isComposition() + " ONavigable=" + otherEnd.isNavigable()
1126             + " otherEnd=" + otherEnd.getFullyQualifiedName());*/
1127         return owning;
1128     }
1129 
1130     private static FastDateFormat df = FastDateFormat.getInstance("MM/dd/yyyy HH:mm:ss");
1131 
1132     /**
1133      * Returns the current Date in the specified format.
1134      *
1135      * @param format The format for the output date
1136      * @return the current date in the specified format.
1137      */
1138     public static String getDate(String format)
1139     {
1140         if (df == null || !format.equals(df.getPattern()))
1141         {
1142             df = FastDateFormat.getInstance(format);
1143         }
1144         return df.format(new Date());
1145     }
1146 
1147     /**
1148      * Returns the current Date in the specified format.
1149      *
1150      * @return the current date with the default format .
1151      */
1152     public static String getDate()
1153     {
1154         return df.format(new Date());
1155     }
1156 }