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.process; 017 018 import org.opengion.fukurou.util.Argument; 019 import org.opengion.fukurou.util.Closer; 020 import org.opengion.fukurou.util.LogWriter; 021 import org.opengion.fukurou.model.Formatter; 022 import org.opengion.fukurou.db.ConnectionFactory; 023 024 import java.util.Map ; 025 import java.util.LinkedHashMap ; 026 027 import java.sql.Connection; 028 import java.sql.PreparedStatement; 029 import java.sql.ParameterMetaData; 030 import java.sql.ResultSet; 031 import java.sql.SQLException; 032 033 /** 034 * Process_DBCountFilter は、データベ?スの存在件数でフィルタリングする 035 * ChainProcess インターフェースの実?ラスです? 036 * 上?プロセスチェインの??タは上流から下流へと渡されます?)から受け取っ? 037 * LineModel を?に、データベ?スの存在チェ?を行い、下流への処?振り?けます? 038 * 具体的には、指定す?SELECT ??、?、?select count(*) from ???』形式にして下さ?? 039 * 検索カラ??、??で、そこには数字が入ります? 040 * 041 * ??タベ?ス接続?等?、ParamProcess のサブクラス(Process_DBParam)に 042 * 設定された接?Connection)を使用します? 043 * 044 * 引数??中にスペ?スを含??合?、ダブルコー??ション("") で括って下さ?? 045 * 引数??の ?』?前後には、スペ?スは挟めません。??key=value の様に 046 * 繋げてください? 047 * 048 * @og.formSample 049 * Process_DBCountFilter -dbid=DBGE -sql="select count(*) from GEA03" 050 * 051 * [ -dbid=DB接続ID ] ??-dbid=DBGE (? Process_DBParam の -configFile で?す?DBConfig.xml ファイルで規? 052 * [ -sql=検索SQL? ] ??-sql="SELECT COUNT(*) FROM GEA03 053 * WHERE SYSTEM_ID = [SYSTEM_ID] 054 * AND CLM = [CLM] 055 * AND FGJ = '1'" 056 * [ -sqlFile=検索SQLファイル ] ??-sqlFile=select.sql 057 * ?? -sql ?-sqlFile が指定されな??合?、エラーです? 058 * [ -count=スルー条件 ] ??-count=[0|1|2] は、検索値に応じたスルー条件? 059 * 0:?件時にスルー(処?継? つまり?なければ継? 060 * 1:?件時にスルー(処?継? つまり?あれば継? 061 * 2:?件以上ある?合にスルー つまり?キー重?に継? 062 * [ -display=[false/true] ] ?結果を標準?力に表示する(true)かしな?false)?初期値:false[表示しない]) 063 * [ -debug=[false/true] ] ?デバッグ??を標準?力に表示する(true)かしな?false)?初期値:false[表示しない]) 064 * 065 * @version 4.0 066 * @author Kazuhiko Hasegawa 067 * @since JDK5.0, 068 */ 069 public class Process_DBCountFilter extends AbstractProcess implements ChainProcess { 070 071 private Connection connection = null; 072 private PreparedStatement pstmt = null ; 073 private ParameterMetaData pMeta = null; // 5.1.1.0 (2009/11/11) setObject に、Type を渡す?(PostgreSQL対? 074 private boolean useParamMetaData = false; // 5.1.1.0 (2009/11/11) setObject に、Type を渡す?(PostgreSQL対? 075 076 private String dbid = null; 077 private String sql = null; 078 private int cntFlag = -2; // スルー条件 [0|1|2] 079 private boolean display = false; // 表示しな? 080 private boolean debug = false; // 5.7.3.0 (2014/02/07) ???? 081 082 private int[] clmNos = null; // ファイルのヘッ??のカラ?号 083 private boolean firstRow = true; // ??の?目 084 private int count = 0; 085 086 private static final Map<String,String> mustProparty ; // ?プロパティ???チェ?用 Map 087 private static final Map<String,String> usableProparty ; // ?プロパティ?整合?チェ? Map 088 089 static { 090 mustProparty = new LinkedHashMap<String,String>(); 091 092 usableProparty = new LinkedHashMap<String,String>(); 093 usableProparty.put( "dbid", "Process_DBParam の -configFile で?す?DBConfig.xml ファイルで規? ); 094 usableProparty.put( "sql", "カウン?QL?sql or sqlFile ??)" + 095 CR + "? \"SELECT COUNT(*) FROM GEA03 " + 096 CR + "WHERE SYSTEM_ID = [SYSTEM_ID] " + 097 CR + "AND CLM = [CLM] AND FGJ = '1'\"" ); 098 usableProparty.put( "sqlFile", "検索SQLファイル(sql or sqlFile ??)? select.sql" ); 099 usableProparty.put( "count", "[0|1|2] は、検索値に応じたスルー条件" + 100 CR + " 0:?件時にスルー(処?継? つまり?なければ継? + 101 CR + " 1:?件時にスルー(処?継? つまり?あれば継? + 102 CR + " 2:?件以上ある?合にスルー つまり?キー重?に継? ); 103 usableProparty.put( "display", "結果を標準?力に表示する(true)かしな?false)? + 104 CR + "(初期値:false:表示しな?" ); 105 usableProparty.put( "debug", "????を標準?力に表示する(true)かしな?false)? + 106 CR + "(初期値:false:表示しな?" ); // 5.7.3.0 (2014/02/07) ???? 107 } 108 109 /** 110 * ?ォルトコンストラクター? 111 * こ?クラスは、動??されます??ォルトコンストラクターで? 112 * super クラスに対して、?な初期化を行っておきます? 113 * 114 */ 115 public Process_DBCountFilter() { 116 super( "org.opengion.fukurou.process.Process_DBCountFilter",mustProparty,usableProparty ); 117 } 118 119 /** 120 * プロセスの初期化を行います?初めに??、呼び出されます? 121 * 初期処?ファイルオープン??オープン?に使用します? 122 * 123 * @og.rev 5.1.2.0 (2010/01/01) setObject に ParameterMetaData の getParameterType を渡す?(PostgreSQL対? 124 * @og.rev 5.3.8.0 (2011/08/01) useParamMetaData ?ConnectionFactory経由で取得?(PostgreSQL対? 125 * 126 * @param paramProcess ??タベ?スの接続???などを持って?オブジェク? 127 */ 128 public void init( final ParamProcess paramProcess ) { 129 Argument arg = getArgument(); 130 131 sql = arg.getFileProparty("sql","sqlFile",true); 132 cntFlag = arg.getProparty("count",cntFlag); 133 display = arg.getProparty("display",display); 134 debug = arg.getProparty("debug",debug); // 5.7.3.0 (2014/02/07) ???? 135 // if( debug ) { println( arg.toString() ); } // 5.7.3.0 (2014/02/07) ???? 136 137 dbid = arg.getProparty("dbid"); 138 connection = paramProcess.getConnection( dbid ); 139 // useParamMetaData = ApplicationInfo.useParameterMetaData( connection ); // 5.1.2.0 (2010/01/01) 140 useParamMetaData = ConnectionFactory.useParameterMetaData( dbid ); // 5.3.8.0 (2011/08/01) 141 } 142 143 /** 144 * プロセスの終?行います??に??、呼び出されます? 145 * 終???ファイルクローズ??クローズ?に使用します? 146 * 147 * @og.rev 4.0.0.0 (2007/11/27) commit,rollback,remove 処?追? 148 * @og.rev 5.1.2.0 (2010/01/01) pMeta のクリア 149 * 150 * @param isOK ト?タルで、OK?たかど? [true:成功/false:失敗] 151 */ 152 public void end( final boolean isOK ) { 153 boolean flag = Closer.stmtClose( pstmt ); 154 pstmt = null; 155 pMeta = null; // 5.1.1.0 (2009/11/11) 156 157 ConnectionFactory.remove( connection,dbid ); 158 159 if( !flag ) { 160 String errMsg = "ス??トメントをクローズ出来ません?; 161 throw new RuntimeException( errMsg ); 162 } 163 } 164 165 /** 166 * 引数の LineModel を??るメソ?です? 167 * 変換処?? LineModel を返します? 168 * 後続??行わな?????タのフィルタリングを行う場?は? 169 * null ??タを返します?つまり?null ??タは、後続??行わな? 170 * フラグの代わりにも使用して?す? 171 * なお?変換処?? LineModel と、オリジナルの LineModel が? 172 * 同?、コピ?(クローン)か?、各処?ソ??決めて?す? 173 * ドキュメントに明記されて???合?、副作用が問題になる?合?? 174 * ???とに自?コピ?(クローン)して下さ?? 175 * 176 * @og.rev 5.1.2.0 (2010/01/01) setObject に ParameterMetaData の getParameterType を渡す?(PostgreSQL対? 177 * @og.rev 5.3.8.0 (2011/08/01) useParamMetaData setNull 対?PostgreSQL対? 178 * @og.rev 5.7.2.2 (2014/01/24) SQL実行エラーを少し詳細に出力します? 179 * 180 * @param data ラインモ? オリジナルのLineModel 181 * 182 * @return 処?換後?LineModel 183 */ 184 public LineModel action( final LineModel data ) { 185 LineModel rtnData = data; 186 187 count++ ; 188 try { 189 if( firstRow ) { 190 pstmt = makePrepareStatement( data ); 191 if( useParamMetaData ) { 192 pMeta = pstmt.getParameterMetaData(); 193 } 194 firstRow = false; 195 if( display ) { println( data.nameLine() ); } // 5.7.3.0 (2014/02/07) ???? 196 } 197 198 // 5.1.1.0 (2009/11/11) setObject に ParameterMetaData の getParameterType を渡す?(PostgreSQL対? 199 if( useParamMetaData ) { 200 for( int i=0; i<clmNos.length; i++ ) { 201 int type = pMeta.getParameterType( i+1 ); 202 // 5.3.8.0 (2011/08/01) setNull 対? 203 // pstmt.setObject( i+1,data.getValue(clmNos[i]),type ); 204 Object val = data.getValue(clmNos[i]); 205 if( val == null || ( val instanceof String && ((String)val).isEmpty() ) ) { 206 pstmt.setNull( i+1, type ); 207 } 208 else { 209 pstmt.setObject( i+1, val, type ); 210 } 211 } 212 } 213 else { 214 for( int i=0; i<clmNos.length; i++ ) { 215 pstmt.setObject( i+1,data.getValue(clmNos[i]) ); 216 } 217 } 218 219 int cnt = -1; 220 ResultSet result = null; 221 try { 222 result = pstmt.executeQuery(); 223 if( result.next() ) { // ?行目固? 224 cnt = result.getInt( 1 ); // ?カラ?固? 225 } 226 } 227 finally { 228 Closer.resultClose( result ) ; 229 } 230 231 if( ( cnt > 2 && cntFlag != 2 ) || 232 ( cnt <= 2 && cnt != cntFlag ) ) { 233 rtnData = null; // 不?? 234 } 235 // if( display ) { printKey( count,cnt,data ); } 236 if( display ) { println( data.dataLine() ); } // 5.1.2.0 (2010/01/01) display の条件変更 237 } 238 catch (SQLException ex) { 239 // 5.7.2.2 (2014/01/24) SQL実行エラーを少し詳細に出力します? 240 String errMsg = "SQL を実行できませんでした? + CR 241 + "errMsg=[" + ex.getMessage() + "]" + CR 242 + "errCode=[" + ex.getErrorCode() + "] State=[" + ex.getSQLState() + "]" + CR 243 + "dbid=[" + dbid + "]" + CR 244 + "sql =[" + sql + "]" + CR 245 + "data=[" + data.dataLine() + "]" + CR ; 246 // String errMsg = "sql=[" + sql + "]" + CR + 247 // "errorCode=[" + ex.getErrorCode() + "] State=[" + ex.getSQLState() + "]" + CR ; 248 throw new RuntimeException( errMsg,ex ); 249 } 250 return rtnData; 251 } 252 253 /** 254 * ?で使用する PreparedStatement を作?します? 255 * 引数?? SQL また?、LineModel から作?した SQL より構築します? 256 * 257 * @og.rev 5.7.2.2 (2014/01/24) SQL実行エラーを少し詳細に出力します? 258 * 259 * @param data ラインモ? 処?象のLineModel 260 * 261 * @return PreparedStatementオブジェク? 262 */ 263 private PreparedStatement makePrepareStatement( final LineModel data ) { 264 265 // カラ?号は、makeFormat の処?設定して?す? 266 Formatter format = new Formatter( data ); 267 format.setFormat( sql ); 268 sql = format.getQueryFormatString(); 269 clmNos = format.getClmNos(); 270 271 final PreparedStatement ps ; 272 try { 273 ps = connection.prepareStatement( sql ); 274 } 275 catch (SQLException ex) { 276 // 5.7.2.2 (2014/01/24) SQL実行エラーを少し詳細に出力します? 277 String errMsg = "PreparedStatement を取得できませんでした? + CR 278 + "errMsg=[" + ex.getMessage() + "]" + CR 279 + "errCode=[" + ex.getErrorCode() + "] State=[" + ex.getSQLState() + "]" + CR 280 + "dbid=[" + dbid + "]" + CR 281 + "sql =[" + sql + "]" + CR 282 + "data=[" + data.dataLine() + "]" + CR ; 283 // String errMsg = "PreparedStatement を取得できませんでした? + CR 284 // + "sql=[" + sql + "]" + CR 285 // + "nameLine=[" + data.nameLine() + "]" ; 286 throw new RuntimeException( errMsg,ex ); 287 } 288 289 return ps; 290 } 291 292 /** 293 * プロセスの処?果のレポ?ト表現を返します? 294 * 処??ログラ?、?力件数、?力件数などの??です? 295 * こ???をそのまま、標準?力に出すことで、結果レポ?トと出来るよ? 296 * 形式で出してください? 297 * 298 * @return 処?果のレポ?? 299 */ 300 public String report() { 301 String report = "[" + getClass().getName() + "]" + CR 302 + TAB + "DBID : " + dbid + CR 303 + TAB + "Output Count : " + count ; 304 305 return report ; 306 } 307 308 /** 309 * 画面出力用のフォーマットを作?します? 310 * 311 * @og.rev 5.7.3.0 (2014/02/07) 表示方法?変更のため、? 312 * 313 * @param rowNo ??タ読み取り件数 314 * @param cnt 検索結果(の件数) 315 * @param data ラインモ? 316 */ 317 // private void printKey( final int rowNo , final int cnt , final LineModel data ) { 318 // StringBuilder buf = new StringBuilder(); 319 // 320 // buf.append( "row=[" ).append( rowNo ).append( "] : " ); 321 // buf.append( "count=[" ).append( cnt ).append( "] " ); 322 // for( int i=0; i < clmNos.length; i++ ) { 323 // if( i == 0 ) { buf.append( "where " ); } 324 // else { buf.append( " and " ); } 325 // buf.append( data.getName( clmNos[i] ) ); 326 // buf.append( " = " ); 327 // buf.append( data.getValue( clmNos[i] ) ); 328 // } 329 // 330 // println( buf.toString() ); 331 // } 332 333 /** 334 * こ?クラスの使用方法を返します? 335 * 336 * @return こ?クラスの使用方? 337 */ 338 public String usage() { 339 StringBuilder buf = new StringBuilder(); 340 341 buf.append( "Process_DBCountFilter は、データベ?スの存在件数でフィルタリングする" ).append( CR ); 342 buf.append( "ChainProcess インターフェースの実?ラスです?" ).append( CR ); 343 buf.append( "上?プロセスチェインの??タは上流から下流へと渡されます?)から" ).append( CR ); 344 buf.append( "受け取っ?LineModel を?に、データベ?スの存在チェ?を行い? ).append( CR ); 345 buf.append( "下流への処?振り?けます?" ).append( CR ); 346 buf.append( "存在チェ?で?す?SELECT ??、?、?select count(*) from ???? ).append( CR ); 347 buf.append( "形式にして下さ??検索カラ??、??で、そこには数字が入ります?" ).append( CR ); 348 buf.append( CR ); 349 buf.append( "??タベ?ス接続?等?、ParamProcess のサブクラス(Process_DBParam)に" ).append( CR ); 350 buf.append( "設定された接?Connection)を使用します?" ).append( CR ); 351 buf.append( CR ); 352 buf.append( "引数??中に空白を含??合?、ダブルコー??ション(\"\") で括って下さ??" ).append( CR ); 353 buf.append( "引数??の ?』?前後には、空白は挟めません。??key=value の様に" ).append( CR ); 354 buf.append( "繋げてください? ).append( CR ); 355 buf.append( CR ).append( CR ); 356 buf.append( getArgument().usage() ).append( CR ); 357 358 return buf.toString(); 359 } 360 361 /** 362 * こ?クラスは、main メソ?から実行できません? 363 * 364 * @param args コマンド引数配? 365 */ 366 public static void main( final String[] args ) { 367 LogWriter.log( new Process_DBCountFilter().usage() ); 368 } 369 }