XML Messaging Using JBossIt's common practice to share data using FTP, but an increasingly popular alternative is to use a messaging service. As always, each approach has its own pros and cons, depending on the nature of "what to share," how easy it is to implement the technology, the need to use an asynchronous process, etc.
In this article, I will focus on data sharing, with the common producer-consumer model, using open source software such as:
The interactions between them are managed by Java Management Extensions (JMX). Please refer to their respective home pages if you are unfamiliar with these frameworks.
As for the Java Messaging Service (JMS) provider, you can choose either WebSphere MQ or JBossMQ. This is fully configurable in the jboss-service.xml file provided. By using JMS, your application becomes "loosely coupled." Some benefits of using it are:
This article is about how to use the set of open source tools listed above, not about why I choose them, nor why I need them. There are obviously a million and one different ways to deal with the producer-consumer model. The idea behind using JMX is to have a more flexible "federated" approach, so that different functions are handled by different processes.
Consider the following hypothetical scenario. We want to share two different kinds of data, coming from two different applications and two different data sources. One application (AppSource1) uses an Oracle database and needs to share a subset of its business contact data. Another application (AppSource2) uses a Sybase database and needs to share a subset its currency data.
The data is shared at specific times:
The contact data, persisted in an interface table named IProducerContact,
is managed and controlled by the application AppSource1. The currency data
is persisted in an interface table, IProducerCcy, by the application
AppSource2. Both AppSource1 and AppSource2
are the producers.
The producers extract the data from the interface tables IProducerContact and IProducerCcy
and then send the data, in an XML format, to a JMS server.
The consumer processes each incoming message, which then populates two interface tables, IConsumerContact
and IConsumerCcy. Once in the interface tables, AppTarget is responsible for
extracting the data from them into the master database.
Figure 1 below depicts this scenario:

Figure 1. Flow of messages
JMX is an optional package for J2SE that provides a standard set of interfaces and enables you to add management capabilities to your applications. It allows developers to write more modular and loosely coupled system components and reduce the complexity of large, interoperating systems.
The core component of JMX is the managed bean, or MBean. A standard MBean is a Java class that implements an interface, which has the following characteristics:
An example in JBoss is shown below:
public class ProducerManager extends ServiceMBeanSupport
implements ProducerManagerMBean {
...
// Constructor
// define your getter/setter method
// define your operations
public void startService() throws Exception {
...
}
public void stopService() throws Exception {
...
}
}
where the ProducerManagerMBean interface is:
public interface ProducerManagerMBean extends ServiceMBean {
...
// define your getter/setter method
// define your "invoked" operation, if any
}
Then, you need to define an XML file service, i.e. jboss-service.xml:
<?xml version="1.0" encoding="UTF-8"?>
<server>
<mbean code="example.jmx.ProducerManager"
name="nusa:service=ProducerManager">
<attribute name="Oracle">false
</attribute>
</mbean>
</server>
Once you have defined your MBean and the XML file service, then you can package them into a .sar file. This service archive file is ready to be deployed into JBoss server.
Let's find out what happens when you deploy an MBean. The sequence of an MBean initialization is in this order:
startService() method.When you delete or override the .sar file--or stop the JBoss
server, but you may not want to do this--the stopService() method is
called. This is the appropriate place to do clean-up operations,
like closing all open connections or sessions.
You can define a dependency between one MBean with another MBean by
using the depends tag:
<?xml version="1.0" encoding="UTF-8"?>
<server>
<mbean code="example.jmx.ProducerManager"
name="nusa:service=ProducerManager">
<attribute name="Oracle">false
</attribute>
<depends optional-attribute-name="MOMManager">
nusa:service=MOMManager
</depends>
<depends optional-attribute-name="DBManager">
nusa:service=DBManager
</depends>
</mbean>
</server>
In this example, the ProducerManager MBean depends on the MOMManager MBean
and DBManager MBean.
Again, what happens if you deploy a .sar file with the above file service? Here is the sequence:
ProducerManager() constructor.ProducerManger (setOracle(), in this instance).MOMManager() constructor.MOMManager.DBManager() constructor.DBManager.startService() method in DBManager. startService() method in MOMManager.startService() method in ProducerManger.When you delete or override that .sar file, here is the sequence:
stopService() method in ProcedureManager.stopService() method in MOMManager.stopService() method in DBManager.Note: Take a look at the order. When you have a dependency, the order is important.
The next thing that we need to know is how to call a method in
an MBean from another MBean. Given the file service mentioned above, how
the MOMManager MBean call a method in DBManager MBean?
The key is to use the invoke() method, such as:
instanceofmbeanserver.invoke ( yourObjectName,
yourMethod,
params,
signature );
The following code is taken from the provided source:
public void processXML(String xmlMsg ,String msgType)
throws Exception {
log.info ( "=== XMLConsumerCcyMDB.processXML() :
invoke XMLConsumer service ");
Object[] params = new Object[] { xmlMsg
,msgType };
String[] signature = new String[] { "java.lang.String"
,"java.lang.String" };
server.invoke(mbean, "processXML", params, signature);
}
The javax.management.MBeanServer.invoke() method is
powerful and can invoke methods of any given complexity by providing details about the method parameter signature and supplying the parameter values.
Note: The yourMethod() method must be defined in your MBean
interface and implemented in your MBean class.
|
Quartz is a job scheduler. One of the provided features is an MBean, called QuartzService,
which is a standard JMX implementation in JBoss:
public class QuartzService extends ServiceMBeanSupport
implements QuartzServiceMBean {
// Constructor
// Getter/setter method ( Properties and JndiName )
// Operations
public void startService() throws Exception {
...
Scheduler scheduler = schedulerFactory.getScheduler();
scheduler.start();
...
}
public void stopService() throws Exception {
...
Scheduler scheduler = schedulerFactory.getScheduler();
scheduler.shutdown ();
...
}
}
The XML file service that you'll need for JBoss is located in this directory:
<your_install_dir>/quartz-1.4.2/src/java \
/main/org/quartz/ee/jmx/jboss/doc-files
When you deploy that XML file service, the MBean starts the scheduler based on the properties defined in quartz.properties or within the XML files service itself, and exposes the scheduler to JNDI.
Then you can get an instance of that MBean by calling a lookup() method:
InitialContext iniCtx = new InitialContext();
scheduler = (Scheduler)iniCtx.lookup("Quartz");
Once you obtain the scheduler, then you can schedule your jobs.
To schedule a job, you need to define the JobDetail and Trigger. For
JobDetail(), I use JMXInvokerJob, which is a Job implementation as a JMX MBean.
The core of the JMXInvokerJob class is:
instanceofmbeanserver.invoke ( yourObjectName,
yourMethod,
params,
signature );
This is exactly what I mention above: invoking a method within an MBean from another MBean.
So in your code, you can have something like this:
job = new JobDetail("job1", "group1", MXInvokerJob.class);
In our scenario, the following code is used:
log.info("=== DBManager.dbScheduler() for Oracle ...");
job = new JobDetail ( "OracleJob",
"OracleGroup",
JMXInvokerJob.class );
job.getJobDataMap().put ( "JMX_OBJECTNAME",
"nusa:service=DBManager" );
job.getJobDataMap().put ( "JMX_METHOD",
"processOracle" );
trigger = new CronTrigger ( "OracleTrigger",
"OracleGroup",
oracleCron );
scheduler.scheduleJob(job, trigger);
That tells the scheduler, which is an instance of QuartzService (and is an
MBean), to invoke the
processOracle() method, implemented in nusa:service=DBManager MBean,
using a cron expression.
What Quartz does in our scenario is just scheduling. The details
and nature of the job are "federated" to another MBean, called
nusa:service=DBManager.
Hibernate is an object/relational persistence mapping, and has
more to do with the data layer. Just like Quartz, it provides an MBean
(called HibernateService). This MBean is responsible for constructing a
Hibernate SessionFactory and exposing it through JNDI.
In our scenario, the Hibernate service is defined like this in our jboss-service.xml file:
<!--
| HibernateService MBean for Oracle
-->
<mbean code="net.sf.hibernate.jmx.HibernateService"
name="jboss.jca:service=ProdOracleHibernateFactory">
<depends>jboss.jca:service=RARDeployer</depends>
<attribute name="MapResources">
mappings/Contact.hbm.xml
</attribute>
<attribute name="JndiName">
java:/OracleHibernateFactory
</attribute>
<attribute name="Datasource">
java:/OracleDS
</attribute>
<attribute name="Dialect">
net.sf.hibernate.dialect.OracleDialect
</attribute>
<attribute name="TransactionStrategy">
net.sf.hibernate.transaction.JTATransactionFactory
</attribute>
<attribute name="TransactionManagerLookupStrategy">
net.sf.hibernate.transaction.JBossTransactionManagerLookup
</attribute>
<attribute name="ShowSql">true</attribute>
<attribute name="CacheProvider">
net.sf.hibernate.cache.TreeCacheProvider
</attribute>
<attribute name="UserTransactionName">
UserTransaction
</attribute>
</mbean>
The ProdOracleHibernateFactory is the Hibernate MBean service
that deals with the Oracle database (through the JNDI namespace java:/OracleDS), using
the Contact.hbm.xml mapping file.
The next step that you have to do is to obtain an instance of
SessionFactory, as follows:
jndiName = (String)server.getAttribute(your_object_name ,"JndiName");
InitialContext ctx = new InitialContext();
sessionFactory = (SessionFactory)ctx.lookup(jndiName);
Your sessionFactory is now ready to be used. For example:
session = sessionFactory.openSession();
transaction = session.beginTransaction();
...
Although Hibernate is not a Java-XML data-binding framework--as opposed to Castor,
JAXB, XMLBeans, etc.--it provides the functionality to generate XML output.
This is handled by the Databinder.toGenericXML() or
Databinder.toXML() methods.
The structure of the XML generated is different.
Given the following mapping document:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping
PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping>
<class name="example.mapping.ICcy"
table="IProducerCcy">
<id name="ccyID" type="long"
column="ccy_id" unsaved-value="0">
<generator class="native"/>
</id>
<property name="origCcy"
column="orig_ccy"
type="string" length="3"
not-null="true"/>
<property name="settledCcy"
column="settled_ccy"
type="string" length="3"
not-null="true"/>
<property name="effectiveFrom"
column="effective_from_date"
type="date"
not-null="true"/>
<property name="ROE"
column="rate_of_exchange"
type="float"
not-null="true"/>
<property name="effectiveTo"
column="effective_to_date"
type="date"
not-null="true"/>
<property name="sendStatus"
column="send_status"
type="string" length="1"
not-null="true"/>
<property name="sendDate"
column="send_date"
type="date"
not-null="true"/>
</class>
</hibernate-mapping>
The toGenericXML() method generates the following XML structure:
<?xml version="1.0" encoding="UTF-8"?>
<hibernate-generic
datetime="04 November 2003 12:12:00">
<object class="ICcy"
package="example.mapping">
<id name="ccyID" type="long">
1</id>
<property name="origCcy" type="string">
<![CDATA[ADP]]></property>
<property name="settledCcy" type="string">
<![CDATA[GBP]]></property>
<property name="effectiveFrom" type="date">
07 October 2003</property>
<property name="roe" type="float">
211.46</property>
<property name="effectiveTo" type="date"/>
<property name="sendStatus" type="string">
<![CDATA[]]></property>
</object>
<object class="ICcy"
package="example.mapping">
<id name="ccyID" type="long">
2</id>
<property name="origCcy" type="string">
<![CDATA[AED]]></property>
<property name="settledCcy" type="string">
<![CDATA[GBP]]></property>
<property name="effectiveFrom" type="date">
07 October 2003</property>
<property name="ROE" type="float">
6.1241</property>
<property name="effectiveTo" type="date"/>
<property name="sendStatus" type="string">
<![CDATA[]]></property>
</object>
</hibernate-generic>
whereas the toXML() method generates this structure:
<?xml version="1.0" encoding="UTF-8"?>
<hibernate-custom
datetime="12 November 2003 11:47:28">
<ICcy id="N10004">
<ccyID>1</ccyID>
<origCcy>ADP</origCcy>
<settledCcy>GBP</settledCcy>
<effectiveFrom>07 October 2003
</effectiveFrom>
<ROE>211.46</ROE>
<effectiveTo>31 December 2999
</effectiveTo>
<sendStatus> </sendStatus>
<sendDate/>
</ICcy>
<ICcy id="N10026">
<ccyID>2</ccyID>
<origCcy>AED</origCcy>
<settledCcy>GBP</settledCcy>
<effectiveFrom>07 October 2003
</effectiveFrom>
<ROE>6.1241</ROE>
<effectiveTo>31 December 2999
</effectiveTo>
<sendStatus> </sendStatus>
<sendDate/>
</ICcy>
</hibernate-custom>
|
Castor is one of the data-binding frameworks for Java. At the time of this writing, there is no JMX implementation for Castor (yet).
In order to use it, we just follow the instructions from the Castor home page:
Note: Although JBoss 4.0.0 provides a Castor .jar file (castor-0.9.5-xml.jar), you need the complete .jar (castor-0.9.5.3.jar). This is needed to handle a date field.
The figure below depicts the design pattern for the producer:

Figure 2. Design pattern for the producer
Based on the following cron expression for Oracle:
<attribute name="OracleCron">
<![CDATA[0 * 08-18 * * ?]]>
</attribute>
QuartzService schedules HibernateService to retrieve data from IProducerContact
using the HSQL SELECT statement:
<attribute name="OracleQuery">
<![CDATA[FROM IContact as contact
WHERE contact.sendStatus <> 'S']]>
</attribute>
Note: IContact here is the name of the persistence class, and not the name of the interface table.
HibernateService, armed with the mapping files, unmarshalls the data retrieved to construct the Java objects.
These objects are passed on to the Databinder.toGenericXML() or Databinder.toXML() methods
to generate XML output.
The XML output is then transformed by XSLT. This new XML format is sent to the JMS provider, such as JBossMQ or WebSphere MQ.
To help you understand the provided code, Figure 3 shows the class diagram:

Figure 3. XMLProducer's class diagram
Figure 4 is the sequence diagram:

Figure 4. XMLProducer's sequence diagram
Figure 5 depicts the design pattern for the consumer:

Figure 5. Design Pattern for the consumer
The consumer has two components, XMLConsumer.jar and XMLConsumerService.sar.
The first one is the MDB component, and the second one is the business process.
There are two types of incoming messages: Contact messages and Ccy messages. These will be consumed by
ContactMDB or CcyMDB, respectively. There's one MDB for one type of message.
This allows a concurrency process. Each MDB will then delegate the process to an MBean,
called XMLConsumerService.
When an XML message is consumed, Castor marshals that message to a Java object.
Then Hibernate will take over this Java object to store the data into the interface tables
IConsumerContact and IConsumerCcy.
Once the data in those interface tables, it's up to AppTarget to put the data
into the master database.
To help you understand the provided code, Figure 6 shows a class diagram:

Figure 6. XMLConsumer's class diagram
and Figure 7 shows a sequence diagram:

Figure 7. XMLConsumer's sequence diagram
|
The provided code for this article has been developed under Windows and Linux using:
The structure of the project file is shown in Figure 8.

Figure 8. Eclipse project structure
Before building the XMLConsumer and XMLProducer, you need to copy the needed .jars--the Sybase JDBC driver, the Oracle JDBC driver, Quartz, and Castor--into
/server/<deploy_config>/lib.
If you use WebSphere MQ, add the following into your standardjboss.xml file:
<invoker-proxy-binding>
<name>wsmq-message-driven-bean</name>
<invoker-mbean>whatever</invoker-mbean>
<proxy-factory>
org.jboss.ejb.plugins.jms.JMSContainerInvoker
</proxy-factory>
<proxy-factory-config>
<JMSProviderAdapterJNDI>WSMQProvider
</JMSProviderAdapterJNDI>
<ServerSessionPoolFactoryJNDI>StdJMSPool
</ServerSessionPoolFactoryJNDI>
<MaximumSize>15</MaximumSize>
<MaxMessages>1</MaxMessages>
<MDBConfig>
<ReconnectIntervalSec>10
</ReconnectIntervalSec>
<DLQConfig>
<!-- Use this for Windows
file system JNDI namespace -->
<DestinationQueue>queue\\DLQ
</DestinationQueue>
<!-- Use this for Linux
file system JNDI namespace -->
<!--DestinationQueue>queue/DLQ
</DestinationQueue-->
<MaxTimesRedelivered>10
</MaxTimesRedelivered>
<TimeToLive>0</TimeToLive>
</DLQConfig>
</MDBConfig>
</proxy-factory-config>
</invoker-proxy-binding>
<container-configuration>
<container-name>WSMQ Message Driven Bean
</container-name>
<call-logging>false</call-logging>
<invoker-proxy-binding-name>
wsmq-message-driven-bean
</invoker-proxy-binding-name>
<container-interceptors>
<interceptor>
org.jboss.ejb.plugins.ProxyFactoryFinderInterceptor
</interceptor>
<interceptor>
org.jboss.ejb.plugins.LogInterceptor
</interceptor>
<interceptor>
org.jboss.ejb.plugins.RunAsSecurityInterceptor
</interceptor>
<!-- CMT -->
<interceptor transaction="Container">
org.jboss.ejb.plugins.TxInterceptorCMT
</interceptor>
<interceptor transaction="Container">
org.jboss.ejb.plugins.CallValidationInterceptor
</interceptor>
<interceptor transaction="Container"
metricsEnabled="true">
org.jboss.ejb.plugins.MetricsInterceptor
</interceptor>
<interceptor transaction="Container">
org.jboss.ejb.plugins.MessageDrivenInstanceInterceptor
</interceptor>
<!-- BMT -->
<interceptor transaction="Bean">
org.jboss.ejb.plugins.MessageDrivenInstanceInterceptor
</interceptor>
<interceptor transaction="Bean">
org.jboss.ejb.plugins.MessageDrivenTxInterceptorBMT
</interceptor>
<interceptor transaction="Bean">
org.jboss.ejb.plugins.CallValidationInterceptor
</interceptor>
<interceptor transaction="Bean"
metricsEnabled="true">
org.jboss.ejb.plugins.MetricsInterceptor
</interceptor>
<interceptor>
org.jboss.resource.connectionmanager.CachedConnectionInterceptor
</interceptor>
</container-interceptors>
<instance-pool>
org.jboss.ejb.plugins.MessageDrivenInstancePool
</instance-pool>
<instance-cache></instance-cache>
<persistence-manager></persistence-manager>
<container-pool-conf>
<MaximumSize>100</MaximumSize>
</container-pool-conf>
</container-configuration>
Add the following into your jms-ds.xml file:
<mbean code="org.jboss.jms.jndi.JMSProviderLoader"
name="jboss.mq:service=JMSProviderLoader,
name=WSMQProvider">
<attribute name="ProviderName">WSMQProvider
</attribute>
<attribute name="ProviderAdapterClass">
org.jboss.jms.jndi.JNDIProviderAdapter
</attribute>
<attribute name="QueueFactoryRef">
QCFProducer
</attribute>
<attribute name="TopicFactoryRef">
QCFProducer
</attribute>
<attribute name="Properties">
java.naming.factory.initial=com.sun.jndi.fscontext.RefFSContextFactory
java.naming.provider.url=file:/your-file-system-JNDI-namespace-directory
</attribute>
</mbean>
Add the following into your META-INF/jboss.xml file:
<jboss>
<enterprise-beans>
<message-driven>
<ejb-name>XMLConsumerCcyMDB
</ejb-name>
<!-- JBossMQ only -->
<!--
<configuration-name>
Standard Message Driven Bean
</configuration-name>
<destination-jndi-name>queue/QProducer
</destination-jndi-name>
-->
<!-- WSMQ only -->
<configuration-name>
WSMQ Message Driven Bean
</configuration-name>
<!-- Use this for Windows
file system JNDI namespace -->
<destination-jndi-name>queue\\QProducer
</destination-jndi-name>
<!-- Use this for Linux
file system JNDI namespace -->
<!--destination-jndi-name>queue/QProducer
</destination-jndi-name-->
<invoker-bindings>
<invoker>
<invoker-proxy-binding-name>
wsmq-message-driven-bean
</invoker-proxy-binding-name>
</invoker>
</invoker-bindings>
</message-driven>
...
</enterprise-beans>
</jboss>
Make sure you've set up the env variables as explained in pages 10-12 of the manual WebSphere MQ: Using Java (PDF). Run the following scripts:
Setup/WSMQ/setupMQ.bat or Setup/WSMQ/setupMQ.shSetup/WSMQ_FileSystemJNDI/setupJMS.bat or Setup/WSMQ_FileSystemJNDI/setupJMS.sh (amend the file system JNDI namespace directory)Optionally, you can test if the queue created is available by running the SendAndReceive program (modify it if needed).
Note: If you define a subcontext when creating a queue within a file system JNDI namespace, the process to get the queue name is different under Windows and Linux:
queue\\QProducer.queue/QProducer.If you use JBossMQ, add the following to your jbossmq-destinations-service.xml file:
<mbean code="org.jboss.mq.server.jmx.Queue"
name="jboss.mq.destination:service=Queue,name=QProducer">
<depends optional-attribute-name="DestinationManager">
jboss.mq:service=DestinationManager
</depends>
</mbean>
Steps to deploy XMLConsumer:
IConsumerSybase.sql if
you use Sybase for the interface tables, or IConsumserOracle.sql for Oracle).XMLConsumer to produce XMLConsumerMDB.jar and XMLConsumerService.sar.QProducer must be bound).Here is a snapshot of server.log (after formatting the line) when the consumer processes an incoming message:
14:00:00,349 INFO [example.mdb.XMLConsumerCcyMDB] \
=== XMLConsumerCcyMDB.processXML() : invoke XMLConsumer service for Ccy
...
14:00:00,349 INFO [example.jmx.ConsumerManager] \
=== ConsumerManager.processXML() : \
<?xml version="1.0" encoding="UTF-8"?>
<CCY>
<CCY_DATA>
<ORIG_CCY>EUR</ORIG_CCY>
<SETTLED_CCY>GBP</SETTLED_CCY>
<EFFECTIVE_FROM>07 October 2003
</EFFECTIVE_FROM>
<ROE>1.4339</ROE>
<EFFECTIVE_TO>31 December 2999
</EFFECTIVE_TO>
</CCY_DATA>
<CCY_DATA>
<ORIG_CCY>USD</ORIG_CCY>
<SETTLED_CCY>GBP</SETTLED_CCY>
<EFFECTIVE_FROM>07 October 2003
</EFFECTIVE_FROM>
<ROE>1.6674</ROE>
<EFFECTIVE_TO>31 December 2999
</EFFECTIVE_TO>
</CCY_DATA>
</CCY>
14:00:00,349 INFO [example.jmx.ConsumerManager] \
=== ConsumerManager.beginTransaction()
14:00:00,349 INFO [example.jmx.ConsumerManager] \
=== ConsumerManager.updateDataCcy() : load mapping for Castor ...
14:00:00,600 DEBUG [example.jmx.ConsumerManager] \
=== ConsumerManager.updateDataCcy() : Hibernate\
insert this : (EUR,GBP,Tue Oct 07 00:00:00 BST 2003,\
1.4339,Tue Dec 31 00:00:00 GMT 2999)
14:00:00,600 INFO [STDOUT] Hibernate: \
insert into IConsumerCcy (orig_ccy, \
settled_ccy, effective_from, roe, \
effective_to) values (?, ?, ?, ?, ?)
select @@identity
14:00:00,600 DEBUG [example.jmx.ConsumerManager] \
=== ConsumerManager.updateDataCcy() : Hibernate \
insert this : (USD,GBP,Tue Oct 07 00:00:00 BST 2003,\
1.6674,Tue Dec 31 00:00:00 GMT 2999)
14:00:00,600 INFO [STDOUT] Hibernate: \
insert into IConsumerCcy (orig_ccy, \
settled_ccy, effective_from, roe, \
effective_to) values (?, ?, ?, ?, ?)
select @@identity
14:00:00,610 INFO [example.jmx.ConsumerManager] \
=== ConsumerManager.endTransaction() : Commit
14:00:00,610 INFO [example.jmx.ConsumerManager] \
=== ConsumerManager.endSession()
Steps to deploy XMLProducer:
IProducerSybase.sql and
IProducerOracle.sql) and tables needed by Quartz (Quartz-sybase.sql
or Quartz-oracle.sql).cron expression used by Quartz).XMLProducer to produce XMLProducer.sar.Here is a snapshot of server.log (after formatting the line)
when the producer sends a message:
14:00:00,199 INFO [example.db.SybaseMessaging] \
=== SybaseMessaging.sendMsg()
14:00:00,199 INFO [example.jmx.MOMManager] \
=== MOMManager.enqueue()
14:00:00,199 INFO [example.jmx.JBossMQManager] \
=== JBossMQManager.enqueue()
14:00:00,209 DEBUG [org.jboss.resource.adapter.\
jdbc.local.LocalManagedConnectionFactory] \
Using properties: {user=baa, password=--hidden--}
14:00:00,269 INFO [example.jmx.JBossMQManager] \
=== Message sent : \
<?xml version="1.0" encoding="UTF-8"?>
<CCY>
<CCY_DATA>
<ORIG_CCY>EUR</ORIG_CCY>
<SETTLED_CCY>GBP</SETTLED_CCY>
<EFFECTIVE_FROM>07 October 2003
</EFFECTIVE_FROM>
<ROE>1.4339</ROE>
<EFFECTIVE_TO>31 December 2999
</EFFECTIVE_TO>
</CCY_DATA>
<CCY_DATA>
<ORIG_CCY>USD</ORIG_CCY>
<SETTLED_CCY>GBP</SETTLED_CCY>
<EFFECTIVE_FROM>07 October 2003
</EFFECTIVE_FROM>
<ROE>1.6674</ROE>
<EFFECTIVE_TO>31 December 2999
</EFFECTIVE_TO>
</CCY_DATA>
</CCY>
14:00:00,279 INFO [example.db.SybaseMessaging] \
=== SybaseMessaging.updateData()
14:00:00,279 INFO [STDOUT] \
Hibernate: select iccy0_.ccy_id as x0_0_ \
from IProducerCcy iccy0_ \
where (iccy0_.send_status<>'S' )
14:00:00,289 INFO [example.db.DBMessaging] \
=== DBMessaging.endTransaction() : Commit
14:00:00,289 INFO [STDOUT] \
Hibernate: update IProducerCcy set orig_ccy=?,\
settled_ccy=?, effective_from_date=?, \
rate_of_exchange=?, effective_to_date=?, \
send_status=?, send_date=? where ccy_id=?
14:00:00,299 INFO [example.db.DBMessaging] \
=== DBMessaging.endSession()
This article was about how to use JBoss, Quartz, Hibernate, Castor, and WebSphere MQ to build a simple XML messaging system. Please consult the forums, Wikis, tutorials, docs, etc. in the Reference section below if you want to find out more about the components used.
Benoit Aumars Benoit Aumars has 14 years' experience in IT, specializing in Java and J2EE. His major interests include design patterns, XML-related technologies, EAI, web services, and SOA. He is currently working with Jardine Lloyd Thompson in London.
Return to ONJava.com.
Copyright © 2007 O'Reilly Media, Inc.