    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 static org.opengion.fukurou.util.StringUtil.nval;
    019
    020import java.io.BufferedInputStream;
    021import java.io.BufferedWriter;
    022import java.io.ByteArrayInputStream;
    023import java.io.ByteArrayOutputStream;
    024import java.io.File;
    025import java.io.IOException;
    026import java.io.InputStream;
    027import java.io.OutputStreamWriter;
    028import java.io.UnsupportedEncodingException;
    029import java.io.Writer;
    030import java.util.Map;
    031
    032import org.opengion.fukurou.util.Closer;
    033import org.opengion.fukurou.util.FileString;
    034import org.opengion.fukurou.util.FileUtil;
    035import org.opengion.fukurou.util.LogWriter;
    036import org.opengion.fukurou.util.SOAPConnect;
    037import org.opengion.fukurou.util.StringUtil;
    038import org.opengion.fukurou.util.URLConnect;
    039import org.opengion.fukurou.util.XHTMLTag;
    040import org.opengion.fukurou.xml.XML2TableParser;
    041import org.opengion.fukurou.xml.XSLT;
    042import org.opengion.hayabusa.common.HybsSystem;
    043import org.opengion.hayabusa.common.HybsSystemException;
    044import org.opengion.hayabusa.db.DBTableModel;
    045import org.opengion.hayabusa.db.DBTableModelUtil;
    046
    047/**
    048 * 指定のURLに接続します。
    049 *
    050 * エンジンでは、URL にアクセスすることで、デーモンを起動したり、
    051 * コマンドを実行(adminメニュー)することが出来ます。
    052 * もちろん、検索条件を指定して、結果を取得することも可能です。
    053 * このタグでは、URLにアクセスして、コマンドを実行したり結果を取得できます。
    054 * さらに、ファイルを POST で転送したり、処理結果を XSLT変換したり出来ます。
    055 *
    056 * @og.formSample
    057 * ●形式：
    058 *     &lt;og:urlConnect
    059 *         url           = "http://･･･ "    必須
    060 *         proxyHost     = "proxy.opengion.org"
    061 *         proxyPort     = "8080"
    062 *         timeout       = "1"
    063 *         keys          = "command,SYSTEM_ID"
    064 *         vals          = "NEW,GE"
    065 *         useSystemUser = "true/false"     初期値:true
    066 *         authUserPass  = "admin:******"   初期値:admin:******
    067 *         display       = "false/true"     初期値:false
    068 *         xslFile       = "filter.xsl"
    069 *         saveFile      = "outdata.xml"
    070 *         soapNameSpace = "MyWebService"
    071 *         soapMethodName= "test"
    072 *         tableId       = "DEFAULT"
    073 *         rowKey        = "item"
    074 *         colKeys       = "person_id,person_name"
    075 *         rtnKeys       = "version,summary"
    076 *         encode        = "UTF-8"
    077 *     /&gt;
    078 *
    079 * url           : 接続するURLを指定します。必須属性です。
    080 * proxyHost     : proxy が存在する場合は、そのホスト名(例：proxy.opengion.org)
    081 * proxyPort     : proxy が存在する場合は、そのポート番号(例：8080)
    082 * timeout       : 通信リンクのオープン時に、指定された秒単位のタイム・アウト値を使用(例：10)
    083 * keys,vals     : URLの指定時に、パラメータ(引数)を追加します。URLに含めても構いません。
    084 *               : SOAPによる呼び出しの場合の詳細については、keysの属性定義を参照して下さい。
    085 * postKey       : POST を使って、postFile属性のファイル内容を送信する時のキーです。
    086 * postFile      : POST を使って、postFile属性のファイル内容を送信します。
    087 *                 postFile を指定せず、postKey のみ指定して、BODY部に何か書き込めば、
    088 *                 そのBODY部の文字列を POSTの内容として送信します。
    089 * authUserPass  : Basic認証を使用する場合の接続ユーザー：パスワードを指定します。
    090 *                 接続時のユーザーとパスワードを、USER:PASSWD 形式 で指定します。
    091 *                 useSystemUser="false" で何も指定しない場合は、Basic認証を使用しません。
    092 * useSystemUser : Basic認証の接続ユーザー：パスワードに、システムユーザーを使用
    093 *                 するかどうかを指定します(初期値:true)。
    094 *                 true の場合は、SYSTEM:***** を使用します。
    095 * xslFile       : 接続先データを取得し、そのデータを XSLT変換する場合のXSLファイルを指定します。
    096 * display       : 接続した結果のレスポンスを画面に表示するかどうかを指定します(初期値:false)。
    097 *                 エンジンの場合、コマンドを投げるだけであれば、結果を取得する必要は
    098 *                 ありません。イメージ的には、取得データが、このタグの位置に置き換わります。
    099 *                 xslFile が指定されている場合、XSLT変換してセーブします。
    100 * saveFile      : 接続先データを取得した結果を、ファイル出力します。
    101 *                 display="true" と、saveFile を併用することはできません。
    102 *                 xslFile が指定されている場合、XSLT変換してセーブします。
    103 * soapNameSpace : SOAPによるWebサービスの呼び出しで、メソッド名及びパラメーターの名前空間を指定します。
    104 *                 この名前空間は、通常WSDLファイルのdescriptionsタグのtargetNamespace属性の値により
    105 *                 定義されます。
    106 * soapMethodName: SOAPによるWebサービスの呼び出しで、メソッド名を指定します。
    107 *                 WSDLファイルで定義されるoperationタグのname属性の値に相当します。
    108 * tableId       : 結果のXMLファイルをDBTableModelに変換した際に、登録するTableIdを指定します。
    109 * rowKey        : XMLをDBTableModelに変換する際の、行を表すタグキーを指定します。
    110 * colKeys       : XMLをDBTableModelに変換する際の、項目を表すタグキーの一覧を指定します。
    111 *                 キーにPARENT_TAG、PARENT_FULL_TAGを指定することで、rowKeyで指定されたタグの
    112 *                 直近の親タグ、及びフルの親タグ名(親タグの階層を"&gt;[タグA]&gt;[タグB]&gt;[タグC]&gt;"で表現)を
    113 *                 取得することができます。
    114 * rtnKeys       : XMLのタグキーを指定して値を取り出します。取り出した値は、{&#064;XX}形式で処理することが可能です。
    115 * encode        : データの入出力を行うエンコードを指定します。
    116 *
    117 * ●body：あり(EVAL_BODY_BUFFERED:BODYを評価し、{&#064;XXXX} を解析します)
    118 *         POSTデータを記述します。
    119 *
    120 * ●Tag定義：
    121 *   &lt;og:urlConnect
    122 *       url              ○【TAG】アクセスする ＵＲＬ を指定します(必須)(必須)。
    123 *       proxyHost          【TAG】プロキシ経由で接続する場合の、プロキシホスト名を指定します
    124 *       proxyPort          【TAG】プロキシ経由で接続する場合の、プロキシポート番号を指定します
    125 *       timeout            【TAG】通信リンクのオープン時に、指定された秒単位のタイム・アウト値を使用
    126 *                                  (初期値:URL_CONNECT_TIMEOUT[={@og.value org.opengion.hayabusa.common.SystemData#URL_CONNECT_TIMEOUT}])。)
    127 *       keys               【TAG】アクセスパラメータキーをCSV形式で複数指定します
    128 *       vals               【TAG】keys属性に対応する値をCSV形式で複数指定します
    129 *       useSystemUser      【TAG】Basic認証で接続するユーザーにSYSTEMユーザーを使用するかどうか[true/false]を指定します(初期値:true)
    130 *       authUserPass       【TAG】Basic認証を使用して接続する場合のユーザー:パスワードを指定します(初期値:null)
    131 *       display            【TAG】接続の結果を表示するかどうかを指定します(初期値:false)
    132 *       xslFile            【TAG】接続の結果を表示する場合にXSLT変換する場合のファイルを指定します
    133 *       saveFile           【TAG】接続の結果をファイルに保存します
    134 *       postKey            【TAG】POST を使って、postFile属性のファイル内容を送信する時のキーを指定します
    135 *       postFile           【TAG】POST を使って、postFile属性のファイル内容を送信します
    136 *       method             【TAG】送信メソッドを指定します(GET/POST/SOAP)
    137 *       errNeglect         【TAG】(通常は使いません) 接続エラーを無視する場合にtrueとします(初期値false)
    138 *       soapNameSpace      【TAG】SOAPによるWebサービスの呼び出しで、メソッド名及びパラメーターの名前空間を指定します
    139 *       soapMethodName     【TAG】SOAPによるWebサービスの呼び出しで、メソッド名を指定します
    140 *       tableId            【TAG】(通常は使いません)結果のDBTableModelを、sessionに登録するときのキーを指定します
    141 *       scope              【TAG】キャッシュする場合のスコープ[request/page/session/applicaton]を指定します(初期値:session)
    142 *       rowKey             【TAG】結果のXMLをDBTableModelに変換する際に、行のキーとなるタグ名を指定します
    143 *       colKeys            【TAG】結果のXMLをDBTableModelに変換する際に、項目のキーとなるタグ名の一覧を指定します
    144 *       rtnKeys            【TAG】結果のXMLを変換する際に、パラメータ(Attributes)として取り込むキーの一覧を指定します
    145 *       encode             【TAG】データの入出力のエンコードを指定します
    146 *       mainTrans          【TAG】(通常使いません)タグで処理される処理がメインとなるトランザクション処理かどうかを指定します(初期値:false)
    147 *       caseKey            【TAG】このタグ自体を利用するかどうかの条件キーを指定します(初期値:null) 5.7.7.2 (2014/06/20)
    148 *       caseVal            【TAG】このタグ自体を利用するかどうかの条件値を指定します(初期値:null) 5.7.7.2 (2014/06/20)
    149 *       caseNN             【TAG】指定の値が、null/ゼロ文字列 でない場合(Not Null=NN)は、このタグは使用されます(初期値:true) 5.7.7.2 (2014/06/20)
    150 *       caseNull           【TAG】指定の値が、null/ゼロ文字列 の場合は、このタグは使用されます(初期値:true) 5.7.7.2 (2014/06/20)
    151 *       debug              【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false)
    152 *   &gt;   ... Body ...
    153 *   &lt;/og:urlConnect&gt;
    154 *
    155 * ●例：
    156 * アドミン関連
    157 * http://localhost:8823/gf/jsp/admin?COMMAND=infomation     [状況表示]
    158 * http://localhost:8823/gf/jsp/admin?COMMAND=close          [プール削除]
    159 * http://localhost:8823/gf/jsp/admin?COMMAND=loginUser      [ログインユーザー]
    160 * http://localhost:8823/gf/jsp/admin?COMMAND=システムパラメータ [システムパラメータ]
    161 *
    162 * 帳票デーモン
    163 * http://localhost:8823/gf/jsp/REP08/result.jsp?cmd=SET&amp;period=5000&amp;command=NEW&amp;timerTask=org.opengion.hayabusa.report.ReportDaemon&amp;name=ReportDaemon  デーモン起動
    164 * http://localhost:8823/gf/jsp/REP08/result.jsp?cmd=CANCEL&amp;period=5000&amp;command=NEW&amp;timerTask=org.opengion.hayabusa.report.ReportDaemon&amp;name=ReportDaemon  デーモン停止
    165 *
    166 *Tomcat Manager 画面
    167 * http://localhost:8823/manager/reload?path=/ver4 アプリケーションを再ロード
    168 *
    169 * @og.rev 3.6.0.0 (2004/09/17) 新規作成
    170 * @og.rev 4.1.0.0 (2007/12/22) POSTメソッドで複数キーを登録できるように属性追加
    171 * @og.rev 5.1.5.0 (2010/04/01) SOAP対応
    172 * @og.group その他部品
    173 *
    174 * @version  4.0
    175 * @author   Kazuhiko Hasegawa
    176 * @since    JDK5.0,
    177 */
    178public class URLConnectTag extends CommonTagSupport {
    179        //* このプログラムのVERSION文字列を設定します。   {@value} */
    180        private static final String VERSION = "5.7.7.2 (2014/06/20)" ;
    181
    182        private static final long serialVersionUID = 577220140620L ;
    183
    184        private static final String DEFAULT_USER = "SYSTEM:MANAGER" ;
    185
    186        private String          urlStr                  = null;
    187        private String[]        keys                    = null;
    188        private String[]        vals                    = null;
    189        private String          xslFile                 = null;
    190        private String          saveFile                = null;
    191        private String          postKey                 = null;
    192        private String          postData                = null;         // postFile ファイルか、BODY部
    193        private int                     timeout                 = HybsSystem.sysInt( "URL_CONNECT_TIMEOUT" );   // 5.8.8.1 (2015/06/05) 新規追加
    194        private boolean         useSystemUser   = true;
    195        private String          authUserPass    = null;
    196        private boolean         display                 = false;
    197        private String          proxyHost               = null;         // 4.0.0 (2007/07/25)
    198        private int             proxyPort               = -1;           // 4.0.0 (2007/07/25)
    199        private String          method                  = "GET";        // 4.1.0.0 (2007/12/22) POSTorGETorSOAP
    200        private boolean         errNglctFlag    = false;        // 4.1.1.0 (2008/01/22) エラー無視フラグ
    201        private String          soapNameSpace   = null;         // 5.1.5.0 (2010/04/01) SOAP対応
    202        private String          soapMethodName  = null;         // 5.1.5.0 (2010/04/01) SOAP対応
    203        private transient DBTableModel table                    = null;         // 5.1.5.0 (2010/04/01) DBTableModel出力対応
    204        private String          tableId                 = HybsSystem.TBL_MDL_KEY; // 5.1.5.0 (2010/04/01) DBTableModel出力対応
    205        private String          rowKey                  = null;         // 5.1.5.0 (2010/04/01) DBTableModel出力対応
    206        private String[]        colKeys                 = null;         // 5.1.5.0 (2010/04/01) DBTableModel出力対応
    207        private String[]        rtnKeys                 = null;         // 5.1.5.0 (2010/04/01) DBTableModel出力対応
    208        private String          encode                  = "UTF-8";      // 5.1.6.0 (2010/05/01) エンコード指定対応
    209
    210        private boolean         isTableOut              = false;        // 5.1.5.0 (2010/04/01) DBTableModel出力対応
    211        private boolean         isOutParse              = false;        // 5.1.5.0 (2010/04/01) DBTableModel出力対応
    212        private boolean         isMainTrans             = true;         // 5.1.6.0 (2010/05/01) DBLastSqlの処理の見直し
    213
    214        /**
    215         * Taglibの開始タグが見つかったときに処理する doStartTag() を オーバーライドします。
    216         *
    217         * @og.rev 5.1.5.0 (2010/04/01) SOAP・DBTableModel出力対応
    218         * @og.rev 5.1.6.0 (2010/05/01) DBLastSqlの処理は、DBTableModelが新規作成された処理でのみ行う。
    219         * @og.rev 5.7.7.2 (2014/06/20) caseKey,caseVal,caseNN,caseNull 属性を追加
    220         *
    221         * @return      後続処理の指示
    222         */
    223        @Override
    224        public int doStartTag() {
    225                // 5.7.7.2 (2014/06/20) caseKey,caseVal,caseNN,caseNull 属性を追加
    226                if( !useTag() ) { return SKIP_BODY ; }
    227
    228                // 5.1.5.0 (2010/04/01) DBTableModel出力対応
    229                if( rowKey != null || colKeys != null || rtnKeys != null ) {
    230                        isOutParse = true;
    231                        if( rowKey != null || colKeys != null ) {
    232                                isTableOut = true;
    233                                useMainTrans( isMainTrans );                    // 5.1.6.0 (2010/05/01) DBLastSqlの処理の見直し
    234                                startQueryTransaction( tableId );
    235                        }
    236                }
    237
    238                // 5.1.5.0 (2010/04/01) SOAPの場合は、postKeyが指定されない。
    239                if( postData != null ) {
    240                        return SKIP_BODY ;                      // Body を評価しない
    241                }
    242                else {
    243                        return EVAL_BODY_BUFFERED ;     // Body を評価する。( extends BodyTagSupport 時)
    244                }
    245        }
    246
    247        /**
    248         * Taglibのタグ本体を処理する doAfterBody() を オーバーライドします。
    249         *
    250         * @return      後続処理の指示(SKIP_BODY)
    251         */
    252        @Override
    253        public int doAfterBody() {
    254                postData = getBodyString();
    255
    256                return SKIP_BODY ;
    257        }
    258
    259        /**
    260         * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。
    261         *
    262         * @og.rev 4.0.1.0 (2007/12/12) PostKeys,PostVals処理を追加
    263         * @og.rev 5.1.5.0 (2010/04/01) SOAP・DBTableModel出力対応
    264         * @og.rev 5.2.0.0 (2010/09/01) エラー処理でNullPointerExceptionが発生するバグを修正
    265         * @og.rev 5.7.7.2 (2014/06/20) caseKey,caseVal,caseNN,caseNull 属性を追加
    266         *
    267         * @return      後続処理の指示
    268         */
    269        @Override
    270        public int doEndTag() {
    271                debugPrint();           // 4.0.0 (2005/02/28)
    272
    273                // 5.7.7.2 (2014/06/20) caseKey,caseVal,caseNN,caseNull 属性を追加
    274                if( !useTag() ) { return EVAL_PAGE ; }
    275
    276                URLConnect conn = null;
    277                ByteArrayOutputStream pipeOut = null;
    278                try {
    279                        conn = connect();
    280
    281                        // 出力先が、画面かファイルかを判断します。
    282                        Writer outWriter = null;
    283                        // 5.1.5.0 (2010/04/01) DBTableModel出力対応
    284                        if( isOutParse ) {
    285                        pipeOut = new ByteArrayOutputStream();
    286                                try {
    287                                        outWriter = new BufferedWriter( new OutputStreamWriter( pipeOut, "UTF-8" ) );
    288                                }
    289                                catch( UnsupportedEncodingException ex ) {
    290                                        throw new HybsSystemException( "不正なエンコードが指定されました。[UTF-8]",ex );
    291                                }
    292                        }
    293                        else if( display ) {
    294                                outWriter = FileUtil.getNonFlushPrintWriter( pageContext.getOut() ) ;           // JspWriter の取得
    295                        }
    296                        else if( saveFile != null ) {
    297                                outWriter = FileUtil.getPrintWriter( new File( saveFile ),"UTF-8" );
    298                        }
    299
    300                        // 出力先が存在する場合。
    301                        if( outWriter != null ) {
    302                                if( xslFile != null ) {
    303                                        XSLT xslt = new XSLT();
    304                                        xslt.setXslFile( xslFile );
    305                                        xslt.setOutFile( outWriter );
    306                                        xslt.transform( conn.getReader() );
    307                                        xslt.close();
    308                                }
    309                                else {
    310                                        outWriter.write( conn.readData() );
    311                                }
    312                                Closer.ioClose( outWriter );
    313                        }
    314                }
    315                catch( IOException ex ) {
    316                        String errMsg = "データ取得中にエラーが発生しました。" + HybsSystem.CR
    317                                                + " url=[" + urlStr + "]"
    318                                                // 5.2.0.0 (2010/09/01) エラー処理でNullPointerExceptionが発生するバグを修正
    319                                                + " message=[" + ( conn == null ? "NO_CONNECTION" : conn.getMessage() ) + "]";
    320                        if( errNglctFlag ) { // 4.1.1.0 (2008/01/22) エラーを無視(標準エラー出力のみ)
    321                                LogWriter.log( errMsg );
    322                        }
    323                        else { // 通常は無視しない
    324                                throw new HybsSystemException( errMsg,ex );
    325                        }
    326                }
    327                finally {
    328                        if( conn != null ) { conn.disconnect(); }
    329                }
    330
    331                // 5.1.5.0 (2010/04/01) DBTableModel出力対応
    332                if( isOutParse ) {
    333                        parse( new BufferedInputStream( new ByteArrayInputStream( pipeOut.toByteArray() ) ) );
    334                        if( isTableOut && table != null && !commitTableObject( tableId, table ) ) {
    335                                jspPrint( "URLConnectTag Query処理が割り込まれました。DBTableModel は登録しません。" );
    336                                return SKIP_PAGE ;
    337                        }
    338                }
    339
    340                return EVAL_PAGE ;
    341        }
    342
    343        /**
    344         * URLに対して接続を行います。
    345         *
    346         * @og.rev 5.1.6.0 (2010/05/01) エンコード指定対応
    347         * @og.rev 5.8.8.1 (2015/06/12) timeout追加
    348         *
    349         * @return 接続オブジェクト
    350         * @throws IOException 入出力エラーが発生したとき
    351         */
    352        private URLConnect connect() throws IOException {
    353                if( useSystemUser ) { authUserPass = DEFAULT_USER; }
    354
    355                // 5.1.5.0 (2010/04/01) SOAP対応
    356                // SOAPの場合、PostDataは、SOAPConnectタグの中で生成します。
    357                URLConnect conn = null;
    358                if( "SOAP".equalsIgnoreCase( method ) ) {
    359                        if( soapNameSpace == null || soapNameSpace.length() == 0
    360                                        || soapMethodName == null || soapMethodName.length() == 0 ) {
    361                                String errMsg = "SOAP接続の場合、soapNameSpace及びsoapMethodNameは必ず指定して下さい。";
    362                                throw new HybsSystemException( errMsg );
    363                        }
    364
    365                        if( postData != null && postData.length() > 0 ) {
    366                                conn = new SOAPConnect( urlStr,authUserPass, soapNameSpace, soapMethodName, postData );
    367                        }
    368                        else {
    369                                conn = new SOAPConnect( urlStr,authUserPass, soapNameSpace, soapMethodName, keys, vals );
    370                        }
    371                }
    372                else {
    373                        String urlEnc = XHTMLTag.urlEncode( keys,vals );
    374                        if( postKey != null ) { // 4.1.0.0 (2007/12/22)
    375                                method = "POST";
    376                                String addEnc = postKey + "=" + postData;
    377                                urlEnc = urlEnc + "&" + addEnc; // &連結
    378                        }
    379
    380                        if( ! "POST".equals( method ) ) { // 4.1.0.0 (2007/12/22)
    381                                // String urlEnc = XHTMLTag.urlEncode( keys,vals );
    382                                urlStr = XHTMLTag.addUrlEncode( urlStr,urlEnc );
    383                        }
    384                        conn = new URLConnect( urlStr,authUserPass );
    385
    386                        // if( postKey != null ) {
    387                        //      conn.setPostData( postKey,postData );
    388                        // }
    389                        if( "POST".equals( method ) && keys != null && vals != null ) { // 4.1.0.0 (2007/12/22)
    390                                conn.setPostData( urlEnc );
    391                        }
    392                }
    393
    394                // 4.0.0 (2007/07/25) プロキシの設定追加
    395                if( proxyHost != null ) {
    396                        conn.setProxy( proxyHost,proxyPort );
    397                }
    398
    399                // 5.1.6.0 (2010/05/01) エンコード指定対応
    400                if( encode != null && encode.length() > 0 ) {
    401                        conn.setCharset( encode );
    402                }
    403
    404                // 5.8.8.1 (2015/06/12) timeout属性追加
    405                if( timeout >= 0 ) {
    406                        conn.setTimeout( timeout );
    407                }
    408                conn.connect();
    409
    410                return conn;
    411        }
    412
    413        /**
    414         * 出力データをパースし、DBTableModel及び属性パラメーターに分解します。
    415         * 現時点では、XMLデータのみパースすることが可能です。
    416         *
    417         * @param input インプットストリーム
    418         */
    419        private void parse( final InputStream input ) {
    420                XML2TableParser parser = new XML2TableParser( input );
    421                parser.setTableCols( rowKey, colKeys );
    422                parser.setReturnCols( rtnKeys );
    423                parser.parse();
    424
    425                // DBTableModelを生成します。
    426                if( isTableOut ) {
    427                        table = DBTableModelUtil.makeDBTable( parser.getCols(), parser.getData(), getResource() );
    428                }
    429
    430                // 戻り値を取得し、Attributeに登録します。
    431                if( rtnKeys != null ) {
    432                        Map<String,String> rtn = parser.getRtn();
    433                        for( Map.Entry<String, String> entry : rtn.entrySet() ) {
    434                                setRequestAttribute( entry.getKey(), entry.getValue() );
    435                        }
    436                }
    437        }
    438
    439        /**
    440         * タグリブオブジェクトをリリースします。
    441         * キャッシュされて再利用されるので、フィールドの初期設定を行います。
    442         *
    443         * @og.rev 5.1.6.0 (2010/05/01) DBLastSqlの処理は、DBTableModelが新規作成された処理でのみ行う。
    444         * @og.rev 5.8.1.1 (2015/06/12) timeout追加
    445         *
    446         */
    447        @Override
    448        protected void release2() {
    449                super.release2();
    450                urlStr                  = null;
    451                proxyHost               = null;         // 4.0.0 (2007/07/25)
    452                proxyPort               = -1;           // 4.0.0 (2007/07/25)
    453                keys                    = null;
    454                vals                    = null;
    455                xslFile                 = null;
    456                saveFile                = null;
    457                postKey                 = null;
    458                postData                = null;
    459                timeout                 = HybsSystem.sysInt( "URL_CONNECT_TIMEOUT" );   // 5.8.1.1 (2015/06/05) 新規追加
    460                useSystemUser   = true;
    461                authUserPass    = null;
    462                display                 = false;
    463                method                  = "GET";        // 4.1.0.0 (2007/12/22)
    464                errNglctFlag    = false;        // 4.1.1.0 (2008/01/22)
    465                soapNameSpace   = null;         // 5.1.5.0 (2010/04/01) SOAP対応
    466                soapMethodName  = null;         // 5.1.5.0 (2010/04/01) SOAP対応
    467                table                   = null;         // 5.1.5.0 (2010/04/01) DBTableModel出力対応
    468                tableId                 = HybsSystem.TBL_MDL_KEY; // 5.1.5.0 (2010/04/01) DBTableModel出力対応
    469                rowKey                  = null;         // 5.1.5.0 (2010/04/01) DBTableModel出力対応
    470                colKeys                 = null;         // 5.1.5.0 (2010/04/01) DBTableModel出力対応
    471                rtnKeys                 = null;         // 5.1.5.0 (2010/04/01) DBTableModel出力対応
    472                isTableOut              = false;        // 5.1.5.0 (2010/04/01) DBTableModel出力対応
    473                isOutParse              = false;        // 5.1.5.0 (2010/04/01) DBTableModel出力対応
    474                encode                  = "UTF-8";      // 5.1.6.0 (2010/05/01) エンコード指定対応
    475                isMainTrans             = true;         // 5.1.6.0 (2010/05/01) DBLastSqlの処理の見直し
    476        }
    477
    478        /**
    479         * 【TAG】アクセスする ＵＲＬ を指定します(必須)。
    480         *
    481         * @og.tag
    482         * 接続するＵＲＬを指定します。(例：http:// ･･････)
    483         * ?以降のパラメータが含まれていても構いません。
    484         * このURL に、keys,vals で指定されたパラメータも追加されます。
    485         *
    486         * @param       url     アクセスする ＵＲＬ
    487         */
    488        public void setUrl( final String url ) {
    489                urlStr = nval( getRequestParameter( url ),urlStr );
    490        }
    491
    492        /**
    493         * 【TAG】プロキシ経由で接続する場合の、プロキシホスト名を指定します。
    494         *
    495         * @og.tag
    496         * 接続先が、プロキシ経由の場合、プロキシのホスト名を指定します。
    497         * 例：proxy.opengion.org
    498         *
    499         * @param       host    プロキシホスト名
    500         */
    501        public void setProxyHost( final String host ) {
    502                proxyHost = nval( getRequestParameter( host ),proxyHost );
    503                useSystemUser = false;  // プロキシ接続時は、システムユーザーは使えません。
    504        }
    505
    506        /**
    507         * 【TAG】プロキシ経由で接続する場合の、プロキシポート番号を指定します。
    508         *
    509         * @og.tag
    510         * 接続先が、プロキシ経由の場合、プロキシのポート番号を指定します。
    511         * 例：8080
    512         *
    513         * @param       port    プロキシポート番号
    514         */
    515        public void setProxyPort( final String port ) {
    516                proxyPort = nval( getRequestParameter( port ),proxyPort );
    517        }
    518
    519        /**
    520         * 【TAG】アクセスパラメータキーをCSV形式で複数指定します。
    521         *
    522         * @og.tag
    523         * アクセスする ＵＲＬに追加するパラメータのキーを指定します。
    524         * カンマ区切りで複数指定できます。
    525         * vals 属性には、キーに対応する値を、設定してください。
    526         * 例:<b>keys="command,SYSTEM_ID"</b> vals="NEW,GE"
    527         * 分解方法は、CSV変数を先に分解してから、getRequestParameter で値を取得します。
    528         * こうしないとデータ自身にカンマを持っている場合に分解をミスる為です。
    529         *
    530         * [SOAP対応]
    531         * SOAPによるWebサービスの呼び出しの場合、keys,valsに指定された値より、env:Envelopタグを
    532         * rootタグとするXMLデータを生成します。
    533         * (BODY部分に直接XMLデータを出力することも可能です。)
    534         * この際、項目名に'&gt;'を含めることで、階層的なXMLデータを表現することができます。
    535         * 例)
    536         *   [属性定義]
    537         *   keys="param0&gt;AAA,param0&gt;BBB,param1&gt;CCC,DDD"
    538         *   vals="v1,v2,v3,v4"
    539         *   [XMLデータ(※データ部のみ)]
    540         *   &lt;param0&gt;
    541         *     &lt;AAA&gt;v1&lt;/AAA&gt;
    542         *     &lt;BBB&gt;v2&lt;/BBB&gt;
    543         *   &lt;/param0&gt;
    544         *   &lt;param1&gt;
    545         *     &lt;CCC&gt;v3&lt;/CCC&gt;
    546         *   &lt;/param1&gt;
    547         *   &lt;DDD&gt;v4&lt;/DDD&gt;
    548         * 項目の値を"null"とすることで、XMLで言うところの「xsi:nil=\"true\"」のデータを表現すること
    549         * もできます。
    550         * また、キー名の先頭を'&#064;'にすることで、項目名に名前空間のPREFIXを付加することができます。
    551         * 一般的には、JavaやRubyで実装されたWebサービスを呼び出しする場合は、必要ありませんが、
    552         * .NETで実装されたWebサービスを呼び出しする場合は、各項目にPREFIXを付与しないと、正しく
    553         * パラメーターを渡すことができません。
    554         * ※現時点では、keysの階層定義は、2階層まで対応しています。
    555         *   3階層以上のXML構造を定義する場合は、postFile属性によるファイル指定又は、Body部分で直接
    556         *   XMLデータを記述して下さい。
    557         *
    558         * @param       key リンク先に渡すキー
    559         * @see         #setVals( String )
    560         */
    561        public void setKeys( final String key ) {
    562                keys = getCSVParameter( key );
    563        }
    564
    565        /**
    566         * 【TAG】keys属性に対応する値をCSV形式で複数指定します。
    567         *
    568         * @og.tag
    569         * キーに設定した値を、カンマ区切り文字で複数して出来ます。
    570         * 指定順序は、キーと同じにしておいて下さい。
    571         * 例:<b>keys="command,SYSTEM_ID"</b> vals="NEW,GE"
    572         * 分解方法は、CSV変数を先に分解してから、getRequestParameter で値を取得します。
    573         * こうしないとデータ自身にカンマを持っている場合に分解をミスる為です。
    574         *
    575         * @param       val names属性に対応する値
    576         * @see         #setKeys( String )
    577         */
    578        public void setVals( final String val ) {
    579                vals = getCSVParameter( val );
    580        }
    581
    582        /**
    583         * 【TAG】送信メソッドを指定します(GET/POST/SOAP)。
    584         *
    585         * @og.tag
    586         * URLConnectTagのメソッドの初期設定はGETです。
    587         * ここで"POST"(大文字)を指定するとkyes,valsの値セットをPOSTで送信します。
    588         * (postKeyが設定されている場合はこの値に関係なくPOSTです)
    589         *
    590         * @og.rev 4.1.0.0 (2007/12/22) 新規作成
    591         *
    592         * @param       post_get        送信メソッド(GET/POST/SOAP)
    593         */
    594        public void setMethod ( final String post_get ) {
    595                method = nval( getRequestParameter( post_get ), method );
    596        }
    597
    598        /**
    599         * 【TAG】Basic認証で接続するユーザーにSYSTEMユーザーを使用するかどうか[true/false]を指定します(初期値:true)。
    600         *
    601         * @og.tag
    602         * useSystemUser="true"(初期値) の場合、URL接続時のコネクションに、Basic認証を
    603         * 使用しますが、その時のユーザーにシステムユーザー(SYSTEM)を使用します。
    604         * useSystemUser="false"の場合は、authUserPass で指定したユーザー：パスワードを
    605         * 使用します。authUserPass で、何も指定されなかった場合は、Basic認証を使用しません。
    606         * 初期値は、true(SYSTEMユーザー認証する) です。
    607         *
    608         * @param   flag [true:SYSTEMユーザー認証する/false:この接続のユーザーで認証する]
    609         * @see #setAuthUserPass( String )
    610         */
    611        public void setUseSystemUser( final String flag ) {
    612                useSystemUser = nval( getRequestParameter( flag ),useSystemUser );
    613        }
    614
    615        /**
    616         * 【TAG】Basic認証を使用して接続する場合のユーザー:パスワードを指定します(初期値:null)。
    617         *
    618         * @og.tag
    619         * 接続時のユーザーとパスワードを、USER:PASSWD 形式で指定します。
    620         * useSystemUser="false"の場合は、ここで指定したユーザーとパスワードを使用します。
    621         * その場合に、何も指定しない場合は、Basic認証を使用しません。
    622         *
    623         * @param       userPass        接続のユーザーとパスワード(USER:PASSWD 形式)
    624         * @see #setUseSystemUser( String )
    625         */
    626        public void setAuthUserPass( final String userPass ) {
    627                authUserPass = nval( getRequestParameter( userPass ),authUserPass );
    628        }
    629
    630        /**
    631         * 【TAG】接続の結果を表示する場合にXSLT変換する場合のファイルを指定します。
    632         *
    633         * @og.tag
    634         *
    635         * 接続先のデータが、XML形式の場合、そのままでは、画面出力できない場合が
    636         * あります。通常は、HTML形式に変換しますが、その変換に、 XSL ファイルを
    637         * 指定することが可能です。
    638         * display="true" の場合や、saveFile を指定した場合に、適用されます。
    639         *
    640         * @param       file    接続の結果を表示する場合にXSLT変換する場合のファイル
    641         * @see #setSaveFile( String )
    642         * @see #setDisplay( String )
    643         */
    644        public void setXslFile( final String file ) {
    645                xslFile = HybsSystem.url2dir( nval( getRequestParameter( file ),xslFile ) );
    646        }
    647
    648        /**
    649         * 【TAG】接続の結果を表示するかどうかを指定します(初期値:false)。
    650         *
    651         * @og.tag
    652         * true で、接続結果を表示します。 false では、何も表示しません(初期値:false)
    653         * 接続結果を表示する使い方より、admin 画面に接続して、キャッシュクリアするような
    654         * 使い方が多いと考え、初期値は、false になっています。
    655         * xslFile が指定されている場合、XSLT変換して画面表示します。
    656         * display="true" と、saveFile を併用することはできません。
    657         *
    658         * @param       flag    接続の結果を表示するかどうか(初期値:false)
    659         * @see #setSaveFile( String )
    660         * @see #setXslFile( String )
    661         */
    662        public void setDisplay( final String flag ) {
    663                display = nval( getRequestParameter( flag ),display );
    664
    665                if( display && saveFile != null ) {
    666                        String errMsg = "display=\"true\" と、saveFile を併用することはできません。";
    667                        throw new HybsSystemException( errMsg );
    668                }
    669        }
    670
    671        /**
    672         * 【TAG】接続の結果をファイルに保存します。
    673         *
    674         * @og.tag
    675         * 接続先のデータを受け取って、ファイルに保存します。その場合、
    676         * xslFile が指定されている場合、XSLT変換してセーブします。
    677         * display="true" と、saveFile を併用することはできません。
    678         *
    679         * @param       file    接続の結果を表示する場合にXSLT変換する場合のファイル
    680         * @see #setXslFile( String )
    681         * @see #setDisplay( String )
    682         */
    683        public void setSaveFile( final String file ) {
    684                saveFile = HybsSystem.url2dir( nval( getRequestParameter( file ),saveFile ) );
    685
    686                if( display ) {
    687                        String errMsg = "display=\"true\" と、saveFile を併用することはできません。";
    688                        throw new HybsSystemException( errMsg );
    689                }
    690        }
    691
    692        /**
    693         * 【TAG】POST を使って、postFile属性のファイル内容を送信する時のキーを指定します。
    694         *
    695         * @og.tag
    696         * 接続先にパラメータ(引数)を投げる場合に、POST を使用できます。
    697         * そのときの キーをここで指定します。
    698         * POSTするデータは、postFileで指定されたファイルか、BODY部に記述された文字列です。
    699         *
    700         * @param       key     POST を使って、postFile属性のファイル内容を送信する時のキー
    701         * @see  #setPostFile( String )
    702         */
    703        public void setPostKey( final String key ) {
    704                postKey = nval( getRequestParameter( key ),postKey );
    705        }
    706
    707        /**
    708         * 【TAG】POST を使って、postFile属性のファイル内容を送信します。
    709         *
    710         * @og.tag
    711         * 接続先にパラメータ(引数)を投げる場合に、POST を使用できます。
    712         * そのときの 送信データのファイルをここで指定します。
    713         * postKey のみ指定されて、postFile が指定されない場合は、BODY部を送信します。
    714         * SOAPによる呼び出しの場合は、ここ(BODY部での定義を含む)で、送信するXMLデータを
    715         * 定義することができます。
    716         *
    717         * @param       file    接続の結果を表示する場合にXSLT変換する場合のファイル
    718         * @see  #setPostKey( String )
    719         */
    720        public void setPostFile( final String file ) {
    721                String postFile = nval( getRequestParameter( file ),null );
    722
    723                if( postFile != null ) {
    724                        FileString fileStr = new FileString();
    725                        fileStr.setFilename( HybsSystem.url2dir( postFile ) );
    726                        postData = fileStr.getValue();
    727                }
    728        }
    729
    730        /**
    731         * 【TAG】接続タイムアウト時間を(秒)で指定します
    732         *              (初期値:URL_CONNECT_TIMEOUT[={@og.value org.opengion.hayabusa.common.SystemData#URL_CONNECT_TIMEOUT}])。
    733         *
    734         * @og.tag
    735         * 実際には、java.net.URLConnection#setConnectTimeout(int) に 1000倍して設定されます。
    736         * 0 は、無限のタイムアウト、マイナスは、設定しません。(つまりJavaの初期値のまま)
    737         * (初期値:システム定数のURL_CONNECT_TIMEOUT[={@og.value org.opengion.hayabusa.common.SystemData#URL_CONNECT_TIMEOUT}])。
    738         *
    739         * @og.rev 5.8.1.1 (2015/06/12) timeout属性追加
    740         *
    741         * @param       tout    タイムアウト時間(秒) (ゼロは、無制限)
    742         * @see         org.opengion.fukurou.util.URLConnect#setTimeout(int)
    743         * @see         java.net.URLConnection#setConnectTimeout(int)
    744         */
    745        public void setTimeout( final String tout ) {
    746                timeout = nval( getRequestParameter( tout ),timeout );
    747        }
    748
    749        /**
    750         * 【TAG】(通常は使いません) 接続エラーを無視する場合にtrueとします(初期値false)。
    751         *
    752         * @og.tag
    753         * trueにするとConnectで発生したエラーを投げずに処理を続行します。
    754         * (標準エラー出力にエラー内容は出力されます)
    755         * 接続エラーが発生しても処理を中断したくない場合に設定します。
    756         *
    757         * @og.rev 4.1.1.0 (2008/01/22) 新規追加
    758         *
    759         * @param       flag    エラーを無視する場合にtrue
    760         */
    761        public void setErrNeglect( final String flag ) {
    762                errNglctFlag = nval( getRequestParameter( flag ), errNglctFlag );
    763        }
    764
    765        /**
    766         * 【TAG】SOAPによるWebサービスの呼び出しで、メソッド名及びパラメーターの名前空間を指定します。
    767         *
    768         * @og.tag
    769         * SOAPによるWebサービスの呼び出しで、メソッド名及びパラメーターの名前空間を指定します。
    770         * この名前空間は、通常WSDLファイルのdescriptionsタグのtargetNamespace属性の値により
    771         * 定義されます。
    772         *
    773         * @og.rev 5.1.5.0 (2010/04/01) 新規追加
    774         *
    775         * @param       ns      名前空間
    776         */
    777        public void setSoapNameSpace( final String ns ) {
    778                soapNameSpace = nval( getRequestParameter( ns ), soapNameSpace );
    779        }
    780
    781        /**
    782         * 【TAG】SOAPによるWebサービスの呼び出しで、メソッド名を指定します。
    783         *
    784         * @og.tag
    785         * SOAPによるWebサービスの呼び出しで、メソッド名を指定します。
    786         * WSDLファイルで定義されるoperationタグのname属性の値に相当します。
    787         *
    788         * @og.rev 5.1.5.0 (2010/04/01) 新規追加
    789         *
    790         * @param       method  メソッド名
    791         */
    792        public void setSoapMethodName( final String method ) {
    793                soapMethodName = nval( getRequestParameter( method ), soapMethodName );
    794        }
    795
    796        /**
    797         * 【TAG】(通常は使いません)結果のDBTableModelを、sessionに登録するときのキーを指定します
    798         *              (初期値:HybsSystem#TBL_MDL_KEY[={@og.value org.opengion.hayabusa.common.HybsSystem#TBL_MDL_KEY}])。
    799         *
    800         * @og.tag
    801         * 検索結果より、DBTableModelオブジェクトを作成します。これを、下流のviewタグ等に
    802         * 渡す場合に、通常は、session を利用します。その場合の登録キーです。
    803         * query タグを同時に実行して、結果を求める場合、同一メモリに配置される為、
    804         * この tableId 属性を利用して、メモリ空間を分けます。
    805         *              (初期値:HybsSystem#TBL_MDL_KEY[={@og.value org.opengion.hayabusa.common.HybsSystem#TBL_MDL_KEY}])。
    806         *
    807         * @param       id sessionに登録する時の ID
    808         */
    809        public void setTableId( final String id ) {
    810                tableId   = nval( getRequestParameter( id ),tableId );
    811        }
    812
    813        /**
    814         * 【TAG】結果のXMLをDBTableModelに変換する際に、行のキーとなるタグ名を指定します。
    815         *
    816         * @og.tag
    817         * 結果のXMLを表形式に変換する際に、行のキーとなるタグ名を指定します。
    818         * このキーのタグを基点として、colKeysで指定されたタグの値を各項目の値として取り込みます。
    819         * (詳細は、colKeysのタグリブ属性マニュアルを参照して下さい。)
    820         *
    821         * @param       key 行のキーとなるタグ名
    822         * @see #setColKeys( String )
    823         */
    824        public void setRowKey( final String key ) {
    825                rowKey = nval( getRequestParameter( key ),rowKey );
    826        }
    827
    828        /**
    829         * 【TAG】結果のXMLをDBTableModelに変換する際に、項目のキーとなるタグ名の一覧を指定します。
    830         *
    831         * @og.tag
    832         * 結果のXMLをDBTableModelに変換する際に、項目のキーとなるタグ名の一覧を指定します。
    833         * rowKeyで行を、colKeysで項目を表現し、rowKeyのタグで囲われた固まりを1つの行とみなします。
    834         * このため、colKeysに指定されたキーのタグでも、rowKeyの外にある場合は、取り込み対象となりません。
    835         *
    836         * また、キーにPARENT_TAG、PARENT_FULL_TAGを指定することで、rowKeyで指定されたタグの
    837         * 直近の親タグ、及びフルの親タグ名(親タグの階層を"&gt;[タグA]&gt;[タグB]&gt;[タグC]&gt;"で表現)を
    838         * 取得することができます。
    839         *
    840         * @param       keys 項目のキーとなるタグ名の一覧
    841         */
    842        public void setColKeys( final String keys ) {
    843                colKeys = StringUtil.csv2Array( getRequestParameter( keys ) );
    844        }
    845
    846        /**
    847         * 【TAG】結果のXMLを変換する際に、パラメータ(Attributes)として取り込むキーの一覧を指定します。
    848         *
    849         * @og.tag
    850         * 結果のXMLを変換する際に、パラメータ(Attributes)として取り込むキーの一覧を指定します。
    851         * ここで指定されたキーのタグの値を取り出し、{&#064;XX}形式(Attributes)として処理できるようにします。
    852         *
    853         * @param       keys パラメーター(Attributes)のキーとなるタグ名の一覧
    854         */
    855        public void setRtnKeys( final String keys ) {
    856                rtnKeys = StringUtil.csv2Array( getRequestParameter( keys ) );
    857        }
    858
    859        /**
    860         * 【TAG】データの入出力のエンコードを指定します。
    861         *
    862         * @og.tag
    863         * データの入出力のエンコードを指定します。
    864         * 初期値は、"UTF-8"です。
    865         *
    866         * @og.rev 5.1.6.0 (2010/05/01) 新規作成
    867         * @param       enc     エンコード
    868         */
    869        public void setEncode( final String enc ) {
    870                encode = nval( getRequestParameter( enc ), encode );
    871        }
    872
    873        /**
    874         * タグの名称を、返します。
    875         * 自分自身のクラス名より、自動的に取り出せないため、このメソッドをオーバーライドします。
    876         *
    877         * @og.rev 4.0.0.0 (2005/01/31) 新規追加
    878         *
    879         * @return  タグの名称
    880         */
    881        @Override
    882        protected String getTagName() {
    883                return "urlConnect" ;
    884        }
    885
    886        /**
    887         * 【TAG】(通常使いません)タグで処理される処理がメインとなるトランザクション処理かどうかを指定します(初期値:false)。
    888         *
    889         * @og.tag
    890         * (通常使いません)タグで処理される処理が、メインとなるトランザクション処理かどうかを指定します。(初期値:false)
    891         * この値は、ファイルダウンロード処理に影響します。この値がtrueに指定された時にcommitされたDBTableModelが
    892         * ファイルダウンロードの対象の表になります。
    893         *
    894         * このパラメーターは、通常、各タグにより実装され、ユーザーが指定する必要はありません。
    895         * 但し、1つのJSP内でDBTableModelが複数生成される場合に、前に処理したDBTableModelについてファイルダウンロードをさせたい
    896         * 場合は、後ろでDBTableModelを生成するタグで、明示的にこの値をfalseに指定することで、ファイルダウンロード処理の対象から
    897         * 除外することができます。
    898         *
    899         * @og.rev 5.1.6.0 (2010/05/01) 新規作成
    900         *
    901         * @param  flag メイントランザクションかどうか
    902         */
    903        public void setMainTrans( final String flag ) {
    904                isMainTrans = nval( getRequestParameter( flag ),isMainTrans );
    905        }
    906
    907        /**
    908         * このオブジェクトの文字列表現を返します。
    909         * 基本的にデバッグ目的に使用します。
    910         *
    911         * @return このクラスの文字列表現
    912         */
    913        @Override
    914        public String toString() {
    915                return org.opengion.fukurou.util.ToString.title( this.getClass().getName() )
    916                                .println( "VERSION"                     ,VERSION                )
    917                                .println( "method"                      ,method                 )
    918                                .println( "urlStr"                      ,urlStr                 )
    919                                .println( "keys"                        ,StringUtil.array2csv( keys ) )
    920                                .println( "vals"                        ,StringUtil.array2csv( vals ) )
    921                                .println( "proxyHost"           ,proxyHost              )
    922                                .println( "proxyPort"           ,proxyPort              )
    923                                .println( "timeout"                     ,timeout                )               // 5.8.1.1 (2015/06/12) 新規追加
    924                                .println( "useSystemUser"       ,useSystemUser  )
    925                                .println( "authUserPass"        ,authUserPass   )
    926                                .println( "display"                     ,display                )
    927                                .println( "postData"            ,postData               )
    928                                .println( "xslFile"                     ,xslFile                )
    929                                .println( "saveFile"            ,saveFile               )
    930                                .println( "errNglctFlag"        ,errNglctFlag   )
    931                                .println( "soapNameSpace"       ,soapNameSpace  )
    932                                .println( "soapMethodName"      ,soapMethodName )
    933                                .println( "tableId"                     ,tableId                )
    934                                .println( "rowKey"                      ,rowKey                 )
    935                                .println( "colKeys"                     ,StringUtil.array2csv( colKeys ) )
    936                                .println( "rtnKeys"                     ,StringUtil.array2csv( rtnKeys ) )
    937                                .println( "Other..."            ,getAttributes().getAttribute() )
    938                                .fixForm().toString() ;
    939        }
    940}