Tuesday, December 22, 2009

Mule JMS message routing using an external ActiveMQ instance

I have a scenario where I'd like Mule to monitor an incoming queue, filter the messages and route to appropriate outgoing queue--using a separate ActiveMQ instance instead of the optional embedded one. While perusing Google results I didn't find a source that explicitly showed how to accomplish this. So using what information I did find from indirect examples and other documentation, this is what I came up with.
First, the connection factory Spring bean:
 <spring:bean name="activeMQConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">  
   <spring:property name="brokerURL" value="tcp://${esb.jms.endpoint}"/>  

Since I have Maven filtering my resources, the actual tcp URI will be replaced with the appropriate environmental property--in my case, being in an active development environment, and using activeMQ 5.3.0, the filtered value would be "tcp://localhost:61616".

Next is the connector definition:
  <jms:connector name="JMSConnector"  
          connectionFactory-ref="activeMQConnectionFactory" >  

And finally, the endpoint:
 <jms:endpoint name="asynchIn" queue="asynch.in"/>  

The service definition for this simple case is:

 <service name="Asynchronous processing">  
     <inbound-endpoint ref="asynchIn" synchronous="false"/>  
      <stdio:outbound-endpoint system="OUT" name="debugTrace" connector-ref="SysOut"/>  
      <jms:outbound-endpoint queue="test.out" />  
      <message-property-filter pattern="JMSType=test"/>  
      <jms:outbound-endpoint queue="test2.out" />  
      <message-property-filter pattern="JMSType=test2"/>  

Notice that the inbound definition contains a wire-tap-router reference, this makes it much easier (IMO) to trace the message flow during development while defining the routing rules and generally tweaking things. Mule will send the message to sysout and also apply filter routing.

The filters generally speak for themselves, in the cases above the filters are based on the type of message.

To test the setup with a vanilla ActiveMQ install (stomp enabled and the stomp gem installed), this quick Ruby script works quite handily:
 require 'stomp'  
  Stomp::Client.open("stomp://localhost:61612").send("/queue/asynch.in","\n\n\n!!!!!!!!!!!!!!\ntest message\n!!!!!!!!!!!!!!!",{:persistent => true, :type => 'test'})  

Mule's wire-tap-router should dump the message:
 system out:ActiveMQBytesMessage {commandId = 3, responseRequired = false, messageId = ID:vsbeta-45609-1261505977249-4:104:-1:1:1, originalDestination = null, originalTransactionId = null, producerId = ID:vsbeta-45609-1261505977249-4:104:-1:1, destination = queue://asynch.in, transactionId = null, expiration = 0, timestamp = 1261518816945, arrival = 0, brokerInTime = 1261518816946, brokerOutTime = 1261518816946, correlationId = null, replyTo = null, persistent = true, type = test, priority = 0, groupID = null, groupSequence = 0, targetConsumerId = null, compressed = false, userID = null, content = org.apache.activemq.util.ByteSequence@7c66f0, marshalledProperties = org.apache.activemq.util.ByteSequence@4a4890, dataStructure = null, redeliveryCounter = 0, size = 0, properties = {content-type=text/plain; charset=UTF-8}, readOnlyProperties = true, readOnlyBody = true, droppable = false} ActiveMQBytesMessage{ bytesOut = null, dataOut = null, dataIn = null }INFO 2009-12-22 14:53:37,033 [JMSConnector.dispatcher.1] org.mule.transport.jms.JmsMessageDispatcher: Connected: endpoint.outbound.jms://test.out  

ActiveMQ's admin screen should show pending messages inside of the test.out or test2.out queues. Messages could be consumed via Stomp:
 require 'stomp'  
 client = Stomp::Client.open("stomp://localhost:61612")  
 client.subscribe("/queue/test.out"){|message| puts "consuming #{message.body} with properties #{message.headers.inspect}"}  

producing output:
 test message  
 !!!!!!!!!!!!!!! with properties {"MULE_ORIGINATING_ENDPOINT"=>"asynchIn", "content_type"=>"text/plain; charset=UTF-8", "MULE_CORRELATION_ID"=>"0f2295b0-ef45-11de-856a-538c667e24a7", "expires"=>"0", "timestamp"=>"1261519075346", "destination"=>"/queue/test.out", "message-id"=>"ID:Rohirrim.local-51739-1261518810672-0:0:7:1:1", "priority"=>"4", "MULE_SESSION"=>"SUQ9MGYyMjk1YjEtZWY0NS0xMWRlLTg1NmEtNTM4YzY2N2UyNGE3", "content-length"=>"46", "MULE_MESSAGE_ID"=>"ID:vsbeta-4  
 5609-1261505977249-4:117:-1:1:1", "correlation-id"=>"0f2295b0-ef45-11de-856a-538c667e24a7", "MULE_ENCODING"=>"UTF-8", "MULE_ENDPOINT"=>"jms://test.out"}=> nil  

This approach enables a single queue to collect asynchronous message requests and leverage Mule's filtering-routers to decouple the producer and consumer. The requests go on the ESB, Mule defines where they should go, and the service components act and process the request independent of the requester.

Thursday, December 10, 2009

We chose Mule for our ESB

After careful consideration of multiple open-source ESB products, Mule made the most sense for implementation into our data information infrastructure. The other major competing providers were OpenESB(GlassFish v3), FUSE (Apache stack) as having an open-source solution was a very strict requirement. Mule is very component oriented and can be quickly setup for integration with existing services (of which we have several). Furthermore, it is Spring-based and supports Maven -- which fits right into our existing application development

Mule has many strong points, the most relevant for our decision being:

  • very mature, years of development and major deliveries

  • a solid installation base across many significant enterprises

  • well-documented with excellent examples and diagrams

  • is open-source (CPAL 1.0)

  • a commercial support model with additional tools (service registry,monitoring)

  • flexible configuration and instantiation options

  • wide-array of built-in and downloadable modules

  • a top-choice in DTS of Utah ESB comparison

  • excellent testing framework

I read a lot on OpenESB, watched presentations and then checked out tutorials. Simply put, OpenESB appears quite overkill for our specific needs. Furthermore, I'm not a fan of vendor lock-in and OpenESB appears to be very heavily biased towards NetBeans (which isn't really a surprise).

As for the Apache side of things, I spent a fair amount of time reading comparisons on ServiceMix and Mule. The favor was typically weighted on Mule's behalf and the one major viable commercial support option for ServiceMix was through
Fuse. Fuse appears to have some good documentation, but it wasn't nearly as in-depth as Mule. Also, going this route appeared to require more "gluing" using Camel and ServiceMix is also more specifically oriented to JBI--a shared trait among both OpenESB and ServiceMix.

Mule made it very easy to get up and running quickly. Within minutes I had implemented a REST service component using an existing endpoint. After some time reading more documentation I recognized a good case for using the template URI pattern and exposed another two REST endpoints in a separate service. Finally, with a Maven archetype, it was very easy to generate a Mule project and tweak it to support multiple environment deployments (dev,test,beta,prod, etc). I created a simple bootloader to start up the Mule context and register a shutdown hook with the JVM. This approach leverages Maven's capabilities in property filtering and distribution assembly. Thus, we can now create standalone distributions with full Maven dependency support (avoiding the hassle of updating MULE_HOME/lib/user), integrated testing, custom property filtering, and artifact assembly for multi-enviroment support.

Friday, March 13, 2009

calling dynamic domain finders in Grails

Had the need today for calling a Grails domain class finder method outside of the normal artifact setup. There's a singleton I wanted to write to cache certain hunks of data from the database. It'd be very convenient to have access to those domain classes to save me the pain of writing boilerplate Hibernate config and EJB classes. So, here's what ended up working.

I injected a GrailsApplication reference into my bean and created a closure that I passed to a new Groovy Timer instance. Inside the closure I'm able to invoke the dynamic finders on the domain classes because I can fetch a new instance this way:

def person_class = grailsApplication.getArtefact("Domain","Person")
def person_instance = person_class.newInstance()

That's simple enough, to actually call the finders (in this case "list") the next step was:

def results = person_class.metaClass.invokeStaticMethod(person_instance,'list',null)

Next plans are to create a generic way of exposing the ability to call the dynamic methods so that any Groovy class in the app has has access to them.

Thursday, March 12, 2009

Maven, Grails and Metro -- it works

I was really stoked about the maven-grails plugin when I had some time to start playing with Grails 1.1-SNAPSHOT last week. In fact, Grails has matured quite a bit since I first looked at it a little more than a year go. Almost two years ago I wrote about an integration of NetSuite's WebServices with Ruby's SOAP4r. We've been using this integration for nearly two years and have found ways to improve our original approach. In fact, usage has significantly increased, so much so that scalability is now becoming a concern. Don't get me wrong, SOAP4r has never actually croaked on us. But it makes sense to de-couple this element from the application and make a full-fledged service layer for additional in-house integrations. It's time to port the code to Java.

So, back to Grails and Maven. With over five years of Maven experiences I'm completely sold on its many benefits. I've been watching Grails and hoping that the two would integrate to a point where it's completely usable to manage a Grails project in Maven. That day is here, and it's solid. I created a prototype (love how fast it was) with Axis using Grails 1.1-SNAPSHOT. I was sold. Then, just two days ago, Grails 1.1 was finalized and became GA. Funny thing, as soon as I upgraded my project I could no longer use my prototype because I would receive the dreaded:

java.lang.LinkageError: loader constraints violated when linking javax/xml/namespace/QName

That really made me sad, my prototype was hosed. I didn't want to start sleuthing the class dependency collision. Mike Heath suggested I check out Apache CXF and Sun's Metro, both of which appear to be more "cleanly" designed than Axis. I spent a while trying to get CXF to work, but apparently it has a bunch of jars that need to be excluded since it hosed grails:run-app (No such property: readable for class: org.springframework.core.io.Class).

Finally, I had some success with Metro in Maven and Grails. I regenerated the NetSuite classes via wsimport, and only had to add jaxws-rt and jaxws-tools to my dependencies (this was helpful, https://metro.dev.java.net/guide/Using_JAX_WS_from_Maven.html). For now, I'm up and running and looking forward to more Grails development.