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.hayabusa.taglib; 017 018import java.util.Locale; 019import java.util.Set; // 6.4.3.4 (2016/03/11) 020import java.util.Enumeration; 021import java.util.concurrent.ConcurrentMap; // 6.4.3.3 (2016/03/04) 022import java.util.concurrent.ConcurrentHashMap; // 6.4.3.3 (2016/03/04) 023 024import javax.servlet.ServletRequest ; 025 026import org.opengion.fukurou.system.DateSet; // 6.4.2.0 (2016/01/29) 027import org.opengion.fukurou.system.ThrowUtil; // 6.4.2.0 (2016/01/29) 028import org.opengion.fukurou.util.ErrorMessage; 029import org.opengion.fukurou.util.StringUtil; 030import org.opengion.fukurou.util.ToString; // 6.1.1.0 (2015/01/17) 031import org.opengion.fukurou.util.ArraySet; // 6.4.3.4 (2016/03/11) 032import org.opengion.hayabusa.common.HybsSystem; 033import org.opengion.hayabusa.common.HybsSystemException; 034import org.opengion.hayabusa.mail.MailManager_DIRECT; 035import org.opengion.hayabusa.db.DBTableModel; 036 037import static org.opengion.fukurou.util.StringUtil.nval; 038 039/** 040 * 定型文およびパラメータの設定によるメールを送信するためのタグです。 041 * 042 * @og.formSample 043 * ●形式:<og:mailSender ptnId="…" action="…" from="…" to="…" /> 044 * ●body:なし 045 * 046 * ●Tag定義: 047 * <og:mailSender2 048 * ptnId ○【TAG】メール定型文のIDを指定します(必須)。 049 * from ○【TAG】送信元(FROM)の社員IDを指定します(必須)。 050 * action ○【TAG】アクション[CHECK/SEND/NOCHECK]をセットします(必須)。 051 * addrCheck 【TAG】メールアドレスの構文とメールアカウントのチェックをするかどうか[true/false]を指定します 052 * to 【TAG】送信先(TO)の社員ID、グループIDをCSV形式で指定します 053 * cc 【TAG】送信先(CC)の社員ID、グループIDをCSV形式で指定します 054 * bcc 【TAG】送信先(BCC)の社員ID、グループIDをCSV形式で指定します 055 * tableId 【TAG】(通常は使いません)宛先のDBTableModelを、sessionに登録するときのキーを指定します 056 * scope 【TAG】キャッシュする場合のスコープ[request/page/session/application]を指定します(初期値:session) 057 * fileURL 【TAG】添付ファイルのセーブディレクトリを指定します (初期値:FILE_URL[=filetemp/]) 058 * filename 【TAG】添付ファイル名をCSV形式で指定します 059 * useStop 【TAG】例外発生した場合、後続JSPの評価を中止するかどうか[true:中止/false:継続]を指定します 060 * debug 【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false) 061 * /> 062 * 063 * ●使用例 064 * <og:mailSender2 > 065 * ptnId = PtnId 定型文ID(定型文マスタに登録されている定型文ID) 066 * action = Action アクション(CHECK:確認あり/SEND:確認後の送信/NOCHECK:確認なし) 067 * from = From 送信元(送信者社員ID) 068 * to = To 送信先(コンマ区切りで複数セット可能、社員ID、グループID) 069 * cc = Cc 送信先(コンマ区切りで複数セット可能、社員ID、グループID) 070 * bcc = Bcc 送信先(コンマ区切りで複数セット可能、社員ID、グループID) 071 * fileURL = 添付ファイルのセーブディレクトリ 072 * filename = 添付ファイル名(ローカルにセーブされたファイル名)(コンマ区切りで複数登録可能) 073 * addrCheck = true/false(メールアカウントの有効チェック) 074 * useStop = true/false エラー発生時に後続JSPの評価を中止する(true)/中止しない(false) 075 * scope = request/session 宛先テーブルの格納スコープ(デフォルト:session) 076 * tableId = TableId 宛先テーブルのID(通常はデフォルトのテーブルモデルID名称を利用します) 077 * debug = true/false 078 * </og:mailSender > 079 * 080 * from には社員IDしかセットできません。 081 * to,cc,bccには社員ID、またはグループIDをコンマ区切りで複数セットできます。 082 * action:CHECK は送信前に、一度送信内容を確認したい場合に利用します。action=CHECKの場合、scopeにはsessionしかセットできません。 083 * action:SEND は確認済のメール文を送信する場合に利用します。 084 * action:NOCHECK は確認なしで送信したい場合に利用します。 085 * 086 * @og.group その他出力 087 * 088 * @version 4.0 089 * @author Sen.Li 090 * @since JDK1.6 091 */ 092public class MailSenderTag2 extends CommonTagSupport { 093 private static final String VERSION = "6.5.0.1 (2016/10/21)" ; 094 private static final long serialVersionUID = 650120161021L ; 095 096 private static final String ACT_CHECK = "CHECK" ; 097 private static final String ACT_SEND = "SEND" ; 098 private static final String ACT_NOCHECK = "NOCHECK" ; 099 // 6.4.3.4 (2016/03/11) String配列 から、Setに置き換えます。 100 private static final Set<String> ACTION_SET = new ArraySet<>( ACT_CHECK , ACT_SEND, ACT_NOCHECK ); 101 102 private static final int MAX_FILE_COUNT = 5 ; 103 private String ptnId ; 104 private String action ; 105 private String from ; 106 private String to ; 107 private String cc ; 108 private String bcc ; 109 private String fileURL = HybsSystem.sys( "FILE_URL" ); 110 private String[] filename ; 111 private String tableId = HybsSystem.TBL_MDL_KEY ; 112 private boolean addrCheck ; 113 private boolean useStop = true; 114 115 /** 116 * デフォルトコンストラクター 117 * 118 * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor. 119 */ 120 public MailSenderTag2() { super(); } // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。 121 122 /** 123 * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。 124 * 125 * @og.rev 6.3.4.0 (2015/08/01) Arrays.toString から String.join に置き換え。 126 * @og.rev 6.4.2.0 (2016/01/29) ex.printStackTrace() を、ThrowUtil#ogStackTrace(Throwable) に置き換え。 127 * @og.rev 6.4.3.3 (2016/03/04) ConcurrentHashMap を受け取ることを明確にするため、I/FをConcurrentMapに変更します。 128 * @og.rev 6.4.3.4 (2016/03/11) String配列 から、Setに置き換えます。 129 * @og.rev 6.5.0.1 (2016/10/21) ErrorMessage をまとめるのと、直接 Throwable を渡します。 130 * 131 * @return 後続処理の指示 132 */ 133 @Override 134 public int doEndTag() { 135 debugPrint(); 136 int rtnCode = EVAL_PAGE; 137 int errCode = ErrorMessage.OK; 138 139 if( check( action, ACTION_SET ) ) { 140 try { 141 tableId = ( tableId == null ) ? HybsSystem.TBL_MDL_KEY:tableId; 142 final MailManager_DIRECT manager = new MailManager_DIRECT(); 143 manager.setResourceManager( getResource() ); 144 DBTableModel table = null; 145 146 if( ACT_NOCHECK.equals( action ) || ACT_CHECK.equals( action ) ){ 147 final ConcurrentMap<String,String> initParamMap = makeParamMap(); // 6.4.3.3 (2016/03/04) 148 manager.create( initParamMap ); 149 } 150 if( ACT_NOCHECK.equals( action ) ) { 151 manager.setDebug( isDebug() ); 152 manager.send(); 153 } 154 else if( ACT_CHECK.equals( action ) ) { 155 setSessionAttribute( "MAIL.FROM_ADDR", manager.getFromAddr() ); 156 setSessionAttribute( "MAIL.PTN_ID", ptnId ); 157 setSessionAttribute( "MAIL.TITLE", manager.getTitle() ); 158 setSessionAttribute( "MAIL.CONTENT", manager.getContent() ); 159 } 160 else if( ACT_SEND.equals( action ) ) { 161 ptnId = (String) getSessionAttribute( "MAIL.PTN_ID" ); 162 final ConcurrentMap<String,String> initParamMap = makeParamMap(); // 6.4.3.3 (2016/03/04) 163 manager.setFromAddr( (String) getSessionAttribute( "MAIL.FROM_ADDR" ) ); 164 manager.setTitle( (String) getSessionAttribute( "MAIL.TITLE" ) ); 165 manager.setContent( (String) getSessionAttribute( "MAIL.CONTENT" ) ); 166 table = ( DBTableModel )getObject( tableId ); 167 manager.create( initParamMap, table ); 168 manager.setDebug( isDebug() ); 169 manager.send(); 170 } 171 startQueryTransaction( tableId ); 172 table = manager.makeDstTable(); 173 if( ! commitTableObject( tableId, table ) ) { 174 jspPrint( "DBTableModel は登録しません。" ); 175 } 176 } 177 catch( final RuntimeException rex ){ 178 if( useStop ) { 179 final ErrorMessage errMsg = new ErrorMessage(); 180 // 6.5.0.1 (2016/10/21) ErrorMessage をまとめるのと、直接 Throwable を渡します。 181 errMsg.addMessage( 0, ErrorMessage.NG, "ERR0040", rex.getMessage() ) 182 .addMessage( rex ); 183 184 jspPrint( TaglibUtil.makeHTMLErrorTable( errMsg, getResource() ) ); 185 rtnCode = SKIP_PAGE; 186 } 187 System.err.println( ThrowUtil.ogStackTrace( rex ) ); // 6.4.2.0 (2016/01/29) 188 errCode = ErrorMessage.WARNING; 189 } 190 setSessionAttribute( "MAIL.ERR_CODE", String.valueOf( errCode ) ); 191 } 192 else { 193 final String errMsg = "指定のアクションは実行できません。アクションエラー" + CR 194 + "action=[" + action + "] " + CR 195 + "actionList=" + String.join( ", " , ACTION_SET ) ; 196 throw new HybsSystemException( errMsg ); 197 } 198 return rtnCode; 199 } 200 201 /** 202 * 【TAG】アクション[CHECK/SEND/NOCHECK]をセットします。 203 * @og.tag 204 * 送信前に、一度送信内容を確認する場合、"CHECK "をセットします。 205 * 確認済のメール文を送信する場合、"SEND"をセットします。 206 * 確認なしで送信する場合、"NOCHECK"をセットします。 207 * 208 * @param act アクション [CHECK/SEND/NOCHECK] 209 */ 210 public void setAction( final String act ) { 211 final String act2 = getRequestParameter( act ); 212 if( act2 != null && act2.length() > 0 ) { action = act2.toUpperCase(Locale.JAPAN); } 213 } 214 215 /** 216 * 【TAG】メール定型文のIDを指定します。 217 * 218 * @og.tag 219 * 定型文マスタに定義されている定型文IDを指定します。 220 * 221 * @param pid 定型文ID 222 */ 223 public void setPtnId( final String pid ) { 224 ptnId = nval( getRequestParameter( pid ),null ); 225 } 226 227 /** 228 * 【TAG】送信元(FROM)の社員IDを指定します。 229 * 230 * @og.tag 231 * 送信元(FROM)の社員IDを指定します。社員マスタに存在している社員ID(例:"C12345")しかセットできません。 232 * 233 * @param fromId 送信元(FROM)の社員ID 234 */ 235 public void setFrom( final String fromId ) { 236 from = nval( getRequestParameter( fromId ), from ); 237 setRequestAttribute( "FROM", from ); 238 } 239 240 /** 241 * 【TAG】送信先(TO)の社員ID、グループIDをCSV形式で指定します。 242 * 243 * @og.tag 244 * 複数のID(社員ID、グループID)をCSV形式でセットできます。 245 * グループIDはグループマスタ管理画面により定義する必要があります。"GP.XXXXX"の形式でセットします。 246 * 247 * @param toIds 送信先(TO)の社員ID、グループID(CSV形式) 248 */ 249 public void setTo( final String toIds ) { 250 to = getRequestParameter( toIds ); 251 } 252 253 /** 254 * 【TAG】送信先(CC)の社員ID、グループIDをCSV形式で指定します。 255 * 256 * @og.tag 257 * 複数のID(社員ID、グループID)をCSV形式でセットできます。 258 * グループIDはグループマスタ管理画面により定義する必要があります。"GP.XXXXX"の形式でセットします。 259 * 260 * @param ccIds 送信先(CC)の社員ID、グループID(CSV形式) 261 */ 262 public void setCc( final String ccIds ) { 263 cc = getRequestParameter( ccIds ); 264 } 265 266 /** 267 * 【TAG】送信先(BCC)の社員ID、グループIDをCSV形式で指定します。 268 * 269 * @og.tag 270 * 複数のID(社員ID、グループID)をCSV形式でセットできます。 271 * グループIDはグループマスタ管理画面により定義する必要があります。"GP.XXXXX"の形式でセットします。 272 * 273 * @param bccIds 送信先(BCC)の社員ID、グループID(CSV形式) 274 */ 275 public void setBcc( final String bccIds ) { 276 bcc = getRequestParameter( bccIds ); 277 } 278 279 /** 280 * 【TAG】添付ファイルのセーブディレクトリを指定します 281 * (初期値:FILE_URL[={@og.value SystemData#FILE_URL}])。 282 * 283 * @og.tag 284 * この属性で指定されるディレクトリに、添付ファイルが存在すると仮定します。 285 * 指定方法は、通常の fileURL 属性と同様に、先頭が、'/' (UNIX) または、2文字目が、 286 * ":" (Windows)の場合は、指定のURLそのままのディレクトリに、そうでない場合は、 287 * fileURL = "{@USER.ID}" と指定すると、FILE_URL 属性で指定のフォルダの下に、 288 * さらに、各個人ID別のフォルダを作成して、そこを使用します。 289 * (初期値:システム定数のFILE_URL[={@og.value SystemData#FILE_URL}])。 290 * 291 * @og.rev 6.4.2.1 (2016/02/05) URLの最後に、"/" を追加する処理を廃止。 292 * 293 * @param url 添付ファイルのセーブディレクトリ 294 * @see org.opengion.hayabusa.common.SystemData#FILE_URL 295 */ 296 public void setFileURL( final String url ) { 297 final String furl = nval( getRequestParameter( url ),null ); 298 if( furl != null ) { 299 fileURL = StringUtil.urlAppend( fileURL,furl ); 300 } 301 } 302 303 /** 304 * 【TAG】添付ファイル名をCSV形式で指定します。 305 * 306 * @og.tag 307 * 複数ファイルをセットできます。 308 * 設定方法は、カンマで区切って並べ複数指定できます。 309 * 310 * @param fname 添付ファイル名 311 */ 312 public void setFilename( final String fname ) { 313 filename = StringUtil.csv2ArrayOnly( getRequestParameter( fname ) ); 314 } 315 316 /** 317 * 【TAG】メールアドレスの構文とメールアカウントのチェックをするかどうか[true:する/false:しない]を指定します。 318 * 319 * @og.tag 320 * メールアドレスの構文とメールアカウントのチェック[true:する/false:しない]を指定します。 321 * メール文合成の段階では、メールアドレスの構文文法についてチェックします。 322 * メール送信の段階では、メールアカウントが有効かについてチェックします。 323 * "true"と指定する場合、エラーが検出されたら、例外を投げて本タグの処理が中止されます。 324 * "false"と指定する場合、エラーが検出されても、例外を投げません。 325 * 326 * @param addrChk 構文,アカウントチェック可否 [true:する/false:しない] 327 */ 328 public void setAddrCheck( final String addrChk ) { 329 addrCheck = nval( getRequestParameter( addrChk ), addrCheck ); 330 } 331 332 /** 333 * 【TAG】例外発生した場合、後続JSPの評価を中止するかどうか[true:中止/false:継続]を指定します。 334 * 335 * @og.tag 336 * "true"と指定する場合、例外が発生したら、後続JSPが評価されません。 337 * "false"と指定する場合、例外が発生しても、後続JSPが評価されます。後続のJSPでは変数 338 * {@MAIL.ERR_CODE}で本タグの実行状況(エラー発生したか)を取得できます。 339 * 340 * @param stop 例外時に後続処理を中止可否 [true:中止/false:継続] 341 */ 342 public void setUseStop( final String stop ) { 343 useStop = nval( getRequestParameter( stop ), useStop ); 344 } 345 346 /** 347 * 【TAG】(通常は使いません)結果のDBTableModelを、sessionに登録するときのキーを指定します 348 * (初期値:HybsSystem#TBL_MDL_KEY[={@og.value HybsSystem#TBL_MDL_KEY}])。 349 * 350 * @og.tag 351 * 検索結果より、DBTableModelオブジェクトを作成します。これを、下流のviewタグ等に 352 * 渡す場合に、通常は、session を利用します。その場合の登録キーです。 353 * query タグを同時に実行して、結果を求める場合、同一メモリに配置される為、 354 * この tableId 属性を利用して、メモリ空間を分けます。 355 * (初期値:HybsSystem#TBL_MDL_KEY[={@og.value HybsSystem#TBL_MDL_KEY}])。 356 * 357 * @param id テーブルID (sessionに登録する時のID) 358 */ 359 public void setTableId( final String id ) { 360 tableId = nval( getRequestParameter( id ),tableId ); // 3.8.0.9 (2005/10/17) 361 } 362 363 /** 364 * タグリブオブジェクトをリリースします。 365 * キャッシュされて再利用されるので、フィールドの初期設定を行います。 366 * 367 */ 368 @Override 369 protected void release2() { 370 super.release2(); 371 from = null; 372 to = null; 373 cc = null; 374 bcc = null; 375 fileURL = HybsSystem.sys( "FILE_URL" ); 376 filename = null; 377 ptnId = null; 378 action = null; 379 tableId = HybsSystem.TBL_MDL_KEY ; 380 addrCheck = false; 381 useStop = true; 382 } 383 384 /** 385 * このオブジェクトの文字列表現を返します。 386 * 基本的にデバッグ目的に使用します。 387 * 388 * @return このクラスの文字列表現 389 * @og.rtnNotNull 390 */ 391 @Override 392 public String toString() { 393 return ToString.title(this.getClass().getName() ) 394 .println( "VERSION" ,VERSION ) 395 .println( "ptnId" ,ptnId ) 396 .println( "action" ,action ) 397 .println( "tableId" ,tableId ) 398 .println( "addrCheck" ,addrCheck ) 399 .println( "useStop" ,useStop ) 400 .println( "from" ,from ) 401 .println( "to" ,to ) 402 .println( "cc" ,cc ) 403 .println( "bcc" ,bcc ) 404 .println( "filename" ,filename ) 405 .println( "fileURL" ,fileURL ) 406 .println( "Other...", getAttributes().getAttribute() ) 407 .fixForm().toString(); 408 } 409 410 /** 411 * リクエスト変数の値より、定型文に必要なパラメータを取得して、パレメータマップに入れます。 412 * パラメータマップは引数としてメールモジュールのマネージャに渡します。 413 * マネージャの中には、定型文を元に、パラメータマップの値とマージしてメールの各項目を合成します。 414 * 415 * @og.rev 6.4.2.0 (2016/01/29) DateSet.getDate( String ) を利用するように修正します。 416 * @og.rev 6.4.3.3 (2016/03/04) ConcurrentHashMap を受け取ることを明確にするため、I/FをConcurrentMapに変更します。 417 * 418 * @return 定型文に必要なパレメータマップ 419 */ 420 private ConcurrentMap<String, String> makeParamMap() { 421 final ConcurrentMap<String, String> paramMap = new ConcurrentHashMap<>(); 422 if( action.endsWith( ACT_NOCHECK ) || action.equals( ACT_CHECK ) ) { 423 final ServletRequest request = this.getRequest(); 424 final Enumeration<?> enu1 = request.getAttributeNames(); 425 while( enu1.hasMoreElements() ) { 426 final String name = (String) enu1.nextElement(); 427 final Object tmpObj = request.getAttribute( name ); 428 if( tmpObj instanceof String ) { 429 putNotNull( paramMap,name,(String)tmpObj ); 430 } 431 } 432 final Enumeration<?> enu2 = request.getParameterNames(); 433 while( enu2.hasMoreElements() ) { 434 final String name = (String) enu2.nextElement(); 435 putNotNull( paramMap,name,request.getParameter( name ) ); 436 } 437 438 putNotNull( paramMap,"FROM" , from ); 439 putNotNull( paramMap,"TO" , to ); 440 putNotNull( paramMap,"CC" , cc ); 441 putNotNull( paramMap,"BCC" , bcc ); 442 } 443 444 putNotNull( paramMap,"PTN_ID" , ptnId ); 445 putNotNull( paramMap,"SYSTEM_ID" , HybsSystem.sys( "SYSTEM_ID" ) ); 446 putNotNull( paramMap,"ADDR_CHECK" , String.valueOf( addrCheck ) ); 447 putNotNull( paramMap,"LOGIN_USERID" , getRequestValue( "USER.ID" ) ); 448 putNotNull( paramMap,"LOGIN_USERNAME" , getRequestValue( "USER.JNAME" ) ); 449 putNotNull( paramMap,"PGID" , getRequestValue( "GUI.KEY" ) ); 450 putNotNull( paramMap,"DATE" , DateSet.getDate( "yyyy/MM/dd" ) ); // 6.4.2.0 (2016/01/29) 451 putNotNull( paramMap,"TIME" , DateSet.getDate( "HH:mm:ss" ) ); // 6.4.2.0 (2016/01/29) 452 453 String[] temp = { "", "", "", "", "" }; 454 if( filename != null && filename.length > 0 ) { 455 final String directory = HybsSystem.url2dir( fileURL ); 456 final int fileCount = filename.length > MAX_FILE_COUNT ? MAX_FILE_COUNT : filename.length; 457 for( int i=0; i<fileCount; i++ ) { 458 temp[i] = StringUtil.urlAppend( directory, filename[i] ); 459 } 460 } 461 putNotNull( paramMap,"ATTACH1", temp[0] ); 462 putNotNull( paramMap,"ATTACH2", temp[1] ); 463 putNotNull( paramMap,"ATTACH3", temp[2] ); 464 putNotNull( paramMap,"ATTACH4", temp[3] ); 465 putNotNull( paramMap,"ATTACH5", temp[4] ); 466 467 return paramMap; 468 } 469 470 /** 471 * ConcurrentMapのnot null制限を回避するため、key,val が、not nullのときだけ、Mapにput します。 472 * 473 * @og.rev 6.4.3.3 (2016/03/04) ConcurrentHashMap を受け取ることを明確にするため、I/FをConcurrentMapに変更します。 474 * 475 * @param cmap putする元となるConcurrentMap 476 * @param key putするときのキー 477 * @param val putするときの値 478 */ 479 private final void putNotNull( final ConcurrentMap<String, String> cmap , final String key , final String val ) { 480 if( key != null && val != null ) { cmap.put( key,val ); } 481 } 482}