Take your time!

Writing your own metafacades is a non-trivial task, if you do it for the first time. You should close the door and get yourself at least two days in a quiet atmosphere, reducing the context switches in your mind to a minimum. Otherwise, it might be a pain! :-)

The next section assumes you have brewed a good cup of coffee (or tea or whatever) and have at least two hours of time. Take a deep breath and start to prepare your working environment.

Prepare the working environment

First, make sure you have the correct directory structure on disk to keep all the artifacts you need to develop an AndroMDA cartridge. The easiest way to get such a correct directory structure is to copy an existing cartridge that already contains its own metafacades. A good example for this is the Hibernate cartridge.

After you copied the cartridge, you will see a directory structure like this:

src/java
src/templates
src/uml

Metafacades are generated from a UML model. Put this UML model in a file into the src/uml directory. Open MagicDraw and import the basic metafacades module which is shipped with AndroMDA. These basic metafacades for UML are in the model file andromda/xml.zips/UMLMetafacadeModel-*.xml.zip located in the AndroMDA binary distribution. You import them using the "File, Use Profile/Module..." menu in MagicDraw. After using the module, you should be able to see the basic facade classes (like ClassifierFacade, etc.) but MagicDraw should show them as read-only.

The next step is to model your own metafacades.

Model and generate your own metafacades

A few rules apply if you want to make AndroMDA generate the metafacades for you. You will see that they are easy to remember and that they make sense. After a short recap to clarify the terminology, the rules will be shown here.

Recap about how metafacades work

Later, the user of your cartridge will load a model into AndroMDA and will try to run your cartridge. At that time, the metadata repository in AndroMDA will instantiate a metaobject for each element of the user's model. After this, AndroMDA optionally instantiates a metafacade object that shields the metaobject.

Terms used to distinguish classes

We choose the following terms when we speak about metafacades:

  • A class of the metamodel is called a metaclass.
  • An instance of a metaclass is called a metaobject.
  • A class representing a metafacade is called a metafacade class.

So, don't confuse a metafacade class with a metaclass!

Modeling rules

There are rules that tell you how to shield a metaclass with a metafacade. Metafacades and metaclasses can relate to each other in the following ways:

  1. A metafacade class can have a direct dependency on a metaclass.
  2. A metafacade class can specialize another metafacade class and (in this case) may omit the dependency to a metaclass (because one of the superclasses of the metafacade class already has such a dependency).
  3. If (in point 2 above) a metafacade class MF2 specializes another metafacade class MF1 and (at the same time) has a direct dependency to a metaclass M2, then the metaclass M2 must specialize the metaclass M1 that is referenced by MF1 as a direct dependency.
  4. If you think point 3 is too cryptic then simply think of parallel class hierarchies: the class ordering in the metafacade class hierarchy must be similar to the class ordering in the metaclass hierarchy.
  5. The root metafacade class in the hierarchy must depend on some metaclass. Other metafacade classes may or may not depend on a metaclass.

There are two rules how to add stereotypes to the classes:

  • The metaclass must have the stereotype "metaclass".
  • The metafacade class must have the stereotype "metafacade".

That's it. No more rules for modeling metafacades.

Look at what you get from the metafacade model

Here, you see a picture of some typical metafacades:

A metafacade can have attributes, operations and associations to other metafacade classes. It can also depend on a metaclass or specialize another metafacade class. Let's talk about what it means if you add various things to a metafacade class.

The code for the metafacades will be generated by the andromda-meta cartridge. (Cool: you use AndroMDA to develop a cartridge that extends AndroMDA!). Each model element that you add to a metafacade class will later be translated by andromda-meta into a bunch of Java elements. The following table shows you which model element will be translated to which Java element:

Model element Java element(s)
Metafacade class Interface, plumbing and implementation classes
Attribute Abstract getter
Operation Abstract method
Association Abstract getter
Dependency Ignored except when the target of the dependency is a metaclass. In that case, a constructor with an argument of the metaclass type is generated.
Specialization Same constructor as in the dependency case except that this constructor calls the "superfacade" constructor.

A metaclass itself translates to three classes in Java:

  • An interface with the method signatures of all generated methods in the metafacade.
  • A class with automatically generated plumbing logic. This is called the "Logic" class.
  • An implementation class which is hand-written. This is called the "LogicImpl" class.

//TODO: Add pictures of generated metafacades here...
//TODO: Describe what the responsibilities of the three classes are...

Write the metafacade implementations

Basically, after having generated all those nice metafacade classes, you will want to implement their real functionality, right? To do that, start your favourite Java IDE (e.g. Eclipse).

Setting up a project in the IDE

Open a project that references all the source files, generated as well as hand-written. Make the IDE project reference the standard, basic metafacade project in the metafacades/uml directory. //TODO: Chad, where are those files in the binary distribution? Metafacade developers should possibly reference a jar file here instead of the source code tree, right?

Implementing the LogicImpl classes

Now, watch out for all those classes that end with "LogicImpl" in their names. These classes have been generated for you but will never be touched by the generator again. This is the place where you can implement your own logic.

Watch out for the "//TODO" tags in the files. You will notice that getters for attributes and associations are there to be filled by hand. This is the place where the facade does its work - you will want to refer to the contents of the metaobject that is shielded by this facade and translate it in some way so that you can return it from one of those getters. Operations in the metafacade model are translated to abstract Java methods - you will also want to implement these in the LogicImpl class.

The role of the metafacade factory

//TODO: Describe how to create new metafacade objects and how the factory knows which one to instantiate, depending on stereotype and context.

//TODO: Insert reference to Configuring metafacades so that we explain everything only once.

Returning references to other metafacades

//TODO: Describe how to shield a metaobject with a metafacade object.

Accessing metafacade namespaces

//TODO: Describe how to get parameters from the metafacade's namespace in order to control code generation.

Deploy the metafacades with your cartridge

After you have modeled, generated and implemented your metafacades, you can deploy them with your cartridge. To make this work, you need to configure an XML file. Read Configuring metafacades to see how to make AndroMDA use your metafacades at the right time.