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:
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 |
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). |
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 |
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 |
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>
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:
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 |
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> ...
... <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> ...
... <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> ...
... <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> ...
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> ...
... <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> ...
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:
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 |