So, to sum it up, I've spent a lot of time recently with Mule 3. In doing so, I came to appreciate one of the nice "themes" of Mule 3.0: the reduction of configuration noise. Annotation support is a feature that particularly reinforces this. I refactored a couple of services that were using a Quartz inbound-endpoint to instead use the new @Schedule annotation. Here's what I did, hopefully it will illustrate how the XML configuration is cut down by some of the new annotations.
The service in question was responsible for executing a configurable command on the system and sending the output to an FTP server. An additional requirement is that the filename on the FTP server needs to have the timestamp of the command execution embedded in it.
Here's how I refactored the implementation to use Mule 3 annotations. First off, here's the service class:
/**
* Simple facility to run a system command and return the output as a String.
*/
public class CommandRunner {
String command;
@Schedule(interval = 5000)
public String runCommand(@OutboundHeaders Map<String, Object> outHeaders) throws Exception {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
PumpStreamHandler streamHandler = new PumpStreamHandler(outputStream, System.out);
CommandLine commandLine = CommandLine.parse(command);
DefaultExecutor executor = new DefaultExecutor();
executor.setStreamHandler(streamHandler);
int exitValue = executor.execute(commandLine);
if (exitValue < 0) {
throw new RuntimeException("Error running: " + command);
}
outputStream.close();
outHeaders.put("COMMAND_TIME_STAMP",new Date().getTime());
return new String(outputStream.toByteArray());
}
public void setCommand(String command) {
this.command = command;
}
}
The @Schedule annotation invokes the "runCommand" method every 5 seconds. Note that there is a Map being passed as the argument to runCommand(). This is annotated with @OutboundHeaders, indicating the contents of this map will be available as message properties on the outbound endpoint. We'll use this to set the COMMAND_TIME_STAMP header to contain the timestamp the command was run. That's it from the Java side. Let's see how this is wired up in the XML config:
<model name="Integration Services">
<service name="CLI to FTP Service">
<component>
<spring-object bean="commandRunner"/>
</component>
<outbound>
<pass-through-router>
<ftp:outbound-endpoint user="${ftp.user}"
password="${ftp.password}"
host="${ftp.host}"
port="${ftp.port}"
path="${ftp.path}"
outputPattern="#[header:COMMAND_TIME_STAMP].txt">
</ftp:outbound-endpoint>
</pass-through-router>
</outbound>
</service>
</model>
Using the @Schedule annotation eliminates the need for explicitly configuring an inbound-endpoint, which is missing from the above. We also don't need to jump through hoops with the MuleMessage in either the service class or with message-properties-transformers to use the COMMAND_TIME_STAMP to name the FTP file.
As I mentioned in my diatribe about implementing component classes, I prefer to avoid implementing Callable on my components. I find doing so couples the code too tightly to the Mule runtime. Using the annotations allows you to implement functionality previously required by getting at the MuleContext without extending or implementing a Mule class. This is a best-of-both-worlds scenario. Your component code can still stay decoupled from Mule, to ease unit testing, while indirectly giving you access to common pieces of the MuleContext (ie, the message payload, inbound and outbound headers, etc.)
So the annotation support, for me, is a welcome addition to the available configuration options. In addition to reducing XML noise it also streamlines integrating POJO's with the message flow.
The improved jBPM support on Mule 3 is another feature I'm excited about. For one reason or another, jBPM has been a constant in practically every Mule project I've worked on in the last year. I'll cover that in the next post.
4 comments:
Great post, thanks for sharing :)
You could have even less XML by using a flow construct, a configuration element newly introduced in Mule 3.
Trying again...
John thanks fos sharing. If you did use flow as David suggests you can almost half the amount of XML needed - http://pastebin.com/XQc3nh1D
Nice, thanks for the tip guys. I haven't had a chance to try out the flow stuff yet - looks very promising...
Post a Comment