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     */
016    package org.opengion.fukurou.db;
017    
018    import org.opengion.fukurou.util.Closer;
019    import org.opengion.fukurou.util.ApplicationInfo;
020    
021    import java.sql.Connection;
022    
023    import java.util.Locale;
024    import java.util.Map;
025    import java.util.HashMap;
026    
027    /**
028     * コネクションをå?有して、トランザクションを実現しますã?
029     *
030     * 基本çš?�«は、TransactionTag で利用されますが、ä¸?ƒ¨、このオブジェクトを
031     * 渡して、直接、利用するケースもありますã?
032     *
033     * トランザクションがすべて完äº?�—た後で、realClose() メソãƒ?ƒ‰を呼び出しますã?
034     * ä¸?º¦でもã?rollback が指定されてã�?‚Œば、ロールバックを行い、コネクションã‚?
035     * 破æ£?�—ますã?それ以外で、commit が指定されてã�?‚Œば、コミットを行いã€?
036     * コネクションをã?プã?ルに戻しますã?どちらもæŒ?®šされてã�?�ªければã€?
037     * コネクションプã?ルに戻すだけになりますã?
038     *
039     * è€?�ˆ方として、下記ã?ような流れになりますã?
040     * <pre>
041     *   TransactionImpl tran = new TransactionImpl( appInfo ) ;
042     *   try {
043     *      ・・・・・
044     *      tran.commit();
045     *      tran.finish();
046     *   }
047     *   catch( Exception ex ) {
048     *      tran.rollback();
049     *   }
050     *   finally {
051     *      tran.realClose()
052     *   }
053     * </pre>
054     *
055     * @og.rev 5.1.9.0 (2010/08/01) 新規作æ?
056     *
057     * @version  5.0
058     * @author       Kazuhiko Hasegawa
059     * @since    JDK6.0,
060     */
061    public class TransactionImpl implements Transaction {
062            //* こã?プログラãƒ??VERSIONæ–?­—å?を設定しますã?       {@value} */
063            private static final String VERSION = "5.3.8.0 (2011/08/01)" ;
064    
065            private static final long serialVersionUID = 538020110801L ;
066    
067            private static final String  DBID = "DEFAULT";
068            private final ApplicationInfo appInfo ;
069    
070            private Connection defconn = null;              // æœ?‚‚利用çŽ??高いDEFAULTã�?�‘、別に変数を用意ã?
071    
072            private final Map<String,Connection> dbidMap = new HashMap<String,Connection>();
073            private boolean isCommit   = false;
074            private boolean isRollback = false;
075            private boolean isError    = false;
076            private boolean isFinish   = false;
077    
078            /**
079             * ApplicationInfo を指定して作æ?する、コンストラクター
080             *
081             * こã?クラスは、基本çš?�«は、TransactionTag クラスから作æ?されますã?
082             *
083             * @param       appInfo å†?ƒ¨統制用のアクセスæƒ??
084             */
085            public TransactionImpl( final ApplicationInfo appInfo ) {
086                    this.appInfo = appInfo ;
087            }
088    
089            /**
090             * æŒ?®šã?DBID に対応したã?Connection オブジェクトを返しますã?
091             * å†?ƒ¨Mapに存在してã�?‚Œば、そのコネクションをã?存在しなければã€?
092             * 新しく作æ?しますã?
093             *
094             * @param       dbid  接続å?ID
095             *
096             * @return      æŒ?®šã?DBID に対応したã?Connectionオブジェクãƒ?
097             */
098            public Connection getConnection( final String dbid ) {
099                    if( dbid == null || dbid.length() == 0 || DBID.equalsIgnoreCase( dbid ) ) {
100                            if( defconn == null ) {
101                                    defconn = ConnectionFactory.connection( DBID,appInfo );
102                            }
103                            return defconn;
104                    }
105    
106                    String udbid = dbid.toUpperCase( Locale.JAPAN );        // 大æ–?­—化
107    
108                    Connection conn = dbidMap.get( udbid );
109                    if( conn == null ) {
110                            conn = ConnectionFactory.connection( udbid,appInfo );
111                            dbidMap.put( udbid,conn );
112                    }
113    
114                    return conn;
115            }
116    
117            /**
118             * コミットå?ç�?�Œ行われた場合に、å?部フラグ(isCommit)ã‚?true にセãƒ?ƒˆしますã?
119             * ?‘回でもコミットが行われており、ロールバックが行われてã�?�ªければã€?
120             * コミットされますã?
121             *
122             * 検索処ç�??みで、エラーが発生してã�?�ªã�??合ã?、コミットも行われなã�?‚±ースがありますã?
123             *
124             * @return 正常:true/異常:false
125             */
126            public boolean commit() {
127                    isCommit = true;
128                    return true;
129            }
130    
131            /**
132             * ロールバック処ç�?�Œ行われた場合に、å?部フラグ(isRollback)ã‚?true にセãƒ?ƒˆしますã?
133             * ?‘回でもロールバックが行われてã�?‚Œば、最終的にはロールバックされますã?
134             *
135             * ロールバックæŒ?®šã?場合ã?、isError フラグã‚?true(エラーæœ?にセãƒ?ƒˆしますã?
136             *
137             * @return 正常:true/異常:false
138             */
139            public boolean rollback() {
140                    isRollback = true;
141                    isError    = true;
142                    return true;
143            }
144    
145            /**
146             * トランザクションの、終äº?™‚処ç�?‚’行いますã?
147             *
148             * 実質çš?�«は、なにもしませんã€?
149             *
150             * @see #close( boolean )
151             *
152             * @return 正常:true/異常:false
153             */
154            public boolean close() {
155                    return close( false );
156            }
157    
158            /**
159             * トランザクションの、終äº?™‚処ç�?‚’行いますã?
160             *
161             * 引数は、正常かどã�?�‹を判定するフラグですã?異常の場合ã?、true をセãƒ?ƒˆしますã?
162             * ここでは、実際には何もしませんがã?å†?ƒ¨çš?�«エラーフラグをセãƒ?ƒˆしますã?
163             * (エラーの場合ã?みセãƒ?ƒˆ。リセãƒ?ƒˆはされません)
164             * ä¸?º¦でもã?エラーが発生したコネクションは、ç?æ£?�—ますã?それ以外ã?、ã?ールに戻しますã?
165             *
166             * @param       errFlag         [true:エラー状æ…?false:通常]
167             *
168             * @return 正常:true/異常:false
169             */
170            public boolean close( final boolean errFlag ) {
171                    if( errFlag ) { isError = true; }
172                    return true;
173            }
174    
175            /**
176             * トランザクションとして、正常終äº?™‚に処ç�?‚’行いますã?
177             *
178             * 実質çš?�«は、å?部のfinishフラグをセãƒ?ƒˆするã�?�‘ですã?
179             * ただしã?こã?フラグがセãƒ?ƒˆされてã�?�ªã�??合ã?、å?ç�?�Œ途中で止まっã�?
180             * 可能性があるためã?トランザクションとしては、正常終äº?�•せることができませんã€?
181             *
182             * @see #realClose()
183             */
184            public void finish() {
185                    isFinish = true;
186            }
187    
188            /**
189             * トランザクションとして、終äº?™‚処ç�?‚’行いますã?
190             *
191             * トランザクションがすべて完äº?�—た後で、呼び出しますã?
192             * ä¸?º¦でもã?Rollback が指定されてã�?‚Œば、ロールバックを行い、コネクションã‚?
193             * 破æ£?�—ますã?それ以外で、Commit が指定されてã�?‚Œば、コミットを行いã€?
194             * コネクションをã?プã?ルに戻しますã?どちらもæŒ?®šされてã�?�ªければã€?
195             * コネクションプã?ルに戻すだけになりますã?
196             *
197             * @og.rev 5.3.8.0 (2011/08/01) å†?ƒ¨変数をå?期化しã?こã?オブジェクトが再利用できるようにするã€?
198             */
199            public void realClose() {
200                    if( defconn != null ) {
201                            connClose( defconn,DBID );
202                    }
203    
204                    for( Map.Entry<String,Connection> entry : dbidMap.entrySet() ) {
205                            String     dbid = entry.getKey();
206                            Connection conn = entry.getValue();
207    
208                            connClose( conn,dbid );
209                    }
210    
211                    // å†?ƒ¨変数をå?期化しますã?
212                    defconn    = null;
213    
214                    // 5.3.8.0 (2011/08/01) å†?ƒ¨変数をå?期化しã?こã?オブジェクトが再利用できるようにするã€?
215    //              dbidMap    = null;
216                    dbidMap.clear();
217    
218                    isCommit   = false;
219                    isRollback = false;
220                    isError    = false;
221                    isFinish   = false;
222            }
223    
224            /**
225             * Connection オブジェクトをクローズしますã?
226             *
227             * 実際にはクローズせず、commit またã?、rollback を行った後ã?
228             * エラー状況に応じて、ConnectionFactory に返却するかã?削除しますã?
229             * なおã?commit またã?、rollback 時にエラーが発生したå?合でもã?無視して
230             * そã?まま、å?ç�?‚’継続しますã?
231             *
232             * @param  conn クローズ処ç�?‚’行う、Connection オブジェクãƒ?
233             * @param  dbid 接続å?ID
234             */
235            private void connClose( final Connection conn, final String dbid ) {
236                    // まずã?コミットかロールバックされたå?合ã?、どちらかの処ç�?�Œå¿?¦?
237                    if( isCommit || isRollback ) {
238                            // commit できる条件?šコミットされã?フィニッシュされ、エラーでなくã?ロールバックでなã�?
239                            if( isCommit && isFinish && (!isError) && (!isRollback) ) {
240                                    Closer.commit( conn );
241                            }
242                            // それ以外ã?、ロールバックするã€?
243                            else {
244                                    Closer.rollback( conn );
245                            }
246                    }
247    
248                    // 残りは、コミットもロールバックもされてã�?�ªã�?�Ÿめã?単にキャãƒ?‚·ュへの返し方のみ判定するã?
249                    // isFinish されてã�?�ªã�?�Œ、エラーにもなってã�?�ªã�??合ã?、接続要因以外ã?問題なので、返却でよいã€?
250                    if( isError ) { ConnectionFactory.remove( conn,dbid ); }        // 削除
251                    else {                  ConnectionFactory.close( conn,dbid );  }        // 返却
252    
253            }
254    }