I had quite a lot of trouble getting all these frameworks to play well together in a way that I was happy with and would allow me to move forward. I did find this article by Quinton Anderson which is incredibly useful but it didn't work for me and I also wanted to make use of Spring 3 annotations more.
My requirements were to use the JBoss ESB to generate a web service, unmarshal the XML, then feed into a custom Spring action ready for persisting. Obviously the ESB itself can do the persisting but as I'm going to be building a Spring application I want to ensure I can get the data into Spring as in the future we'll be building business logic in there. Just to complicate things a little further and again for future scalability the message itself would be sent over JMS once received into the bus.
The appropriate snippets of my jboss-esb.xml as as follows :-
<?xml version="1.0"?> <jbossesb parameterReloadSecs="5" xmlns="http://anonsvn.labs.jboss.com/labs/jbossesb/trunk/product/etc/schemas xml/jbossesb-1.3.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://anonsvn.labs.jboss.com/labs/jbossesb/trunk/product/etc/schemas/xml/jbossesb-1.3.0.xsd http://anonsvn.jboss.org/repos/labs/labs/jbossesb/trunk/product/etc/schemas/xml/jbossesb-1.3.0.xsd">
<providers>
<jms-provider connection-factory="ConnectionFactory" name="ReceiveMarshalledDatex2Message">
<jms-bus busid="marshalledDatex2Channel">
<jms-message-filter dest-name="queue/SimpleJMSRequest" dest-type="QUEUE"/>
</jms-bus>
</jms-provider>
</providers>
<services>
<service category="WsServiceCategory" description="I receive messages and send over JMS" invmScope="GLOBAL" name="WsService">
<property name="maxThreads" value="100"/>
<actions inXsd="/request.xsd" mep="RequestResponse" outXsd="/response.xsd" responseLocation="RESPONSE" webservice="true">
<action class="org.jboss.soa.esb.actions.Notifier" name="NotifyAction2">
<property name="okMethod" value="notifyOK"/>
<property name="destinations">
<NotificationList type="ok">
<target class="NotifyQueues">
<queue jndiName="queue/SimpleJMSRequest"/>
</target>
</NotificationList>
</property>
</action>
</service>
<service category="Datex2_Service"
description="Processes a unmarshalled Datex2 Message" invmScope="GLOBAL"n ame="ProcessDatex2MarshalledService">
<property name="maxThreads" value="100"/>
<listeners>
<jms-listener busidref="marshalledDatex2Channel" is-gateway="true" maxThreads="100" name="ListenDatex2Marshall"/>
</listeners>
<actions>
<action class="com.thales.esbtest.ConvertDatex2ActionWs" name="UnmarshalXML"/>
<action class="com.thales.esbtest.MyTestSpringAction" name="MySpringAction">
<property name="springContextXml" value="/lib/applicationContext.xml"/>
</action>
</actions>
.....
For the JMS you'll need to add a file (jbm-queue-service.xml) into your ESB archive to declare the JMS queue :
<?xml version="1.0" encoding="UTF-8"?>
<server>
<mbean code="org.jboss.jms.server.destination.QueueService"
name="jboss.esb.quickstart.destination:service=Queue,name=SimpleJMSRequest"
xmbean-dd="xmdesc/Queue-xmbean.xml">
<depends optional-attribute-name="ServerPeer">jboss.messaging:service=ServerPeer</depends>
<depends>jboss.messaging:service=PostOffice</depends>
</mbean>
</server>
In addition, I found I needed a deployment.xml file to ensure the queue is created before the ESB is processed :
<?xml version="1.0" encoding="UTF-8"?>
<jbossesb-deployment>
<depends>jboss.esb.quickstart.destination:service=Queue,name=SimpleJMSRequest
</depends>
</jbossesb-deployment>s.messaging:service=PostOffice</depends>
</mbean>
</server>
My unmarshall action looks like
public class ConvertDatex2ActionWs {
private JAXBContext jaxbContext;
public ConvertDatex2ActionWs() {
try {
jaxbContext = JAXBContext.newInstance("eu.datex2.schema._2_0rc2._2_0");
} catch (JAXBException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Process
public Object process(Message message) throws ActionProcessingException {
DeliverDatex2Request deliverDatex2Request = null;
try {
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
deliverDatex2Request = (DeliverDatex2Request) unmarshaller.unmarshal(new StreamSource(new StringReader(
(String) message.getBody().get())));
} catch (JAXBException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (deliverDatex2Request == null)
return null;
message.getBody().add("unmarshalled", deliverDatex2Request.getDatex2Message());
return message;
}
@OnSuccess
public Object processSuccess(Message message) {
..
}
@OnException
public void manualRollback(Message message, Throwable theError) {
System.out.println("on exception called");
theError.printStackTrace();
}
}
My custom Spring Action :
public class MyTestSpringAction extends AbstractSpringAction {
public void process(final Message message) throws ActionProcessingException, ActionLifecycleException,
BeansException {
...
AutService service = (AutService) getBeanFactory().getBean("AutService");
service.write(...);
}
}
My AutService implementation :
@Service("AutService")
public class AutServiceImpl implements AutService, InitializingBean {
@Autowired
private LocationDao locationDao;
public void write(...) {
Location entity = new Location();
...
locationDao.save(entity);
}
My implementation DAO class :
@Repository
public class JpaLocationDao implements LocationDao {
private EntityManager entityManager;
@PersistenceContext
public void setEntityManager(EntityManager em) {
this.entityManager = em;
}
public void save(Location location) {
this.entityManager.merge(location);
}
}
Now importantly! my persistence.xml :
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
<persistence-unit name="AutJPA" transaction-type="JTA">
<!-- <jta-data-source>java:/XAOracleDS</jta-data-source> -->
<jta-data-source>java:/AutTransactedDB</jta-data-source>
<properties>
<!-- Auto-detect entity classes -->
<property name="hibernate.archive.autodetection" value="class, hbm"/>
<property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.JBossTransactionManagerLookup"/>
<property name="jboss.entity.manager.factory.jndi.name" value="persistence-units/AutJPA"/>
<property name="hibernate.ejb.cfgfile" value="/lib/hibernate.cfg.xml" />
</properties>
</persistence-unit>
</persistence>
My applicationContext.xml
...
<context:load-time-weaver weaver-class="org.jboss.instrument.classloading.JBoss5LoadTimeWeaver"/>
<!-- tell spring to use annotation based configurations -->
<!-- tell spring where to find the beans -->
<context:annotation-config />
<context:component-scan base-package="com.thales.esbtest"/>
<jee:jndi-lookup id="myEmf" jndi-name="persistence-units/AutJPA" />
<tx:annotation-driven mode="proxy" transaction-manager="txManager" />
<bean
class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<!-- Configure Transaction Support - Access the JTA transaction manager -->
<bean id="txManager"
class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManagerName" value="java:/TransactionManager" />
<property name="userTransactionName" value="UserTransaction" />
</bean>
<!-- Use Spring AOP capabilities to manage transactions -->
<aop:config>
<aop:pointcut id="accountTransactions"
expression="execution(* com.thales.esbtest.MyTestSpringAction.*(..))" />
<aop:advisor pointcut-ref="accountTransactions"
advice-ref="txAdvice" />
</aop:config>
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="process" propagation="REQUIRED" />
<tx:method name="*" propagation="SUPPORTS" read-only="true" />
</tx:attributes>
</tx:advice>
</beans>
Finally my hibernate.cfg.xml
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hbm2ddl.auto">create</property>
<property name="show_sql">true</property>
<property name="dialect">org.hibernatespatial.postgis.PostgisDialect</property>
<!-- <property name="dialect">org.hibernatespatial.oracle.OracleSpatial10gDialect</property> -->
<property name="current_session_context_class">thread</property>
<property name="hibernate.session_factory_name">SessionFactory</property>
<property name="hibernate.transaction.factory_class">org.hibernate.transaction.JTATransactionFactory</property>
<property name="hibernate.transaction.manager_lookup_class">org.hibernate.transaction.JBossTransactionManagerLookup</property>
<property name="hibernate.validator.apply_to_ddl">false</property>
<property name="hibernate.validator.autoregister_listeners">false</property>
<mapping class="com.thales.esbtest.Location" />
</session-factory>
</hibernate-configuration>
There's a few more enhancements needed. I still need to specify my entity classes in the hibernate.cfg.xml which I'd like to eliminate and have these be found automatically. Some other gotchas that I had to solve were :
1) You'll need to install the Snowdrop utility http://www.jboss.org/snowdrop Without this you'll get an I/O failure during classpath scanning; nested exception is java.util.zip.ZipException: error in opening zip file
I took the 3 Jar files and installed them in the JBoss lib directory.
2) You'll need to install the springsource aspectj weaver and tools libraries from http://ebr.springsource.com/repository/app/bundle otherwise you'll get a java.lang.NoClassDefFoundError: org/aspectj/weaver/reflect/ReflectionWorld$ReflectionWorldException
3) Finally I was getting security exception and I finally tracked this down to https://access.redhat.com/jbossnetwork/restricted/softwareDetail.html?softwareId=1012 where you need to replace cglib
I hope someone finds this useful as you can spend a long while scratching around trying to pull all this together. In a future blog I will show how easy this was using Gradle and Eclipse.
The versions I was using :
JBoss 5.1.0.GA (Enterprise Version)
Spring 3.0.5
Hibernate 3.3.2.GA (comes with JBoss 5.1.0.GA)