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.hayabusa.taglib; 017 018 import org.opengion.hayabusa.common.HybsSystemException; 019 import org.opengion.fukurou.util.LogWriter; 020 import static org.opengion.fukurou.util.StringUtil.nval ; 021 import org.opengion.fukurou.util.FileUtil ; 022 023 import org.opengion.fukurou.process.MainProcess; 024 import org.opengion.fukurou.process.HybsProcess; 025 import org.opengion.fukurou.process.LoggerProcess; 026 import org.opengion.fukurou.process.Process_Logger; 027 028 import javax.servlet.jsp.JspWriter ; 029 import javax.servlet.http.HttpServletRequest ; 030 import javax.servlet.http.HttpServletResponse; 031 032 import java.util.List; 033 import java.util.ArrayList; 034 import java.util.Set; 035 import java.util.HashSet; 036 037 import java.io.PrintWriter ; 038 import java.io.ObjectOutputStream; 039 import java.io.ObjectInputStream; 040 import java.io.IOException; 041 042 /** 043 * HybsProcess を継承した、ParamProcess,FirstProcess,ChainProcess の実?ラス? 044 * 実行す?MainProcess を起動するクラスです? 045 * LoggerProcess は、最初に定義するクラスで、画面ログ、ファイルログ、を定義します? 046 * また?エラー発生時に、指定?メールアドレスにメール送信できます? 047 * Process_Logger は、なくても構いませんが??する?合?、最も最初に?しなければ 048 * なりません? 049 * 050 * ParamProcess は、??定義できるクラスで、データベ?ス接続情報を定義します? 051 * (??タベ?ス接続しなければ)なくても構いません? 052 * 053 * FirstProcess は、??実行する最初?クラスで、このクラスで??タが作?されます? 054 * ループ???、この FirstProcess で?作?され?LineModel オブジェクトを 055 * ?行づつ下位? ChainProcess に流して?ます? 056 * ChainProcess は、FirstProcess で作?されたデータを?受け取り、??ます? 057 * 処?象から外れる?合?、LineModel ?null に設定する為、下流には流れません? 058 * フィルタチェインの様に使用します?なくても構いませんし??存在しても構いません? 059 * 060 * @og.formSample 061 * ●形式?lt;og:mainProcess 062 * useJspLog ="[true/false]" 063 * useDisplay="[true/false]" > 064 * <og:process processID="ZZZ" > 065 * <og:param key="AAA" value="111" /> 066 * </og:process > 067 * </og:mainProcess > 068 * ●body?あ?EVAL_BODY_BUFFERED:BODYを評価し?{@XXXX} を解析しま? 069 * 070 * ●Tag定義?? 071 * <og:mainProcess 072 * command 【TAG?通常使?せん)処??実行を?す?command を設定できま?初期値:NEW) 073 * useJspLog 【TAG】ログ出力?に、JspWriter(つまり?HTML上?返り値)を使用するかど?[true/false]を指定しま?初期値:false) 074 * useDisplay 【TAG】画面表示先に、JspWriter(つまり?HTML上?返り値)を使用するかど?[true/false]を指定しま?初期値:false) 075 * useThread 【TAG】独立した別スレ?で実行するかど?[true/false]を指定しま?初期値:false) 076 * delayTime 【TAG】要求に対して、???実行開始を?させる時間を?しま?初期値:0? 077 * debug 【TAG】デバッグ??を?力するかど?[true/false]を指定しま?初期値:false) 078 * > ... Body ... 079 * </og:mainProcess> 080 * 081 * ●使用? 082 * <og:mainProcess 083 * useJspLog="true" > 084 * <og:process processID="DBReader" > 085 * <og:param key="dbid" value="FROM" /> 086 * <og:param key="sql" value="select * from GE02" /> 087 * </og:process > 088 * <og:process processID="DBWriter" > 089 * <og:param key="dbid" value="TO" /> 090 * <og:param key="table" value="GE02" /> 091 * </og:process > 092 * </og:mainProcess > 093 * 094 * @og.group 画面表示 095 * 096 * @version 4.0 097 * @author Kazuhiko Hasegawa 098 * @since JDK5.0, 099 */ 100 public class MainProcessTag extends CommonTagSupport { 101 //* こ?プログラ??VERSION??を設定します? {@value} */ 102 private static final String VERSION = "4.0.0.0 (2006/09/31)" ; 103 104 private static final long serialVersionUID = 400020060931L ; 105 106 /** command 引数に渡す事?出来?コマン? 新?{@value} */ 107 public static final String CMD_NEW = "NEW" ; 108 109 private List<HybsProcess> list = null; 110 111 private String command = CMD_NEW ; 112 private boolean isJspLog = false; 113 private boolean isDisplay = false; 114 private boolean useThread = false; 115 116 private int delayTime = 0; // 処???時間(? 117 private static final Set<String> lockSet = new HashSet<String>(); 118 private String urlKey = null ; 119 private boolean skipFlag = false; 120 121 // 4.0.0 (2007/03/06) Cleanable インターフェースによる初期化?? 122 // static { 123 // Cleanable clr = new Cleanable() { 124 // public void clear() { 125 // ConnDataFactory.clear(); 126 // lockSet.clear(); 127 // } 128 // }; 129 // 130 // SystemManager.addCleanable( clr ); 131 // } 132 133 /** 134 * Taglibの開始タグが見つかったときに処??doStartTag() ?オーバ?ライドします? 135 * 136 * @return 後続???? 137 */ 138 @Override 139 public int doStartTag() { 140 HttpServletRequest request = (HttpServletRequest)pageContext.getRequest(); 141 urlKey = getUrlKey( request ); 142 143 synchronized( lockSet ) { 144 // 新規追??、true , すでに存在すれば、false を返します? 145 boolean lock = lockSet.add( urlKey ); 146 skipFlag = !CMD_NEW.equalsIgnoreCase( command ) || ( !lock && delayTime > 0 ) ; 147 } 148 149 if( skipFlag ) { 150 System.out.println( "Skip Process : " + urlKey ); 151 return ( SKIP_BODY ); // 処?ません? 152 } 153 else { 154 list = new ArrayList<HybsProcess>(); 155 return ( EVAL_BODY_BUFFERED ); // Body を評価する 156 } 157 } 158 159 /** 160 * Taglibの終?グが見つかったときに処??doEndTag() ?オーバ?ライドします? 161 * 162 * @return 後続???? 163 */ 164 @Override 165 public int doEndTag() { 166 debugPrint(); // 4.0.0 (2005/02/28) 167 168 if( skipFlag ) { return(SKIP_PAGE); } 169 170 // ログの出力?を?り替えます? 171 if( isJspLog || isDisplay ) { 172 initLoggerProcess(); 173 } 174 175 boolean isOK = true; 176 try { 177 DelayedProcess process = new DelayedProcess( delayTime,urlKey,list ); 178 if( useThread ) { 179 new Thread( process ).start(); 180 } 181 else { 182 process.run(); 183 } 184 185 // 実行結果を?"DB.ERR_CODE" キーでリクエストにセ?する? 186 int errCode = process.getKekka(); 187 setRequestAttribute( "DB.ERR_CODE", String.valueOf( errCode ) ); 188 } 189 catch( Throwable th ) { 190 isOK = false; 191 LogWriter.log( th ); 192 try { 193 HttpServletResponse responce = (HttpServletResponse)pageContext.getResponse(); 194 responce.sendError( 304 , "ERROR:" + th.getMessage() ); 195 } 196 catch( IOException ex ) { 197 LogWriter.log( ex ); 198 } 199 } 200 201 if( isOK ) { return(EVAL_PAGE); } 202 else { return(SKIP_PAGE); } 203 } 204 205 /** 206 * タグリブオブジェクトをリリースします? 207 * キャ?ュされて再利用される?で、フィールド?初期設定を行います? 208 * 209 */ 210 @Override 211 protected void release2() { 212 super.release2(); 213 command = CMD_NEW ; 214 isJspLog = false; 215 isDisplay = false; 216 useThread = false; 217 delayTime = 0; // 処???時間(? 218 list = null; 219 } 220 221 /** 222 * 親クラスに登録するプロセスをセ?します? 223 * 224 * @param process 登録するプロセス 225 */ 226 protected void addProcess( final HybsProcess process ) { 227 if( ! list.isEmpty() && process instanceof LoggerProcess ) { 228 String errMsg = "LoggerProcess は、最も最初に?しなければなりません?; 229 throw new HybsSystemException( errMsg ); 230 } 231 list.add( process ); 232 } 233 234 /** 235 * 【TAG?通常使?せん)処??実行を?す?command を設定できま?初期値:NEW)? 236 * 237 * @og.tag 238 * こ?処??、command="NEW" の場合?み実行されます?RENEW時にはなにも行いません? 239 * 初期値は、NEW です? 240 * 241 * @param cmd コマン? 242 * @see <a href="../../../../constant-values.html#org.opengion.hayabusa.taglib.MainProcessTag.CMD_NEW">コマンド定数</a> 243 */ 244 public void setCommand( final String cmd ) { 245 command = nval( getRequestParameter( cmd ),command ); 246 } 247 248 /** 249 * 【TAG】ログ出力?に、JspWriter(つまり?HTML上?返り値)を使用するかど?[true/false]を指定しま?初期値:false)? 250 * 251 * @og.tag 252 * ログファイルは、processタグで、Logger を指定する?合に、パラメータ logFile にて 253 * ファイル?System.out/System.err 形式で?します? 254 * こ?場合?JSP 特有?Writerである、JspWriter(つまり?HTML上?返り値)は?? 255 * できません? 256 * ここでは、特別に ログの出力?を?JspWriter に?替えるかど?を指示 257 * できます? 258 * true を指定すると、画面出?JspWriter) に?替わります? 259 * 初期値は、false です? 260 * 261 * @param flag JspWriter出?[true:行う/false:行わない] 262 */ 263 public void setUseJspLog( final String flag ) { 264 isJspLog = nval( getRequestParameter( flag ),isJspLog ); 265 } 266 267 /** 268 * 【TAG】画面表示先に、JspWriter(つまり?HTML上?返り値)を使用するかど?[true/false]を指定しま?初期値:false)? 269 * 270 * @og.tag 271 * 画面表示は、processタグで、Logger を指定する?合に、パラメータ dispFile にて 272 * ファイル?System.out/System.err 形式で?します? 273 * こ?場合?JSP 特有?Writerである、JspWriter(つまり?HTML上?返り値)は?? 274 * できません? 275 * ここでは、特別に ログの出力?を?JspWriter に?替えるかど?を指示 276 * できます? 277 * true を指定すると、画面出?JspWriter) に?替わります? 278 * 初期値は、false です? 279 * 280 * @param flag JspWriter出?[true:行う/false:行わない] 281 */ 282 public void setUseDisplay( final String flag ) { 283 isDisplay = nval( getRequestParameter( flag ),isDisplay ); 284 } 285 286 /** 287 * 【TAG】独立した別スレ?で実行するかど?[true/false]を指定しま?初期値:false)? 288 * 289 * @og.tag 290 * MainProcess 処?実行する?合?比?実行時間が長?ースが?えられます? 291 * そこで、実行時に、スレ?を生成して処?行えば?同期に処?行う 292 * 事が可能です? 293 * ただし?そ?場合?出力につ?は、JspWriter 等で返すことは出来ません? 294 * 起動そのも?を?URL?? http で呼び出す?であれば、返り値を無視す? 295 * ことで、アプリサーバ?側のスレ?で処?きます? 296 * 初期値は??次処?false)です? 297 * 298 * @param flag [true:スレ?を使?false:?処?行う] 299 */ 300 public void setUseThread( final String flag ) { 301 useThread = nval( getRequestParameter( flag ),useThread ); 302 } 303 304 /** 305 * 【TAG】要求に対して、???実行開始を?させる時間を?しま?初期値:0?? 306 * 307 * @og.tag 308 * プロセス起動が、同時に大量に発生した?合に、すべての処?行うのではなく? 309 * ある程度?て、?の処??回?で済ますことが?来る?合があります? 310 * 例えば、更新??タ毎にトリガが起動されるケースなどです? 311 * それら?開始時刻を遅らせる事で、同時発生?トリガを1回のプロセス処? 312 * 実行すれ?、???度が向上します? 313 * ここでは、??開始されると、タイマ?をスタートさせ??時間経過後に? 314 * 処?開始するよ?しますが、その間?受け取ったリクエスト?、すべて 315 * 処?ず??れます? 316 * ここでは、リクエスト?タイミングと処??開始タイミングは厳?制御して 317 * ?せんので、??重?る可能性があります?よって、アプリケーション側で 318 * リクエストが?処?れても問題な??、制限をかける?があります? 319 * ?は、リクエスト引数単位に制御されます? 320 * 321 * @param time 処?始する遅延時間(? 322 */ 323 public void setDelayTime( final String time ) { 324 delayTime = nval( getRequestParameter( time ),delayTime ); 325 } 326 327 /** 328 * ログの出力?を?り替えます? 329 * 330 * LoggerProcess が存在すれば、そのログに、PrintWriter を直接?します? 331 * 存在しな??合?、デフォル?LoggerProcess を作?して、指定します? 332 */ 333 private void initLoggerProcess() { 334 final LoggerProcess logger ; 335 HybsProcess process = list.get(0); 336 if( process instanceof LoggerProcess ) { 337 logger = (LoggerProcess)process; 338 } 339 else { 340 logger = new Process_Logger(); 341 list.add( 0,logger ); 342 } 343 344 JspWriter out = pageContext.getOut(); 345 PrintWriter writer = FileUtil.getNonFlushPrintWriter( out ); 346 if( isJspLog ) { 347 logger.setLoggingWriter( writer ); 348 } 349 350 if( isDisplay ) { 351 logger.setDisplayWriter( writer ); 352 } 353 } 354 355 /** 356 * こ?リクエスト?引数を返します? 357 * 358 * @param request HttpServletRequestオブジェク? 359 * 360 * @return request.getRequestURL() + "?" + request.getQueryString() 361 */ 362 private String getUrlKey( final HttpServletRequest request ) { 363 StringBuffer address = request.getRequestURL(); 364 String query = request.getQueryString(); 365 if( query != null ) { 366 address.append( '?' ).append( query ); 367 } 368 return address.toString(); 369 } 370 371 /** 372 * シリアライズ用のカスタ?リアライズ書き込みメソ? 373 * 374 * @og.rev 4.0.0.0 (2006/09/31) 新規追? 375 * @serialData ?のオブジェクト?、シリアライズされません? 376 * 377 * @param strm ObjectOutputStreamオブジェク? 378 * @throws IOException 入出力エラーが発生した?? 379 */ 380 private void writeObject( final ObjectOutputStream strm ) throws IOException { 381 strm.defaultWriteObject(); 382 } 383 384 /** 385 * シリアライズ用のカスタ?リアライズ読み込みメソ? 386 * 387 * ここでは、transient 宣?れた?変数の??初期化が?なフィールド?み設定します? 388 * 389 * @og.rev 4.0.0.0 (2006/09/31) 新規追? 390 * @serialData ?のオブジェクト?、シリアライズされません? 391 * 392 * @param strm ObjectInputStreamオブジェク? 393 * @see #release2() 394 * @throws IOException シリアライズに関する入出力エラーが発生した?? 395 * @throws ClassNotFoundException クラスを見つけることができなかった?? 396 */ 397 private void readObject( final ObjectInputStream strm ) throws IOException , ClassNotFoundException { 398 strm.defaultReadObject(); 399 } 400 401 /** 402 * こ?オブジェクト???表現を返します? 403 * 基本???目?使用します? 404 * 405 * @return こ?クラスの??表現 406 */ 407 @Override 408 public String toString() { 409 return org.opengion.fukurou.util.ToString.title( this.getClass().getName() ) 410 .println( "VERSION" ,VERSION ) 411 .println( "list" ,list ) 412 .fixForm().toString() ; 413 } 414 415 private static final class DelayedProcess implements Runnable { 416 private final int delayTime ; 417 private final String urlKey; 418 private final List<HybsProcess> list; 419 private int errCode = MainProcess.RETURN_INIT ; 420 421 public DelayedProcess( final int delayTime,final String urlKey,final List<HybsProcess> list ) { 422 this.delayTime = delayTime; 423 this.urlKey = urlKey; 424 this.list = list; 425 } 426 427 public int getKekka() { return errCode; } 428 429 public void run() { 430 if( delayTime > 0 ) { 431 try { 432 Thread.sleep( delayTime * 1000L ); 433 } 434 catch( InterruptedException ex2 ) { 435 System.out.println( "InterruptedException:" + ex2.getMessage() ); 436 } 437 } 438 synchronized( lockSet ) { 439 lockSet.remove( urlKey ); // 処??開始前に解除します?取りこぼし対? 440 } 441 442 try { 443 MainProcess process = new MainProcess(); 444 process.setList( list ); 445 process.run(); 446 errCode = process.getKekka(); 447 } 448 catch( Throwable th ) { 449 errCode = MainProcess.RETURN_NG; 450 LogWriter.log( th ); 451 } 452 } 453 } 454 }