「Struts2 + Spring + Slim3の連携に挑戦」の修正版です。
前回の内容を修正しました。
改めてSlim3のLocalTransactionとGlobalTransactionについて調べた結果、前回の内容では不完全だったことがわかりました。
今回は完全に書き直しです。
- Slim3の新規プロジェクト作成
- まず最初に、EclipseのSlim3プラグインを使用してSlim3の新規プロジェクトを作成します。
プロジェクト名とルートパッケージ Project name s3sample Root Package com.brightgenerous.s3.sample.data - 不要なファイルを削除しておきます。
削除するファイルとディレクトリ /src/application_en.properties /src/application_ja.properties /war/css /war/ktrwjr /war/common.jsp
- Jarファイル追加
- 以下のjarファイルを「war/WEB-INF/lib」に追加します。
追加するjarファイル aopalliance-1.0 commons-beanutils-1.7.0 commons-digester-2.0 commons-fileupload-1.2.1 commons-io-1.3.2 commons-lang-2.3 commons-logging-1.0.4 commons-validator-1.3.1 freemarker-gae-pre3 javassist ognl-3.0 spring-aop spring-beans spring-context spring-core spring-tx spring-web struts2-convention-plugin-2.2.1.1 struts2-core-2.2.1.1 struts2-spring-plugin-2.2.1.1 xwork-core-2.2.1.1 freemarker-gae-pre3は、gae用のfreemarkerです。
Springは2.5を使用します。
- web.xml
- 「war/WEB-INF」に配置するweb.xmlファイルです。
slim3.rootPackage com.brightgenerous.s3.sample.data contextConfigLocation classpath:applicationContext*.xml DatastoreFilter org.slim3.datastore.DatastoreFilter struts2 org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter actionPackages com.brightgenerous.s3.sample.action DatastoreFilter /* REQUEST struts2 /* GlobalTransactionServlet org.slim3.datastore.GlobalTransactionServlet 1 GlobalTransactionServlet /slim3/gtx org.springframework.web.context.ContextLoaderListener com.brightgenerous.s3.sample.gae.GaeInitListener /slim3/gtx admin - Slim3の新規プロジェクトを作成して生成されるweb.xmlの内容の
ほとんど少しを消すことになります。
「com.brightgenerous.s3.sample.gae.GaeInitListener」は、独自に実装するクラスです。ソースは「実装するクラス」にて後述します。
- applicationContext.xml
- 「classpath:applicationContext*.xml」(src直下)に配置します。
PROPAGATION_REQUIRED transactionInterceptor *ServiceImpl 「transactionManager」のみ用意してやれば他はそのまま使えます。なかなかナイスな設計です。
「transactionManager」と「transactionInterceptor」を用意します。
「com.brightgenerous.s3.sample.gae.GaeFixInternalPersistenceAnnotationProcessor」、 「com.brightgenerous.s3.sample.gae.Slim3TransactionManager」、 「com.brightgenerous.s3.sample.gae.Slim3TransactionInterceptor」については、後述です。
- 実装するクラス
- 1.com.brightgenerous.s3.sample.gae.GaeInitListener
package com.brightgenerous.s3.sample.gae; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.servlet.http.HttpSessionAttributeListener; import javax.servlet.http.HttpSessionBindingEvent; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; import ognl.OgnlRuntime; public class GaeInitListener implements ServletContextListener, HttpSessionListener, HttpSessionAttributeListener { @Override public void contextInitialized(ServletContextEvent sce) { OgnlRuntime.setSecurityManager(null); } @Override public void contextDestroyed(ServletContextEvent arg0) { } @Override public void sessionCreated(HttpSessionEvent arg0) { } @Override public void sessionDestroyed(HttpSessionEvent arg0) { } @Override public void attributeAdded(HttpSessionBindingEvent arg0) { } @Override public void attributeRemoved(HttpSessionBindingEvent arg0) { } @Override public void attributeReplaced(HttpSessionBindingEvent arg0) { } }
- OGNLのセキュリティマネージャがなんとかかんとか...理由については、詳しく調べていません。
- 2.com.brightgenerous.s3.sample.gae.GaeFixInternalPersistenceAnnotationProcessor
package com.brightgenerous.s3.sample.gae; public class GaeFixInternalPersistenceAnnotationProcessor { }
- 「java.lang.NoClassDefFoundError」を回避することだけが目的です。
- 3.com.brightgenerous.s3.sample.gae.Slim3TransactionManager
package com.brightgenerous.s3.sample.gae; import org.slim3.datastore.Datastore; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.TransactionException; import org.springframework.transaction.support.AbstractPlatformTransactionManager; import org.springframework.transaction.support.DefaultTransactionStatus; public class Slim3TransactionManager extends AbstractPlatformTransactionManager { private static final long serialVersionUID = 3423679590583692519L; @Override protected void doBegin(Object x_arg0, TransactionDefinition x_arg1) throws TransactionException { TransactionObject transactionObject = (TransactionObject) x_arg0; transactionObject.setTransaction(Datastore.beginGlobalTransaction()); } @Override protected void doCommit(DefaultTransactionStatus x_arg0) throws TransactionException { TransactionObject transactionObject = (TransactionObject) x_arg0.getTransaction(); transactionObject.getTransaction().commit(); } @Override protected Object doGetTransaction() throws TransactionException { return new TransactionObject(); } @Override protected void doRollback(DefaultTransactionStatus x_arg0) throws TransactionException { TransactionObject transactionObject = (TransactionObject) x_arg0.getTransaction(); transactionObject.getTransaction().rollback(); } }
package com.brightgenerous.s3.sample.gae; import java.io.Serializable; import org.slim3.datastore.GlobalTransaction; public class TransactionObject implements Serializable { private static final long serialVersionUID = -8353097480608667182L; private GlobalTransaction p_transaction; public GlobalTransaction getTransaction() { return p_transaction; } public void setTransaction(GlobalTransaction x_transaction) { p_transaction = x_transaction; } }
package com.brightgenerous.s3.sample.gae; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Slim3GlobalTransaction { }
- 「org.springframework.jdbc.datasource.DataSourceTransactionManager」の実装を参考にして、Slim3用に簡単に対応させています。
「TransactionObject」、「Slim3GlobalTransaction」も作成します。このクラスのみ自作です。間違い等あれば指摘していただけるとありがたいです。
- 4.com.brightgenerous.s3.sample.gae.Slim3TransactionInterceptor
private void injectTransaction(Object x_obj, TransactionInfo x_txInfo) { TransactionStatus txStatus = x_txInfo.getTransactionStatus(); DefaultTransactionStatus dtxStatus; if (!(txStatus instanceof DefaultTransactionStatus)) { return; } dtxStatus = (DefaultTransactionStatus) txStatus; Object tx = dtxStatus.getTransaction(); if (tx instanceof TransactionObject) { tx = ((TransactionObject) tx).getTransaction(); } if (!(tx instanceof GlobalTransaction)) { return; } @SuppressWarnings("rawtypes") Class clazz = x_obj.getClass(); do { Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { if (!field.isAccessible()) { field.setAccessible(true); } Slim3GlobalTransaction s3gtx = field.getAnnotation(Slim3GlobalTransaction.class); if (s3gtx != null) { if (field.getType().isInstance(tx)) { try { field.set(x_obj, tx); } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (IllegalArgumentException e) { throw new RuntimeException(e); } } } } clazz = clazz.getSuperclass(); } while ((clazz != null) && !clazz.equals(Object.class)); }
- 「org.springframework.transaction.interceptor.TransactionInterceptor」のソースをコピーしてきて、
上記のメソッドが適当な箇所で呼ばれるように書き換えます。
ライセンスを考慮して全体は公開しませんが、元のソースを読めば変更箇所はわかるはずです。
以上でStruts2 + Spring + Slim3の設定は完了です。
次回こそ、このフレームワークを使用して簡単なサンプルを書いてみます。
0 件のコメント:
コメントを投稿