Like I said here we are evaluating Mule to see if we can use it in our situation. One of the things we must do with Mule is to call our business services that are implemented by EJB3 classes based on a message that was put on a JMS topic. To my surprise this isn't a standard thing in Mule (the creators of Mule want to be JDK1.4 compliant, so there is no room for standard support EJB3, as far as I understand it).
After some searching I came up with several possible solutions of which I think the next one is the best (at least in our situation):

  • Create the EJB3 bean
  • Of course, you have to build the EJB3 beans that implement your business services. I have the following interface:

    JAVA:
    1. package net.pascalalma.mule.ejb;
    2.  
    3. import javax.ejb.Remote;
    4.  
    5. public interface SquareRemote
    6. {
    7.     public Integer calculate(Integer number);
    8. }

    and this implementating class:

    JAVA:
    1. package net.pascalalma.mule.ejb;
    2.  
    3. import javax.ejb.Stateless;
    4.  
    5. @Stateless
    6. public class SquareBean implements SquareRemote
    7. {
    8.    public Integer calculate(Integer number)
    9.     {
    10.         return number * number;
    11.     }
    12. }

  • Create Mule Config
  • In a separate Maven module I defined my Mule config file. To create this module I make use of a specific Maven archetype for Mule projects as I described here.
    This is my Mule Config file:

    XML:
    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <mule xmlns="http://www.mulesource.org/schema/mule/core/2.2"
    3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4.     xmlns:spring="http://www.springframework.org/schema/beans"
    5.     xmlns:jee="http://www.springframework.org/schema/jee"
    6.     xmlns:vm="http://www.mulesource.org/schema/mule/vm/2.2"
    7.     xsi:schemaLocation="
    8.        http://www.mulesource.org/schema/mule/core/2.2 http://www.mulesource.org/schema/mule/core/2.2/mule.xsd
    9.        http://www.mulesource.org/schema/mule/vm/2.2 http://www.mulesource.org/schema/mule/vm/2.2/mule-vm.xsd
    10.        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
    11.        http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd">
    12.  
    13.     <spring:beans>
    14.         <jee:remote-slsb id="squareEJB" jndi-name="net.pascalalma.mule.ejb.SquareRemote"
    15.                          business-interface="net.pascalalma.mule.ejb.SquareRemote">
    16.             <jee:environment>
    17.                 java.naming.factory.initial=org.apache.openejb.client.LocalInitialContextFactory
    18.                 java.naming.provider.url=rmi://localhost:1099
    19.                 openejb.jndiname.format={interfaceClass}
    20.             </jee:environment>
    21.         </jee:remote-slsb>
    22.     </spring:beans>
    23.  
    24.     <model name="main">
    25.         <service name="EjbCall">
    26.             <inbound>
    27.                 <vm:inbound-endpoint path="square" synchronous="true" />
    28.             </inbound>
    29.              <component>
    30.                 <spring-object bean="squareEJB"/>
    31.             </component>
    32.         </service>
    33.     </model>
    34. </mule>

    As you see I added a spring-bean definition. With this, I create a 'Spring' wrapper around my EJB3 class and that wrapper is used lateron in the config to inject the component in Mule.
    In the configuration of the Spring bean I set up my initial context for OpenEJB in this case, because that is where this set up will be tested with. I also set the jndiname format property, so it matches the format that is used in Glassfish which is our application server in the 'real' world.

  • Create test class
  • In the test class we will run Mule as a standalone process by using the MuleClient object. And we will put a value on the inbound endpoint of our defined service, like this:

    JAVA:
    1. package net.pascalalma.mule.mathservice;
    2.  
    3. import org.mule.api.MuleMessage;
    4. import org.mule.module.client.MuleClient;
    5. import org.mule.tck.FunctionalTestCase;
    6.  
    7. public class MathServiceTestCase extends FunctionalTestCase {
    8.  
    9.     protected String getConfigResources() {
    10.         return "mule-config.xml";
    11.     }
    12.  
    13.     public void testMathService() throws Exception {
    14.         MuleClient client = new MuleClient();
    15.  
    16.         MuleMessage result = client.send("vm://square", new Integer(5), null);
    17.  
    18.         assertNotNull(result.getPayloadAsString());
    19.         assertEquals("25",result.getPayloadAsString());
    20.     }
    21. }

  • Add OpenEJB3.1 to pom
  • We will deploy the EJB in OpenEJB at runtime so we need the OpenEJB depencies with the 'test' scope. Here is the snippet of the pom.xml:

    XML:
    1. <dependency>
    2.             <groupId>org.apache.openejb</groupId>
    3.             <artifactId>openejb-core</artifactId>
    4.             <version>3.1</version>
    5.             <scope>test</scope>
    6.             <exclusions>
    7.                 <exclusion>
    8.                     <groupId>commons-lang</groupId>
    9.                     <artifactId>commons-lang</artifactId>
    10.                 </exclusion>
    11.             </exclusions>
    12.         </dependency>

    As you can see I make use of OpenEJB3.1 instead of OpenEJB1.0 that is used with the supplied examples in Mule (to use the 3.1 version you must exclude the commons-lang dependency to avoid a NoSuchMethodError).
    The complete pom can be found here.

  • Add ejb-jar.xml
    To have our EJB3 classes deployed in OpenEJB I added an empty ejb-jar.xml to the classpath by adding the file to the /test/resources/META-INF directory. Here is a snippet of my project in Netbeans:
  • Test the project
  • Now you can perform a mvn clean install to test your Mule configuration. You will get a result like this:

    -------------------------------------------------------
    T E S T S
    -------------------------------------------------------
    Running net.pascalalma.mule.mathservice.MathServiceTestCase

    ========================================================================
    = Testing: math service (net.pascalalma.mule.mathservice.MathServiceTestCase) =
    ========================================================================
    Apache OpenEJB 3.1 build: 20081009-03:31

    http://openejb.apache.org/

    Result: 25

    Results :

    [jar:jar]
    Building jar: /Users/pascal/projects/mathService/target/mathservice-1.0-SNAPSHOT.jar
    [install:install]
    Installing /Users/pascal/projects/mathService/target/mathservice-1.0-SNAPSHOT.jar to /Users/pascal/.m2/repository/net/pascalalma/mule/mathservice/1.0-SNAPSHOT/mathservice-1.0-SNAPSHOT.jar
    ------------------------------------------------------------------------
    BUILD SUCCESSFUL
    ------------------------------------------------------------------------
    Total time: 19 seconds
    Finished at: Sat Mar 28 15:30:13 CET 2009
    Final Memory: 27M/48M
    ------------------------------------------------------------------------