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    }