Wednesday, February 9, 2011

Hello Mule

So, you are a sort of Java programmer (meaning you can develop simple applications using NetBeans or Eclipse), you are looking for an open source ESB and Mule looks promising; you do not want to waste your time reading tons of documentation but just start in the most effective way evaluating Mule, addressing your concerns about being able to solve yourself the problems (inevitably) you will  face in real life. Then this post might be helpful.
As I also did I suppose you started reading the book ("Mule in Action") . After 20 pages you gave up and changed strategy: downloaded latest Mule distribution, along with source code (of course, we are programmers and "code is the model") and start analyzing samples. Surprise, samples look very different from what you already learned from the book so you go on Mule site: of course, latest major release changed the approach going for flows instead of services (looks familiar for open source projects?). At this point you run out of ideas how to tackle the problem in an effective way but you are still confident in Mule, so let me provide  some help!
Let's start defining the approach: we will try to extend some Mule functionality so that we get familiar with code and concepts; for some reason I don't remember I choose to focus on FTP transport so I quickly wrote a sample using ftp endpoint to read files from Microsoft site (!) and store it on local HDD:
<flow name="FTP input">
               <ftp:inbound-endpoint user="anonymous" password="123456"
                                host="ftp.microsoft.com" path="/developr/rfc/wfw" port="21">
                        <file:filename-wildcard-filter pattern="*.386,*.xml" />

              </ftp:inbound-endpoint>

             <file:outbound-endpoint path="c:\temp"
                    outputPattern="#[header:originalFilename]__#[function:datestamp].txt">
            </file:outbound-endpoint>
  </flow>
(In order to run the sample install Mule, Eclipse and Mule IDE).
Running the sample we face our first problem: an IO exception is thrown, stating that Mule it's unable to delete the source file (of course, MS site is read only); thus we found out several facts:
  • by default the ftp transport deletes the source file after successfully processing it
  • some options that looks very valuable in real life projects are not available in community edition (like fileAge and moveTo..)
OK, finally we found a real challenge: extending community edition transport with functionality from enterprise edition. To be able to do this we will have to setup our development environment (this might by no means be the ideal solution but it was the quickest I found):
  • Install also NetBeans
  • Create a project using Maven Project template
  • Edit pom.xml and add the flowing XML snippet:
    <dependency>
      <groupId>org.mule.transports</groupId>
      <artifactId>mule-transport-ftp</artifactId>
      <version>3.1.0</version>
      <scope>compile</scope>
    </dependency>
By compiling the project you will get added all the Mule and depending on jars ; after that you can use the "Download Source" option (right click on Libraries folder)to have access to source code.
First thing we have to do is define the schema for our extension; we will use ftpext as our target namespace. We will add the three missing attributes:
  • fileAge
  • moveToDirectory
  • moveToPattern
Yes, you are right, I forgot to tell you where from you can download sources: https://mule-ftpext.googlecode.com/svn/trunk/
The schema must  be located in src\main\resources\META-INF directory together with spring.handlers and spring.schemas property files (we will briefly describe them lately).
Since the schema must be located somewhere Mule can read it I choose to host it in IIS (yes, I am am using Windows...) at http://localhost/schemaftpext/mule-ftpext.xsd. In order for Mule to know about our extension we have to edit accordingly:
  • spring.handlers, that associates with our schema URI the namespace handler (we'll speak about later)
  • spring.schemas that specify the location for the XSD
Mule uses Spring Beans (former Spring Configuration?) to parse configuration files and, based on attached schemes populate Java Beans properties; in order to be able to carry out this task it needs schema handlers to be registered in spring.handlers property files included in jars that need to benefit from this service (see \src\org\mule\config\spring\handlers\MuleNamespaceHandler.java for a more complex sample). Our namespace handler (aka org.mule.transport.ftpext.config.FtpExtNamespaceHandler) will be used to parse ftpext namespace constructs. Since we are targeting inbound endpoint (so far) we will need to have our own specialised calsses as follows:

  • FtpExtConnector extending FtpConnector; this class will host the properties for the newly attributes we have defined (fileAge and so on); also getProtocol method needs overriden in order to return our schema (ftpext) and not ftp as base class does;
  • FtpExtMessageReceiver extending FtpMessageReceiver; this class will overide some methods in order to cope with added functionality;
  • FtpExtUrlEndpointURIBuilder extending FtpUrlEndpointURIBuilder; we need setEndpoint method overriden in order to generate addresses with ftp:// protocol prefix (the default implementation uses the schema as protocol specification and we will end up with addresses like ftpext://..)
The mail logic of our extension is located in FtpExtMessageReceiver:
  • listFiles will return only files obeying the fileAge condition (if specified)
  • postProcess method will deal with file moving if moveTo... attributes are specified
Let's switch to our test environment, Eclipse. I suppose you have already created a test Mule project )also adding a configuration file). At this point you can add reference to our ftpext jar (built with NetBeans).

Several tricks:
  • you can associate sources to classes we have mentioned above (FtpExt...) by double clicking on the class name (in library content) and then selecting the sources folder (this worked differently every time I used it but finally you will be able to pick up the right folder :-)); after rebuilding jar in NetBens  close all sources related to FtpExt you suppose to debug, refresh the library (by pressing F5 for instance) and reopen the desired source (otherwise you will not be able to see latest changes);
  • When doing changes to XSD file(s) go to Window->Preferences->General->Network Connections->Cache and remove the modified entries; unless you do this Eclipse will not see the changes;
  • You can also navigate into Mule source code from Eclipse by just opening the Mule Libraries tree, locating the class and double clicking on it; you can set breakpoints or jump to definitions by highlighting (selecting) items and pressing F3;
So, enough for now! In some next post we will analyze problems we will face in real life projects as well as the solutions we can adopt (as you can see the sources are far more complex than the extension we have talked requires); fortunately it proves that Mules has been designed for extensibility so our programming capabilities will not rust (in peace...if you know what I mean).