Package org.andromda.metafacades.uml

Source Code of org.andromda.metafacades.uml.EntityMetafacadeUtils

package org.andromda.metafacades.uml;

import java.text.CharacterIterator;
import java.text.StringCharacterIterator;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Random;

import org.andromda.core.common.ExceptionUtils;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.StringUtils;


/**
* Utilities for dealing with entity metafacades
*
* @author Chad Brandon
*/
public class EntityMetafacadeUtils
{
    /**
     * <p/> Converts a string following the Java naming conventions to a
     * database attribute name. For example convert customerName to
     * CUSTOMER_NAME.
     * </p>
     *
     * @param modelElementName the string to convert
     * @param separator character used to separate words
     * @return string converted to database attribute format
     */
    public static String toSqlName(
        String modelElementName,
        Object separator)
    {
        ExceptionUtils.checkEmpty(
            "modelElementName",
            modelElementName);

        StringBuffer sqlName = new StringBuffer();
        StringCharacterIterator iterator = new StringCharacterIterator(StringUtils.uncapitalize(modelElementName));

        for (char character = iterator.first(); character != CharacterIterator.DONE; character = iterator.next())
        {
            if (Character.isUpperCase(character))
            {
                sqlName.append(separator);
            }
            character = Character.toUpperCase(character);
            sqlName.append(character);
        }
        return StringEscapeUtils.escapeSql(sqlName.toString());
    }

    /**
     * Gets the SQL name. (i.e. column name, table name, etc.). If it can't find
     * the corresponding tagged value with the specified <code>name</code>,
     * then it uses the element name by default and just returns that.
     *
     * @param prefix the optional prefix to add to the sql name (i.e. table name
     *        prefix, etc.).
     * @param element from which to retrieve the SQL name.
     * @param name the name of the tagged value.
     * @param nameMaxLength if this is not null, then the name returned will be
     *        trimmed to this length (if it happens to be longer).
     * @param separator character used to separate words
     * @return the SQL name as a String.
     */
    public static String getSqlNameFromTaggedValue(
        String prefix,
        ModelElementFacade element,
        String name,
        Short nameMaxLength,
        Object separator)
    {
        return getSqlNameFromTaggedValue(
            prefix,
            element,
            name,
            nameMaxLength,
            null,
            separator);
    }

    /**
     * Gets the SQL name. (i.e. column name, table name, etc.). If it can't find
     * the corresponding tagged value with the specified <code>name</code>,
     * then it uses the element name by default and just returns that.
     *
     * @param element from which to retrieve the SQL name.
     * @param name the name of the tagged value.
     * @param nameMaxLength if this is not null, then the name returned will be
     *        trimmed to this length (if it happens to be longer).
     * @param suffix the optional suffix to add to the sql name (i.e. foreign
     *        key suffix, etc.)
     * @param separator character used to separate words
     * @return the SQL name as a String.
     */
    public static String getSqlNameFromTaggedValue(
        ModelElementFacade element,
        String name,
        Short nameMaxLength,
        String suffix,
        Object separator)
    {
        return getSqlNameFromTaggedValue(
            null,
            element,
            name,
            nameMaxLength,
            suffix,
            separator);
    }

    /**
     * Gets the SQL name. (i.e. column name, table name, etc.). If it can't find
     * the corresponding tagged value with the specified <code>name</code>,
     * then it uses the element name by default and just returns that.
     *
     * @param element from which to retrieve the SQL name.
     * @param name the name of the tagged value.
     * @param nameMaxLength if this is not null, then the name returned will be
     *        trimmed to this length (if it happens to be longer).
     * @param separator character used to separate words
     * @return the SQL name as a String.
     */
    public static String getSqlNameFromTaggedValue(
        ModelElementFacade element,
        String name,
        Short nameMaxLength,
        Object separator)
    {
        return getSqlNameFromTaggedValue(
            null,
            element,
            name,
            nameMaxLength,
            null,
            separator);
    }

    /**
     * Gets the SQL name. (i.e. column name, table name, etc.). If it can't find
     * the corresponding tagged value with the specified <code>name</code>,
     * then it uses the element name by default and just returns that.
     *
     * @param prefix the optional prefix to add to the sql name (i.e. table name
     *        prefix, etc.).
     * @param element from which to retrieve the SQL name.
     * @param name the name of the tagged value.
     * @param nameMaxLength if this is not null, then the name returned will be
     *        trimmed to this length (if it happens to be longer).
     * @param suffix the optional suffix to add to the sql name (i.e. foreign
     *        key suffix, etc.)
     * @param separator character used to separate words
     * @return the SQL name as a String.
     */
    public static String getSqlNameFromTaggedValue(
        String prefix,
        final ModelElementFacade element,
        String name,
        final Short nameMaxLength,
        String suffix,
        final Object separator)
    {
        if (element != null)
        {
            Object value = element.findTaggedValue(name);
            StringBuffer buffer = new StringBuffer(StringUtils.trimToEmpty((String)value));
            if (StringUtils.isEmpty(buffer.toString()))
            {
                // if we can't find the tagValue then use the
                // element name for the name
                buffer = new StringBuffer(toSqlName(
                            element.getName(),
                            separator));
                suffix = StringUtils.trimToEmpty(suffix);
                prefix = StringUtils.trimToEmpty(prefix);
                if (nameMaxLength != null)
                {
                    final short maxLength = (short)(nameMaxLength.shortValue() - suffix.length() - prefix.length());
                    buffer =
                        new StringBuffer(
                            EntityMetafacadeUtils.ensureMaximumNameLength(
                                buffer.toString(),
                                new Short(maxLength)));
                }
                if (StringUtils.isNotBlank(prefix))
                {
                    buffer.insert(
                        0,
                        prefix);
                }
                if (StringUtils.isNotBlank(suffix))
                {
                    buffer.append(suffix);
                }
            }
            name = buffer.toString();
        }
        return name;
    }

    /**
     * <p/> Trims the passed in value to the maximum name length.
     * </p>
     * If no maximum length has been set then this method does nothing.
     *
     * @param name the name length to check and trim if necessary
     * @param nameMaxLength if this is not null, then the name returned will be
     *        trimmed to this length (if it happens to be longer).
     * @return String the string to be used as SQL type
     */
    public static String ensureMaximumNameLength(
        String name,
        Short nameMaxLength)
    {
        if (StringUtils.isNotEmpty(name) && nameMaxLength != null)
        {
            short max = nameMaxLength.shortValue();
            if (name.length() > max)
            {
                name = name.substring(
                        0,
                        max);
            }
        }
        return name;
    }

    /**
     * Gets all identifiers for an entity. If 'follow' is true, and if
     * no identifiers can be found on the entity, a search up the
     * inheritance chain will be performed, and the identifiers from
     * the first super class having them will be used.   If no
     * identifiers exist, a default identifier will be created if the
     * allowDefaultIdentifiers property is set to true.
     *
     * @param entity the entity for which to retrieve the identifiers
     * @param follow a flag indicating whether or not the inheritance hiearchy
     *        should be followed
     * @return the collection of identifiers.
     */
    public static Collection getIdentifiers(
        final Entity entity,
        final boolean follow)
    {
        final Collection identifiers = new ArrayList(entity.getAttributes());
        MetafacadeUtils.filterByStereotype(
            identifiers,
            UMLProfile.STEREOTYPE_IDENTIFIER);

        return identifiers.isEmpty() && follow && entity.getGeneralization() instanceof Entity
            ? getIdentifiers((Entity)entity.getGeneralization(), follow)
            : identifiers;
    }

    /**
     * Constructs a sql type name from the given <code>mappedName</code> and
     * <code>columnLength</code>.
     *
     * @param typeName the actual type name (usually retrieved from a mappings
     *        file, ie NUMBER(19).
     * @param columnLength the length of the column.
     * @return the new name co
     */
    public static String constructSqlTypeName(
        final String typeName,
        final String columnLength)
    {
        String value = typeName;
        if (StringUtils.isNotEmpty(typeName))
        {
            final char beginChar = '(';
            final char endChar = ')';
            final int beginIndex = value.indexOf(beginChar);
            final int endIndex = value.indexOf(endChar);
            if (beginIndex != -1 && endIndex != -1 && endIndex > beginIndex)
            {
                String replacement = value.substring(
                        beginIndex,
                        endIndex) + endChar;
                value = StringUtils.replace(
                        value,
                        replacement,
                        beginChar + columnLength + endChar);
            }
            else
            {
                value = value + beginChar + columnLength + endChar;
            }
        }
        return value;
    }

    /**
     * Constructs and returns the foreign key constraint name for the given <code>associationEnd</code>, <code>suffix</code>, <code>sqlNameSeperator</code>
     * and <code>maxLengthProperty</code>.
     *
     * @param associationEnd the association end for which to construct the constraint name.
     * @param suffix the suffix appeneded to the constraint name (if not limited by length).
     * @param sqlNameSeperator the SQL name seperator to use (i.e. '_').
     * @param maxLengthProperty the numeric value stored as a string indicating the max length the constraint may be.
     * @return the constructed foreign key constraint name.
     */
    public static String getForeignKeyConstraintName(EntityAssociationEnd associationEnd, String suffix, String sqlNameSeperator, String maxLengthProperty)
    {
        String constraintName;

        final Object taggedValueObject = associationEnd.findTaggedValue(
                UMLProfile.TAGGEDVALUE_PERSISTENCE_FOREIGN_KEY_CONSTRAINT_NAME);
        if (taggedValueObject == null)
        {
            // we construct our own foreign key constraint name here
            StringBuffer buffer = new StringBuffer();

            final ClassifierFacade type = associationEnd.getOtherEnd().getType();
            if (type instanceof Entity)
            {
                Entity entity = (Entity)type;
                buffer.append(entity.getTableName());
            }
            else
            {
                // should not happen
                buffer.append(type.getName().toUpperCase());
            }

            buffer.append(sqlNameSeperator);
            buffer.append(associationEnd.getColumnName());
            constraintName = buffer.toString();

            // we take into consideration the maximum length allowed
            final short maxLength = (short)(Short.valueOf(maxLengthProperty).shortValue() - suffix.length());
            buffer = new StringBuffer(EntityMetafacadeUtils.ensureMaximumNameLength(constraintName, new Short(maxLength)));
            buffer.append(suffix);
            constraintName = EntityMetafacadeUtils.getUniqueForeignKeyConstraintName(buffer.toString());
        }
        else
        {
            // use the tagged value
            constraintName = taggedValueObject.toString();
        }
        return constraintName;
    }

    /**
     * An interal static cache for foreign key names (allows us to keep track
     * of which ones have been used).  Its not great that its static, but for now
     * this is the easiest way to enforce this.
     */
    private static Collection foreignKeyConstraintNameCache = new ArrayList();

    /**
     * Retrieves a unique foreign key constraint name given the proposedName.  Compares the proposedName
     * against any foreign key names already stored in an internal collection.
     *
     * @param proposedName the proposed foreign key name.
     * @return the unique foreign key name.
     */
    private static String getUniqueForeignKeyConstraintName(String proposedName)
    {
        final char[] characters = proposedName.toCharArray();
        int numericValue = 0;
        for (int ctr = 0; ctr < characters.length; ctr++)
        {
            numericValue = numericValue + Character.getNumericValue(characters[0]);
        }
        return getUniqueForeignKeyConstraintName(proposedName, new Random(numericValue));
    }

    /**
     * Retrieves a unique foreign key constraint name given the proposedName.  Compares the proposedName
     * against any foreign key names already stored in an internal collection.
     *
     * @param proposedName the proposed foreign key name.
     * @param random the Random number generator to use for enforcing uniqueness.
     * @return the unique foreign key name.
     */
    private static String getUniqueForeignKeyConstraintName(String proposedName, final Random random)
    {
        String name;
        if (foreignKeyConstraintNameCache.contains(proposedName))
        {
            final char[] characters = proposedName.toCharArray();
            int randomInt = random.nextInt(characters.length);
            char randomChar = Character.toUpperCase(characters[randomInt]);
            proposedName = proposedName.substring(0, proposedName.length() - 1) + randomChar;
            name = getUniqueForeignKeyConstraintName(proposedName, random);
        }
        else
        {
            name = proposedName;
            foreignKeyConstraintNameCache.add(name);
        }
        return name;
    }

    /**
     * Clears out the foreign key cache.
     */
    public static void clearForeignKeyConstraintNameCache()
    {
        foreignKeyConstraintNameCache.clear();
    }
}
TOP

Related Classes of org.andromda.metafacades.uml.EntityMetafacadeUtils

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.