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