In this blog post I will show how to extend Mule in a simple way using the recently released Mule DevKit. The goal of the Mule DevKit is to accelerate the development of Mule extensions by abstracting you from Mule specific stuff so that you just focus on what your are trying to build.
My idea here is to create a simple Cloud Connector to interact with Google Maps API but the concepts covered here can be used in other scenarios as well. Since the Mule DevKit is intended for developers, expect many code snippets so that you can go through this example on your own and play around with the code. You can get the full source code here.
Setting up the project
Getting started is as simple as running a Maven archetype to get the project structure created:
After running the archetype simply import the project into your IDE. If you use Eclipse (including MuleStudio) just remember to run mvn eclipse:eclipse to get your project set up correctly.
The central piece of the generated project is the GoogleMapsModule class:
Note: javadoc comments were removed for clarity
Import things to notice:
- The class is annotated with @Module: classes annotated with @Module are to be exported as Mule modules.
- A method is annotated with @Processor: methods annotated with @Processor are invokable from Mule. You can annotate as many methods as you want. These methods can have any type and number of parameters and there is no restriction for the return type.
- A field is annotated with @Configurable: fields annotated with @Configurable can be assigned from Mule. You can annotate as many fields as you want and they can be of any type.
Let’s tweak the code a litte bit. Remember we want to interact with Google Maps API:
Basically the changes are:
- The @Configurable field distanceUnit: we want to tell Google Maps API the distance unit in which the distance should we expressed. Since there are only two possibilities (kilometers and miles) we use an enumerated type. The Mule DevKit provides special support for enums.
- The @Processor method getDistance: calls Google Maps API to get the distance between the places denoted by origin and destination.
To generate the Mule code automagically just run: mvn clean compile
Testing the new Connector
We have everthing set up, now it’s time to test our code. A test class called GoogleMapsModuleTest has been created when the archetype was executed and it contains convenience methods to easily write tests that exercise your Cloud Connector from a Mule’s perspective. We need to change the mule-config.xml file located in src/test/resources in order to invoke our method getDistance:
A couple of things to remark:
- A namespace has been declared for our new Connector with the prefix googlemaps. Behind the scenes the Mule DevKit generated a schema file that will allow us to take advantage of some of the IDE features, like autocomplete and xml validation.
- An element config appears outside a flow: this element must be present in order to configure our connector. Even of the connector had no configurable fields, an empty config element must still be there.
- A flow that invokes the get-distance Message Processor: this Message Processor is responsible -among other things- for calling our Java method annotated with @Processor. Notice that the Message Processor name is slightly different from our Java method: all letters are now lower case and words are splitted with a dash character.
We are ready to run GoogleMapsModuleTest which has a single test that will exercise the flow ‘testFlow’. Let’s say we know beforehand the distance between Milbrae and San Francisco is 23.8 km so we open GoogleMapsModuleTest change the test ‘testFlow’:
The test passes. Nice!
Let’s add a few more changes to our Connector:
By adding the @Optional annotation, specifying a value for the parameter origin is not mandatory. The @Default annotation is used together with @Optional, and provides a default value for a parameter when is not stated explicitly. So in this case, if an invocation does not specify the origin then the distance should be calculated from San Francisco. Therefore, these two invocations are valid and equivalent:
Though this example might seem trivial I think it clearly demonstrates the power of the Mule DevKit: using a few annotations can turn any regular POJO into a Mule extension without writing a single line of Mule specific code. In addition, what happens inside the @Processor annotated methods can vary from a simple HTTP request to Google Maps API to a much more complex interaction with 3rd party APIs -or an aggregation of calls- and yet you will be able to easily invoke it from Mule and get advantage of all the features Mule provides out of the box.
Also keep in mind that the Mule DevKit provides many more features than the ones covered in this blog post: support for streaming APIs, automatic connection management, support for complex collections, automatic documentation generation, just to mention a few. We’ll keep blogging about these in the future but you can also take a look at the Mule DevKit’s documentation.
We would love to hear your comments/thoughts about the Mule DevKit. Feel free to post any questions or comments here or in our forums.