JBossESB上でJPAを実現する方法
JBossESB上でDBアクセスってどうやるんだろうと思って調べてみた。
単純にDBアクセスするならNotifySqlTableとかを使えばいいのかもしれないけど、トランザクション管理もしたいしな…と思い良い方法ないのかなと思って調べてみた。
するとドンピシャ、まさに求めている情報を発見。
Combining ESB, JPA, Hibernate, JTA and Spring |JBoss Developer
JBossESBには「AbstractSpringAction」なる基底クラスが用意されているので、それを継承してSpring駆動なJPA設定をしなさいとのこと。(POJOでアノテーションベースでないのが少し残念だけど。。。)
さっそくやってみたらいきなり問題に直面した。
どうやら「jbossesb-rosetta.jar」の中にAbstractSpringActionが存在しないらしくコンパイルが通らない。。
マジかよ〜と思って調べて
AbstractSpringAction location in jboss |JBoss Developer
を発見。
AbstractSpringActionは「${JBOSS_HOME}/server/
◆pom.xml
<properties> <jboss.rosetta.version>4.10-SNAPSHOT</jboss.rosetta.version> <jboss.spring.lib>${JBOSS_HOME}/server/sample/deploy/spring.esb</jboss.spring.lib> </properties> <dependencies> <dependency> <groupId>jboss.soa.spring</groupId> <artifactId>jbossesb-spring</artifactId> <version>${jboss.rosetta.version}</version> <type>jar</type> <scope>system</scope> <systemPath>${jboss.spring.lib}/jbossesb-spring.jar</systemPath> </dependency> <dependencies>
さてここからは本題のJPA設定。
今回はサンプルとして「Id, Data」の2カラムあって「Id」がPrimaryキーというエンティティを作成した。
◆SampleEntity.java
package org.sample.soa.esb.entity; import javax.persistence.Entity; import javax.persistence.Id; @Entity(org.sample.soa.esb.entity.SampleEntity) public class SampleEntity { @Id private int id; private String data; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getData() { return data; } public void setData(String data) { this.data = data; } }
エンティティにアクセスするためにサービスクラスを用意。
◆SampleService.java
package org.sample.soa.esb.service; import org.sample.soa.esb.entity.SampleEntity; public interface SampleService { public void insert(int id, String data); public void delete(int id); public SampleEntity find(int id); }
◆SampleServiceImpl.java
package org.sample.soa.esb.service.impl; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.PostPersist; import javax.persistence.PrePersist; import org.sample.soa.esb.entity.SampleEntity; import org.sample.soa.esb.service.SampleService; import org.springframework.transaction.annotation.Transactional; @Transactional public class SampleServiceImpl implements SampleService { @PersistenceContext private EntityManager em; public void insert(int id, String data) { SampleEntity he = new SampleEntity(); he.setId(id); he.setData(data); em.persist(he); } public void delete(int id) { SampleEntity he = new SampleEntity(); he.setId(id); em.remove(he); } public SampleEntity find(int id) { return em.find(SampleEntity.class, id); } }
アクションクラスはHTTPでリクエストを受け、パラメータで指定されたデータをINSERTするような仕様とした。
◆SampleAction.java
package org.sample.soa.esb.actions; import java.util.Map; import org.jboss.soa.esb.actions.AbstractSpringAction; import org.jboss.soa.esb.actions.ActionLifecycleException; import org.jboss.soa.esb.helpers.ConfigTree; import org.jboss.soa.esb.http.HttpRequest; import org.jboss.soa.esb.message.Message; import org.sample.soa.esb.entity.SampleEntity; import org.sample.soa.esb.service.SampleService; import org.springframework.beans.BeansException; public class SampleAction extends AbstractSpringAction { public SampleAction(ConfigTree configTree) { super(configTree); } public Message process(Message message) throws BeansException, ActionLifecycleException { HttpRequest request = HttpRequest.getRequest(message); Map<String, String[]> params = request.getQueryParams(); String tmp = ((String[]) params.get("id"))[0]; String data = ((String[]) params.get("data"))[0]; if (tmp == null || data == null) { throw new RuntimeException("can't insert data."); } SampleService service = (SampleService) getBeanFactory().getBean( "sampleService"); int id = Integer.parseInt(tmp); service.insert(id, data); SampleEntity entity = service.find(id); message.getBody().add( "Result : id = [" + entity.getId() + "], data = [" + entity.getData() + "]"); // service.delete(100); return message; } }
<?xml version="1.0"?> <jbossesb parameterReloadSecs="5" xmlns="http://anonsvn.labs.jboss.com/labs/jbossesb/trunk/product/etc/schemas/xml/jbossesb-1.2.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.2.0.xsd http://anonsvn.jboss.org/repos/labs/labs/jbossesb/trunk/product/etc/schemas/xml/jbossesb-1.2.0.xsd"> <services> <service name="JPA" description="" category="JPAService" invmScope="GLOBAL"> <listeners> <http-gateway name="jpa-gw" /> </listeners> <actions> <action name="jpa" class="org.sample.soa.esb.actions.SampleAction"> <property name="springContextXml" value="applicationContext.xml" /> </action> </actions> </service> </services> </jbossesb>
◆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_1_0.xsd" version="1.0"> <persistence-unit name="sample"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <jta-data-source>java:/DefaultDS</jta-data-source> <properties> <property name="jboss.entity.manager.factory.jndi.name" value="jndi-name/sample" /> <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect" /> <property name="hibernate.hbm2ddl.auto" value="create-drop" /> <property name="hibernate.transaction.flush_before_completion" value="true" /> <property name="hibernate.show_sql" value="true" /> <property name="hibernate.format_sql" value="true" /> <property name="hibernate.use_sql_comments" value="false" /> <property name="hibernate.max_fetch_depth" value="3" /> </properties> </persistence-unit> </persistence>
◆applicationContext.xml
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jee="http://www.springframework.org/schema/jee" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd"> <jee:jndi-lookup id="datasource" jndi-name="jndi-name/sample" lookup-on-startup="false" expected-type="javax.persistence.EntityManagerFactory" /> <tx:annotation-driven /> <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager" /> <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" /> <bean id="sampleService" class="org.sample.soa.esb.service.impl.SampleServiceImpl" /> </beans>
ここで大事なのがこの設定。
<jee:jndi-lookup id="datasource" jndi-name="jndi-name/sample" lookup-on-startup="false" expected-type="javax.persistence.EntityManagerFactory" />
Combining ESB, JPA, Hibernate, JTA and Spring |JBoss Developer
ここにもコメントされているんだが、「lookup-on-startup」と「expected-type」がないとアプリケーションのロード順の問題でデプロイに失敗することがある。(自分の場合はホットデプロイ時に必ずエラーが発生した。)
そのため、この2つを忘れず設定することが必要。
うん、うまくいった。