Flex, Java Remoting, and JMS [null message body]

So I was pounding out some code this afternoon, ran into a small snag and thought I’d post. Neuro-physiologists tell us that we better remember what we write down so here goes.

Similar to my post a few months ago, I made a simple omission in my coding flurry.

I was working with a backend Java class that published messages to [ActiveMQ] JMS. I wrote up a simple VO class to publish via JMS.


package com.dl.sifagents.vo;

import java.io.Serializable;

public class ZISEventVO implements Serializable
{
public String eventType = "";
public String payloadPackage = "";
public String payloadElement = "";
public String xml = "";
}

On the Flex side, I wrote up an AS3 implementation


package com.dl.sifagents.vo
{
[RemoteClass(alias="com.dl.sifagents.vo.ZISEventVO")]
[Bindable]
public class ZISEventVO
{
public var eventType:String;
public var payloadPackage:String;
public var payloadElement:String;
public var xml:String;
}
}

I published the VO to JMS…


public void publishObjectToJMS(Serializable o)
{
try {
ObjectMessage message = _pubSession.createObjectMessage();
message.setObject(o);
_publisher.publish(message, Message.DEFAULT_DELIVERY_MODE, Message.DEFAULT_PRIORITY, 5 * 60 * 1000);
} catch (JMSException e1) {
e1.printStackTrace();
}
}

I received the JMS message in Flex (via BlazeDS) but the message body was null. I checked and doubled checked my Java VO implementation vs AS3 VO implementation and couldn’t find any naming conflicts or errors.

Then it hit me, in my haste I’d forgotten to upload the Java VO class to BlazeDS (i.e. to the WEB-INF/classes folder)!

That’s my piece of humble pie for the week 🙂 Back to work.

[Tunkey] BlazeDS JMS ActiveMQ

I spent some time this week with BlazeDS and JMS. I wanted to integrate a Flex RIA with some [existing] backend Java classes. One goal was to interface the two in a loosely coupled fashion, enter Java Message Service (JMS).

The RIA uses a mx:producer to publish messages to a JMS topic which the backend Java class is listening in on [consuming] elsewhere in the enterprise. I used an ‘external install’ of ActiveMQ.

I downloaded the turnkey BlazeDS server to get things rolling.

I came across a few great posts in looking into this…

Michael Martin’s Simplified BlazeDS and JMS

Christophe Coenraets
Flex and JMS: Portfolio Viewer (LCDS jRun)
30 Minutes Flex Test-Drive for Java Developers (FDS)

To be helpful, I’ve included some error messages and their causes:

Flex Runtime Error:
There was an unhandled failure on the server. MessageClient has been invalidated.
Cause: ActiveMQ not running.

Flex Runtime Error:
Client.Message.Encoding
Type ‘com.dl.samples.PersonVO’ not found.
Cannot create class of type ‘com.dl.samples.PersonVO’.
Cause: Java classes not on server.

Java Runtime Error
javax.naming.NameNotFoundException: messageTopic
at org.apache.activemq.jndi.ReadOnlyContext.lookup(ReadOnlyContext.java:225)
at javax.naming.InitialContext.lookup(Unknown Source)
at Chat.(Chat.java:55)
at Chat.main(Chat.java:27)
Cause: jndi.properties not present for java class

Java Runtime [BlazeDS] Error
[BlazeDS] JMS consumer for JMS destination ‘[destinationName]’ is being removed from the JMS adapter due to the following error: Name jms is not bound in this Context
[BlazeDS] JMS consumer for JMS destination ‘[destinationName]’ is stopping.
[BlazeDS] The corresponding MessageClient for JMS consumer for JMS destination ‘[destinationName]’ is being invalidated

Cause: context.xml Resource names do not match messaging-config.xml connection-factory / destination-jndi-name tags. (i.e. the ‘org.apache.activemq.ActiveMQConnectionFactory’ resource name in context.xml should match the connection-factory value in messaging-config and the ‘org.apache.activemq.command.ActiveMQTopic’ resource name in context.xml should match the destination-jndi-name value in messaging-config).

Adding the logging pattern ‘Service.Message.JMS’ to your services-config.xml can be very helpful in debugging BlazeDS JMS problems.

Here are the config files

C:/blazeds/tomcat/webapps/MyApp/WEB-INF/flex/services-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<services-config>
<services>
<service-include file-path="messaging-config.xml" />
</services>
<security/>
<channels>
<channel-definition id="my-amf" class="mx.messaging.channels.AMFChannel">
<endpoint url="http://localhost:8400/BlazeTest/messagebroker/amf" class="flex.messaging.endpoints.AMFEndpoint"/>
</channel-definition>
</channels>
<logging>
<target class="flex.messaging.log.ConsoleTarget" level="Debug">
<properties>
<prefix>[BlazeDS] </prefix>
<includeDate>false</includeDate>
<includeTime>false</includeTime>
<includeLevel>false</includeLevel>
<includeCategory>false</includeCategory>
</properties>
<filters>
<pattern>Endpoint.*</pattern>
<pattern>Service.*</pattern>
<pattern>Configuration</pattern>
<pattern>Service.Message.JMS</pattern>
</filters>
</target>
</logging>
</services-config>

C:/blazeds/tomcat/webapps/MyApp/WEB-INF/flex/messaging-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<service id="message-service" class="flex.messaging.services.MessageService">
<adapters>
<adapter-definition id="actionscript" class="flex.messaging.services.messaging.adapters.ActionScriptAdapter" default="true" />
<adapter-definition id="jms" class="flex.messaging.services.messaging.adapters.JMSAdapter"/>
</adapters>
<default-channels>
<channel ref="my-amf"/>
</default-channels>
<destination id="simpleJMS">
<properties>
<jms>
<destination-type>Topic</destination-type>
<!--<message-type>javax.jms.TextMessage</message-type>-->
<message-type>javax.jms.ObjectMessage</message-type>
<connection-factory>java:comp/env/TopicConnectionFactory</connection-factory>
<destination-jndi-name>java:comp/env/messageTopic</destination-jndi-name>
<delivery-mode>NON_PERSISTENT</delivery-mode>
<message-priority>DEFAULT_PRIORITY</message-priority>
<acknowledge-mode>AUTO_ACKNOWLEDGE</acknowledge-mode>
<initial-context-environment>
<property>
<name>Context.INITIAL_CONTEXT_FACTORY</name>
<value>org.apache.activemq.jndi.ActiveMQInitialContextFactory</value>
</property>
<property>
<name>Context.PROVIDER_URL</name>
<value>tcp://localhost:61616</value>
</property>
</initial-context-environment>
</jms>
</properties>
<channels>
<channel ref="my-amf"/>
</channels>
<adapter ref="jms"/>
</destination>
</service>

C:/blazeds/tomcat/webapps/MyApp/WEB-INF/web.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<display-name>BlazeDS</display-name>
<description>BlazeDS Application</description>
<!-- Http Flex Session attribute and binding listener support -->
<listener>
<listener-class>flex.messaging.HttpFlexSession</listener-class>
</listener>
<!-- MessageBroker Servlet -->
<servlet>
<servlet-name>MessageBrokerServlet</servlet-name>
<display-name>MessageBrokerServlet</display-name>
<servlet-class>flex.messaging.MessageBrokerServlet</servlet-class>
<init-param>
<param-name>services.configuration.file</param-name>
<param-value>/WEB-INF/flex/services-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>MessageBrokerServlet</servlet-name>
<url-pattern>/messagebroker/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>

C:/blazeds/tomcat/webapps/MyApp/META-INF/context.xml

<?xml version="1.0" encoding="UTF-8"?>
<Context path="/BlazeTest">
<Resource name="TopicConnectionFactory"
type="org.apache.activemq.ActiveMQConnectionFactory"
description="JMS Connection Factory"
factory="org.apache.activemq.jndi.JNDIReferenceFactory"
brokerURL="tcp://localhost:61616"
brokerName="myBroker"/>
<Resource name="messageTopic"
type="org.apache.activemq.command.ActiveMQTopic"
description="a simple topic"
factory="org.apache.activemq.jndi.JNDIReferenceFactory"
physicalName="messageTopic"/>
</Context>

Using the above messaging-config’s destination the message will come across as an ObjectMessage in Java 🙂