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.process; 017 018import org.opengion.fukurou.util.Argument; 019import org.opengion.fukurou.util.StringUtil; 020import org.opengion.fukurou.util.FileUtil; 021import org.opengion.fukurou.util.LogWriter; 022 023import java.util.List; 024import java.util.ArrayList; 025import java.util.Date; 026 027/** 028 * MainProcess は、HybsProcess を継承した、ParamProcess,FirstProcess,ChainProcess 029 * の実装クラスを実行するメインメソッドを持つクラスです。 030 * ParamProcess は、唯一 最初に定義できるクラスで、データベース接続やエラーメール 031 * などの共通なパラメータを定義します。なくても構いません。 032 * FirstProcess は、処理を実行する最初のクラスで、このクラスでデータが作成されます。 033 * ループ処理は、この FirstProcess で順次作成された LineModel オブジェクトを 034 * 1行づつ下位の ChainProcess に流していきます。 035 * ChainProcess は、FirstProcess で作成されたデータを、受け取り、処理します。 036 * 処理対象から外れる場合は、LineModel を null に設定する為、下流には流れません。 037 * フィルタチェインの様に使用します。なくても構いませんし、複数存在しても構いません。 038 * 039 * このクラスは、Runnable インターフェースを実装しています。 040 * 041 * 各実装クラスに引数を指定する場合は、-キー=値 形式で指定します。 042 * キーと値の間には、スベースを入れないで下さい。 043 * 先頭が - なら引数。 # ならコメント になります。 044 * - でも # でもない引数は、HybsProcess のサブクラスになります。 045 * 046 * Usage: java org.opengion.fukurou.process.MainProcess サブChainProcessクラス [[-キー=値] ・・・] [・・・] 047 * [ParamProcess実装クラス ]:ParamProcess を実装したクラス 048 * -キー=値 :各サブクラス毎の引数。 - で始まり、= で分割します。 049 * -AAA=BBB :引数は、各クラス毎に独自に指定します。 050 * FirstProcess実装クラス :FirstProcess を実装したクラス 051 * -キー=値 :各サブクラス毎の引数。 - で始まり、= で分割します。 052 * -AAA=BBB :引数は、各クラス毎に独自に指定します。 053 * #-AAA=BBB :先頭が - なら引数。 # ならコメント になります。 054 * [ChainProcess実装クラス1]:ChainProcess を実装したクラス:複数指定できます。 055 * -CCC=DDD 056 * [ChainProcess実装クラス2]:ChainProcess を実装したクラス:複数指定できます。 057 * -EEE=FFF 058 * 059 * @version 4.0 060 * @author Kazuhiko Hasegawa 061 * @since JDK5.0, 062 */ 063public final class MainProcess implements Runnable { 064 private static final String CR = System.getProperty("line.separator"); 065 066 /** main 処理のリターン値 初期化 {@value} */ 067 public static final int RETURN_INIT = -1; 068 /** main 処理のリターン値 正常値 {@value} */ 069 public static final int RETURN_OK = 0; 070 /** main 処理のリターン値 正常値 {@value} */ 071 public static final int RETURN_WARN = 1; 072 /** main 処理のリターン値 異常値 {@value} */ 073 public static final int RETURN_NG = 2; 074 075 private List<HybsProcess> list = null; 076 private ParamProcess param = null; 077 private LoggerProcess logger = null; 078 private int kekka = RETURN_INIT; 079 080 /** 081 * HybsProcess クラスを管理しているリストをセットします。 082 * 083 * 引数のListオブジェクトは、浅いコピーで、取り込みます。 084 * 085 * @param list HybsProcessリスト 086 * @throws IllegalArgumentException 引数が、null の場合。 087 */ 088 public void setList( final List<HybsProcess> list ) { 089 if( list == null ) { 090 String errMsg = "引数の List に、null は設定できません。" ; 091 throw new IllegalArgumentException( errMsg ); 092 } 093 this.list = new ArrayList<HybsProcess>( list ); 094 } 095 096 /** 097 * HybsProcess クラスを初期化します。 098 * 099 * 主に、ParamProcess クラスの取り出し(または、作成)処理を分離しています。 100 * 101 * @og.rev 5.1.5.0 (2010/04/01) 出力が2重、3重に出力されるのを回避します。 102 */ 103 private void init() { 104 if( list == null ) { 105 String errMsg = "リスト が null です。まず、setList( List<HybsProcess> ) が必要です。"; 106 throw new RuntimeException( errMsg ); 107 } 108 109 try { 110 // List の最上位は、必ず、LoggerProcess を配備する。 111 HybsProcess process = list.get(0); 112 if( process instanceof LoggerProcess ) { 113 logger = (LoggerProcess)process; 114 logger.init( null ); 115 list.remove(0); // List上から、LoggerProcess を削除しておきます。 116 process = list.get(0); // 次の取得を行っておく。プログラムの都合 117 } 118 else { 119 logger = new Process_Logger(); 120 logger.putArgument( "logFile" , "System.out" ); 121 logger.putArgument( "dispFile" , "System.out" ); 122 logger.init( null ); 123 } 124 125 // その次は、ParamProcess かどうかをチェック 126 if( process instanceof ParamProcess ) { 127 param = (ParamProcess)process; 128 param.setLoggerProcess( logger ); 129 param.init( null ); 130 list.remove(0); // List上から、ParamProcess を削除しておきます。 131 } 132 } 133 catch (Throwable th) { 134 StringBuilder errMsg = new StringBuilder(); 135 errMsg.append( "初期化中に例外が発生しました。" ).append( CR ); 136 errMsg.append( th.getMessage() ) ; 137 String errStr = errMsg.toString(); 138 139 logger.errLog( errStr,th ); 140 LogWriter.log( errStr ); 141 142 // 5.1.5.0 (2010/04/01) 出力が2重、3重に出力されるのを回避します。 143 if( param != null ) { param.end( false ); } 144 logger.end( false ); 145 146 throw new RuntimeException( errStr,th ); // 4.0.0 (2005/01/31) 147 } 148 } 149 150 /** 151 * HybsProcess クラスを実行します。 152 * 153 * @og.rev 5.1.2.0 (2010/01/01) 実行中の経過表示を、標準出力ではなく、エラー出力に変更 154 * @og.rev 5.1.5.0 (2010/04/01) 出力が2重、3重に出力されるのを回避します。 155 * @og.rev 5.3.4.0 (2011/04/01) タイトル追加 156 * @og.rev 5.5.4.5 (2012/07/27) 処理の最後に結果を出力します。 157 */ 158 public void run() { 159 init(); 160 161 long st = System.currentTimeMillis(); 162 logger.logging( "=================================================================" ); 163 logger.logging( new Date( st ) + " 処理を開始します。" ); 164 logger.logging( getClass().getName() ); 165 166 kekka = RETURN_NG; 167 LineModel model = null; 168 int rowNo = 0; 169 int cnt = list.size(); 170 try { 171 // 初期化 途中でエラーが発生すれば、終了します。 172 logger.logging( "初期化処理を行います。" ); 173 // if( param != null ) { logger.logging( param.toString() ); } 174 175 // List には、FirstProcess と ChainProcess のみ存在する。 176 HybsProcess process ; 177 for( int i=0; i<cnt; i++ ) { 178 process = list.get(i); 179 process.setLoggerProcess( logger ); 180 process.init( param ); 181 // logger.logging( process.toString() ); 182 } 183 184 logger.logging( "Process を実行します。" ); 185 FirstProcess firstProcess = (FirstProcess)list.get(0); 186 ChainProcess chainProcess ; 187 while( firstProcess.next() ) { 188 model = firstProcess.makeLineModel( rowNo ); 189 for( int i=1; i<cnt && model != null ; i++ ) { 190 chainProcess = (ChainProcess)list.get(i); 191 model = chainProcess.action( model ); 192 } 193 rowNo++; 194 // 5.1.2.0 (2010/01/01) 実行中の経過表示を、標準出力ではなく、エラー出力に変更します。 195 if( rowNo%50 == 0 ) { System.err.print( "." ); } 196 if( rowNo%1000 == 0 ) { System.err.println( " Count=[" + rowNo + "]" ); } 197 } 198 kekka = RETURN_OK; 199 logger.logging( " Total=[" + rowNo + "]" ); 200 System.err.println( " Total=[" + rowNo + "]" ); // 5.5.4.5 (2012/07/27) 処理の最後に結果を出力します。 201 } 202 catch (Throwable th) { 203 kekka = RETURN_NG; 204 205 StringBuilder errMsg = new StringBuilder(); 206 errMsg.append( CR ); // 5.1.5.0 (2010/04/01) 先に改行しておきます。 207 errMsg.append( "データ処理中に例外が発生しました。 [" ); 208 errMsg.append( rowNo ).append( "]行目" ).append( CR ); 209 errMsg.append( th.getMessage() ).append( CR ) ; 210 211 if( model != null ) { errMsg.append( model.toString() ).append( CR ) ; } 212 213 for( int i=0; i<cnt; i++ ) { 214 HybsProcess process = list.get(i); 215 errMsg.append( process.toString() ); 216 } 217 String errStr = errMsg.toString(); 218 logger.errLog( errStr,th ); 219 LogWriter.log( errStr ); 220 } 221 finally { 222 // 終了 必ず全ての endメソッドをコールします。 223 logger.logging( "終了処理を行います。" ); 224 StringBuilder buf = new StringBuilder(); 225 // 5.3.4.0 (2011/04/01) ロガーのreport()を呼びます。(タイトルを追加) 226 if( param != null ) { 227 buf.append( logger.report() ).append( CR ); 228 buf.append( param.report() ); 229 } 230 231 boolean isOK = kekka == RETURN_OK; 232 for( int i=0; i<cnt; i++ ) { 233 HybsProcess process = list.get(i); 234 if( process != null ) { 235 buf.append( CR ).append( process.report() ); 236 process.end( isOK ); 237 } 238 } 239 // 一番最後に、ParamProcess を終了します。 240 if( param != null ) { param.end( isOK ); } // 5.5.4.5 (2012/07/27) 一連のProcessの end() の最後にします。 241 242 buf.append( CR ); 243 logger.logging( buf.toString() ); 244 logger.logging( "実行結果は、[" + errCode(kekka) + "] です。" ); 245 long ed = System.currentTimeMillis(); 246 logger.logging( "合計処理時間 = " + (ed-st) + " (ms) です。" ); 247 logger.logging( new Date( ed ) + " 終了しました。" ); 248 249 // 一番最後に、ParamProcess を終了します。 250 logger.end( isOK ); 251 } 252 } 253 254 /** 255 * 処理の実行結果を返します。 256 * 257 * @return 実行結果 258 * @see #RETURN_INIT 259 */ 260 public int getKekka() { return kekka; } 261 262 /** 263 * 処理を行うメインメソッドです。 264 * 265 * @og.rev 4.0.0.0 (2007/11/22) ConnDataFactory の使用を廃止 266 * 267 * @param args コマンド引数配列 268 */ 269 public static void main( final String[] args ) { 270 if( args.length == 0 ) { 271 LogWriter.log( usage() ); 272 return ; 273 } 274 275 // 引数の加工 276 List<HybsProcess> list = makeHybsProcessList( args ); 277 278 // 特別に、LoggerProcess がなければ、標準出力を使用するロガーを登録する。 279 HybsProcess prcs = list.get(0); 280 if( ! (prcs instanceof LoggerProcess) ) { 281 LoggerProcess logger = new Process_Logger(); 282 logger.setDisplayWriter( FileUtil.getLogWriter( "System.out" ) ); 283 list.add( 0,logger ); 284 } 285 286 // 引数リスト(HybsProcessリスト)を登録 287 MainProcess process = new MainProcess(); 288 process.setList( list ); 289 290 // 処理の実行開始 291 process.run(); 292 } 293 294 /** 295 * メインに渡された引数配列 より、各 ChainProcess インスタンス を作成します。 296 * 297 * @param args メインに渡された引数配列 298 * 299 * @return ChainProcessインスタンスのList 300 */ 301 private static List<HybsProcess> makeHybsProcessList( final String[] args ) { 302 ArrayList<HybsProcess> list = new ArrayList<HybsProcess>(); 303 304 HybsProcess process = null; 305 Argument argment = new Argument( MainProcess.class.getName() ); 306 for( int i=0; i<args.length; i++ ) { 307 int type = argment.getArgumentType( args[i] ) ; 308 309 switch( type ) { 310 case Argument.CMNT : continue; 311 case Argument.ARGS : 312 process = (HybsProcess)StringUtil.newInstance( args[i] ); 313 list.add( process ); 314 break; 315 case Argument.PROP : 316 if( process != null ) { 317 process.putArgument( args[i] ); 318 } 319 break; 320 default: break; 321 } 322 } 323 return list; 324 } 325 326 /** 327 * エラーコードに対するメッセージを返します。 328 * 329 * @param code エラーコード 330 * 331 * @return エラーコードに対するメッセージ 332 */ 333 public String errCode( final int code ) { 334 final String errMsg ; 335 switch( code ) { 336 case RETURN_INIT : errMsg = "初期化" ; break; 337 case RETURN_OK : errMsg = "正常" ; break; 338 case RETURN_WARN : errMsg = "警告" ; break; 339 case RETURN_NG : errMsg = "異常" ; break; 340 default :errMsg = "未定義エラー" ; break; 341 } 342 return errMsg ; 343 } 344 345 /** 346 * このクラスの使用方法を返します。 347 * 348 * @return このクラスの使用方法 349 */ 350 private static String usage() { 351 352 StringBuilder buf = new StringBuilder(); 353 354 buf.append( "ChainProcess を実装した各クラスを、順次実行します。" ).append( CR ); 355 buf.append( "キーと値の間には、スベースを入れないで下さい。").append( CR ).append( CR ); 356 357 buf.append( "Usage: java org.opengion.fukurou.process.MainProcess サブChainProcessクラス [[-キー=値] ・・・] [・・・] " ).append( CR ); 358 buf.append( " サブChainProcessクラス :ChainProcess を実装したクラス" ).append( CR ); 359 buf.append( " -キー=値 :各サブクラス毎の引数。 - で始まり、= で分割します。" ).append( CR ); 360 buf.append( " -AAA=BBB :複数指定できます。" ).append( CR ); 361 buf.append( " サブChainProcessクラス :複数指定できます。" ).append( CR ); 362 buf.append( " -CCC=DDD " ).append( CR ); 363 364 return buf.toString(); 365 } 366}