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.system.Closer ; 020import org.opengion.fukurou.util.FileUtil ; 021import org.opengion.fukurou.util.StringUtil ; 022import org.opengion.fukurou.system.LogWriter; 023import org.opengion.fukurou.system.ThrowUtil; // 6.4.2.0 (2016/01/29) 024import org.opengion.fukurou.mail.MailTX ; 025 026import java.util.Map ; 027import java.util.LinkedHashMap ; 028import java.io.PrintWriter ; 029import java.io.StringWriter ; 030 031/** 032 * Process_Logger は、画面出力、ファイルログ、エラーメールを管理する、 033 * ロギング関係の LoggerProcess インターフェースの実装クラスです。 034 * 035 * MainProcess で使用されるログと、各種 Process で使用されるディスプレイを 036 * 管理します。また、エラー発生時の、メール送信機能も、ここで用意します。 037 * 038 * 引数文字列中にスペースを含む場合は、ダブルコーテーション("") で括って下さい。 039 * 引数文字列の 『=』の前後には、スペースは挟めません。必ず、-key=value の様に 040 * 繋げてください。 041 * 042 * @og.formSample 043 * Process_Logger -logFile=ABC.txt -dispFile=System.out 044 * 045 * [ -logFile=ログ出力先指定 ] : -logFile=[ファイル名/System.out/System.err] (初期値:null) 046 * [ -dispFile=画面出力先指定 ] : -dispFile=[ファイル名/System.out/System.err](初期値:null) 047 * [ -host=メールサーバ ] : -host=メールサーバー 048 * [ -from=送信From ] : -from=送信元アドレス 049 * [ -to=受信To ] : -to=送信先アドレスをCSV形式で並べる 050 * [ -charset=キャラクタセット ] : -charset=メール送信時のキャラクタセット [ISO-2022-JP / Windows-31J] 051 * [ -subject=タイトル ] : -subject=タイトル 052 * [ -message=本文雛形 ] : -message=本文雛形文章 053 * [ -msgFile=本文雛形ファイル ] : -msgFile=本文を格納しているファイルのアドレス 054 * [ -{@XXXX}=YYYY ] : メッセージ本文の {@XXXX} 文字列を、YYYY 文字列に変換します。 055 * 056 * @version 4.0 057 * @author Kazuhiko Hasegawa 058 * @since JDK5.0, 059 */ 060public class Process_Logger extends AbstractProcess implements LoggerProcess { 061 062 private String logFile ; // ログ出力先 063 private String dispFile ; // 画面出力先 064 065 private PrintWriter logWriter ; 066 private PrintWriter dispWriter ; 067 068 // 6.3.1.1 (2015/07/10) JspWriter を設定されたかどうかを管理します。 069 private boolean isJspLogWriter ; 070 private boolean isJspDispWriter ; 071 072 /** メール送信時のデフォルトキャラクタセット {@value} */ 073 public static final String DEFAULT_CHARSET = "ISO-2022-JP" ; 074 private String host = "mail.opengion.org"; 075 private String from = "DUMMY@DUMMY"; 076 private String to ; 077 private String subject ; // 5.3.1.0 (2011/03/10) 078 private boolean useErrMail ; 079 080 /** staticイニシャライザ後、読み取り専用にするので、ConcurrentHashMap を使用しません。 */ 081 private static final Map<String,String> MUST_PROPARTY ; // [プロパティ]必須チェック用 Map 082 /** staticイニシャライザ後、読み取り専用にするので、ConcurrentHashMap を使用しません。 */ 083 private static final Map<String,String> USABLE_PROPARTY ; // [プロパティ]整合性チェック Map 084 085 static { 086 MUST_PROPARTY = new LinkedHashMap<>(); 087 088 USABLE_PROPARTY = new LinkedHashMap<>(); 089 USABLE_PROPARTY.put( "logFile", "ログ出力先指定のファイル名を指定します(初期値:null)" + 090 CR + "『System.out』,『System.err』は特殊な名称です。" ); 091 USABLE_PROPARTY.put( "dispFile", "画面出力先指定のファイル名を指定します(初期値:null)" + 092 CR + "『System.out』,『System.err』は特殊な名称です。" ); 093 USABLE_PROPARTY.put( "host", "メールサーバー" ); 094 USABLE_PROPARTY.put( "from", "送信元アドレス" ); 095 USABLE_PROPARTY.put( "to", "送信先アドレスをCSV形式で並べる" ); 096 USABLE_PROPARTY.put( "charset", "メール送信時のキャラクタセット [ISO-2022-JP / Windows-31J]" ); 097 USABLE_PROPARTY.put( "subject", "タイトル" ); 098 USABLE_PROPARTY.put( "message", "本文雛形文章" ); 099 USABLE_PROPARTY.put( "msgFile", "本文雛形を格納しているファイルのアドレス" ); 100 USABLE_PROPARTY.put( "{@", "{@XXXX}=YYYY 汎用文字変換" + 101 CR + "メッセージ本文の {@XXXX} 文字列を、YYYY 文字列に変換します。" ); 102 USABLE_PROPARTY.put( "{@ARG.", "{@ARG.XXX} 予約文字変換 上記引数を割り当てます。" ); 103 USABLE_PROPARTY.put( "{@DATE.", "{@DATE.XXX} 予約文字変換 の文字を変換します。" + 104 CR + "(SimpleDateFormat 形式の日付、時刻等)" ); 105 USABLE_PROPARTY.put( "{@ENV.", "{@ENV.XXX} 予約文字変換 システムプロパティーの文字を変換します。" + 106 CR + "(java -Dkey=value オプションで引き渡します。)" ); 107 } 108 109 /** 110 * デフォルトコンストラクター。 111 * このクラスは、動的作成されます。デフォルトコンストラクターで、 112 * super クラスに対して、必要な初期化を行っておきます。 113 * 114 */ 115 public Process_Logger() { 116 super( "org.opengion.fukurou.process.Process_Logger",MUST_PROPARTY,USABLE_PROPARTY ); 117 } 118 119 /** 120 * プロセスの初期化を行います。初めに一度だけ、呼び出されます。 121 * 初期処理(ファイルオープン、DBオープン等)に使用します。 122 * 123 * @og.rev 5.3.4.0 (2011/04/01) タイトル追加 124 * 125 * @param paramProcess データベースの接続先情報などを持っているオブジェクト 126 */ 127 public void init( final ParamProcess paramProcess ) { 128 final Argument arg = getArgument(); 129 130 logFile = arg.getProparty( "logFile" ); // ログ出力先 131 dispFile = arg.getProparty( "dispFile" ); // 画面出力先 132 133 if( logWriter == null && logFile != null ) { 134 logWriter = FileUtil.getLogWriter( logFile ); 135 } 136 137 if( dispWriter == null && dispFile != null ) { 138 dispWriter = FileUtil.getLogWriter( dispFile ); 139 } 140 141 host = arg.getProparty( "host",host ); // メールサーバー 142 from = arg.getProparty( "from",from ); // 送信元アドレス 143 to = arg.getProparty( "to" ,to ); // 送信先アドレス 144 subject = arg.getProparty( "subject" ); // 5.3.4.0 (2011/04/01) タイトル 145 useErrMail = host != null && from != null && to != null ; 146 } 147 148 /** 149 * プロセスの終了を行います。最後に一度だけ、呼び出されます。 150 * 終了処理(ファイルクローズ、DBクローズ等)に使用します。 151 * 152 * @param isOK トータルで、OKだったかどうか[true:成功/false:失敗] 153 */ 154 public void end( final boolean isOK ) { 155 if( logWriter != null ) { 156 logWriter.flush(); 157 Closer.ioClose( logWriter ); 158 } 159 160 if( dispWriter != null ) { 161 dispWriter.flush(); 162 Closer.ioClose( dispWriter ); 163 } 164 } 165 166 /** 167 * ログファイルにメッセージを表示します。 168 * 169 * @og.rev 6.3.1.1 (2015/07/10) JspWriter を使用する場合は、タグをエスケープする必要がある。 170 * 171 * @param msg 表示するメッセージ 172 */ 173 @Override 174 public void logging( final String msg ) { 175 if( logWriter != null ) { 176 // 6.3.1.1 (2015/07/10) 177 final String msg2 = isJspLogWriter ? StringUtil.htmlFilter( msg ) : msg ; 178 logWriter.println( msg2 ) ; 179 } 180 } 181 182 /** 183 * ディスプレイにメッセージを表示します。 184 * 185 * @param msg 表示するメッセージ 186 */ 187 @Override 188 public void println( final String msg ) { 189 if( dispWriter != null ) { 190 // 6.3.1.1 (2015/07/10) 191 final String msg2 = isJspDispWriter ? StringUtil.htmlFilter( msg ) : msg ; 192 dispWriter.println( msg2 ) ; 193 } 194 } 195 196 /** 197 * エラーログにメッセージを表示します。 198 * ここに書き込まれたメッセージは、通常ログと、特殊ログの 199 * 両方に書き込まれます。 200 * 特殊ログとは、メール連絡等のことです。 201 * 202 * @og.rev 6.3.1.1 (2015/07/10) JspWriter を使用する場合は、タグをエスケープする必要がある。 203 * @og.rev 6.4.2.0 (2016/01/29) ex.printStackTrace() を、ThrowUtil#ogStackTrace(Throwable) に置き換え。 204 * 205 * @param msg 表示するメッセージ 206 * @param th Throwable例外オブジェクト 207 */ 208 public void errLog( final String msg,final Throwable th ) { 209 String sendMsg = msg; 210 if( logWriter != null ) { 211 if( th != null ) { 212 final StringWriter errMsg = new StringWriter(); 213 errMsg.append( msg ).append( CR ); 214 System.err.println( ThrowUtil.ogStackTrace( th ) ); // 6.4.2.0 (2016/01/29) 215 sendMsg = errMsg.toString(); 216 } 217 // 6.3.1.1 (2015/07/10) 218 final String msg2 = isJspLogWriter ? StringUtil.htmlFilter( sendMsg ) : sendMsg ; 219 logWriter.println( msg2 ) ; 220 } 221 println( sendMsg ) ; 222 if( useErrMail ) { sendmail( sendMsg ) ; } 223 } 224 225 /** 226 * メール送信を行います。 227 * 228 * @og.rev 5.3.4.0 (2011/04/01) タイトル追加 229 * 230 * @param msg 送信するメッセージ 231 */ 232 private void sendmail( final String msg ) { 233 234 final Argument arg = getArgument(); 235 236 final String charset = arg.getProparty( "charset", DEFAULT_CHARSET ); 237 final MailTX mail = new MailTX( host,charset ); 238 mail.setFrom( from ); 239 mail.setTo( StringUtil.csv2Array( to ) ); 240 mail.setSubject( subject ); // 5.3.4.0 (2011/04/01) 241 242 final String message = arg.getFileProparty( "message","msgFile",false ); 243 244 // {@XXX} 変換は、Argument クラスの機能を使う。 245 // 6.1.0.0 (2014/12/26) refactoring 246 mail.setMessage( arg.changeParam( message ) + CR + msg ); 247 mail.sendmail(); 248 } 249 250 /** 251 * ログ出力用のPrintWriterを設定します。 252 * 通常は、引数の -logFile=XXXX で指定しますが、直接 PrintWriter を 253 * 渡す必要があるケース(JSPなどで使用するケース)で使用します。 254 * 引数より、こちらの設定のほうが、優先されます。 255 * ※ JspWriter を渡す場合の PrintWriter は、flushing および、close 処理を 256 * 行わない NonFlushPrintWriter を設定してください。 257 * 258 * ※ 6.3.1.1 (2015/07/10) 259 * このメソッドは、JspWriter を設定する時のみ使用されるので、出力時には 260 * StringUtil#htmlFilter(String) を使って、タグをエスケープします。 261 * そのための、フラグを用意します。 262 * 263 * @og.rev 6.3.1.1 (2015/07/10) JspWriter を使用する場合は、タグをエスケープする必要がある。 264 * 265 * @param logWriter ログ出力用のPrintWriter 266 */ 267 public void setLoggingWriter( final PrintWriter logWriter ) { 268 this.logWriter = logWriter; 269 if( logWriter != null ) { isJspLogWriter = true; } // 6.3.1.1 (2015/07/10) 270 } 271 272 /** 273 * 画面表示用のPrintWriterを設定します。 274 * 通常は、引数の -dispFile=XXXX で指定しますが、直接 PrintWriter を 275 * 渡す必要があるケース(JSPなどで使用するケース)で使用します。 276 * 引数より、こちらの設定のほうが、優先されます。 277 * ※ JspWriter を渡す場合の PrintWriter は、flushing および、close 処理を 278 * 行わない NonFlushPrintWriter を設定してください。 279 * 280 * ※ 6.3.1.1 (2015/07/10) 281 * このメソッドは、JspWriter を設定する時のみ使用されるので、出力時には 282 * StringUtil#htmlFilter(String) を使って、タグをエスケープします。 283 * そのための、フラグを用意します。 284 * 285 * @og.rev 6.3.1.1 (2015/07/10) JspWriter を使用する場合は、タグをエスケープする必要がある。 286 * 287 * @param dispWriter 画面表示用のPrintWriter 288 */ 289 public void setDisplayWriter( final PrintWriter dispWriter ) { 290 this.dispWriter = dispWriter; 291 if( dispWriter != null ) { isJspDispWriter = true; } // 6.3.1.1 (2015/07/10) 292 } 293 294 /** 295 * プロセスの処理結果のレポート表現を返します。 296 * 処理プログラム名、入力件数、出力件数などの情報です。 297 * この文字列をそのまま、標準出力に出すことで、結果レポートと出来るような 298 * 形式で出してください。 299 * 300 * @og.rev 5.3.4.0 (2011/04/01) タイトル追加 301 * 302 * @return 処理結果のレポート 303 * @og.rtnNotNull 304 */ 305 public String report() { 306 return "[" + getClass().getName() + "]" + CR 307 + TAB + "Subject : " + subject + CR 308 + TAB + "Log File : " + logFile + CR 309 + TAB + "Display File : " + dispFile ; 310 } 311 312 /** 313 * このクラスの使用方法を返します。 314 * 315 * @return このクラスの使用方法 316 * @og.rtnNotNull 317 */ 318 public String usage() { 319 final StringBuilder buf = new StringBuilder( BUFFER_LARGE ) 320 .append( "Process_Logger は、画面出力、ファイルログ、エラーメールを管理する、" ).append( CR ) 321 .append( "ロギング関係の LoggerProcess インターフェースの実装クラスです。" ).append( CR ) 322 .append( CR ) 323 .append( "MainProcess で使用されるログと、各種 Process で使用されるディスプレイを" ).append( CR ) 324 .append( "管理します。また、エラー発生時の、メール送信機能も、ここで用意します。" ).append( CR ) 325 .append( CR ) 326 .append( "引数文字列中に空白を含む場合は、ダブルコーテーション(\"\") で括って下さい。" ).append( CR ) 327 .append( "引数文字列の 『=』の前後には、空白は挟めません。必ず、-key=value の様に" ).append( CR ) 328 .append( "繋げてください。" ).append( CR ) 329 .append( CR ).append( CR ) 330 .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_Logger().usage() ); 342 } 343}