MetafacadeBase.java
package org.andromda.core.metafacade;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.log4j.Logger;
/**
* Base class for all metafacades.
*
* @author <a href="http://www.mbohlen.de">Matthias Bohlen </a>
* @author Chad Brandon
* @author Wouter Zoons
* @author Bob Fields
*/
public class MetafacadeBase implements Serializable, Comparable
{
private static final long serialVersionUID = 34L;
/**
* The meta object which this metafacade wraps.
*/
private Object metaObject;
/**
* Constructs a new instance of this class with the given <code>metaObject</code>
* and <code>context</code>. The metaObject is the meta model element which
* this metafacade insulates. The <code>context</code> is the name of the
* context for this metafacade instance.
*
* @param metaObjectIn the meta object.
* @param contextIn the context of this meta object.
*/
public MetafacadeBase(
final Object metaObjectIn,
final String contextIn)
{
this.metaObject = metaObjectIn;
this.context = contextIn;
}
/**
* Retrieves the <code>owner</code> of this metafacade (for example: an operation owns its parameters, a class owns
* its attributes).
* <p>
* By default <code>null</code> is returned, however this method is overridden by subclasses which have a
* <code>parent</code> or <code>owner</code>. This is used to give the model validation messages more context as to
* where the validation error occurred. </p>
*
* @return the owner of this metafacade.
*/
public Object getValidationOwner()
{
return null;
}
/**
* Retrieves the <code>name</code> of this metafacade used within the validation messages.
* <p>
* By default <code>null</code> is returned, however this method is overridden by subclasses model elements that do
* have a name. </p>
*
* @return the owner of this metafacade.
*/
public String getValidationName()
{
return null;
}
/**
* Stores whether or not this metafacade has
* been initialized.
*/
private boolean initialized = false;
/**
* Sets the flag indicating this metafacade has been initialized.
*/
final void setInitialized()
{
this.initialized = true;
}
/**
* Indicates if this metafacade has been initialized.
*
* @return true/false
*/
final boolean isInitialized()
{
return this.initialized;
}
/**
* Validates that this facade's meta object is in a valid state.
* <p>
* Validate is called during metafacade creation by the factory. In the lifecycle of a metafacade it is validated
* only once, this is enforced by the caching within the metafacade factory.</p>
*
* @param validationMessages any messages generated during validation.
*/
public final void validate(final Collection<ModelValidationMessage> validationMessages)
{
this.validateInvariants(validationMessages);
}
/**
* <p>
* The logic of modeled OCL invariants from derived metafacades will be generated into this method and validation
* messages created and collected into the <code>messages</code> collection. This method is called by {@link #validate(Collection validationMessages)}
* </p>
* By default this method is empty. </p>
* @param messages Collection of org.andromda.core.metafacade.ModelValidationMessage
*/
public void validateInvariants(final Collection<ModelValidationMessage> messages)
{
// By default this does nothing
}
/**
* A lifecycle method, providing the ability for sub classes to take any action after the factory has completely
* initialized a metafacade, but before it has been validated for completeness.
*/
public void initialize()
{
// By default this does nothing
}
/**
* Returns one facade for a particular metaObject. Contacts the MetafacadeFactory to manufacture the proper
* metafacade. In certain cases <code>metaObject</code> can also be a metafacade instance; in that case the actual
* meta model element is retrieved from the metafacade and a metafacade is constructed from that.
*
* @param metaObjectIn the underlying meta model element. A metafacade is created for each.
* @return MetafacadeBase the facade
* @see MetafacadeFactory
*/
protected MetafacadeBase shieldedElement(final Object metaObjectIn)
{
MetafacadeBase metafacade = null;
if (metaObjectIn != null)
{
final String contextIn = this.getContext();
metafacade = MetafacadeFactory.getInstance().createMetafacade(
metaObjectIn,
contextIn);
// - The metafacade we've just got may have been found in the cache.
// If so, it can have an arbitrary context (because it's cached).
// We now need to set the context once again, so that all
// other metafacade mappings based on the context work as expected.
if(metafacade != null)
{
metafacade.resetMetafacadeContext(contextIn);
}
}
return metafacade;
}
/**
* Returns a collection of facades for a collection of metaobjects. Contacts the MetafacadeFactory to manufacture
* the proper facades.
*
* @param metaobjects the objects to decorate
* @return Collection of MetafacadeBase-derived objects
* @see MetafacadeFactory
*/
protected List shieldedElements(final Collection metaobjects)
{
final List metafacades = new ArrayList();
if (metaobjects != null)
{
for (final Object metaobject : metaobjects)
{
metafacades.add(this.shieldedElement(metaobject));
}
}
return metafacades;
}
/**
* Stores the context for this metafacade
*/
private String context = null;
/**
* Gets the context for this metafacade.
*
* @return the context name.
*/
final String getContext()
{
String contextIn = this.context;
if (StringUtils.isBlank(contextIn))
{
contextIn = this.getMetafacadeName();
}
return contextIn;
}
/**
* Sets the context for this metafacade. This is used to pass the context along from a metafacade specializing this
* metafacade (since we use delegate inheritance between shared and non-shared metafacades), as well as to pass the
* context to a metafacade being created within another.
*
* @param contextIn the metafacade interface name representing the context.
* @see MetafacadeMapping#isContextRoot()
*/
public void setMetafacadeContext(final String contextIn)
{
this.context = contextIn;
}
/**
* Resets the metafacade context after the metafacade was retrieved from the metafacade cache.
* DO NOT CALL THIS METHOD BY HAND, it is reserved for use in the MetafacadeFactory.
* @see org.andromda.core.metafacade.MetafacadeFactory
* @param contextIn the context defined by MetafacadeFactory
*/
public void resetMetafacadeContext(String contextIn)
{
throw new IllegalStateException("Method resetMetafacadeContext() must be overridden by concrete metafacade class (" + this.getClass().getName() + ")! Please re-generate your metafacades using the new andromda-meta cartridge.");
}
/**
* Stores the namespace for this metafacade
*/
private String metafacadeNamespace = null;
/**
* Gets the current namespace for this metafacade
*
* @return String
*/
final String getMetafacadeNamespace()
{
return this.metafacadeNamespace;
}
/**
* Sets the namespace for this metafacade.
*
* @param namespaceIn
*/
final void setNamespace(final String namespaceIn)
{
this.metafacadeNamespace = namespaceIn;
}
/**
* Returns true or false depending on whether the <code>property</code> is registered or not.
*
* @param property the name of the property to check.
* @return true/false on whether or not its registered.
*/
protected boolean isConfiguredProperty(final String property)
{
return MetafacadeFactory.getInstance().isPropertyRegistered(
this,
property);
}
/**
* Gets a configured property from the container. Note that the configured property must be registered first.
* Needs to be public so that a metafacade reference passed to a utility class can call this method.
*
* @param property the property name
* @return Object the configured property instance (mappings, etc)
*/
public Object getConfiguredProperty(final String property)
{
return MetafacadeFactory.getInstance().getRegisteredProperty(
this,
property);
}
/**
* Attempts to set the property with <code>name</code> having the specified <code>value</code> on this metafacade.
* @param nameIn
* @param value
*/
protected void setProperty(
final String nameIn,
final Object value)
{
MetafacadeFactory.getInstance().registerProperty(
this.getMetafacadeName(),
nameIn,
value);
}
/**
* Gets the current meta model object for this metafacade. This is used from {@link MetafacadeFactory} when
* attempting to construct a metafacade from a metafacade. This allows us to get the meta object for this metafacade
* so that the meta object can be used instead.
*
* @return the underlying model's meta object instance.
*/
public final Object getMetaObject()
{
return this.metaObject;
}
/**
* The metafacade logger instance.
*/
protected Logger logger;
/**
* Package-local setter, called by facade factory. Sets the logger to use inside the facade's code.
*
* @param loggerIn the logger to set
*/
final void setLogger(final Logger loggerIn)
{
this.logger = loggerIn;
}
/**
* The flag indicating whether or not this metafacade is a context root.
*/
protected boolean contextRoot = false;
/**
* Sets whether or not this metafacade represents a contextRoot. If it does represent a context root, then {@link
* #getMetafacadeContext()}returns the metafacade interface for this metafacade, otherwise the regular
* <code>context</code> is returned.
*
* @param contextRootIn
*/
final void setContextRoot(final boolean contextRootIn)
{
this.contextRoot = contextRootIn;
}
/**
* Gets the <code>context</code> for this metafacade. This is either the <code>contextRoot</code> (if one exists),
* or the regular <code>context</code>.
*
* @return the metafacade's context.
*/
public String getMetafacadeContext()
{
String metafacadeContext = this.getContext();
if (this.contextRoot)
{
metafacadeContext = this.getMetafacadeName();
}
return metafacadeContext;
}
/**
* Stores the name of the interface for this metafacade
*/
private String metafacadeName = null;
/**
* Gets the name for this metafacade.
*
* @return the metafacade's name.
*/
final String getMetafacadeName()
{
if (this.metafacadeName == null)
{
this.metafacadeName = MetafacadeImpls.instance().getMetafacadeClass(this.getClass().getName()).getName();
}
return this.metafacadeName;
}
/**
* @see Object#equals(Object)
*/
@Override
public boolean equals(Object object)
{
boolean equals = false;
if (object instanceof MetafacadeBase)
{
MetafacadeBase that = (MetafacadeBase)object;
equals = this.metaObject.equals(that.metaObject);
}
return equals;
}
/**
* @see Object#hashCode()
*/
@Override
public int hashCode()
{
return this.metaObject.hashCode();
}
/**
* In order to speed up the check for this property (which will happen many times), we cache it :-)
*/
private Boolean metafacadePropertyCachingEnabled = null;
/**
* A check to verify whether or not to make use of metafacade property caching. This method check if the {@link
* MetafacadeProperties#ENABLE_METAFACADE_PROPERTY_CACHING} namespace property has been set, if this is not the case
* then the caching will be enabled by default.
* @return this.metafacadePropertyCachingEnabled.booleanValue()
*/
public final boolean isMetafacadePropertyCachingEnabled()
{
if (this.metafacadePropertyCachingEnabled == null)
{
final String enableCache =
(String)this.getConfiguredProperty(MetafacadeProperties.ENABLE_METAFACADE_PROPERTY_CACHING);
this.metafacadePropertyCachingEnabled = Boolean.valueOf(enableCache);
}
return this.metafacadePropertyCachingEnabled;
}
/**
* The instance of this class as the appropriate metafacade instance.
*/
private MetafacadeBase THIS = null;
/**
* The metafacade instance of <code>this</code>. This should be used when
* you'd need to check if <code>this</code> was an instance of a given metafacade.
* For example: <code>THIS() instanceof SomeMetafacade</code>.
*
* This <strong>MUST</strong> be used instead of <em>this</em> in order to access the correct
* metafacade instance in the hierarchy (since we use delegate inheritance).
* @return this.shieldedElement(this.metaObject)
*/
protected final MetafacadeBase THIS()
{
return this.THIS == null ? this.THIS = this.shieldedElement(this.metaObject) : this.THIS;
}
/**
* @see Object#toString()
*/
@Override
public String toString()
{
return super.toString() + '[' + this.metafacadeName + ": " + this.metaObject.getClass().getName() + ']';
}
/**
* Allow sorting and use in TreeSet. ValidationName is overridden in descendants.
* @see Comparable#compareTo(Object)
*/
public int compareTo(Object object)
{
if (object==null || !(object instanceof MetafacadeBase))
{
return -1;
}
MetafacadeBase metafacade = (MetafacadeBase)object;
if (metafacade.getValidationName()==null)
{
return -1;
}
return metafacade.getValidationName().compareTo(this.getValidationName());
}
/**
* For debug purposes, when we need more than just class and metaclass name
* @return String representation of all properties including metaObject info
* @see Object#toString()
*/
public String getDebug()
{
return ToStringBuilder.reflectionToString(this) + '[' + this.metafacadeName + ": " + this.metaObject.getClass().getName() + ": " + ToStringBuilder.reflectionToString(this.metaObject) + ']';
}
}