TemplateObject.java

package org.andromda.core.common;

import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.andromda.core.configuration.Namespaces;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.log4j.Logger;

/**
 * Contains the configuration of a template object which are objects that are
 * made available to the cartridge templates.
 *
 * @author Chad Brandon
 * @author Bob Fields
 */
public class TemplateObject
{
    private static final Logger logger = Logger.getLogger(TemplateObject.class);

    /**
     * The name of this template object made available to the
     * template.
     */
    private String name;

    /**
     * Gets the current name of this TemplateObject.
     *
     * @return String
     */
    public String getName()
    {
        final String methodName = "TemplateObject.getName";
        if (StringUtils.isEmpty(this.name))
        {
            throw new TemplateObjectException(methodName + " - templateObject '" + this + "' has no name defined");
        }
        return this.name;
    }

    /**
     * Caches the template objects.
     */
    private final Map<String, Object> objectCache = new HashMap<String, Object>();

    /**
     * Defines the class should be used in a static way
     */
    private static final String STATIC_SUFFIX = ".class";
    
    /**
     * Returns the actuall object instance described by this
     * template object.
     *
     * @return the actual object instance.
     */
    public Object getObject()
    {
        final String methodName = "TemplateObject.getTemplateObject";
        if (StringUtils.isEmpty(this.className))
        {
            throw new TemplateObjectException(methodName + " - templateObject '" + this + "' has no className defined");
        }
        Object templateObject = this.objectCache.get(this.className);
        try
        {
            if (templateObject == null)
            {
                final Class templateObjectClass;
                if(this.className.endsWith(STATIC_SUFFIX))
                {
                    templateObjectClass = ClassUtils.loadClass(StringUtils.substringBefore(this.className, STATIC_SUFFIX));
                    templateObject = templateObjectClass; 
                }
                else
                {
                    templateObjectClass = ClassUtils.loadClass(this.className);
                    templateObject = templateObjectClass.newInstance();
                }
                this.objectCache.put(this.className, templateObject);
            }

            // - we want to set the properties each time we retrieve (in case they've changed)
            this.setProperties(templateObject);
        }
        catch (final Throwable throwable)
        {
            throw new TemplateObjectException(throwable);
        }
        return templateObject;
    }

    /**
     * Sets all the nested properties on the templateObject object.
     *
     * @param templateObject the template object on which to populate properties.
     */
    protected void setProperties(final Object templateObject)
    {
        for (final String reference : propertyReferences)
        {
            String value = Namespaces.instance().getPropertyValue(
                    this.getNamespace(),
                    reference);
            if (value != null)
            {
                if (this.getLogger().isDebugEnabled())
                {
                    this.getLogger().debug(
                        "populating template object '" + this.name + "' property '" + reference + "' with value '" +
                        value + "' for namespace '" + namespace + '\'');
                }
                try
                {
                    Introspector.instance().setProperty(templateObject, reference, value);
                }
                catch (final Exception exception)
                {
                    // - don't throw the exception
                    final String message =
                        "Error setting property '" + reference + "' with '" + value + "' on templateObject --> '" +
                        templateObject + '\'';
                    logger.warn(message);
                }
            }
        }
    }

    /**
     * Sets the name of the template object (this name will be what the template class is stored under in the template)
     *
     * @param name the name of the template object.
     */
    public void setName(final String name)
    {
        this.name = StringUtils.trimToEmpty(name);
    }

    /**
     * The name of the class for this template object.
     */
    private String className;

    /**
     * Sets the class of the transformation object.
     *
     * @param className the name of the template object class.
     */
    public void setClassName(final String className)
    {
        ExceptionUtils.checkEmpty("className", className);
        this.className = className;
    }

    /**
     * The property references that configure this template object.
     */
    private final Collection<String> propertyReferences = new ArrayList<String>();

    /**
     * Adds a templateObject property reference (used to customize templateObjects). Property references are used to
     * populate bean like properties of template objects.
     *
     * @param reference the name of the property reference.
     */
    public void addPropertyReference(final String reference)
    {
        this.propertyReferences.add(reference);
    }

    /**
     * The resource in which the template object was found.
     */
    private URL resource;

    /**
     * The resource in which the templateObject was found.
     *
     * @return the resource as a URL.
     */
    public URL getResource()
    {
        return resource;
    }

    /**
     * Sets the resource in which the templateObject was defined.
     *
     * @param resource the resource on which this template object was defined.
     */
    public void setResource(final URL resource)
    {
        this.resource = resource;
    }

    /**
     * The namespace to which this template object belongs.
     */
    private String namespace;

    /**
     * Gets the namespace to which this template object belongs.
     *
     * @return Returns the namespace.
     */
    public String getNamespace()
    {
        return namespace;
    }

    /**
     * Sets the namespace to which this template object belongs.
     *
     * @param namespace The namespace to set.
     */
    public void setNamespace(final String namespace)
    {
        this.namespace = StringUtils.trimToEmpty(namespace);
    }

    /**
     * Gets the namespace logger (the logger under which output for this
     * template object should be written).
     *
     * @return the logger instance.
     */
    protected Logger getLogger()
    {
        return AndroMDALogger.getNamespaceLogger(this.namespace);
    }

    /**
     * @see Object#toString()
     */
    public String toString()
    {
        return ToStringBuilder.reflectionToString(this);
    }
}