001/*
002 * Copyright (c) 2009 The openGion Project.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
013 * either express or implied. See the License for the specific language
014 * governing permissions and limitations under the License.
015 */
016package org.opengion.hayabusa.taglib;
017
018import org.opengion.fukurou.db.Transaction;
019import org.opengion.fukurou.db.TransactionImpl;
020import org.opengion.fukurou.util.ToString;                                              // 6.1.1.0 (2015/01/17)
021
022/**
023 * コネクションを共有して、トランザクションを実現します。
024 *
025 * 通常のタグでは、コネクションプールより、その時々のコネクションを取り出して利用するため、
026 * タグごとに異なるコネクションで処理されます。
027 * また、commit や rollback などもそれぞれのタグで行われるため、連続処理時にエラーが
028 * 発生しても、中途半端な状態になります。
029 * ここでは、各 DBID 単位にコネクションを共有し、このタグの間は、同じオブジェクトを
030 * commit や、rollback せずに使いまわすようにします。
031 * これにより、複数タグ間のトランザクションや、異なる DBID 間のトランザクションを
032 * 実現します。
033 *
034 * このタグは、doEndTag() メソッドが正常に呼び出されることで、トランザクションが成立します。
035 * つまり、途中で、JSP出力が、SKIP_PAGE された場合は、commit もされません。
036 * これは、データベースエラー以外のエラーでも、トランザクション処理されることを意味します。
037 *
038 * @og.formSample
039 * ●形式:<og:transaction > ... </og:transaction >
040 * ●body:あり(EVAL_BODY_INCLUDE:BODYをインクルードし、{@XXXX} は解析しません)
041 *
042 * ●Tag定義:
043 *   <og:transaction
044 *       debug              【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false)
045 *   >   ... Body ...
046 *   </og:transaction>
047 *
048 * ●使用例
049 *     <og:transaction >
050 *         <og:query command="NEW" dbid="SERVER1" >
051 *             insert into XX01 (aa,bb,cc) values ('AA','BB','CC') />
052 *         </og:query >
053 *         <og:query command="NEW" dbid="SERVER2" >
054 *             update YY02 set aa='AA',bb='BB',cc='CC' where uniq='00001' />
055 *         </og:query >
056 *     </og:transaction >
057 *
058 * @og.rev 5.1.9.0 (2010/08/01) 新規作成
059 * @og.group DB登録
060 *
061 * @version  5.0
062 * @author       Kazuhiko Hasegawa
063 * @since    JDK6.0,
064 */
065public class TransactionTag extends CommonTagSupport {
066        /** このプログラムのVERSION文字列を設定します。   {@value} */
067        private static final String VERSION = "6.4.3.3 (2016/03/04)" ;
068        private static final long serialVersionUID = 643320160304L ;
069
070        // TransactionTag では、Transaction インターフェースではなく、実装クラスで管理します。
071        private transient TransactionImpl tran;                         // 6.3.9.0 (2015/11/06) transient 追加
072
073        /**
074         * デフォルトコンストラクター
075         *
076         * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor.
077         */
078        public TransactionTag() { super(); }            // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
079
080        /**
081         * Taglibの開始タグが見つかったときに処理する doStartTag() を オーバーライドします。
082         *
083         * @return      後続処理の指示( EVAL_BODY_INCLUDE )
084         */
085        @Override
086        public int doStartTag() {
087                tran = new TransactionImpl( getApplicationInfo() );
088
089                return EVAL_BODY_INCLUDE ;      // Body インクルード( extends TagSupport 時)
090        }
091
092        /**
093         * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。
094         *
095         * TransactionTag の doEndTag() では、途中で、SKIP_PAGE されると、呼ばれません。
096         * これは、データベース以外のタグで、エラー等が発生したことになります。
097         * 最後の、endCommit() が呼ばれない限り、トランザクションは commit されずに、
098         * rollback されます。
099         *
100         * @og.rev 6.3.6.1 (2015/08/28) AutoCloseable の close() メソッドに対応。正常時は、commit()。
101         * @og.rev 6.4.3.3 (2016/03/04) 一般的なタグで、SKIP_PAGE された場合、rollback するようにします。
102         *
103         * @return      後続処理の指示
104         */
105        @Override
106        public int doEndTag() {
107                debugPrint();           // 4.0.0 (2005/02/28)
108
109                if( tran != null ) { tran.endCommit(); }                // 6.4.3.3 (2016/02/26
110
111                return EVAL_PAGE ;              // ページの残りを評価する。
112        }
113
114        /**
115         * タグの処理中(セッターメソッドを除く)の例外を全て受け取ります。
116         *
117         * タグの中のボディ部の評価中、または Tag.doStartTag(), Tag.doEndTag(),
118         * IterationTag.doAfterBody(), BodyTag.doInitBody() のいずれもの
119         * メソッドの中で、Throwableが投げられたときに呼び出されます。
120         *
121         * このメソッドはセッターメソッドの中でThrowableが起きた場合は呼び出されません。
122         *
123         * @og.rev 6.3.6.1 (2015/08/28) AutoCloseable の close() メソッドに対応。異常時は、rollback()。
124         *
125         * @param       th      このタグを通過してきたThrowableな例外
126         */
127        @Override
128        public void doCatch( final Throwable th ) throws Throwable {
129                if( tran != null ) { tran.rollback(); }
130                super.doCatch( th );
131        }
132
133        /**
134         * タグリブオブジェクトをリリースします。
135         * キャッシュされて再利用されるので、フィールドの初期設定を行います。
136         *
137         * @og.rev 6.3.6.1 (2015/08/28) AutoCloseable の close() メソッドに対応。終了時は、finish()。
138         */
139        @Override
140        protected void release2() {
141                super.release2();
142
143                // finish() は、TransactionImpl のメソッドです。
144                if( tran != null ) { tran.finish(); }
145                tran = null;
146        }
147
148        /**
149         * Transactionオブジェクトを返します。
150         *
151         * @og.rev 6.3.6.1 (2015/08/28) Transactionオブジェクトの取得方法変更。
152         *
153         * @return      Transactionオブジェクト
154         */
155        protected Transaction getTranObj() {
156                return tran ;
157        }
158
159        /**
160         * このオブジェクトの文字列表現を返します。
161         * 基本的にデバッグ目的に使用します。
162         *
163         * @return このクラスの文字列表現
164         * @og.rtnNotNull
165         */
166        @Override
167        public String toString() {
168                return ToString.title( this.getClass().getName() )
169                                .println( "VERSION"             ,VERSION        )
170                                .println( "Other..."    ,getAttributes().getAttribute() )
171                                .fixForm().toString() ;
172        }
173}