Last week I posted about Writing Mule Transformers, this week I’m going to continue with some more advanced features users can take advantage of.
Lifecycle
All objects in Mule have lifecycle associated with them. Lifecycle calls can be added as necessary. For transformers, there are two lifecycle methods that are most useful.
By default the AbstractEventAwareTransfromer and AbstractTransformer both implement the org.mule.api.lifecycle.Initialisable interface. This means that once all bean properties are set on the transformer (if any) the doInitialise() method will be called. This is useful for transformers to do any initialization or validation work. For example, the transformer may need to load an external file resource in order to be able to perform its function, this should be done in the doInitialise() method.
Additionally, transformers may want to clear up resources when the transformer is no longer needed. To do this a transformer just needs to implement org.mule.api.lifecycle.Disposable and implement the dispose() method.
Discoverable Transformers
Mule has a nifty feature of being able to perform automatic transformations. The most common use of this is calling the getPayload() method on a MuleMessage passing in the required type i.e.
Document doc = (Document)muleMessage.getPayload(org.dom4j.Document.class);
This will tell Mule to look at the current payload type, and see if it can find a transformer that can convert it to an org.dom4j.Document object. Mule provides quite a few standard transformers for switching between common types such as Strings, byte[], InputStream, etc. Also, Transports usually have transformers for specific message types such as JMSMessage or HttpRequest.
To make a transformer discoverable it needs to implement the org.mule.api.transformer.DiscoverableTransformer. This interface introduces two methods-
public interface DiscoverableTransformer { int getPriorityWeighting(); void setPriorityWeighting(int weighting); }
The priority weighting is used to resolve conflicts when two or more transformers match the search criteria. The weighting is a number between 1 and 10, with 10 being the highest priority. As a rule, Mule transformers have a priority of 1 and should always have a lower priority than any custom transformers. Lets make our OrderToHtml transformer (from last week) discoverable-
public class OrderToHtmlTransformer implements AbstractMessageAwareTransformer , DiscoverableTransformer { private int weighting = DiscoverableTransformer. DEFAULT_PRIORITY_WEIGHTING + 1; int getPriorityWeighting() { return weighting; } void setPriorityWeighting(int weighting) { this.weighting = weighting; } }
Since this transformer converts from an Order object to a String, when Mule tries to discover a transformer the Mule-provided ObjectToString transformer will match as well as the ObjectToHtml transformer. However, the ObjectToHtml transformer has a higher priority weighting and will be used to do the transformation. To test this out, the following would work-
MuleMessage message = new DefaultMuleMessage(new Order(…)); String html = (String)muleMessage.getPayload(java.lang.String.class);
Making the Transformer Available
After creating the transformer, it needs to be registered so that Mule can discover the transformer at run-time. There are two ways of doing this.
Using Xml
If you are using XML configuration, you can just configure using a custom-transformer element, and Mule will discover it.
Bootstrapping the Registry
If you want your transformer to be loaded automatically by Mule when your module (JAR) is on the class path, you need to add a registry-bootstrap.properties file to your JAR under the following directory: /META-INF/services/org/mule/config.
The contents of the registry-bootstrap.properties should look something like this:
orderToHtml=com.foo.OrderToHtml
When Mule starts, it will discover this bootstrap file before loading any configuration and will install any objects listed in the file into the local registry. For more information, see Bootstrapping the Registry.