    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.Map;
    019
    020import org.opengion.fukurou.util.ErrorMessage;
    021import org.opengion.fukurou.util.JSONScan;
    022import org.opengion.fukurou.util.ToString;
    023import org.opengion.hayabusa.db.DBColumn;
    024import org.opengion.hayabusa.db.DBTableModel;
    025
    026import static org.opengion.fukurou.util.StringUtil.nval;
    027
    028/**
    029 * IOr (Information Organizer) に接続し、ﾃﾞｰﾀﾍﾞｰｽに追加/更新/削除を行うﾀｸﾞです。
    030 *
    031 * DBTableModel内のﾃﾞｰﾀを JSON形式 の文字列に出力し、IOr へﾃﾞｰﾀ登録を要求します。
    032 * DBTableModel内のﾃﾞｰﾀより loadFile が優先されます。
    033 *
    034 * 実行後にﾘｸｴｽﾄﾊﾟﾗﾒｰﾀに以下の値がｾｯﾄされます。
    035 *   DB.COUNT    : 実行結果の件数
    036 *   DB.ERR_CODE : 実行結果のｴﾗｰｺｰﾄﾞ
    037 *   DB.ERR_MSG  : 実行結果のｴﾗｰﾒｯｾｰｼﾞ
    038 *
    039 * ※ このﾀｸﾞは、Transaction ﾀｸﾞの対象です。
    040 *
    041 * @og.formSample
    042 * ●形式：
    043 *     &lt;og:iorUpdate
    044 *         url           = "http://･･･ "    必須
    045 *         authURL       = "http://･･･ "    必須
    046 *         authUserPass  = "admin:******"   必須
    047 *         appliName     = "ﾃﾞｰﾀﾃｰﾌﾞﾙ名"
    048 *         callMethod    = "saveReport"
    049 *     /&gt;
    050 *
    051 * ●Tag定義：
    052 *   &lt;og:iorUpdate
    053 *       url              ○【TAG】ｱｸｾｽする URL を指定します (必須)
    054 *       proxyHost          【TAG】ﾌﾟﾛｷｼ経由で接続する場合の、ﾌﾟﾛｷｼﾎｽﾄ名を指定します
    055 *       proxyPort          【TAG】ﾌﾟﾛｷｼ経由で接続する場合の、ﾌﾟﾛｷｼﾎﾟｰﾄ番号を指定します
    056 *       timeout            【TAG】通信ﾘﾝｸのｵｰﾌﾟﾝ時に、指定された秒単位のﾀｲﾑ･ｱｳﾄ値を使用します
    057 *                                  (初期値:URL_CONNECT_TIMEOUT[={@og.value SystemData#URL_CONNECT_TIMEOUT}])
    058 *       authURL          ○【TAG】JSONｺｰﾄﾞで認証するURLを指定します (必須)
    059 *       authUserPass     ○【TAG】Basic認証を使用して接続する場合のﾕｰｻﾞｰ:ﾊﾟｽﾜｰﾄﾞを指定します (必須)
    060 *       companyId          【TAG】企業IDを指定します
    061 *       appliName          【TAG】ｱﾌﾟﾘｹｰｼｮﾝの名前を指定します
    062 *       callMethod         【TAG】関数名を指定します
    063 *       display            【TAG】接続の結果を表示するかどうかを指定します (初期値:false)
    064 *       loadFile           【TAG】ﾌｧｲﾙからURL接続結果に相当するﾃﾞｰﾀを読み取ります
    065 *       scope              【TAG】ｷｬｯｼｭする場合のｽｺｰﾌﾟ[request/page/session/application]を指定します (初期値:session)
    066 *       selectedAll        【TAG】ﾃﾞｰﾀを全件選択済みとして処理するかどうか[true/false]を指定します(初期値:false)
    067 *       selectedOne        【TAG】ﾃﾞｰﾀを1件選択済みとして処理するかどうか[true/false]を指定します(初期値:false)
    068 *       displayMsg         【TAG】実行結果を画面上に表示するﾒｯｾｰｼﾞﾘｿｰｽIDを指定します (初期値:VIEW_DISPLAY_MSG[=])
    069 *       tableId            【TAG】(通常は使いません)結果のDBTableModelを、sessionに登録するときのｷｰを指定します
    070 *       stopError          【TAG】処理ｴﾗｰの時に処理を中止するかどうか[true/false]を設定します (初期値:true)
    071 *       dispError          【TAG】ｴﾗｰ時にﾒｯｾｰｼﾞを表示するか[true/false]を設定します。通常はstopErrorと併用 (初期値:true)
    072 *       quotCheck          【TAG】ﾘｸｴｽﾄ情報の ｼﾝｸﾞﾙｸｫｰﾄ(') 存在ﾁｪｯｸを実施するかどうか[true/false]を設定します
    073 *                                  (初期値:USE_SQL_INJECTION_CHECK)
    074 *       useTimeView        【TAG】処理時間を表示する TimeView を表示するかどうかを指定します
    075 *                                  (初期値:VIEW_USE_TIMEBAR[={@og.value SystemData#VIEW_USE_TIMEBAR}])
    076 *       caseKey            【TAG】このﾀｸﾞ自体を利用するかどうかの条件ｷｰを指定します (初期値:null)
    077 *       caseVal            【TAG】このﾀｸﾞ自体を利用するかどうかの条件値を指定します (初期値:null)
    078 *       caseNN             【TAG】指定の値が、null/ｾﾞﾛ文字列 でない場合(Not Null=NN)は、このﾀｸﾞは使用されます (初期値:判定しない)
    079 *       caseNull           【TAG】指定の値が、null/ｾﾞﾛ文字列 の場合は、このﾀｸﾞは使用されます (初期値:判定しない)
    080 *       caseIf             【TAG】指定の値が、true/TRUE文字列の場合は、このﾀｸﾞは使用されます (初期値:判定しない)
    081 *       debug              【TAG】ﾃﾞﾊﾞｯｸﾞ情報を出力するかどうか[true/false]を指定します (初期値:false)
    082 *   /&gt;
    083 *
    084 * ●使用例
    085 *     &lt;og:iorUpdate
    086 *         url           = "http://･･･ "
    087 *         authURL       = "http://･･･ "
    088 *         authUserPass  = "admin:******"
    089 *         appliName     = "ﾃﾞｰﾀﾃｰﾌﾞﾙ名"
    090 *         callMethod    = "saveReport"
    091 *   /&gt;
    092 *
    093 * @og.rev 8.0.2.0 (2021/11/30) 新規作成
    094 * @og.group その他部品
    095 *
    096 * @version  8.0
    097 * @author   LEE.M
    098 * @since    JDK17.0,
    099 */
    100public class IorUpdateTag extends IorQueryTag {
    101        /** このﾌﾟﾛｸﾞﾗﾑのVERSION文字列を設定します。 {@value} */
    102        private static final String VERSION = "8.0.2.0 (2021/11/30)" ;
    103        private static final long serialVersionUID = 802020211130L ;
    104
    105        private boolean selectedAll     ;                                                                                               // ﾃﾞｰﾀの全件選択済
    106        private boolean selectedOne     ;                                                                                               // ﾃﾞｰﾀの1件選択済
    107        private boolean quotCheck       ;                                                                                               // ｸｵｰﾄﾁｪｯｸ
    108
    109        /**
    110         * ﾃﾞﾌｫﾙﾄｺﾝｽﾄﾗｸﾀｰ
    111         *
    112         */
    113        public IorUpdateTag() { super(); }      // これも、自動的に呼ばれるが、空のﾒｿｯﾄﾞを作成すると警告されるので、明示的にしておきます。
    114
    115        /**
    116         * Taglibの開始ﾀｸﾞが見つかったときに処理する doStartTag() を ｵｰﾊﾞｰﾗｲﾄﾞします。
    117         *
    118         * @return      後続処理の指示
    119         */
    120        @Override
    121        public int doStartTag() {
    122                if( useTag() ) {
    123                        dyStart = System.currentTimeMillis();                                                           // 現在時刻
    124
    125                        table = (DBTableModel)getObject( tableId );
    126                        startQueryTransaction( tableId );
    127
    128                        if( table == null || table.getRowCount() == 0 ) { return SKIP_BODY ; }
    129
    130                        super.quotCheck = quotCheck;
    131                }
    132                return SKIP_BODY;                                                                                                               // Body を評価しない
    133        }
    134
    135        /**
    136         * Taglibの終了ﾀｸﾞが見つかったときに処理する doEndTag() を ｵｰﾊﾞｰﾗｲﾄﾞします。
    137         *
    138         * @return      後続処理の指示
    139         */
    140        @Override
    141        public int doEndTag() {
    142
    143                debugPrint();
    144                if( !useTag() ) { return EVAL_PAGE ; }
    145
    146                // ﾕｰｻﾞｰ:ﾊﾟｽﾜｰﾄﾞ から ﾕｰｻﾞｰとﾊﾟｽﾜｰﾄﾞを取得します。
    147                checkUsrPw();
    148
    149                // 読取ﾌｧｲﾙ指定無し
    150                if( loadFile == null ) {
    151                        // ﾃｰﾌﾞﾙﾓﾃﾞﾙ から JSON形式 に変更します。
    152                        postData = tbl2Json();
    153                }
    154                // 読取ﾌｧｲﾙ指定有り
    155                else {
    156                        // ﾌｧｲﾙ からﾃﾞｰﾀを読取ります。
    157                        postData = outJson();
    158                }
    159
    160                // URLに対して応答結果を取得します。
    161                rtnData = retResponse();
    162
    163                int errCode = ErrorMessage.OK;                                                                                  // ｴﾗｰｺｰﾄﾞ
    164                // 応答結果の HTTPｽﾃｰﾀｽｺｰﾄﾞ を設定します。
    165                errCode = getStatus( rtnData );
    166
    167                int rtnCode = EVAL_PAGE;
    168                // 正常／警告
    169                if( errCode < ErrorMessage.NG ) {
    170                        // 応答結果の 実行件数 を取得します。
    171                        executeCount = getCount( rtnData );
    172                        if( executeCount > 0 ){
    173                                // 処理後のﾒｯｾｰｼﾞを作成します。
    174                                errCode = makeMessage();
    175                        }
    176                }
    177                // 異常
    178                else {
    179                        rtnCode = stopError ? SKIP_PAGE : EVAL_PAGE ;
    180                }
    181
    182                // 処理時間(queryTime)などの情報出力の有効/無効を指定します。
    183                if( useTimeView ) {
    184                        final long dyTime = System.currentTimeMillis() - dyStart;
    185                        jspPrint( "<div id=\"queryTime\" value=\"" + (dyTime) + "\"></div>" );
    186                }
    187                return rtnCode;
    188        }
    189
    190        /**
    191         * ﾀｸﾞﾘﾌﾞｵﾌﾞｼﾞｪｸﾄをﾘﾘｰｽします。
    192         * ｷｬｯｼｭされて再利用されるので、ﾌｨｰﾙﾄﾞの初期設定を行います。
    193         */
    194        @Override
    195        protected void release2() {
    196                super.release2();
    197                selectedAll     = false;                                                                                                        // ﾃﾞｰﾀの全件選択済
    198                selectedOne     = false;                                                                                                        // ﾃﾞｰﾀの1件選択済
    199                quotCheck       = false;                                                                                                        // ｸｵｰﾄﾁｪｯｸ
    200        }
    201
    202        /**
    203         * ﾃｰﾌﾞﾙﾓﾃﾞﾙ から JSON形式 に変更します。
    204         *
    205         * @return      JSON形式の文字列
    206         */
    207        private String tbl2Json() {
    208                final int[] rowNo = getParameterRows();
    209                final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );
    210
    211                if( rowNo.length > 0 ) {
    212                        // ---------------------------------------------------------------------
    213                        // 共通要求ｷｰを設定します。
    214                        // 例：{"company_id":"XXXXX","user_id":"admin","session_id":"$session_id$","report_name":"YYYYY" …}
    215                        // ---------------------------------------------------------------------
    216                        setComJson();
    217                        buf.append( JSONScan.map2Json( mapParam ) );
    218
    219                        // ---------------------------------------------------------------------
    220                        // 共通要求ｷｰ以外の ｷｰを設定します。
    221                        // ---------------------------------------------------------------------
    222                        // 共通要求ｷｰの末尾に ,"data":{ 文字列を追加します。
    223                        // 例：{"company_id":"XXXXX", …}を {"company_id":"XXXXX", … ,"data":{ …} に
    224                        buf.setLength(buf.length()-1);
    225                        buf.append( ",\"data\":{\n\"headers\":[\n" );
    226
    227                        // ---------------------------------------------------------------------
    228                        // ﾃｰﾌﾞﾙﾓﾃﾞﾙの列を追加します。
    229                        // 例："headers": [{"display_label": "品目番号", "display": "PN"}, … ],"rows" …
    230                        // ---------------------------------------------------------------------
    231                        final DBColumn[] clms = table.getDBColumns();
    232
    233                        for( final DBColumn clm : clms ) {
    234                                // ｷｰと値をﾏｯﾋﾟﾝｸﾞします。
    235                                final Map<String,String> mapHeader = Map.of( IOR_DISP_LBL , clm.getLabel() , IOR_DISP_KEY ,clm.getName() );
    236
    237                                buf.append( JSONScan.map2Json( mapHeader ) )
    238                                        .append( ',' );
    239                        }
    240
    241                        // ---------------------------------------------------------------------
    242                        // ﾃｰﾌﾞﾙﾓﾃﾞﾙの行を追加します。
    243                        // 例："rows": [{"cols": [1, "GEN", "20211130", 32.4, "kg"]}, … ]}}
    244                        // ---------------------------------------------------------------------
    245                        buf.setLength(buf.length()-1);
    246                        buf.append( "],\n\"rows\":[\n" );
    247
    248                        int row;
    249                        for( int i=0; i<rowNo.length; i++ ) {
    250                                row = rowNo[i];
    251
    252                                buf.append( i == 0 ? "{\"cols\":[" : ",\n{\"cols\":[" );
    253                                for( int j=0; j<clms.length; j++ ) {
    254                                        buf.append( '"' )
    255                                                .append( table.getValue( row, j ) )
    256                                                .append( "\"," );
    257                                }
    258                                buf.setLength(buf.length()-1);
    259                                buf.append( "]}" );
    260                        }
    261                        buf.append( "\n]}}" );
    262                }
    263                return buf.toString();
    264        }
    265
    266        /**
    267         * 表示ﾃﾞｰﾀの HybsSystem.ROW_SEL_KEY を元に、選ばれた 行番号の
    268         * 配列を返します。
    269         * なにも選ばれていない場合は、ｻｲｽﾞ０の配列を返します。
    270         *
    271         * @return      選ばれた 行番号 (選ばれていない場合は、ｻｲｽﾞ０の配列を返す)
    272         * @og.rtnNotNull
    273         */
    274        @Override
    275        protected int[] getParameterRows() {
    276                final int[] rowNo;
    277                if( selectedAll ) {
    278                        final int rowCnt = table.getRowCount();
    279                        rowNo = new int[ rowCnt ];
    280                        for( int i=0; i<rowCnt; i++ ) {
    281                                rowNo[i] = i;
    282                        }
    283                }
    284                else if( selectedOne ) {
    285                        rowNo = new int[] {0};
    286                }
    287                else {
    288                        rowNo = super.getParameterRows();
    289                }
    290                return rowNo;
    291        }
    292
    293        /**
    294         * 【TAG】ﾃﾞｰﾀを全件選択済みとして処理するかどうか[true/false]を指定します(初期値:false)。
    295         *
    296         * @og.tag
    297         * 全てのﾃﾞｰﾀを選択済みﾃﾞｰﾀとして扱って処理します。
    298         * 全件処理する場合に、(true/false)を指定します。
    299         * 初期値は false です。
    300         *
    301         * changeOnly よりも selectedAll="true" が優先されます。
    302         *
    303         * @param       all     ﾃﾞｰﾀを全件選択済み [true:全件選択済み/false:通常]
    304         */
    305        public void setSelectedAll( final String all ) {
    306                selectedAll = nval( getRequestParameter( all ),selectedAll );
    307        }
    308
    309        /**
    310         * 【TAG】ﾃﾞｰﾀを1件選択済みとして処理するかどうか[true/false]を指定します(初期値:false)。
    311         *
    312         * @og.tag
    313         * 先頭行の1件だけを選択済みとして処理します。
    314         * まとめ処理のﾃﾞｰﾀを処理する場合などに使われます。
    315         * 初期値は false です。
    316         *
    317         * @param       one     先頭行の1件だけを選択済みとして処理するかどうか [true:処理する/false:通常]
    318         */
    319        public void setSelectedOne( final String one ) {
    320                selectedOne = nval( getRequestParameter( one ),selectedOne );
    321        }
    322
    323        /**
    324         * このｵﾌﾞｼﾞｪｸﾄの文字列表現を返します。
    325         * 基本的にﾃﾞﾊﾞｯｸﾞ目的に使用します。
    326         *
    327         * @return このｸﾗｽの文字列表現
    328         * @og.rtnNotNull
    329         */
    330        @Override
    331        public String toString() {
    332                return ToString.title( this.getClass().getName() )
    333                                .println( "VERSION"             ,VERSION        )
    334                                .fixForm().toString()
    335                        + CR
    336                        + super.toString() ;
    337        }
    338}