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 }