    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 org.opengion.hayabusa.common.HybsSystem;
    019import org.opengion.hayabusa.common.HybsSystemException;
    020import org.opengion.hayabusa.resource.UserInfo;
    021import org.opengion.hayabusa.resource.GUIInfo;
    022
    023import org.opengion.fukurou.system.ThrowUtil;                                   // 6.4.2.0 (2016/01/29)
    024import org.opengion.fukurou.system.BuildNumber;
    025import org.opengion.fukurou.util.EnumType ;
    026import org.opengion.fukurou.util.ErrorMessage;
    027import org.opengion.fukurou.system.LogWriter;                                   // 6.4.2.0 (2016/01/29)
    028import org.opengion.fukurou.util.StringUtil ;
    029import org.opengion.fukurou.util.ToString;                                              // 6.1.1.0 (2015/01/17)
    030import org.opengion.fukurou.mail.MailTX ;
    031import static org.opengion.fukurou.util.StringUtil.nval ;
    032
    033/**
    034 * JSPのエラー発生時の処理を行うタグです。
    035 *
    036 * JSPでは、エラー発生時に、エラーページに飛ばす機能があります。現在のエンジンでは、
    037 * common/error.jsp ページ内で、処理を行っていますが、表示形式の整形、エラーメールの送信、
    038 * ログへの出力、エラー文字列の表示(Exceptionをそのままユーザーに見せるのは良くない)
    039 * などの、細かい対応が必要です。
    040 * ここでは、それらをタグ化して、属性で指定できるようにしました。
    041 *
    042 * エラー発生時にメールでエラー内容を飛ばすことも可能です。
    043 * これは、システムパラメータの COMMON_MAIL_SERVER に、ERROR_MAIL_TO_USERS に送信します。
    044 * ERROR_MAIL_TO_USERS が未設定の場合は、送信しません。
    045 *
    046 * @og.formSample
    047 * ●形式：
    048 *     &lt;og:error
    049 *          useMail     = "[true|false]"                    メール送信可否を指定します(初期値:true)
    050 *          logMsgType  = "[LONG|MEDIUM|SHORT|NONE]"        ログに書き込むメッセージの形式を指定(初期値:MEDIUM)
    051 *          viewMsgType = "[LONG|MEDIUM|SHORT|NONE|ALLNONE|TABLE|TABLE_ST]"  画面に表示するメッセージの形式を指定(初期値:SHORT)
    052 *     /&gt;
    053 *
    054 * ●body：あり(EVAL_BODY_BUFFERED:BODYを評価し、{&#064;XXXX} を解析します)
    055 *
    056 * ●Tag定義：
    057 *   &lt;og:error
    058 *       useMail            【TAG】メール送信可否を指定します(初期値:true)
    059 *       logMsgType         【TAG】ログに書き込むメッセージの形式を指定(初期値:MEDIUM)
    060 *       viewMsgType        【TAG】画面に書き込むメッセージの形式を指定(初期値:SHORT)
    061 *       debug              【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false)
    062 *       skipPage           【TAG】エラーが発生した時に、以降の処理をスキップするか(初期値:false[=スキップしない])
    063 *   &gt;   ... Body ...
    064 *   &lt;/og:error&gt;
    065 *
    066 * ●使用例
    067 *     &lt;og:error /&gt;
    068 *
    069 * @og.rev 4.0.0.0 (2005/08/31) 新規作成
    070 * @og.group エラー処理
    071 *
    072 * @version  4.0
    073 * @author       Kazuhiko Hasegawa
    074 * @since    JDK5.0,
    075 */
    076public class ErrorTag extends CommonTagSupport {
    077        /** このプログラムのVERSION文字列を設定します。   {@value} */
    078        private static final String VERSION = "7.2.4.0 (2020/05/11)" ;
    079        private static final long serialVersionUID = 724020200511L ;
    080
    081        /**
    082         * ログメッセージタイプ 属性として指定できる選択肢を定義します。
    083         */
    084        private static final EnumType<String> LOG_MSGTYPE =
    085                                new EnumType<>( "ログメッセージタイプ" , "MEDIUM" )
    086                                        .append( "LONG"         ,"詳細メッセージを作成します。" )
    087                                        .append( "MEDIUM"       ,"標準メッセージを作成します。" )
    088                                        .append( "SHORT"        ,"簡易メッセージを作成します。" )
    089                                        .append( "NONE"         ,"メッセージを作成しません。" ) ;
    090
    091        /**
    092         * 表示メッセージタイプ 属性として指定できる選択肢を定義します。
    093         */
    094        private static final EnumType<String> VIEW_MSGTYPE =
    095                                new EnumType<>( "表示メッセージタイプ" , "SHORT" )
    096                                        .append( "LONG"         ,"詳細メッセージを作成します。" )
    097                                        .append( "MEDIUM"       ,"標準メッセージを作成します。" )
    098                                        .append( "SHORT"        ,"簡易メッセージを作成します。" )
    099                                        .append( "NONE"         ,"メッセージを作成しません。" )
    100                                        .append( "ALLNONE"      ,"何も出力しません。" )
    101                                        .append( "TABLE"        ,"テーブル形式でエラーメッセージのみを表示します。" )
    102                                        .append( "TABLE_ST"     ,"テーブル形式＋スタックトレース情報。" );
    103
    104        private final String MAIL_SERVER = nval( HybsSystem.sys( "COMMON_MAIL_SERVER" ),null );
    105        private final String MAIL_USERS  = nval( HybsSystem.sys( "ERROR_MAIL_TO_USERS" ),null ) ;
    106
    107        private final String FROM_USER   = nval( HybsSystem.sys( "ERROR_MAIL_FROM_USER" ),"ENGINE@DUMMY" ); // 4.4.0.1 (2009/08/08)
    108
    109        private final String TITLE = "【" + HybsSystem.sys( "SYSTEM_ID" ) + "】"
    110                                                                                         + HybsSystem.sys( "GUI_TOP_TITLE" ) + "Error!" ;
    111
    112        private boolean useMail         = true;
    113        private String  logMsgType      = LOG_MSGTYPE.getDefault();
    114        private String  viewMsgType     = VIEW_MSGTYPE.getDefault();
    115
    116        private boolean skipPage        ;                       // 4.1.0.0 (2008/01/11)
    117        private String  messageBody     ;                       // 4.1.0.0 (2008/01/11)
    118
    119        /**
    120         * デフォルトコンストラクター
    121         *
    122         * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor.
    123         */
    124        public ErrorTag() { super(); }          // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
    125
    126        /**
    127         * Taglibの開始タグが見つかったときに処理する doStartTag() を オーバーライドします。
    128         *
    129         * @og.rev 4.1.0.0 (2008/01/11) 新規作成
    130         *
    131         * @return      後続処理の指示( EVAL_BODY_BUFFERED )
    132         */
    133        @Override
    134        public int doStartTag() {
    135                return EVAL_BODY_BUFFERED ;     // Body を評価する。( extends BodyTagSupport 時)
    136        }
    137
    138        /**
    139         * Taglibのタグ本体を処理する doAfterBody() を オーバーライドします。
    140         *
    141         * @og.rev 4.1.0.0 (2008/01/11) 新規作成
    142         *
    143         * @return      後続処理の指示(SKIP_BODY)
    144         */
    145        @Override
    146        public int doAfterBody() {
    147                messageBody = getBodyString();
    148                return SKIP_BODY ;
    149        }
    150
    151        /**
    152         * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。
    153         *
    154         * @og.rev 4.0.0.0 (2005/12/31) UserInfo が存在しない場合の処理を追加します。
    155         * @og.rev 4.1.0.0 (2008/01/11) ボディー部分のメッセージを表示する。
    156         * @og.rev 5.0.0.4 (2009/08/28) ALLNONE追加
    157         * @og.rev 5.1.8.0 (2010/07/01) テーブル形式メッセージ表示対応
    158         * @og.rev 6.2.1.0 (2015/03/13) UserInfo が null の場合の処理を追加。
    159         * @og.rev 6.4.2.0 (2016/01/29) LogSenderの廃止に伴い、LogWriter を直接呼び出します。
    160         * @og.rev 6.7.7.1 (2017/04/07) viewMsgTypeに、TABLE_ST の追加(スタックトレースを含む詳細)
    161         * @og.rev 6.9.0.0 (2018/01/31) エラー表示情報の内容を修正します。
    162         *
    163         * @return      後続処理の指示
    164         */
    165        @Override
    166        public int doEndTag() {
    167                debugPrint();           // 4.0.0 (2005/02/28)
    168
    169                final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE )
    170                        .append( CR )
    171                        .append( "Title   :" ).append( TITLE ).append( CR )
    172                        .append( "Version :" ).append( BuildNumber.ENGINE_INFO ).append( CR );
    173
    174                // 4.0.0 (2005/12/31) UserInfo が存在しない場合の処理を追加します。
    175                String userId = null;
    176                try {
    177                        final UserInfo userInfo = (UserInfo)getSessionAttribute( HybsSystem.USERINFO_KEY );     // 6.2.1.0 (2015/03/13)
    178                        if( userInfo != null ) {
    179                                userId = userInfo.getUserID();
    180                                buf.append( "ID=[" ).append( userId )
    181                //                      .append( "] NAME=[" ).append( userInfo.getJname() )
    182                                        .append( "] LOGIN=[" ).append( HybsSystem.getDate( userInfo.getLoginTime() ) )
    183                                        .append( ']' );                                         // 6.0.2.5 (2014/10/31) char を append する。
    184                        }
    185                }
    186                catch( final HybsSystemException ex ) {
    187                        buf.append( "User is null" );
    188                }
    189                buf.append( CR )
    190                        .append( "GUI Information  : " );
    191                final GUIInfo guiInfo = (GUIInfo)getSessionAttribute( HybsSystem.GUIINFO_KEY );
    192                final String guiId ;
    193                // 6.4.1.1 (2016/01/16) PMD refactoring. Avoid if (x != y) ..; else ..;
    194                if( guiInfo == null ) {
    195                        guiId = null ;
    196                        buf.append( "GUI is null" );
    197                }
    198                else {
    199                        guiInfo.addErrorCount();
    200                        guiId = guiInfo.getKey();
    201                        buf.append( "KEY=[" ).append( guiId )
    202                                .append( "] LABEL=[" ).append( guiInfo.getLabel() )
    203                                .append( ']' );                                         // 6.0.2.5 (2014/10/31) char を append する。
    204                }
    205                buf.append( CR ).append( CR );
    206
    207//              final Throwable th = pageContext.getException() ;
    208//              if( th != null ) {
    209//                      buf.append( th.getMessage() ).append( CR );
    210//              }
    211//              buf.append( "-----" ).append( CR );
    212
    213                final String errHeader = buf.toString();
    214//              final String errHeader = ThrowUtil.ogThrowMsg( buf.toString() , th );           // 6.9.2.1 (2018/03/12)
    215
    216                // ログ情報出力
    217                // 6.9.0.0 (2018/01/31) エラー表示情報の内容を修正します。
    218                final Throwable th = pageContext.getException() ;
    219//              final String logMsg = getStackTrace( th , logMsgType );
    220                final String logMsg = getStackTrace( th , errHeader , logMsgType );
    221
    222                // 6.4.2.0 (2016/01/29) LogSenderの廃止に伴い、LogWriter を直接呼び出します。
    223                // 6.4.3.2 (2016/02/19) Time= は、LogWriter でも出力しているため、やめます。
    224                final String timMsg = new StringBuilder( BUFFER_MIDDLE )
    225                        .append( "[User="   ).append( userId )
    226                        .append( " , Gui="  ).append( guiId )
    227                        .append( " , Msg="  ).append( messageBody )
    228                        .append( ']'        ).append( CR )
    229//                      .append( errHeader  ).append( CR )                                      // 6.9.0.0 (2018/01/31)
    230                        .append( logMsg     ).append( CR ).toString();
    231
    232                LogWriter.log( timMsg );
    233
    234                // メール送信
    235                if( useMail && MAIL_SERVER != null && MAIL_USERS != null ) {
    236                        final String[] to = StringUtil.csv2Array( MAIL_USERS );
    237
    238                        final MailTX tx = new MailTX( MAIL_SERVER );
    239                        tx.setFrom( FROM_USER );
    240                        tx.setTo( to );
    241                        tx.setSubject( TITLE );
    242                        tx.setMessage( timMsg );                                        // 6.4.3.2 (2016/02/19) ほとんど同じなので。
    243                        tx.sendmail();
    244                }
    245
    246                // 画面出力
    247                // 5.0.0.2 (2009/09/15) ALLNONE以外のみ出力
    248                if( !"ALLNONE".equals( viewMsgType ) ) {
    249                        final String viewMsg ;
    250                        if( logMsgType.equals( viewMsgType ) ) {
    251                                viewMsg = timMsg;                                               // 6.4.3.2 (2016/02/19) ほとんど同じなので。
    252                        }
    253                        // 6.9.0.0 (2018/01/31) エラー表示情報の内容を修正します。
    254                        else {
    255                                viewMsg = getStackTrace( th , errHeader , viewMsgType );
    256                        }
    257//                      // 5.1.8.0 (2010/07/01) テーブル形式メッセージ表示対応
    258//                      else if( "TABLE".equals( viewMsgType ) ) {
    259//                              viewMsg = getTableMsg( pageContext.getException() , false );    // 6.7.7.1 (2017/04/07)
    260//                      }
    261//                      // 6.7.7.1 (2017/04/07) viewMsgTypeに、TABLE_ST の追加(スタックトレースを含む詳細)
    262//                      else if( "TABLE_ST".equals( viewMsgType ) ) {
    263//                              viewMsg = errHeader + getTableMsg( pageContext.getException() , true );
    264//                      }
    265//                      else {
    266//                              viewMsg = errHeader + getStackTrace( pageContext.getException() ,viewMsgType );
    267//                      }
    268                        jspPrint( viewMsg );
    269                }
    270
    271                // 6.3.6.1 (2015/08/28) なんとなくまとめました。
    272                return skipPage ? SKIP_PAGE : EVAL_PAGE ;
    273        }
    274
    275        /**
    276         * タグリブオブジェクトをリリースします。
    277         * キャッシュされて再利用されるので、フィールドの初期設定を行います。
    278         *
    279         */
    280        @Override
    281        protected void release2() {
    282                super.release2();
    283                useMail         = true;
    284                logMsgType      = LOG_MSGTYPE.getDefault();
    285                viewMsgType     = VIEW_MSGTYPE.getDefault();
    286                skipPage        = false;                                                // 4.1.0.0 (2008/01/11)
    287                messageBody     = null;                                                 // 4.1.0.0 (2008/01/11)
    288        }
    289
    290        /**
    291         * この Throwable オブジェクトの詳細メッセージ文字列を返します。
    292         * このクラスは、発生元の Throwable の StackTrace を、例外チェーン機能
    293         * を利用して取得しています。
    294         * また、"org.opengion." を含むスタックトレースのみ、メッセージとして追加します。
    295         *
    296         * @og.rev 5.0.0.2 (2009/09/15) ALLNONE追加
    297         * @og.rev 6.4.2.0 (2016/01/29) ThrowUtil を使用して、メッセージの簡略化を行います。
    298         * @og.rev 6.9.0.0 (2018/01/31) エラー表示情報の内容を修正します。
    299         * @og.rev 6.9.2.1 (2018/03/12) スタックトレース情報の処理方法を変更
    300         * @og.rev 7.2.4.0 (2020/05/11) MEDIUM時のメッセージ変更
    301         *
    302         * @param    thr Throwableオブジェクト
    303         * @param    errMsg エラー表示情報
    304         * @param    type スタックトレースを行うタイプ [LONG|MEDIUM|SHORT|NONE|ALLNONE|TABLE|TABLE_ST]
    305         *
    306         * @return   メッセージ
    307         * @og.rtnNotNull
    308         */
    309        private String getStackTrace( final Throwable thr , final String errMsg , final String type ) {
    310                // if( "NONE".equals( type ) ) { return ""; }
    311                if( "NONE".equals( type ) || "ALLNONE".equals( type ) ) { return ""; } // 5.0.0.2 (2009/09/15)
    312
    313                if( "SHORT".equals( type ) ) {
    314                        return thr == null ? errMsg : thr.getMessage();
    315                }
    316                else if( "MEDIUM".equals( type ) ) {
    317//                      return errMsg;
    318                        return thr == null ? errMsg : errMsg + CR + thr.getMessage();           // 7.2.4.0 (2020/05/11)
    319                }
    320                else if( "LONG".equals( type ) ) {
    321                        return ThrowUtil.ogStackTrace( errMsg,thr );
    322                }
    323                else if( "TABLE".equals( type ) ) {
    324//                      return getTableMsg( errMsg,null );
    325                        return getTableMsg( errMsg , thr , false );             // 6.9.2.1 (2018/03/12)
    326                }
    327                else if( "TABLE_ST".equals( type ) ) {
    328                        return getTableMsg( errMsg , thr , true );              // 6.9.2.1 (2018/03/12)
    329                }
    330
    331                return ThrowUtil.ogStackTrace( thr );
    332        }
    333
    334        /**
    335         * この Throwable オブジェクトのエラーメッセージ文字列をテーブル形式で返します。
    336         * スタックトレースを含めるかどうかを、引数で指定します。
    337         *
    338         * @og.rev 5.1.8.0 (2010/07/01) テーブル形式メッセージ表示対応
    339         * @og.rev 6.7.7.1 (2017/04/07) viewMsgTypeに、TABLE_ST の追加(スタックトレースを含む詳細)
    340         * @og.rev 6.8.5.0 (2018/01/09) forward 時のエラーを、session に登録しておきます。
    341         * @og.rev 6.9.0.0 (2018/01/31) エラー表示情報の内容を修正します。
    342         * @og.rev 6.9.2.1 (2018/03/12) スタックトレース情報の処理方法を変更
    343         *
    344         * @param    errMsg エラー表示情報
    345         * @param    thr Throwableオブジェクト
    346         * @param    isST スタックトレース情報を使用するかどうか [true:使用する/false:使用しない]
    347         *
    348         * @return   メッセージ
    349         * @og.rtnNotNull
    350         */
    351//      private String getTableMsg( final Throwable thr , final String errMsg ) {
    352//      private String getTableMsg( final String errMsg , final Throwable thr ) {
    353        private String getTableMsg( final String errMsg , final Throwable thr , final boolean isST ) {
    354//              final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );
    355
    356                ErrorMessage errMsgObj = (ErrorMessage)getSessionAttribute( HybsSystem.ERR_MSG_KEY );
    357                if( errMsgObj == null ) { errMsgObj = new ErrorMessage( "System Error!" ); }
    358
    359                errMsgObj.addMessage( errMsg )                          // 6.9.0.0 (2018/01/31)
    360//                      .addMessage( thr );                                             // 6.9.0.0 (2018/01/31)
    361                        .addMessage( thr , isST );                              // 6.9.2.1 (2018/03/12)
    362
    363                return TaglibUtil.makeHTMLErrorTable( errMsgObj, getResource() );
    364        }
    365
    366        /**
    367         * 【TAG】エラー発生時に管理者にメール送信するかどうかを指定します(初期値:true)。
    368         *
    369         * @og.tag
    370         * メールは、システムパラメータの COMMON_MAIL_SERVER に、ERROR_MAIL_TO_USERS に送信します。
    371         * ERROR_MAIL_TO_USERS が未設定の場合は、送信しません。
    372         * 初期値は、true(送信する)です。
    373         *
    374         * @param       flag メール送信可否 [true:する/false:しない]
    375         */
    376        public void setUseMail( final String flag ) {
    377                useMail = nval( getRequestParameter( flag ),useMail );
    378        }
    379
    380        /**
    381         * 【TAG】ログに書き込むメッセージの形式を指定(初期値:MEDIUM)。
    382         *
    383         * @og.tag
    384         * ログ、および、メール送信時のメッセージの形式を指定します。
    385         * エラー時のExceptionは、階層構造になっており、ルートまでさかのぼることが
    386         * 可能です。また、通常は、スタックとレース情報より、エラーのプログラムを
    387         * 特定することで、早く対応することが可能になります。
    388         * メッセージの形式には、LONG|MEDIUM|SHORT|NONE が指定できます。
    389         * ボディー部分に記述されたメッセージは全ての場合で出力されます。
    390         *
    391         *   ・LONG   : すべてのスタックトレース情報を取得します。
    392         *   ・MEDIUM : org.opengion以下のパッケージのみスタックトレース情報を取得します。
    393         *   ・SHORT  : メッセージ部分のみ情報を取得します。
    394         *   ・NONE   : 取得しません。
    395         *
    396         * 初期値は、MEDIUM です。
    397         *
    398         * @param       logType ログに書き込むメッセージの形式 [LONG|MEDIUM|SHORT|NONE]
    399         * @see         #setViewMsgType( String )
    400         */
    401        public void setLogMsgType( final String logType ) {
    402                logMsgType = LOG_MSGTYPE.nval( logType );
    403        }
    404
    405        /**
    406         * 【TAG】画面に書き込むメッセージの形式を指定(初期値:MEDIUM)。
    407         *
    408         * @og.tag
    409         * 画面に表示するメッセージの形式を指定します。
    410         * エラー時のExceptionは、階層構造になっており、ルートまでさかのぼることが
    411         * 可能です。また、通常は、スタックとレース情報より、エラーのプログラムを
    412         * 特定することで、早く対応することが可能になります。
    413         * メッセージの形式には、LONG|MEDIUM|SHORT|NONE|ALLNONE|TABLE が指定できます。
    414         * ボディー部分に記述されたメッセージは全ての場合で出力されます。
    415         *
    416         *   ・LONG    : すべてのスタックトレース情報を取得します。
    417         *   ・MEDIUM  : org.opengion以下のパッケージのみスタックトレース情報を取得します。
    418         *   ・SHORT   : メッセージ部分のみ情報を取得します。
    419         *   ・NONE    : 取得しません。
    420         *   ・ALLNONE : ヘッダも表示しません。
    421         *   ・TABLE   : テーブル形式でエラーメッセージのみを表示します。
    422         *   ・TABLE_ST: テーブル形式＋スタックトレース情報。" );
    423         *
    424         * 初期値は、SHORT です。
    425         *
    426         * @param       viewType 画面に出力するメッセージの形式 [LONG|MEDIUM|SHORT|NONE|ALLNONE|TABLE]
    427         * @see         #setLogMsgType( String )
    428         */
    429        public void setViewMsgType( final String viewType ) {
    430                viewMsgType = VIEW_MSGTYPE.nval( viewType );
    431        }
    432
    433        /**
    434         * 【TAG】エラーが発生した時に、以降の処理をスキップするか(初期値:false[=スキップしない])。
    435         *
    436         * @og.tag
    437         * エラーが発生した時に、以降の処理をスキップするかを設定します。
    438         * trueが設定された場合は、以降の処理をスキップします。
    439         *
    440         * 初期値は、false(スキップしない) です。
    441         *
    442         * @param       flag 以降の処理のスキップ [true:する/false:しない]
    443         */
    444        public void setSkipPage( final String flag ) {
    445                skipPage = nval( getRequestParameter( flag ),skipPage );
    446        }
    447
    448        /**
    449         * デバッグ時の文字列を返します。
    450         *
    451         * @return      このオブジェクトのデバッグ表現文字列
    452         * @og.rtnNotNull
    453         */
    454        @Override
    455        public String toString() {
    456                return ToString.title( this.getClass().getName() )
    457                                .println( "VERSION"                                             ,VERSION        )
    458                                .println( "useMail"                                             ,useMail        )
    459                                .println( "logMsgType"                                  ,logMsgType     )
    460                                .println( "viewMsgType"                                 ,viewMsgType)
    461                                .println( "messageBody"                                 ,messageBody)
    462                                .println( "skipPage"                                    ,skipPage)
    463                                .println( "COMMON_MAIL_SERVER"                  ,MAIL_SERVER    )
    464                                .println( "ERROR_MAIL_TO_USERS"                 ,MAIL_USERS             )
    465                                .println( "MAIL_DAEMON_DEFAULT_USER"    ,FROM_USER              )
    466                                .println( "Other..."                                    ,getAttributes().getAttribute() )
    467                                .fixForm().toString() ;
    468        }
    469}