Archive
Mule 3 Deployment Gotchas / Workarounds
Mule is an open source enterprise service bus written in Java. I’ve worked with Mule 2.2 quite a bit but only recently have started to work with Mule 3. This post details some of the pains involved with the transition, none of which are well documented or hinted at in the Migration guide.
Gotchas/Workarounds
Mule IDE specific
The Mule IDE is really a misnomer – it’s not a standalone product, but instead an Eclipse plugin. See the installation guide for more information.
XML validation warnings
By default, Eclipse 3.5 will flag all sorts of spurious errors in your XML configuration file. See the blog post for more details, but here’s the short version on how to solve it:
General
These issues exist whether you use the IDE to deploy the app or deploy the app via the command line.
Failure to launch / Timeouts
Mule is configured via XML. You must declare the namespaces and schema locations in order to make use of the built-in Mule constructs. For instance, here’s a snippet of one of my Mule configurations:
<mule xmlns="http://www.mulesoft.org/schema/mule/core" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:spring="http://www.springframework.org/schema/beans" xmlns:vm="http://www.mulesoft.org/schema/mule/vm" xmlns:script="http://www.mulesoft.org/schema/mule/scripting" xmlns:http="http://www.mulesoft.org/schema/mule/http" xmlns:cxf="http://www.mulesoft.org/schema/mule/cxf" xmlns:xm="http://www.mulesoft.org/schema/mule/xml" xmlns:pattern="http://www.mulesoft.org/schema/mule/pattern" xmlns:servlet="http://www.mulesoft.org/schema/mule/servlet" xmlns:jetty="http://www.mulesoft.org/schema/mule/jetty" xmlns:test="http://www.mulesoft.org/schema/mule/test" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/3.1/mule.xsd http://www.mulesoft.org/schema/mule/http http://www.mulesoft.org/schema/mule/http/3.1/mule-http.xsd http://www.mulesoft.org/schema/mule/cxf http://www.mulesoft.org/schema/mule/cxf/3.1/mule-cxf.xsd http://www.mulesoft.org/schema/mule/scripting http://www.mulesoft.org/schema/mule/scripting/3.1/mule-scripting.xsd http://www.mulesoft.org/schema/mule/pattern http://www.mulesoft.org/schema/mule/pattern/3.1/mule-pattern.xsd http://www.mulesoft.org/schema/mule/xml http://www.mulesoft.org/schema/mule/xml/3.1/mule-xml.xsd http://www.mulesoft.org/schema/mule/vm http://www.mulesoft.org/schema/mule/vm/3.1/mule-vm.xsd http://www.mulesoft.org/schema/mule/servlet http://www.mulesoft.org/schema/mule/servlet/3.1/mule-servlet.xsd http://www.mulesoft.org/schema/mule/test http://www.mulesoft.org/schema/mule/test/3.1/mule-test.xsd http://www.mulesoft.org/schema/mule/jetty http://www.mulesoft.org/schema/mule/jetty/3.1/mule-jetty.xsd" >
Make absolutely sure that the version of the xsd that you include matches the major version of mule that you’re using! If you accidentally place a 3.0 instead of a 3.1 in any of those entries, your app will mysteriously fail to launch and you’ll get a stack trace like the following:
INFO 2011-06-09 17:21:20,015 [main] org.mule.MuleServer: Mule Server initializing...
INFO 2011-06-09 17:21:20,298 [main] org.mule.lifecycle.AbstractLifecycleManager: Initialising RegistryBroker
INFO 2011-06-09 17:21:20,355 [main] org.mule.config.spring.MuleApplicationContext: Refreshing org.mule.config.spring.MuleApplicationContext@19bb5c09: startup date [Thu Jun 09 17:21:20 EDT 2011]; root of context hierarchy
WARN 2011-06-09 17:22:36,265 [main] org.springframework.beans.factory.xml.XmlBeanDefinitionReader: Ignored XML validation warning
java.net.ConnectException: Operation timed out
at org.apache.xerces.util.ErrorHandlerWrapper.createSAXParseException(Unknown Source)
at org.apache.xerces.util.ErrorHandlerWrapper.warning(Unknown Source)
at org.apache.xerces.impl.XMLErrorReporter.reportError(Unknown Source)
at org.apache.xerces.impl.XMLErrorReporter.reportError(Unknown Source)
at org.apache.xerces.impl.xs.traversers.XSDHandler.reportSchemaWarning(Unknown Source)
at org.apache.xerces.impl.xs.traversers.XSDHandler.getSchemaDocument1(Unknown Source)
at org.apache.xerces.impl.xs.traversers.XSDHandler.getSchemaDocument(Unknown Source)
at org.apache.xerces.impl.xs.traversers.XSDHandler.parseSchema(Unknown Source)
at org.apache.xerces.impl.xs.XMLSchemaLoader.loadSchema(Unknown Source)
Deploying via command line
While it’s nice to be able to use an IDE to develop Mule applications, I prefer to deploy from the command line. This allows me to script the launch of the applications. Furthermore, this approach works in a headless (screenless) remote server, whereas the IDE approach will not. The basic way to deploy an app has changed from Mule 2.2 to Mule 3. It used to be that you would call mule -config /path/to/your/config.xml
. Now you move your application to the $MULE_HOME/apps
folder and run mule
, which in turn will deploy all the apps in the apps
folder. This can be very handy, especially when coupled with the Hot Deployment features of Mule; you no longer need to have one terminal per mule app you’re running. From the article, “Mule 3: A New Deployment Model”, here are the ostensible steps you must take to deploy your application in this manner:
- Create a directory under: $MULE_HOME/apps/foo
- Jar custom classes (if any), and put them under: $MULE_HOME/apps/foo/lib
- Put the master Mule config file at: $MULE_HOME/apps/foo/mule-config.xml (note that it has to be named: mule-config.xml
- Start your app with: mule -app foo
While these instructions are correct, there are a lot of gotchas involved. Let me detail them below.
Relative paths
There is often a need to make reference to resources within your configuration file. For instance, you might need to configure an embedded Jetty webserver and tell Jetty where its configuration file is located. When you do this, it’s crucial that you prepend relative paths in the XML configuration file with ${app.home}
.
The reason for this is that the current working directory in which you launch the mule
process becomes the current working directory for all of your application configuration files. So if you have mule-config.xml
in the root of your folder, and conf/jetty.xml
in that same folder, then your reference to the jetty.xml
should be ${app.home}/conf/jetty.xml
. Otherwise, if you just use conf/jetty.xml
and launch mule from a folder that’s not the same as the root folder of your application, all of your paths will break.
Property files / Resources
As the step #2 above says, you must jar up all of your compiled classes and include them in the lib folder of your project. If you don’t do this, you’ll get an exception when your component / custom classes are attempted to be instantiated.
What should be emphasized is that all resources that you reference from within your code must end up in the jar as well. By default, that won’t happen. You can use something like the solution presented in Ant Build: copy properties file to jar file to get this to happen.
Unintentional Application Deletion
When you deploy an app by copying a zip or folder into the apps directory and then running mule, Mule will launch it and then create a text file called ‘$APP_NAME-anchor.text’. If you delete this file, Mule will “undeploy this app in a clean way”. What isn’t noted by this is that it will delete the corresponding zip/folder. So be careful not to accidentally delete your whole project. (Not that I did that or anything).
JDBC drivers problems
One nice feature of the hot deploy process is that Mule will automatically load all of the jars in the lib
folder and ensure that they’re on the classpath. Unfortunately there is an extremely annoying problem with JDBC drivers, in which they corresponding jar will be loaded correctly, but then will fail to be found at runtime.
At startup:
Loading the following jars:
=============================
file:/opt/local/Mule/mule-standalone-3.1.1/apps/XMLPlayer/lib/mysql-connector-java-5.1.13-bin.jar
=============================
<!-- snip -->
WARN 2011-06-09 15:56:12,130 [http://XMLPlayer].connector.http.mule.default.receiver.2 org.hibernate.cfg.SettingsFactory: Could not obtain connection to query metadata
java.sql.SQLException: No suitable driver found for jdbc:mysql://localhost:3306/db
The exact same project works perfectly in the Mule IDE. The only solution I’ve found is to copy the mysql-connector-java-5.1.13-bin.jar
into $MULE_HOME/lib/endorsed
. There is a similar bug report but it was closed for some reason. It most certainly does not work the way you would intuitively expect.
Conclusion
Mule 3 has many improvements over Mule 2, particular with the introduction of Flows. Unfortunately, deployment is a much tricker problem than it was in Mule 2, and the resources online are woefully inadequate for the task at hand. I hope this blog post helps some poor soul going through the same frustration I went through to get a Mule 3 application deployed.
Embed a Jetty file server within Mule 3.1.1
This post details how to embed a Jetty webserver within Mule, such that static files hosted within your application are accessible to the outside world. The resources describing how to do this are few and far between; I also found them erroneous. For some reason, any time I include a test:component element in my Mule configuration files, I get a timeout. By eliminating that piece, I got things to work.
These config files assume that both jetty.xml
and mule-config.xml
are located in the same folder, namely conf
.
mule-config.xml
<mule xmlns="http://www.mulesoft.org/schema/mule/core" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:spring="http://www.springframework.org/schema/beans" xmlns:http="http://www.mulesoft.org/schema/mule/http" xmlns:xm="http://www.mulesoft.org/schema/mule/xml" xmlns:jetty="http://www.mulesoft.org/schema/mule/jetty" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/3.1/mule.xsd http://www.mulesoft.org/schema/mule/http http://www.mulesoft.org/schema/mule/http/3.1/mule-http.xsd scripting.xsd http://www.mulesoft.org/schema/mule/xml http://www.mulesoft.org/schema/mule/xml/3.1/mule-xml.xsd http://www.mulesoft.org/schema/mule/jetty http://www.mulesoft.org/schema/mule/jetty/3.1/mule-jetty.xsd" > <description> This configuration uses an embedded Jetty instance to serve static content. </description> <jetty:connector configFile="${app.home}/conf/jetty.xml" name="jetty_connector" ></jetty:connector> <!-- do not use localhost here or you will not be able to access the server except locally.--> <jetty:endpoint address="http://0.0.0.0:8080" name="jettyEndpoint" connector-ref="jetty_connector" path="/"> </jetty:endpoint> <model name="Jetty"> <service name="jettyUMO"> <inbound> <jetty:inbound-endpoint ref="jettyEndpoint" /> </inbound> </service> </model> </mule>
jetty.xml
Modified from Newbie Guide to Jetty, namely changing class names (the classes in question are bundled with Mule 3.1.1, in the Jar file found in $MULE_HOME/lib/opt/jetty-6.1.26.jar
).
<?xml version="1.0"?> <!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd"> <Configure id="FileServer" class="org.mortbay.jetty.Server"> <Set name="handler"> <New class="org.mortbay.jetty.handler.HandlerList"> <Set name="handlers"> <Array type="org.mortbay.jetty.Handler"> <Item> <New class="org.mortbay.jetty.handler.ResourceHandler"> <!-- Jetty 6.1.26, which comes with Mule 3.1, does not have this method --> <!--<Set name="directoriesListed">true</Set>--> <Set name="welcomeFiles"> <Array type="String"> <Item>index.html</Item> </Array> </Set> <!-- This folder maps to the root URL configured for this Jetty endpoint. If I wanted to start serving content from the a folder named "static", I would replace the . with "static".--> <Set name="resourceBase">.</Set> </New> </Item> <Item> <New class="org.mortbay.jetty.handler.DefaultHandler" /> </Item> </Array> </Set> </New> </Set> </Configure>
A gist with both of these code snippets can be found here.
Conclusion
With these two configuration files, you can launch an embedded instance of Jetty within your application, and use it to serve static content. Due to a limitation in the version of Jetty 6.1.26 which Mule 3.1.1 comes with, you cannot use the Jetty instance to list the contents of folders; instead the client must know the absolute path to the file. For my purposes this was not a problem.
How to use Java .properties files in Mule
Externalizing ports and IP addresses (or anything else for that matter) in Mule
Mule is a great piece of open source software known as an Enterprise Service Bus. It is designed to make it easy to integrate various systems which were not explicitly built to work with each other. For instance, it handles all the details of various transport mechanisms (e-mail, HTTP, TCP, UDP, files) that your data might be shuttled around in, as well as the transformers that convert data from one format to another (e.g., the bytes of a TCP packet, into a String, into an XML document, into a Java object representing that XML).
Mule services are configured via XML, in particular the Spring framework. This post is designed to inform the reader as to how to incorporate Java .properties files into the XML.
.properties files, for those who are unfamiliar, is a simple Key=Value storage mechanism in widespread use in Java development. From the wikipedia explanation, here are a few lines of a .properties file:
website = http://en.wikipedia.org/
language = English
# The backslash below tells the application to continue reading
# the value onto the next line.
message = Welcome to \
Wikipedia!
The documentation for Mule / Spring advises that you break up configuration files into multiple files and then reassemble them as needed. In Mule’s case, this allows you to run one instance of mule per small function, allowing you to restart just the piece that needs to when a change is made, rather than bringing down all the pieces. Furthermore it makes it easy to reason about each modular piece when broken down in this way.
Unfortunately, splitting the files up like this can easily cause a lot of duplication, especially of IP addresses and ports. If you are sending objects to the same IP address and port from multiple configuration files, you might end up with multiple instances of lines of configuration like
tcp:inbound-endpoint address="tcp://192.56.33.21:235"
Fortunately, by storing the IP addresses and ports in .properties file, you can eliminate code duplication and allow the variables to be changed in a single place and have the change reflected in all files referencing these variables. Additionally, if you name the variables properly, the impenetrable IP addresses instead become self documenting strings:
tcp:inbound-endpoint address="${email.server.address}"
This ${x}
syntax should be familiar to anyone who has used Ant in the past. This basically says, find the property with the key email.server.address
and textually substitute its value here. This assumes that you have a .properties file with the line
email.server.address=tcp://192.56.33.21:235
For the purposes of this post, assume that the line is defined in a file called test.properties.
Unfortunately, the way to do this is not clearly defined in any document I’ve seen, which is why I want to explain how to do it here.
Existing information
The first result in google for “mule java properties” is Mule: Configuring Properties, which is 5 years old and refers to Mule 1.5 (I figured this out the hard way). There is more up to date information by searching for “configuring properties”, particularly Configuring Properties – Mule 2.x User Guide.
Here is the relevant information:
To load properties from a file, you can use the standard Spring element
:
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd"
<context:property-placeholder location="smtp.properties"/>
(In other words you need to add those schema declarations at the top of your file, after the description field, before creating a context:property-placeholder
element to tell Mule all the .properties files you want pulled in to your file).
Would that it were so easy.
If you change this example to the name of your .properties file, you will probably get a FileNotFoundException, even if you give the complete path to the .properties file.
A Fatal error: class path resource [C:/Mule/mule-standalone-2.2.1/conf/test.properties] cannot be opened because it does not exist
This message is extremely unhelpful because the file does exist at that exact location. After some digging, I found two workarounds, one of which is hinted at by the error message, another is not.
Classpath
By default, the .properties file is searched for in the classpath that the Mule environment runs in. Thus you need to ensure that the folder in which your test.properties file is located in is also on that classpath.
The wrapper.conf
file in $MULE_HOME/conf is where the classpath is defined:
wrapper.java.classpath.1=%MULE_LIB%
wrapper.java.classpath.2=%MULE_EXE%/../conf
wrapper.java.classpath.3=%MULE_HOME%/lib/boot/*.jar
If you place your .properties files in any of those folders, it will be picked up. That’s probably not the ideal place for your files, however. If you wish to add an additional folder, you merely add another entry. For instance, if I store the .properties files in /Dev/Mule/Configs/Properties, I would add the line
wrapper.java.classpath.4=/Dev/Mule/Configs/Properties
Note that you must add the consecutive numbers to each classpath you add, or Mule will not pick up on the change correctly.
You can make it explicit to the readers of your configuration file that you are including a .properties file that’s located on the classpath with the classpath prefix:
<context:property-placeholder location="classpath:test.properties">
Absolute locations
If you wish to specify the absolute path to a resource rather than relying on classpath resolution, you must prefix the path with file///
. So our previous example becomes
<context:property-placeholder location="file///Dev/Mule/Configs/Properties/test.properties">
(You also need 3 slashes even if you’re on Windows)
Conclusion
It’s a very good idea to externalize ports and IP addresses from the XML configuration files that Mule needs to run. This allows you to make changes to the ports and IP addresses in one place rather than in all the files that reference them. It also allows you to associate a more meaningful name to the addresses than an IP address; it is self-documenting in that regard. Unfortunately the process for importing .properties files into your Mule configuration files is not well documented, which is what I am attempting to remedy here.