UMLMetafacadeUtils.java
package org.andromda.metafacades.uml;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.andromda.core.metafacade.MetafacadeConstants;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Predicate;
import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.FastDateFormat;
import org.apache.log4j.Logger;
/**
* Contains utilities that are common to the UML metafacades.
*
* @author Chad Brandon
* @author Bob Fields
*/
public class UMLMetafacadeUtils
{
/**
* The logger instance.
*/
private static final Logger logger = Logger.getLogger(UMLMetafacadeUtils.class);
/**
* Returns true or false depending on whether or not this Classifier or any of its specializations is of the given
* type having the specified <code>typeName</code>
* @param classifier
* @param typeName the name of the type (i.e. datatype::Collection)
* @return true/false
*/
public static boolean isType(ClassifierFacade classifier, String typeName)
{
boolean isType = false;
if (classifier != null && typeName != null)
{
final String type = StringUtils.trimToEmpty(typeName);
String name = StringUtils.trimToEmpty(classifier.getFullyQualifiedName(true));
isType = name.equals(type);
// if this isn't a type defined by typeName, see if we can find any
// types that inherit from the type.
if (!isType)
{
isType = CollectionUtils.find(classifier.getAllGeneralizations(), new Predicate()
{
public boolean evaluate(Object object)
{
String name = StringUtils.trimToEmpty(
((ModelElementFacade)object).getFullyQualifiedName(true));
return name.equals(type);
}
}) != null;
}
if (!isType)
{
// Match=true if the classifier name is in a different package than datatype::, i.e. PrimitiveTypes::
// or the name is the same. Allows using Java, UML Standard types instead of AndroMDA types
String lastType = typeName;
if (!StringUtils.isBlank(StringUtils.substringAfterLast(typeName, ":")))
{
lastType = StringUtils.substringAfterLast(typeName, ":");
}
String classifierType = classifier.getFullyQualifiedName();
if (!StringUtils.isBlank(StringUtils.substringAfterLast(classifierType, ":")))
{
classifierType = StringUtils.substringAfterLast(classifierType, ":");
}
// If FQN class name is the same as the mapped implementation Class Name
name = StringUtils.trimToEmpty(classifier.getFullyQualifiedName(true));
// IgnoreCase allows primitive and wrapped types to both return true
if (lastType.equalsIgnoreCase(classifierType)
|| lastType.equalsIgnoreCase(name) || lastType.equalsIgnoreCase(classifier.getFullyQualifiedName()))
{
isType = true;
}
}
}
return isType;
}
// TODO: Move this to an external configuration. Distinguish between Java, C# reserved words.
private static List<String> reservedWords = new ArrayList<String>();
private static void populateReservedWords()
{
synchronized (reservedWords)
{
if (reservedWords.isEmpty())
{
reservedWords.add("abstract");
reservedWords.add("as");
reservedWords.add("assert");
reservedWords.add("auto");
reservedWords.add("bool");
reservedWords.add("boolean");
reservedWords.add("break");
reservedWords.add("byte");
reservedWords.add("case");
reservedWords.add("catch");
reservedWords.add("char");
reservedWords.add("checked");
reservedWords.add("class");
reservedWords.add("const");
reservedWords.add("continue");
reservedWords.add("decimal");
reservedWords.add("default");
reservedWords.add("delegate");
reservedWords.add("delete");
reservedWords.add("deprecated");
reservedWords.add("do");
reservedWords.add("double");
reservedWords.add("else");
reservedWords.add("enum");
reservedWords.add("event");
reservedWords.add("explicit");
reservedWords.add("export");
reservedWords.add("extends");
reservedWords.add("extern");
reservedWords.add("false");
reservedWords.add("final");
reservedWords.add("finally");
reservedWords.add("fixed");
reservedWords.add("float");
reservedWords.add("foreach");
reservedWords.add("for");
reservedWords.add("function");
reservedWords.add("goto");
reservedWords.add("if");
reservedWords.add("implements");
reservedWords.add("implicit");
reservedWords.add("import");
reservedWords.add("in");
reservedWords.add("inline");
reservedWords.add("instanceof");
reservedWords.add("int");
reservedWords.add("interface");
reservedWords.add("internal");
reservedWords.add("is");
reservedWords.add("lock");
reservedWords.add("long");
reservedWords.add("namespace");
reservedWords.add("native");
reservedWords.add("new");
reservedWords.add("null");
reservedWords.add("object");
reservedWords.add("operator");
reservedWords.add("out");
reservedWords.add("override");
reservedWords.add("package");
reservedWords.add("params");
reservedWords.add("private");
reservedWords.add("property");
reservedWords.add("protected");
reservedWords.add("public");
reservedWords.add("readonly");
reservedWords.add("ref");
reservedWords.add("register");
reservedWords.add("return");
reservedWords.add("sbyte");
reservedWords.add("sealed");
reservedWords.add("short");
reservedWords.add("signed");
reservedWords.add("sizeof");
reservedWords.add("static");
reservedWords.add("strictfp");
reservedWords.add("shring");
reservedWords.add("struct");
reservedWords.add("super");
reservedWords.add("switch");
reservedWords.add("synchronized");
reservedWords.add("this");
reservedWords.add("thread");
reservedWords.add("throw");
reservedWords.add("throws");
reservedWords.add("transient");
reservedWords.add("true");
reservedWords.add("try");
reservedWords.add("typedef");
reservedWords.add("typeof");
reservedWords.add("uint");
reservedWords.add("ulong");
reservedWords.add("unchecked");
reservedWords.add("union");
reservedWords.add("unsafe");
reservedWords.add("unsigned");
reservedWords.add("ushort");
reservedWords.add("using");
reservedWords.add("virtual");
reservedWords.add("union");
reservedWords.add("unsigned");
reservedWords.add("uuid");
reservedWords.add("var");
reservedWords.add("void");
reservedWords.add("volatile");
reservedWords.add("while");
}
}
}
/**
* Returns true if the value is a reserved keyword in Java or C#, or cannot be used as a name
* @param name the String to check if a keyword
* @return true/false
*/
public static boolean isReservedWord(String name)
{
boolean reserved = false;
populateReservedWords();
if (StringUtils.isNotBlank(name) && reservedWords.contains(name.toLowerCase()))
{
reserved = true;
}
return reserved;
}
/**
* Gets the getter prefix for a getter operation given the <code>type</code>.
*
* @param type the type from which to determine the prefix.
* @return the getter prefix.
*/
public static String getGetterPrefix(final ClassifierFacade type)
{
return type != null && type.isBooleanType() && type.isPrimitive() ? "is" : "get";
}
/**
* Gets the getter prefix for a getter operation given the <code>type</code>,
* taking multiplicity into account for booleans
*
* @param type the type from which to determine the prefix.
* @param lowerBound If > 0 then type is not optional, thus primitive isBoolean()
* @return the getter prefix.
*/
public static String getGetterPrefix(final ClassifierFacade type, int lowerBound)
{
// Automatically converted to primitive type or wrapped type based on lowerBound
return type != null && type.isBooleanType() && (lowerBound > 0 || type.isPrimitive()) ? "is" : "get";
}
/**
* Returns true if the passed in constraint <code>expression</code> is of type <code>kind</code>, false otherwise.
*
* @param expression the expression to check.
* @param kind the constraint kind (i.e. <em>inv</em>,<em>pre</em>, <em>body</em>, etc).
* @return true/false
*/
public static boolean isConstraintKind(String expression, String kind)
{
Pattern pattern = Pattern.compile(".*\\s*" + StringUtils.trimToEmpty(kind) + "\\s*\\w*\\s*:.*", Pattern.DOTALL);
Matcher matcher = pattern.matcher(StringUtils.trimToEmpty(expression));
return matcher.matches();
}
// TODO extract the mappings into the configurable metafacade namespace in UMLProfile
private static Map<String, String> implCollection = new HashMap<String, String>();
/**
* Transforms the declared type to implementation type for a declared Collection.
* Default: Collection=LinkedList, List=ArrayList, Set=HashSet, SortedSet=TreeSet.
* Retains the generics and package in the template declaration, if any
*
* @param input the declared Collection type to be transformed into an implementation type
* @return the Collection implementation declaration.
*/
public static String getImplCollection(final String input)
{
synchronized (implCollection)
{
// Populate collection map based on profile.xml settings
// TODO Use mapped implementation type instead of model types
if (implCollection.isEmpty())
{
// Put all mappings into Map, removing the initial 'datatype::'
//implCollection.put("List", "ArrayList");
//implCollection.put("Set", "HashSet");
//implCollection.put("SortedSet", "TreeSet");
//implCollection.put("Map", "HashMap");
//implCollection.put("SortedMap", "TreeMap");
implCollection.put(UMLProfile.COLLECTION_TYPE_NAME.substring(
UMLProfile.COLLECTION_TYPE_NAME.lastIndexOf(':')+1),
UMLProfile.COLLECTION_IMPL_TYPE_NAME.substring(
UMLProfile.COLLECTION_IMPL_TYPE_NAME.lastIndexOf(':')+1));
implCollection.put(UMLProfile.LIST_TYPE_NAME.substring(
UMLProfile.LIST_TYPE_NAME.lastIndexOf(':')+1),
UMLProfile.LIST_IMPL_TYPE_NAME.substring(
UMLProfile.LIST_IMPL_TYPE_NAME.lastIndexOf(':')+1));
implCollection.put(UMLProfile.MAP_TYPE_NAME.substring(
UMLProfile.MAP_TYPE_NAME.lastIndexOf(':')+1),
UMLProfile.MAP_IMPL_TYPE_NAME.substring(
UMLProfile.MAP_IMPL_TYPE_NAME.lastIndexOf(':')+1));
implCollection.put(UMLProfile.ORDERED_MAP_TYPE_NAME.substring(
UMLProfile.ORDERED_MAP_TYPE_NAME.lastIndexOf(':')+1),
UMLProfile.ORDERED_MAP_IMPL_TYPE_NAME.substring(
UMLProfile.ORDERED_MAP_IMPL_TYPE_NAME.lastIndexOf(':')+1));
implCollection.put(UMLProfile.ORDERED_SET_TYPE_NAME.substring(
UMLProfile.ORDERED_SET_TYPE_NAME.lastIndexOf(':')+1),
UMLProfile.ORDERED_SET_IMPL_TYPE_NAME.substring(
UMLProfile.ORDERED_SET_IMPL_TYPE_NAME.lastIndexOf(':')+1));
implCollection.put(UMLProfile.SET_TYPE_NAME.substring(
UMLProfile.SET_TYPE_NAME.lastIndexOf(':')+1),
UMLProfile.SET_IMPL_TYPE_NAME.substring(
UMLProfile.SET_IMPL_TYPE_NAME.lastIndexOf(':')+1));
}
}
String collectionImpl = input;
// No transformation if no package on fullyQualifiedName
if (input.indexOf('.') > 0)
{
String collectionType = null;
String genericType = null;
String pkg = null;
if (input.indexOf('<') > 0)
{
collectionType = input.substring(0, input.indexOf('<'));
genericType = input.substring(input.indexOf('<'));
if (genericType.startsWith("<? extends "))
{
// Implementation collection type cannot declare 'extends'
genericType = '<' + genericType.substring(11);
}
}
else
{
collectionType = input;
genericType = "";
}
if (collectionType.indexOf('.') > 0)
{
pkg = collectionType.substring(0, collectionType.lastIndexOf('.')+1);
collectionType = collectionType.substring(collectionType.lastIndexOf('.')+1);
}
else
{
pkg = "java.util.";
logger.warn("UMLMetafacadeUtils pkg not found for " + collectionType);
}
String implType = implCollection.get(collectionType);
if (implType == null)
{
logger.warn("UMLMetafacadeUtils colectionImpl not found for " + collectionType);
collectionImpl = pkg + "ArrayList" + genericType;
}
else
{
//logger.info("UMLMetafacadeUtils translated from " + collectionType + " to " + implType);
collectionImpl = pkg + implType + genericType;
}
}
return collectionImpl;
}
/**
* Determines if the class/package should be generated. Will not be generated if it has any
* stereotypes: documentation, docOnly, Future, Ignore, analysis, perspective,
* or any invalid package identifier characters ` ~!@#%^&*()-+={}[]:;<>,?/|
* @param mef ModelElementFacade class to check for stereotypes.
* @return false if it has any Stereotypes DocOnly, Future, Ignore configured in UMLProfile
*/
public static boolean shouldOutput(ModelElementFacade mef)
{
boolean rtn = true;
if (mef!=null)
{
try
{
PackageFacade pkg = (PackageFacade) mef.getPackage();
if (mef instanceof PackageFacade)
{
pkg = (PackageFacade) mef;
}
if (mef.hasStereotype(UMLProfile.STEREOTYPE_DOC_ONLY) ||
mef.hasStereotype(UMLProfile.STEREOTYPE_FUTURE) ||
mef.hasStereotype(UMLProfile.STEREOTYPE_IGNORE))
{
rtn = false;
}
if (pkg != null &&
( pkg.hasStereotype(UMLProfile.STEREOTYPE_DOC_ONLY) ||
pkg.hasStereotype(UMLProfile.STEREOTYPE_FUTURE) ||
pkg.hasStereotype(UMLProfile.STEREOTYPE_IGNORE) ||
pkg.hasStereotype("analysis") ||
pkg.hasStereotype("perspective") ||
// Verify package does not have any Java disallowed characters
StringUtils.containsAny(pkg.getName(), " `~!@#%^&*()-+={}[]:;<>,?/|") ||
"PrimitiveTypes".equals(pkg.getName()) ||
"datatype".equals(pkg.getName())))
{
rtn = false;
}
}
catch (Exception ex)
{
// Output=true anyway just in case we want this output
logger.error("UMLMetafacadeUtils.shouldOutput for " + mef.toString() + ' ' + ex.getClass().getName() + ": "+ ex.getMessage());
}
}
return rtn;
}
/**
* Get the classname without the package name and without additional template<> parameters.
*
* @param facade
* @param enableTemplating
* @return getNameWithoutPackage
*/
// TODO This should really be a method on ModelElementFacade
public static String getClassDeclaration(ModelElementFacade facade, boolean enableTemplating)
{
return UMLMetafacadeUtils.getClassDeclaration(facade, facade.getName(), enableTemplating);
}
private static final String namespaceScopeOperator = ".";
private static final String COMMA = ", ";
private static final String LT = "<";
private static final String GT = ">";
/**
* Get the classname without the package name and without additional template<> parameters.
*
* @param facade
* @param className Class name to use in the class declaration, overrides facade.getName()
* @param enableTemplating Whether template declaration should be created.
* @return getNameWithoutPackage
*/
// TODO This should really be a method on ModelElementFacade
public static String getClassDeclaration(ModelElementFacade facade, String className, boolean enableTemplating)
{
if (StringUtils.isBlank(className))
{
className = facade.getName();
}
String fullName = StringUtils.trimToEmpty(className);
final String packageName = facade.getPackageName(true);
final String metafacadeNamespaceScopeOperator = MetafacadeConstants.NAMESPACE_SCOPE_OPERATOR;
if (StringUtils.isNotBlank(packageName))
{
fullName = packageName + metafacadeNamespaceScopeOperator + fullName;
}
final TypeMappings languageMappings = facade.getLanguageMappings();
if (languageMappings != null)
{
fullName = StringUtils.trimToEmpty(languageMappings.getTo(fullName));
// now replace the metafacade scope operators
// with the mapped scope operators
fullName = StringUtils.replace(
fullName,
metafacadeNamespaceScopeOperator,
namespaceScopeOperator);
}
// remove the package qualifier
if (fullName.indexOf('.')>-1)
{
fullName = fullName.substring(fullName.lastIndexOf('.')+1);
}
if (facade.isTemplateParametersPresent() && enableTemplating)
{
// we'll be constructing the parameter list in this buffer
final StringBuilder buffer = new StringBuilder();
// add the name we've constructed so far
buffer.append(fullName);
// start the parameter list
buffer.append(LT);
// loop over the parameters, we are so to have at least one (see
// outer condition)
int size = facade.getTemplateParameters().size();
int i = 1;
for (TemplateParameterFacade parameter : facade.getTemplateParameters())
{
if (parameter != null)
{
/*String name = parameter.getValidationName();
if (name==null && parameter.getParameter() != null)
{
name = parameter.getParameter().getName();
}
buffer.append(name);*/
buffer.append(parameter.getName());
if (i < size)
{
buffer.append(COMMA);
i++;
}
}
}
// we're finished listing the parameters
buffer.append(GT);
// we have constructed the full name in the buffer
fullName = buffer.toString();
}
return fullName;
}
private static final String QUESTION = "?";
/**
* Get the generic template<?, ?> declaration.
*
* @param facade
* @param enableTemplating
* @return getGenericTemplate
*/
// TODO This should really be a method on ModelElementFacade
public static String getGenericTemplate(ModelElementFacade facade, boolean enableTemplating)
{
String fullName = "";
if (facade != null && facade.isTemplateParametersPresent() && enableTemplating)
{
// we'll be constructing the parameter list in this buffer
final StringBuilder buffer = new StringBuilder();
// start the parameter list
buffer.append(LT);
// loop over the parameters, we are so to have at least one (see
// outer condition)
for (Iterator<TemplateParameterFacade> parameterIterator =
facade.getTemplateParameters().iterator(); parameterIterator.hasNext();)
{
parameterIterator.next();
buffer.append(QUESTION);
if (parameterIterator.hasNext())
{
buffer.append(COMMA);
}
}
// we're finished listing the parameters
buffer.append(GT);
// we have constructed the full name in the buffer
fullName = buffer.toString();
}
return fullName;
}
/**
* Get the fully-qualified classname without the additional template<> parameters.
*
* @param facade
* @return getFQNameWithoutTemplate
*/
// TODO This should really be a method on ModelElementFacade
public static String getFQNameWithoutTemplate(ModelElementFacade facade)
{
String fullName = StringUtils.trimToEmpty(facade.getName());
final String packageName = facade.getPackageName(true);
final String metafacadeNamespaceScopeOperator = MetafacadeConstants.NAMESPACE_SCOPE_OPERATOR;
if (StringUtils.isNotBlank(packageName))
{
fullName = packageName + metafacadeNamespaceScopeOperator + fullName;
}
final TypeMappings languageMappings = facade.getLanguageMappings();
if (languageMappings != null)
{
fullName = StringUtils.trimToEmpty(languageMappings.getTo(fullName));
fullName = StringUtils.replace(
fullName,
metafacadeNamespaceScopeOperator,
namespaceScopeOperator);
}
return fullName;
}
/**
* Returns the number of methods without stereotypes or with SimpleClass stereotype. .
* @param mef ModelElementFacade class to check for stereotypes.
* @param outletFile Name of output file currently being processed. How do we get this in template?
* @param refOutput Should .ref files be output?
* @return false if it has any Stereotypes DocOnly, Future, Ignore configured in UMLProfile
*/
public static boolean shouldOutput(ModelElementFacade mef, String outletFile, boolean refOutput)
{
boolean rtn = true;
if (outletFile==null)
{
return rtn;
}
if (outletFile.endsWith(".ref") && !refOutput)
{
rtn = false;
}
else
{
rtn = shouldOutput(mef);
}
return rtn;
}
/**
* Supplies a result for type = <new value>; initialization for all types
* @param facade Type to create default object for
* @return Constructor String with facade name
*/
public String createConstructor(ModelElementFacade facade)
{
return createConstructor(facade, false);
}
/**
* Supplies a result for type = <new value>; initialization for all types
* @param facade Type to create default object for
* @param useMany Return constructor with multiplicity type instead of underlying type
* @return Constructor String with facade name
*/
public String createConstructor(ModelElementFacade facade, boolean useMany)
{
return createConstructor(facade, useMany, null);
}
/**
* Supplies a result for type = <new value>; initialization for all types
* @param facade Type to create default object for
* @param useMany Return constructor with multiplicity type instead of underlying type
* @param parent Object containing this facade, which may have an attribute named dependency to a different type
* @return Constructor String with facade name
*/
public String createConstructor(ModelElementFacade facade, boolean useMany, ModelElementFacade parent)
{
if (facade==null)
{
return "facade was null";
}
String rtn = "";
String toString = "";
ClassifierFacade type = null;
String typeName = facade.getFullyQualifiedName();
String name = facade.getName();
String defaultValue = "";
// TODO: Default collection type from properties
String collectionType = "java.util.ArrayList";
Boolean isMany = null;
boolean isEnumeration = false;
int maxLength = 9999;
/*if (parent != null)
{
// See if a named dependency exists with the same facadeName
for (final DependencyFacade dependency : parent.getSourceDependencies())
{
if (dependency.getName().equals(facade.getName()) && dependency instanceof DependencyFacade)
{
facade = ((DependencyFacade)dependency).getTargetElement();
toString = ".toString()";
break;
}
}
}*/
try {
if (logger.isDebugEnabled())
{
logger.debug("name=" + name + " typeName=" + typeName + " useMany=" + useMany + " facade=" + facade + " parent=" + parent);
}
// Use persistence or validation annotations to limit the created value length
String length = (String)facade.findTaggedValue("andromda_persistence_column_length");
if (length != null && length.length()>0 && StringUtils.isNumeric(length))
{
maxLength = Integer.parseInt(length);
}
else
{
length = (String)facade.findTaggedValue("andromda_persistence_column_precision");
if (length != null && length.length()>0 && StringUtils.isNumeric(length))
{
maxLength = Integer.parseInt(length);
}
else
{
length = (String)facade.findTaggedValue("andromda_validation_length");
if (length != null && length.length()>0 && StringUtils.isNumeric(length))
{
maxLength = Integer.parseInt(length);
}
else
{
length = (String)facade.findTaggedValue("andromda_validation_precision");
if (length != null && length.length()>0 && StringUtils.isNumeric(length))
{
maxLength = Integer.parseInt(length);
}
}
}
}
if (facade instanceof ClassifierFacade)
{
ClassifierFacade classifier = (ClassifierFacade) facade;
type = classifier;
typeName = classifier.getFullyQualifiedName();
}
if (facade instanceof AttributeFacade)
{
AttributeFacade attr = (AttributeFacade) facade;
defaultValue = attr.getDefaultValue();
type = attr.getType();
if (useMany)
{
typeName = attr.getGetterSetterTypeName();
}
else
{
typeName = type.getFullyQualifiedName();
}
if (attr.getUpper()>1 || attr.getUpper()==-1)
{
isMany = true;
}
}
else if (facade instanceof ParameterFacade)
{
ParameterFacade attr = (ParameterFacade) facade;
defaultValue = attr.getDefaultValue();
type = attr.getType();
typeName = type.getFullyQualifiedName();
if (type.isEnumeration())
{
facade = type;
}
else if (useMany)
{
typeName = collectionType + '<' + type.getFullyQualifiedName() + '>';
}
else
{
typeName = type.getFullyQualifiedName();
}
if (attr.getUpper()>1 || attr.getUpper()==-1)
{
isMany = true;
}
}
if (facade instanceof AssociationEndFacade)
{
AssociationEndFacade attr = (AssociationEndFacade) facade;
type = attr.getType();
if (useMany)
{
typeName = attr.getGetterSetterTypeName();
}
else
{
typeName = type.getFullyQualifiedName();
}
if (attr.getUpper()>1 || attr.getUpper()==-1)
{
isMany = true;
}
facade = attr.getType();
}
// TODO: Make this work for attribute types other than String.
if (parent != null && StringUtils.isEmpty(defaultValue) && ("String".equals(typeName) || "java.lang.String".equals(typeName)))
{
// See if a named dependency exists with the same facadeName
for (final DependencyFacade dependency : parent.getSourceDependencies())
{
if (dependency.getName().equals(facade.getName()))
{
facade = dependency.getTargetElement();
// DependencyFacade type comes back empty for UML2::Integer
// Need to get metaObject Name property and verify it is not null.
if (facade instanceof ClassifierFacade)
{
type = (ClassifierFacade) facade;
}
typeName = facade.getFullyQualifiedName();
toString = ".toString()";
if (logger.isDebugEnabled())
{
logger.debug(parent + " " + facade + " = "
+ dependency + " type=" + type + " typeName="
+ typeName);
}
break;
}
}
}
if (type instanceof EnumerationFacade)
{
EnumerationFacade enumer = (EnumerationFacade) type;
//type = enumer.getLiteralType().getFullyQualifiedName();
Collection<AttributeFacade> literals = enumer.getLiterals();
if (StringUtils.isEmpty(defaultValue) && !literals.isEmpty())
{
// Just get the first enumeration literal
Object literal = literals.iterator().next();
if (literal instanceof EnumerationLiteralFacade)
{
EnumerationLiteralFacade enumLiteral = (EnumerationLiteralFacade) literal;
defaultValue = enumLiteral.getValue();
}
else if (literal instanceof AttributeFacade)
{
AttributeFacade attrib = (AttributeFacade) literal;
defaultValue = attrib.getEnumerationValue();
if (defaultValue==null)
{
defaultValue = attrib.getDefaultValue();
}
}
// Literal value is always a String. Remove quotes if part of default (i.e. class attribute).
defaultValue = StringUtils.remove(defaultValue, "\"");
defaultValue = enumer.getFullyQualifiedName() + ".fromValue(\"" + defaultValue + "\")";
}
else
{
defaultValue = enumer.getName() + '.' + defaultValue;
}
isEnumeration = true;
if (logger.isDebugEnabled())
{
logger.debug("EnumerationFacade=" + facade + " type=" + type + " literals=" + literals.size() + " default=" + defaultValue);
}
}
if (type != null && type.findTaggedValue("andromda_persistence_lob_type")!=null)
{
typeName = String.valueOf(type.findTaggedValue("andromda_persistence_lob_type"));
// LOB Types have a different datatype than the underlying declared type
}
if (useMany && (isMany==null || isMany.booleanValue()) && !typeName.endsWith("[]"))
{
typeName = UMLMetafacadeUtils.getImplCollection(typeName);
if (!typeName.startsWith("java.util") && type != null)
{
if (type.equals("java.util.Collection") || typeName.equals("java.util.List"))
{
rtn = "new " + collectionType + "<" + typeName + ">()";
}
else if (typeName.equals("java.util.Set"))
{
rtn = "new java.util.HashSet<" + typeName + ">()";
}
else if (typeName.equals("java.util.Map"))
{
rtn = "new java.util.HashMap<" + typeName + ">()";
}
else
{
rtn = "new " + collectionType + '<' + typeName + ">()";
}
}
else
{
// Assume array or type Collection<type>
rtn = "new " + typeName + "()";
}
}
else if ("String".equals(typeName) || "java.lang.String".equals(typeName))
{
if (defaultValue != null && defaultValue.trim().length() > 0)
{
if (defaultValue.startsWith("\"") || defaultValue.startsWith("'"))
{
defaultValue = defaultValue.substring(1, defaultValue.length()-1);
}
if (defaultValue.endsWith("\"") || defaultValue.endsWith("'"))
{
defaultValue = defaultValue.substring(0, defaultValue.length()-2);
}
if (defaultValue.trim().length() > maxLength)
{
logger.warn("Attribute default for " + facade.getFullyQualifiedName() + " is longer than max column length " + maxLength);
defaultValue = defaultValue.substring(0, maxLength-1);
}
}
rtn = '\"' + (StringUtils.isNotBlank(defaultValue) ? defaultValue : name) + '\"';
}
else if ("Boolean".equals(typeName) || "java.lang.Boolean".equals(typeName))
{
rtn = (StringUtils.isNotBlank(defaultValue) ? "Boolean." + defaultValue.toUpperCase() : "Boolean.TRUE");
}
else if ("boolean".equals(typeName))
{
rtn = (StringUtils.isNotBlank(defaultValue) ? defaultValue : "true");
}
else if ("int".equals(typeName) || "short".equals(typeName) || "long".equals(typeName)
|| "byte".equals(typeName) || "float".equals(typeName) || "double".equals(typeName))
{
rtn = (StringUtils.isNotBlank(defaultValue) ? defaultValue : "1");
}
else if ("java.util.Date".equals(typeName))
{
rtn = "new " + typeName + "()";
}
else if ("java.sql.Timestamp".equals(typeName))
{
rtn = "new java.sql.Timestamp(System.currentTimeMillis())";
}
else if ("java.util.Calendar".equals(typeName))
{
rtn = "java.util.Calendar.getInstance()";
}
else if ("org.joda.time.LocalTime".equals(typeName))
{
rtn = "new org.joda.time.LocalTime(1, 1)";
}
else if ("char".equals(typeName))
{
rtn = "'" + (StringUtils.isNotEmpty(defaultValue) ? defaultValue : name.substring(0, 1)) + "'";
}
else if ("Character".equals(typeName))
{
rtn = "new Character('" + (StringUtils.isNotEmpty(defaultValue) ? "new Character(" + defaultValue : name.substring(0, 1)) + "')";
}
else if ("Byte".equals(typeName) || "java.lang.Byte".equals(typeName))
{
rtn = "new Byte(\"" + facade.getName() + "\")";
}
else if ("Short".equals(typeName) || "java.lang.Short".equals(typeName)
|| "Integer".equals(typeName) || "java.lang.Integer".equals(typeName)
|| "Long".equals(typeName) || "java.lang.Long".equals(typeName)
|| "Float".equals(typeName) || "java.lang.Float".equals(typeName)
|| "Double".equals(typeName) || "java.lang.Double".equals(typeName)
|| "java.math.BigDecimal".equals(typeName))
{
rtn = (!StringUtils.isEmpty(defaultValue) ? typeName + ".valueOf(" + defaultValue + ")" : typeName + ".valueOf(1)");
}
else if ("java.math.BigInteger".equals(typeName))
{
rtn = (!StringUtils.isEmpty(defaultValue) ? "java.math.BigInteger.valueOf(" + defaultValue + ')' : "java.math.BigInteger.valueOf(1)");
}
else if ("byte[]".equals(typeName))
{
rtn = (StringUtils.isNotBlank(defaultValue) ? defaultValue : '\"' + name + '\"') + ".getBytes()";
}
else if ("char[]".equals(typeName))
{
String value = StringUtils.isNotBlank(defaultValue) ? defaultValue : name;
if (!value.startsWith("\""))
{
value = "\"" + value;
}
if (!value.endsWith("\""))
{
value = value + "\"";
}
rtn = value + ".toCharArray()";
}
else if ("String[]".equals(typeName))
{
rtn = "new String[] { " + (StringUtils.isNotBlank(defaultValue) ? defaultValue : '\"' + name + '\"') + " }";
}
else if (isEnumeration)
{
if (useMany)
{
rtn = collectionType + '<' + defaultValue + '>';
}
else
{
rtn = defaultValue;
}
}
else if (!StringUtils.isEmpty(defaultValue))
{
rtn = "new " + typeName + '(' + defaultValue + ')';
}
else if (type != null && type.hasStereotype("EmbeddedValue"))
{
// EmbeddedValue classes will always be abstract with Impl generated classes.
rtn = "new " + typeName + "Impl()";
}
else if (type instanceof GeneralizableElementFacade)
{
// If type has a descendant with name <typeName>Impl, assume typeNameImpl must be instantiated instead of typeName
if (typeName.endsWith("[]"))
{
rtn = "{ new " + typeName.substring(0, typeName.length()-2) + "() }";
}
else
{
rtn = "new " + typeName + "()";
}
//if (facade instanceof ClassifierFacade)
//{
//ClassifierFacade classifier = (ClassifierFacade)facade;
// If type is abstract, choose Impl descendant if exists, or the last descendant
if (type.isAbstract())
{
// Can't instantiate abstract class - pick some descendant
for (GeneralizableElementFacade spec : type.getSpecializations())
{
if (spec.getName().equals(type.getName() + "Impl"))
{
rtn = '(' + type.getName() + ")new " + typeName + "Impl()";
break;
}
rtn = '(' + type.getName() + ")new " + spec.getFullyQualifiedName() + "()";
}
}
//}
GeneralizableElementFacade generalization = (GeneralizableElementFacade)type;
for (GeneralizableElementFacade spec : generalization.getSpecializations())
{
if (spec.getName().equals(type.getName() + "Impl"))
{
rtn = '(' + type.getName() + ")new " + spec.getFullyQualifiedName() + "Impl()";
}
}
}
else if (typeName.endsWith("[]"))
{
rtn = "new " + typeName + " { new " + typeName.substring(0, typeName.length()-2) + "() }";
}
else
{
rtn = "new " + typeName + "()";
}
rtn = StringUtils.replace(rtn, "java.util.Collection", "java.util.ArrayList") + toString;
rtn = StringUtils.replace(rtn, "java.util.Set", "java.util.HashSet") + toString;
if (logger.isDebugEnabled())
{
logger.debug("facade=" + facade + " facadeName=" + facade.getName() + " type=" + type + " typeName=" + typeName + " name=" + name + " isMany=" + isMany + " defaultValue=" + defaultValue + " rtn=" + rtn);
}
} catch (RuntimeException e) {
logger.error(e + " facade=" + facade + " facadeName=" + facade.getName() + " parent=" + parent + " type=" + type + " typeName=" + typeName + " name=" + name + " isMany=" + isMany + " defaultValue=" + defaultValue);
e.printStackTrace();
}
return rtn;
}
/**
* TODO Reference this logic from AssociationEnd
* Determine if this association end owns the relationship. i.e. if the associationEnd property
* belonging to the Entity on the opposite end owns the relationship. Based on tagged value,
* multiplicity, aggregation/composition. If all else fails, the longest name owns the
* association, or else the alphabetically first name. One side of a relationship must
* always own the association and be created and deleted first.
* @param associationEnd the association end
* @return true if the associationEnd (property of the entity on the other end) is owned by the entity on the other end
*/
public static boolean isOwningEnd(AssociationEndFacade associationEnd)
{
boolean owning = false;
AssociationEndFacade otherEnd = associationEnd.getOtherEnd();
//String assoc = ((Entity)otherEnd.getValidationOwner()).getName() + "." + associationEnd.getName() + " -> " + associationEnd.getType().getName() + " ";
if (BooleanUtils.toBoolean(
ObjectUtils.toString(otherEnd.findTaggedValue(
"andromda_persistence_associationEnd_primary"))))
{
owning = true;
}
// See if this end or the other end is tagged as the association owner
else if (BooleanUtils.toBoolean(
ObjectUtils.toString(associationEnd.findTaggedValue(
"andromda_persistence_associationEnd_primary"))))
{
owning = false;
}
// Navigable side always owns the relationship
else if (associationEnd.isNavigable() && !otherEnd.isNavigable())
{
owning = true;
//LOGGER.info("Owning=true: " + assoc + "nav=" + associationEnd.isNavigable() + " Onav=" + otherEnd.isNavigable());
}
else if (!associationEnd.isNavigable() && otherEnd.isNavigable())
{
owning = false;
//LOGGER.info("Owning=false: " + assoc + "nav=" + associationEnd.isNavigable() + " Onav=" + otherEnd.isNavigable());
}
// Other side: aggregation/composition side does not own the bidirectional relationship
else if (otherEnd.isAggregation() || otherEnd.isComposition())
{
owning = false;
//LOGGER.info("Owning=true: " + assoc + "Oagg=" + otherEnd.isAggregation() + " Ocomp=" + otherEnd.isComposition());
}
else if (associationEnd.isAggregation() || associationEnd.isComposition())
{
owning = true;
//LOGGER.info("Owning=false: " + assoc + "Oagg=" + associationEnd.isAggregation() + " Ocomp=" + otherEnd.isComposition());
}
// The many side of 1:M owns the bidirectional relationship
else if (!associationEnd.isMany() && otherEnd.isMany())
{
owning = true;
//LOGGER.info("Owning=true: " + assoc + "many=" + associationEnd.isMany() + " Omany=" + otherEnd.isMany());
}
// Other side: the many side of 1:M owns the bidirectional relationship if no composition/aggregation
else if (associationEnd.isMany() && !otherEnd.isMany())
{
owning = false;
//LOGGER.info("Owning=false: " + assoc + "many=" + associationEnd.isMany() + " Omany=" + otherEnd.isMany());
}
// The optional side of 1:1 or M:M owns the bidirectional relationship
else if (associationEnd.getLower() > 0 && otherEnd.getLower() == 0)
{
owning = true;
//LOGGER.info("Owning=true: " + assoc + "many=" + associationEnd.isMany() + " Omany=" + otherEnd.isMany());
}
// If bidirectional 1:1 or M:M, choose the side with the longest type name because it typically indicates a composition relationship
/*else if (this.getOtherEnd().getType().getName().length()
> this.getType().getName().length())*/
else if (associationEnd.getName().length()
< otherEnd.getName().length())
{
owning = (associationEnd.getName().length() < otherEnd.getName().length());
//LOGGER.info("Owning=true: " + assoc + "endLength=" + associationEnd.getName().length() + " Olength=" + otherEnd.getName().length());
}
// If length is the same, alphabetically earliest is the owner
else if (associationEnd.getName().compareTo(
otherEnd.getName()) < 0)
{
owning = (associationEnd.getName().compareTo(otherEnd.getName()) < 0);
//LOGGER.info("Owning=true: " + assoc + "name=" + associationEnd.getName() + " < OName=" + otherEnd.getName());
}
/*LOGGER.info(((Entity)associationEnd.getOtherEnd().getValidationOwner()).getName()
+ "." + associationEnd.getName() +" IsOwningEnd=" + owning + " for "
+ ((Entity)associationEnd.getOtherEnd().getValidationOwner()).getName()
+ " OName=" + otherEnd.getName() + " Aggregation=" + associationEnd.isAggregation()
+ " Composition=" + associationEnd.isComposition() + " Navigable=" + associationEnd.isNavigable()
+ " !Navigable=" + !otherEnd.isNavigable() + " Many=" + associationEnd.isMany()
+ " OMany=" + otherEnd.isMany() + " Upper=" + associationEnd.getUpper()
+ " OUpper=" + otherEnd.getUpper() + " OAggregation=" + otherEnd.isAggregation()
+ " OComposition=" + otherEnd.isComposition() + " ONavigable=" + otherEnd.isNavigable()
+ " otherEnd=" + otherEnd.getFullyQualifiedName());*/
return owning;
}
private static FastDateFormat df = FastDateFormat.getInstance("MM/dd/yyyy HH:mm:ss");
/**
* Returns the current Date in the specified format.
*
* @param format The format for the output date
* @return the current date in the specified format.
*/
public static String getDate(String format)
{
if (df == null || !format.equals(df.getPattern()))
{
df = FastDateFormat.getInstance(format);
}
return df.format(new Date());
}
/**
* Returns the current Date in the specified format.
*
* @return the current date with the default format .
*/
public static String getDate()
{
return df.format(new Date());
}
}