Writing the metafacades descriptor

Now that you have written metafacades, you'll want to tell AndroMDA under which conditions it should instantiate them.

Because metafacades are a namespace component they MUST be registered in a namespace descriptor. This descriptor is what allows the metafacades namespace to be "discovered" on the classpath. This namespace descriptor also registers the set of metafacades as a component within the AndroMDA core.

Each metafacades descriptor must comply with the following XSD Schema.

The metafacade descriptor allows the AndroMDA Core to discover a set of metafacades on the classpath automatically. The AndroMDA Core also uses this descriptor to determine what metafacades must be mapped to what meta model objects. The metafacades descriptor must reside within the META-INF/andromda subdirectory of your cartridge (or shared metafacades library) and must be named metafacades.xml

A cartridge's descriptor should only reference metafacades, never metaclasses. Doing so detaches your cartridge from any specific UML version; instead, your cartridge should depend on the generic AndroMDA facades which allows your cartridge to be used in combination with any supported/future UML version.

However, when writing the generic metafacades you will need to depend on the metaclasses, essentially you will need to extend the facade model for each supported UML version and indicate how your facades relate to the metaclasses of that UML version. Only in these cases you will need to reference metaclasses in the metafacades.xml resource.

Let's have a look at part of the metafacades descriptor from the Hibernate cartridge:

<metafacades>
    ...
    <property reference="hibernateVersion"/>
    <property reference="hibernateXMLPersistence"/>
    <property reference="hibernateXMLPersistIDAsAttribute"/>
    ...
    <metafacade class="org.andromda.cartridges.hibernate.metafacades.HibernateEntityLogicImpl" contextRoot="true">
        <mapping>
            <stereotype>ENTITY</stereotype>
        </mapping>
        <property reference="hibernateMappingStrategy"/>
        <property reference="defaultEntityDiscriminatorColumn"/>
        <property reference="defaultEntityDiscriminatorType"/>
    </metafacade>
    <metafacade class="org.andromda.cartridges.hibernate.metafacades.HibernateAssociationEndLogicImpl">
        <mapping>
            <property name="type.hibernateEntityMetaType"/>
        </mapping>
        <property reference="hibernateAssociationEndOuterJoin"/>
        <property reference="listTypeImplementation"/>
        <property reference="setTypeImplementation"/>
        <property reference="mapTypeImplementation"/>
        <property reference="bagTypeImplementation"/>
        <property reference="specificCollectionInterfaces"/>
        <property reference="defaultCollectionInterface"/>
        <property reference="associationEndCollectionIndexName"/>
        <property reference="associationEndCollectionIndexType"/>
    </metafacade>
    ...
    <metafacade class="org.andromda.cartridges.hibernate.metafacades.HibernateServiceLogicImpl" contextRoot="true">
        <mapping>
            <stereotype>SERVICE</stereotype>
        </mapping>
    </metafacade>
    <metafacade class="org.andromda.cartridges.hibernate.metafacades.HibernateTypeLogicImpl">
        <property reference="hibernateTypeMappingsUri"/>
    </metafacade>
    <metafacade class="org.andromda.cartridges.hibernate.metafacades.HibernateEnumerationLogicImpl">
        <mapping>
            <stereotype>ENUMERATION</stereotype>
        </mapping>
    </metafacade>
    <metafacade class="org.andromda.cartridges.hibernate.metafacades.HibernateEntityAttributeLogicImpl">
        <mapping>
            <context>org.andromda.cartridges.hibernate.metafacades.HibernateEntity</context>
        </mapping>
        <property reference="hibernateTypeMappingsUri"/>
    </metafacade>
    <metafacade class="org.andromda.cartridges.hibernate.metafacades.HibernateEmbeddedValueLogicImpl" contextRoot="true">
        <mapping>
            <stereotype>EMBEDDED_VALUE</stereotype>
        </mapping>
        <property reference="embeddedValueImplementationNamePattern"/>
    </metafacade>
    <metafacade class="org.andromda.cartridges.hibernate.metafacades.HibernateEntityAttributeLogicImpl">
        <mapping>
            <context>org.andromda.cartridges.hibernate.metafacades.HibernateEmbeddedValue</context>
        </mapping>
        <property reference="sqlMappingsUri"/>
        <property reference="jdbcMappingsUri"/>
    </metafacade>
    ...
</metafacades>
            

This is what part of the UML1.4 metafacades descriptor looks like, notice how the MOF-UML1.4 metaclasses are used:

<metafacades metaclassPattern="{0}.{1}$Impl">
    <default class="org.andromda.metafacades.uml14.ModelElementFacadeLogicImpl"/>
    <property reference="languageMappingsUri"/>
    <property reference="wrapperMappingsUri"/>
    ...
    <metafacade class="org.andromda.metafacades.uml14.ClassifierFacadeLogicImpl">
        <mapping class="org.omg.uml.foundation.core.Classifier$Impl"/>
        <property reference="classifierNameMask"/>
    </metafacade>    
    <metafacade class="org.andromda.metafacades.uml14.EnumerationLiteralFacadeLogicImpl">
        <mapping class="org.omg.uml.foundation.core.EnumerationLiteral$Impl"/>
        <property reference="enumerationLiteralNameMask"/>
    </metafacade>
    <metafacade class="org.andromda.metafacades.uml14.EnumerationFacadeLogicImpl">
        <mapping class="org.omg.uml.foundation.core.UmlClass$Impl">
            <stereotype>ENUMERATION</stereotype>
        </mapping>
        <property reference="enumerationNameMask"/>
        <property reference="typeSafeEnumsEnabled"/>
    </metafacade>
    ...
    <metafacade class="org.andromda.metafacades.uml14.ActivityGraphFacadeLogicImpl">
        <mapping class="org.omg.uml.behavioralelements.activitygraphs.ActivityGraph$Impl"/>
    </metafacade>
    <metafacade class="org.andromda.metafacades.uml14.ObjectFlowStateFacadeLogicImpl">
        <mapping class="org.omg.uml.behavioralelements.activitygraphs.ObjectFlowState$Impl"/>
    </metafacade>
    ...
    <metafacade class="org.andromda.metafacades.uml14.ValueObjectLogicImpl" contextRoot="true">
        <mapping class="org.omg.uml.foundation.core.UmlClass$Impl">
            <stereotype>VALUE_OBJECT</stereotype>
        </mapping>
    </metafacade>
    <metafacade class="org.andromda.metafacades.uml14.ValueObjectAssociationEndLogicImpl">
        <mapping class="org.omg.uml.foundation.core.AssociationEnd$Impl">
            <context>org.andromda.metafacades.uml.ValueObject</context>
        </mapping>
        <property reference="useArraysForMultiplicitiesOfTypeMany"/>
    </metafacade>
    ...
    <metafacade class="org.andromda.metafacades.uml14.EntityLogicImpl" contextRoot="true">
        <mapping class="org.omg.uml.foundation.core.UmlClass$Impl">
            <stereotype>ENTITY</stereotype>
        </mapping>
        <property reference="allowDefaultIdentifiers"/>
        <property reference="defaultIdentifierPattern"/>
        <property reference="defaultIdentifierType"/>
        <property reference="defaultIdentifierVisibility"/>
        <property reference="relationNameSeparator"/>
        <property reference="entityNameMask"/>
    </metafacade>
    <metafacade class="org.andromda.metafacades.uml14.EntityAttributeLogicImpl">
        <mapping class="org.omg.uml.foundation.core.Attribute$Impl">
            <context>org.andromda.metafacades.uml.Entity</context>
        </mapping>
        <property reference="sqlMappingsUri"/>
        <property reference="jdbcMappingsUri"/>
        <property reference="entityPropertyNameMask"/>
    </metafacade>
    <metafacade class="org.andromda.metafacades.uml14.EntityAssociationEndLogicImpl">
        <mapping class="org.omg.uml.foundation.core.AssociationEnd$Impl">
            <context>org.andromda.metafacades.uml.Entity</context>
        </mapping>
        <property reference="sqlMappingsUri"/>
        <property reference="jdbcMappingsUri"/>
        <property reference="entityPropertyNameMask"/>
    </metafacade>
    ...
    <metafacade class="org.andromda.metafacades.uml14.ServiceLogicImpl" contextRoot="true">
        <mapping class="org.omg.uml.foundation.core.UmlClass$Impl">
            <stereotype>SERVICE</stereotype>
        </mapping>
    </metafacade>
    <metafacade class="org.andromda.metafacades.uml14.ServiceOperationLogicImpl">
        <mapping class="org.omg.uml.foundation.core.Operation$Impl">
            <property name="owner.serviceMetaType"/>
        </mapping>
    </metafacade>
            

The following describes each element/attribute within the metafacades.xml file and what effect it has on the metafacade configuration process:

<metafacades/>

The <metafacades/> element is the root of the metafacades.xml file. This root contains the rest of the metafacade configuration information.

Attribute Description Required?
metaclassPattern Specifies the pattern of the metaclass implementation classes based on the name of the metaclass interface, for example {0}.{1}Impl might be the value, where {0} represents the metaclass interface package and {1} the name of the metafacade. At least one set of registered metafacades must have this attribute defined.
<metafacades metaclassPattern="{0}.{1}$Impl">
...
</metafacades>                            
                        
No, if undefined, the metafacades will only be available to the namespace defined by the namespace attribute

<property/>

If you've read the documentation on AndroMDA Cartridges then you're probably familiar with namespace properties. Namespace properties allow us to configure different namespaces or aspects of an AndroMDA plugin.

The root <metafacades/> element can take one or more optional nested namespace <property/> elements. Namespace property elements are used to define references as well as default values for these properties which can then be configured by the cartridge client. Once these property references are defined, each can then by retrieved from within a metafacade implementation class by calling getConfiguredProperty(java.lang.String). For example, this daoNamePattern in this metafacade descriptor snippet here defines the pattern to use when constructing the DAO name within the Spring Cartridge.

<metafacades namespace="spring">
    <property reference="daoNamePattern" default="{0}Dao"/>
    ...
    <metafacade class="org.andromda.cartridges.spring.metafacades.SpringEntityLogicImpl" contextRoot="true">
        <mapping class="org.omg.uml.foundation.core.UmlClass$Impl">
            <stereotype>ENTITY</stereotype>
        </mapping>
    </metafacade>
    ...
</metafacades>               
                

This property can then be retrieved from within a metafacade implementation class contained within the spring cartridge, like so:

private String getDaoNamePattern()
{
    return String.valueOf(this.getConfiguredProperty("daoNamePattern"));
}                    
                
Attribute Description Required?
reference

Specifies the reference to the property that will be externally configured. This is the name that a cartridge client must supply in order to configure the value of this property.

Yes
default

Supplies the default value to supply to the metafacade if no property (and value) are supplied by the cartridge client.

No, if unspecified AndroMDA will output warning messages when the cartridge client runs AndroMDA (that is, if no value has been provided by the client).

<default/>

The root <metafacade/> element can have one and only one <default/> element. This default element allows us to configure the default metafacade to be applied if no applicable metafacade mapping was found in any of <metafacade/> mapping definitions. For example, within the UML 1.4 metafacades descriptor we have the following default configuration defined, which means: apply the model element facade org.andromda.metafacades.uml14.ModelElementFacadeLogicImpl to any meta model element that does not have any applicable metafacade mapping available.

<metafacades namespace="uml-1.4" shared="true">
    ...
    <default class="org.andromda.metafacades.uml14.ModelElementFacadeLogicImpl"/>
    ...
</metafacades>
                
Attribute Description Required?
class Defines the name of the metafacade implementation class for the default metafacade. Yes

<metafacade/>

The <metafacade/> element allows us to configure a mapping (and any applicable namespace properties) to a metafacade class. The <metafacade/> is nested directly under the root <metafacades/> element. For example this <metafacade/> element below tells AndroMDA to construct an instance of org.andromda.cartridges.spring.metafacades.SpringQueryOperationLogicImpl when AndroMDA finds a meta model element of type org.omg.uml.foundation.core.Operation$Impl, created within the context of org.andromda.cartridges.spring.metafacades.SpringEntity and having a valid query property (valid meaning the property is not-null, true if boolean, or a non-empty collection if a collection property).

<metafacades namespace="spring">
    ...    
    <metafacade class="org.andromda.cartridges.spring.metafacades.SpringQueryOperationLogicImpl">
        <mapping class="org.omg.uml.foundation.core.Operation$Impl">
            <context>org.andromda.cartridges.spring.metafacades.SpringEntity</context>
            <property name="query"/>
        </mapping>
        ...
    </metafacade>    
    ...
</metafacades>
Attribute Description Required?
class

Specifies the metafacade implementation class that should be instantiated when this mapping is matched.

Yes
contextRoot Indicates that this metafacade mapping will be treated as a context root for other metafacades. For example this metafacade mapping below is indicating that the metafacade constructed from org.andromda.cartridges.webservice.metafacades.WebServiceLogicImpl will be a context root (since it will play the context for the metafacade construced from a org.andromda.cartridges.webservice.metafacades.WebServiceOperationLogicImpl instance, which in turn will be a context for some other metafacade).
...
<metafacade class="org.andromda.cartridges.webservice.metafacades.WebServiceLogicImpl" contextRoot="true">
    <mapping class="org.omg.uml.foundation.core.UmlClass$Impl">
        <stereotype>WEBSERVICE</stereotype>
    </mapping>
    ...
</metafacade>
...
<metafacade class="org.andromda.cartridges.webservice.metafacades.WebServiceOperationLogicImpl" contextRoot="true">
    <mapping class="org.omg.uml.foundation.core.Operation$Impl">
        <context>org.andromda.cartridges.webservice.metafacades.WebService</context>
    </mapping>
    ...
</metafacade>
...
                        
Yes

<property/>

Each <metafacade/> can take one or more <property/> references.

Similar to the namespace <property/> references described above, we also have property references which can be used within the scope of a single metafacade (whereas the namespace property references are available to the entire namespace). This allows us to narrow the scope of the property, and if applicable be able to configure the property differently per metafacade within the same namespace. For example, this is how we would define the same daoNamePattern property used in the example above. You'll notice the only difference is the property reference is a child of the <metafacade/> instead of the <metafacades/> element like a namespace property reference. These property references can then be retrieved from within the metafacade implementation class (just like above).

<metafacades namespace="spring">
    ...
    <metafacade class="org.andromda.cartridges.spring.metafacades.SpringEntityLogicImpl" contextRoot="true">
        <mapping class="org.omg.uml.foundation.core.UmlClass$Impl">
            <stereotype>ENTITY</stereotype>
        </mapping>
        <property reference="daoNamePattern" default="{0}Dao"/>
    </metafacade>
    ...
</metafacades>               
                

<mapping/>

Each <metafacade/> must take a single <mapping/> element. The <mapping/> is the element containing the nested elements that tell AndroMDA how exactly a meta model object should be mapped to a specific metafacade.

This <mapping/> element allows metafacades to be mapped by a combination of the following attributes:

  • stereotypes - each meta model element can be mapped by one or more stereotypes.
  • context - each meta model element can be mapped by one context. A context is is a metafacade interface name, the context must be the context under which the metafacade is created.
  • properties - each meta model element can be mapped by one or more properties that apply to it.
Attribute Description Required?
class Specifies the class of the meta model element to which the metafacade should apply when this <mapping/> is matched. For example, you'll see that this mapping indicates that it shall be matched on each occurrence of org.omg.uml.foundation.core.Operation$Impl while the model is being processed.
...
<mapping class="org.omg.uml.foundation.core.Operation$Impl">
    ...
</mapping>
...
                        
Yes

<stereotype/>

Each <mapping/> can take one or more optional nested <stereotype/> elements. Having a single stereotype tells AndroMDA to match the meta model element having that stereotype. For example this here tells AndroMDA to apply org.andromda.cartridges.webservice.metafacades.WebServiceLogicImpl to any meta model element of type org.omg.uml.foundation.core.Classifier$Impl having the stereotype SERVICE:

...  
<metafacade class="org.andromda.cartridges.webservice.metafacades.WebServiceLogicImpl">
    <mapping class="org.omg.uml.foundation.core.Classifier$Impl">
        <stereotype>SERVICE</stereotype>
    </mapping>
</metafacade>   
...                
                
Having two or more stereotypes means match on the meta model element having all indicated stereotypes. For example this here tells AndroMDA to apply org.andromda.cartridges.webservice.metafacades.WebServiceLogicImpl to any meta model element of type org.omg.uml.foundation.core.UmlClass$Impl having the stereotype WEBSERVICE AND SERVICE:
...
<metafacade class="org.andromda.cartridges.webservice.metafacades.WebServiceLogicImpl">
    <mapping class="org.omg.uml.foundation.core.UmlClass$Impl">
        <stereotype>WEBSERVICE</stereotype>
        <stereotype>SERVICE</stereotype>
    </mapping>
</metafacade>
...                    
                
If you wanted to 'OR' them together, meaning you wanted the metafacade applied for either stereotype you'd just create more <metafacade/> elements containing the new mapping with the new stereotype(s). For example this here tells AndroMDA to apply org.andromda.cartridges.webservice.metafacades.WebServiceLogicImpl to any meta model element of type org.omg.uml.foundation.core.UmlClass$Impl that has either the WEBSERVICE OR SERVICE stereotype.
...
<metafacade class="org.andromda.cartridges.webservice.metafacades.WebServiceLogicImpl">
    <mapping class="org.omg.uml.foundation.core.UmlClass$Impl">
        <stereotype>WEBSERVICE</stereotype>
    </mapping>
</metafacade>
<metafacade class="org.andromda.cartridges.webservice.metafacades.WebServiceLogicImpl">
    <mapping class="org.omg.uml.foundation.core.UmlClass$Impl">
        <stereotype>SERVICE</stereotype>
    </mapping>
</metafacade>
...                    
                
It is also possible to combine a <context/> element with one or more stereotypes like this example here; which means apply org.andromda.cartridges.spring.metafacades.SpringQueryOperationLogicImpl to any meta model element of type org.omg.uml.foundation.core.Operation that has the FINDER_METHOD stereotype and is created in the context of org.andromda.cartridges.spring.metafacades.SpringEntity.
...
<metafacade class="org.andromda.cartridges.spring.metafacades.SpringQueryOperationLogicImpl">
    <mapping class="org.omg.uml.foundation.core.Operation$Impl">
        <context>org.andromda.cartridges.spring.metafacades.SpringEntity</context>
        <stereotype>FINDER_METHOD</stereotype>
    </mapping>
</metafacade>     
...               
                

<context/>

Each <mapping/> can take an optional nested <context/> element. This context allows us to specify that a metafacade must be created within the context of another metafacade in order to be mapped. Note that you can only specify a single context per <mapping/>. For example, this here tells AndroMDA to apply the org.andromda.metafacades.uml14.EntityAssociationEndFacadeLogicImpl to any meta model element of type org.omg.uml.foundation.core.AssociationEnd$Impl when creating the metafacade within the context of org.andromda.metafacades.uml.Entity.

...
<metafacade class="org.andromda.metafacades.uml14.EntityAssociationEndFacadeLogicImpl">
    <mapping class="org.omg.uml.foundation.core.AssociationEnd$Impl">
        <context>org.andromda.metafacades.uml.Entity</context>        
    </mapping>
</metafacade>
...
                
As you know, a context can be combined with one or more stereotypes like you saw in the example above. It can also be combined with one or more properties within a <mapping/> as well. For example, this here is used to construct the EntityQueryOperationFacade, it tells AndroMDA to apply org.andromda.metafacades.uml14.EntityQueryOperationFacadeLogicImpl to any meta model element of type org.omg.uml.foundation.core.Operation$Impl when constructed within the context of org.andromda.metafacades.uml.Entity and when the query property on the metafacade evaluates as a valid property.
...
<metafacade class="org.andromda.metafacades.uml14.EntityQueryOperationFacadeLogicImpl">
    <mapping class="org.omg.uml.foundation.core.Operation$Impl">
        <context>org.andromda.metafacades.uml.Entity</context>   
        <property name="query"/>   
    </mapping>
</metafacade>        
...            
                

<property/>

Each <mapping/> can take one or more optional nested <property/> elements. Properties can be used without specifying a value, or they can be used with a value.

When mapping without a value, the property must be considered valid.

A property is considered valid in the following cases:

  • The property is not null.
  • If a collection type the property is not empty.
  • If a boolean type the property is not false.

As you probably know from above, properties can be used in combination with both a <context/> or one or more <stereotype/> elements.

Attribute Description Required?
name Defines the name of the property to be evaluated. This must be a valid property on the given metafacade in order to be mapped. Yes
value Defines the value the property must match in order to be mapped. For example, this here indicates the query property on the metafacade must evaluate to false in order to be mapped.
...
<metafacade class="org.andromda.cartridges.spring.metafacades.BusinessOperationLogicImpl">
    <mapping class="org.omg.uml.foundation.core.Operation$Impl">
        <property name="query">false</property>
    </mapping>
</metafacade>
...
No