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.fukurou.system;                                                            // 6.4.2.0 (2016/01/29) package変更 fukurou.util → fukurou.system
017
018import java.io.IOException;
019import java.io.Closeable;
020import java.sql.Connection;
021import java.sql.ResultSet;
022import java.sql.Statement;
023import java.sql.SQLException;
024import java.util.zip.ZipFile;           // 5.5.2.6 (2012/05/25)
025
026import static org.opengion.fukurou.system.HybsConst.CR;                         // 6.1.0.0 (2014/12/26) refactoring
027
028/**
029 * Closer.java は、共通的に使用される close処理を集約した、クラスです。
030 *
031 * 各種 close() 処理では、Exception が発生しても、どうすることも出来ない
032 * ケースが多々あります。また、close() 処理中の Exception の為だけに、
033 * try ~ catch 節を用意しなければならず、finally 節内からの さらなる
034 * throw など、コーディング上、本流以外の箇所で、色々と問題が発生します。
035 * ここでは、とりあえず、LogWriter.log するだけにしていますが、
036 * 将来的には、エラーを別ファイルにセーブしたり、データベースに書き込んだり
037 * 出来ると思います。
038 *
039 * また、close 処理とは異なりますが、commit や、rollback など、finally 節に
040 * 書き込んで、必ず処理したいが、Exception 発生時に、どうしようもない処理も、
041 * ここに集約していきます。
042 *
043 * @og.rev 6.4.2.0 (2016/01/29) エラー処理を統一的に行います。
044 * @og.rev 6.4.2.0 (2016/01/29) package変更 fukurou.util → fukurou.system
045 *
046 * @version  4.0
047 * @author       Kazuhiko Hasegawa
048 * @since    JDK5.0,
049 */
050public final class Closer {
051        // 6.4.2.0 (2016/01/29) エラー処理を統一的に行います。
052        private static final String IO_CLOSE_ERR        = "ストリーム close 処理でエラーが発生しました。" ;
053        private static final String COMMIT_ERR          = "Connection を commit することが出来ません。" ;
054        private static final String ROLLBACK_ERR        = "Connection を rollback することが出来ません。" ;
055        private static final String CONN_CLOSE_ERR      = "Connection を close することが出来ません。" ;
056        private static final String STMT_CLOSE_ERR      = "Statement を close することが出来ません。" ;
057        private static final String RESULT_CLOSE_ERR= "ResultSet を close することが出来ません。" ;
058        private static final String ZIP_CLOSE_ERR       = "ZipFile/JarFile を close することが出来ません。" ;
059        private static final String UNNONE_ERR          = "予期せぬエラーが発生しました。" ;
060
061        /**
062         * すべてが staticメソッドなので、コンストラクタを呼び出さなくしておきます。
063         *
064         */
065        private Closer() {}
066
067        /**
068         * io関連の close 処理時の IOException を無視して、close 処理を行います。
069         * ここでは、処理中のエラーは、System.err に出力するだけで無視します。
070         *
071         * これにより、try ~ catch ~ finally 処理で、close を finally 処理から
072         * 例外を送出させなくてすむようになります。
073         * 引数が、null の場合は、何も処理しません。(正常:trueを返します。)
074         *
075         * @og.rev 4.0.0.0 (2007/02/08) 新規追加
076         *
077         * @param obj Closeableインターフェースを実装したIO関連オブジェクト
078         *
079         * @return 正常:true/異常:false
080         */
081        public static boolean ioClose( final Closeable obj ) {
082                boolean isOK = true;
083
084                try {
085                        if( obj != null ) { obj.close(); }
086                }
087                catch( final IOException ex ) {
088                        isOK = false;
089                        logWriter( IO_CLOSE_ERR , obj.toString() , ex );
090                }
091                catch( final RuntimeException ex ) {
092                        isOK = false;
093                        logWriter( UNNONE_ERR , obj.toString() , ex );
094                }
095
096                return isOK;
097        }
098
099        /**
100         * Connection オブジェクトを commit します。
101         * ここでは、処理中のエラーは、System.err に出力するだけで無視します。
102         *
103         * @og.rev 4.0.0.0 (2007/02/08) 新規追加
104         *
105         * @param conn コネクションオブジェクト
106         *
107         * @return 正常:true/異常:false
108         */
109        public static boolean commit( final Connection conn ) {
110                boolean isOK = true;
111
112                try {
113                        if( conn != null ) { conn.commit(); }
114                }
115                catch( final SQLException ex ) {
116                        logWriter( COMMIT_ERR , ex.getSQLState() , ex );
117                }
118                catch( final RuntimeException ex ) {
119                        isOK = false;
120                        logWriter( UNNONE_ERR , ex.getMessage() , ex );
121                }
122
123                return isOK;
124        }
125
126        /**
127         * Connection オブジェクトをrollbackします。
128         * ここでは、処理中のエラーは、標準出力に出力するだけで無視します。
129         *
130         * @og.rev 4.0.0.0 (2007/02/08) 新規追加
131         * @og.rev 8.1.0.4 (2022/01/28) Connection#isClosed で先に判定する。
132         *
133         * @param conn コネクションオブジェクト
134         *
135         * @return 正常:true/異常:false
136         */
137        public static boolean rollback( final Connection conn ) {
138                boolean isOK = true;
139
140                try {
141//                      if( conn != null ) { conn.rollback(); }
142                        if( conn != null && !conn.isClosed() ) { conn.rollback(); }     // 8.1.0.4 (2022/01/28)
143                }
144                catch( final SQLException ex ) {
145                        logWriter( ROLLBACK_ERR , ex.getSQLState() , ex );
146                }
147                catch( final RuntimeException ex ) {
148                        isOK = false;
149                        logWriter( UNNONE_ERR , ex.getMessage() , ex );
150                }
151
152                return isOK;
153        }
154
155        /**
156         * Connection オブジェクトをcloseします。
157         * ここでは、処理中のエラーは、標準出力に出力するだけで無視します。
158         *
159         * ここでは、現実の Connection の close() メソッドを呼び出しますので、
160         * キャッシュ等で使用しているコネクションには適用しないでください。
161         *
162         * @og.rev 4.0.0.0 (2007/02/08) 新規追加
163         * @og.rev 5.5.5.0 (2012/07/28) commit追加
164         * @og.rev 5.9.4.0 (201601//08) commit前にvalidのチェックを行う(10秒でタイムアウト)
165         *
166         * @param conn コネクションオブジェクト
167         *
168         * @return 正常:true/異常:false
169         */
170        public static boolean connClose( final Connection conn ) {
171                boolean isOK = true;
172
173                try {
174                        if( conn != null && ! conn.isClosed() ) {
175                                if( conn.isValid(10) ){         // 5.9.4.0 (2016/01/08)
176                                        conn.commit();                  // 5.5.5.0 (2012/07/28)
177                                }
178                                conn.close();
179                        }
180                }
181                catch( final SQLException ex ) {
182                        logWriter( CONN_CLOSE_ERR , ex.getSQLState() , ex );
183                }
184                catch( final RuntimeException ex ) {
185                        isOK = false;
186                        logWriter( UNNONE_ERR , ex.getMessage() , ex );
187                }
188
189                return isOK;
190        }
191
192        /**
193         * Statement オブジェクトをクローズします。
194         * ここでは、処理中のエラーは、標準出力に出力するだけで無視します。
195         *
196         * @og.rev 4.0.0.0 (2007/02/08) 新規追加
197         * @og.rev 8.1.0.3 (2022/01/21) isClosed()チェック他
198         *
199         * @param stmt Statementオブジェクト
200         *
201         * @return 正常:true/異常:false
202         */
203        public static boolean stmtClose( final Statement stmt ) {
204                boolean isOK = true;
205
206                try {
207//                      if( stmt != null ) { stmt.close(); }
208                        if( stmt != null && !stmt.isClosed() ) { stmt.close(); }        // 8.1.0.3 (2022/01/21)
209                }
210                catch( final SQLException ex ) {
211                        logWriter( STMT_CLOSE_ERR , ex.getSQLState() , ex );
212                }
213                catch( final RuntimeException ex ) {
214                        isOK = false;
215                        logWriter( UNNONE_ERR , ex.getMessage() , ex );
216                }
217
218                return isOK;
219        }
220
221        /**
222         * ResultSet オブジェクトをクローズします。
223         * ここでは、処理中のエラーは、標準出力に出力するだけで無視します。
224         *
225         * @og.rev 4.0.0.0 (2007/02/08) 新規追加
226         * @og.rev 8.1.0.3 (2022/01/21) isClosed()チェック他
227         *
228         * @param result ResultSetオブジェクト
229         *
230         * @return 正常:true/異常:false
231         */
232        public static boolean resultClose( final ResultSet result ) {
233                boolean isOK = true;
234
235                try {
236//                      if( result != null ) { result.close(); }
237                        if( result != null && !result.isClosed() ) { result.close(); }  // 8.1.0.3 (2022/01/21)
238                }
239                catch( final SQLException ex ) {
240                        logWriter( RESULT_CLOSE_ERR , ex.getSQLState() , ex );
241                }
242                catch( final RuntimeException ex ) {
243                        isOK = false;
244                        logWriter( UNNONE_ERR , ex.getMessage() , ex );
245                }
246
247                return isOK;
248        }
249
250        /**
251         * ZipFile オブジェクトをクローズします。
252         * Jar ファイルも、このメソッドでクローズします。
253         * ここでは、処理中のエラーは、標準出力に出力するだけで無視します。
254         *
255         * @og.rev 5.5.2.6 (2012/05/25) findbugs対応に伴い、新規追加
256         *
257         * @param zipFile ZipFileオブジェクト
258         *
259         * @return 正常:true/異常:false
260         */
261        public static boolean zipClose( final ZipFile zipFile ) {
262                boolean isOK = true;
263
264                try {
265                        if( zipFile != null ) { zipFile.close(); }
266                }
267                catch( final IOException ex ) {
268                        logWriter( ZIP_CLOSE_ERR , zipFile.getName() , ex );
269                }
270                catch( final RuntimeException ex ) {
271                        isOK = false;
272                        logWriter( UNNONE_ERR , ex.getMessage() , ex );
273                }
274
275                return isOK;
276        }
277
278        /**
279         * AutoCloseable オブジェクトをクローズします。
280         * これは、Java1.7 で導入された、try-with-resourcesブロックの終了時に自動的に呼び出される
281         * close() メソッドを、使用します。
282         * 基本的には、try-with-resourcesブロックを使用すべきですが、Exception を発生させたくないため
283         * ここで、close() する処理を残しておきます。
284         * ちなみに、IO系や、SQL系も、AutoCloseable を継承していますが、独自のエラーメッセージを出せないため、
285         * エラーの内容がわかっている場合は、個々に適したクロースメソッドを呼び出してください。
286         *
287         * @og.rev 6.4.2.0 (2016/01/29) エラー処理を統一的に行います。
288         *
289         * @param autoClose AutoCloseableオブジェクト
290         *
291         * @return 正常:true/異常:false
292         */
293        public static boolean autoClose( final AutoCloseable autoClose ) {
294                boolean isOK = true;
295
296                try {
297                        if( autoClose != null ) { autoClose.close(); }
298                }
299                catch( final Throwable th ) {
300                        isOK = false;
301                        logWriter( UNNONE_ERR , th.getMessage() , th );
302                }
303
304                return isOK;
305        }
306
307        /**
308         * Exception 発生時の処理を、統一します。
309         * ここでは、LogWriter に、書き出します。
310         *
311         * @og.rev 6.4.2.0 (2016/01/29) エラー処理を統一的に行います。
312         *
313         * @param msg  エラー時のメッセージ
314         * @param cmnt コメント
315         * @param th   Throwableオブジェクト
316         */
317        private static void logWriter( final String msg , final String cmnt , final Throwable th ) {
318                final String errMsg = msg + th.getMessage() + ":" + cmnt + CR;
319                LogWriter.log( errMsg );
320                LogWriter.log( th );
321        }
322}