    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.plugin.table;
    017
    018import org.opengion.hayabusa.common.HybsSystemException;
    019import org.opengion.hayabusa.db.AbstractTableFilter;
    020import org.opengion.hayabusa.db.DBColumn;
    021import org.opengion.hayabusa.db.DBTableModel;
    022
    023import org.opengion.hayabusa.resource.ResourceFactory;
    024import org.opengion.hayabusa.resource.ResourceManager;
    025
    026import org.opengion.fukurou.util.ErrorMessage;
    027import org.opengion.fukurou.util.StringUtil;
    028import java.util.regex.Pattern;
    029import java.util.regex.Matcher;
    030import java.util.Locale;
    031
    032/**
    033 * TableFilter_DBARG は、TableFilter インターフェースを継承した、DBTableModel 処理用の
    034 * 実装クラスです。
    035 *
    036 * ここでは、テキストから、オブジェクト名、カラム名、クラス、利用桁数を切り出します。
    037 *
    038 * ソースのテキスト部は、",NAME_JA VARCHAR2(100) " という形式のテキストになっています。
    039 * これを、カラム部、クラス名部、使用桁数部に分解します。上記の例では、
    040 * それぞれを、NAME_JA、VARCHAR2、100 に分解して、文字列配列に格納します。
    041 * また、これらのソースに、"--" や "/ * ･･･ * /" などのコメントが含まれるケースが
    042 * あります。"--" コメントは、それ以降を無視しますが、"/ *" コメントは、複数行に
    043 * またがる為、今回は処理対象から外します。
    044 * ソースのテキスト部には、それら以外に、OBJECT_NAME に相当する行や、");" などの
    045 * ソースの最初や最後の無効な部分があります。無効な部分は、null を返すことで
    046 * 登録処理から省いてください。
    047 *
    048 * パラメータは、tableFilterタグの keys, vals にそれぞれ記述するか、BODY 部にCSS形式で記述します。
    049 * 【パラメータ】
    050 *  {
    051 *       TEXT       : 処理をおこなう、ソースのテキスト部のカラム名
    052 *       OBJ_NAME   : キーとなるオブジェクト名のカラム名
    053 *       SEQNO      : ソースの行番号のカラム名
    054 *       CLM        : 処理結果のカラム名を格納するカラム名
    055 *       CLS_NAME   : 処理結果のクラス名を格納するカラム名
    056 *       USE_LENGTH : 処理結果の利用桁数を格納するカラム名
    057 *       CLM_NAME   : 処理結果のカラム名称（ラベル）を格納するカラム名
    058 *       MAX_LENGTH : 処理結果の桁数を格納するカラム名
    059 *  }
    060 *
    061 * @og.formSample
    062 * ●形式：
    063 *              select A.OBJECT_NAME AS OBJ_NAME,B.LINE AS SEQNO,'' AS CLM ,
    064 *                      '' AS CLS_NAME,'' AS USE_LENGTH,'' AS CLM_NAME,
    065 *                      '' AS TABLE_NAME ,'' AS MAX_LENGTH,
    066 *                      B.TEXT , '{&#064;SYSTEM_ID}' AS SYSTEM_ID,'{&#064;TBLSYU}' AS TBLSYU
    067 *              from USER_OBJECTS A inner join USER_SOURCE B
    068 *              on    A.OBJECT_NAME = B.NAME
    069 *              where A.OBJECT_TYPE = 'TYPE'
    070 *              and   B.TYPE        = 'TYPE'
    071 *              and   not A.OBJECT_NAME like '%ARRAY'
    072 *              order by A.OBJECT_NAME,B.LINE
    073 *      ① &lt;og:tableFilter classId="DBARG"
    074 *                              keys="TEXT,OBJ_NAME,SEQNO,CLM,CLS_NAME,USE_LENGTH,CLM_NAME,MAX_LENGTH"
    075 *                              vals="TEXT,OBJ_NAME,SEQNO,CLM,CLS_NAME,USE_LENGTH,CLM_NAME,MAX_LENGTH" /&gt;
    076 *
    077 *      ② &lt;og:tableFilter classId="DBARG" &gt;
    078 *               {
    079 *                      TEXT         : TEXT       ;
    080 *                      OBJ_NAME     : OBJ_NAME   ;
    081 *                      SEQNO        : SEQNO      ;
    082 *                      CLM          : CLM        ;
    083 *                      CLS_NAME     : CLS_NAME   ;
    084 *                      USE_LENGTH   : USE_LENGTH ;
    085 *                      CLM_NAME     : CLM_NAME   ;
    086 *                      MAX_LENGTH   : MAX_LENGTH ;
    087 *               }
    088 *         &lt;/og:tableFilter&gt;
    089 *
    090 * @og.rev 5.6.6.0 (2013/07/05) keys の整合性チェックを追加
    091 *
    092 * @version  0.9.0  2000/10/17
    093 * @author   Kazuhiko Hasegawa
    094 * @since    JDK1.1,
    095 */
    096public class TableFilter_DBARG extends AbstractTableFilter {
    097        /** このプログラムのVERSION文字列を設定します。   {@value} */
    098        private static final String VERSION = "6.5.0.1 (2016/10/21)" ;
    099
    100        // 6.4.1.1 (2016/01/16) pt  → PTN1  refactoring
    101        private static final Pattern PTN1 = Pattern.compile( "[^\\w]*([\\w]*)[^\\w]*(VARCHAR2|NUMBER)[\\s]*([\\(\\d,\\)]*)",Pattern.CASE_INSENSITIVE );
    102                                                                                                //                         (______)       (_______________)       (_____________)
    103
    104        // 5.5.7.4 (2012/10/25) OBJ_NAME,SEQNO 追加
    105        private static final String[] KEYS  = { "TEXT","OBJ_NAME","SEQNO","CLM","CLS_NAME","USE_LENGTH","CLM_NAME","MAX_LENGTH" };
    106        private static final int TEXT           = 0;
    107        private static final int OBJ_NAME       = 1;                    // 5.5.7.4 (2012/10/25) OBJ_NAME 追加
    108        private static final int SEQNO          = 2;                    // 5.5.7.4 (2012/10/25) SEQNO 追加
    109        private static final int CLM            = 3;
    110        private static final int CLS_NAME       = 4;
    111        private static final int USE_LENGTH     = 5;
    112        private static final int CLM_NAME       = 6;
    113        private static final int MAX_LENGTH     = 7;
    114
    115        /**
    116         * デフォルトコンストラクター
    117         *
    118         * @og.rev 6.4.1.1 (2016/01/16) keysMap を、サブクラスから設定させるように変更。
    119         */
    120        public TableFilter_DBARG() {
    121                super();
    122                initSet( "TEXT"                 , "処理をおこなう、ソースのテキスト部のカラム名"              );
    123                initSet( "OBJ_NAME"             , "キーとなるオブジェクト名のカラム名"                                   );
    124                initSet( "SEQNO"                , "ソースの行番号のカラム名"                                                        );
    125                initSet( "CLM"                  , "処理結果のカラム名を格納するカラム名"                          );
    126                initSet( "CLS_NAME"             , "処理結果のクラス名を格納するカラム名"                          );
    127                initSet( "USE_LENGTH"   , "処理結果の利用桁数を格納するカラム名"                          );
    128                initSet( "CLM_NAME"             , "処理結果のカラム名称（ラベル）を格納するカラム名"    );
    129                initSet( "MAX_LENGTH"   , "処理結果の桁数を格納するカラム名"                                    );
    130        }
    131
    132        /**
    133         * DBTableModel処理を実行します。
    134         *
    135         * @og.rev 5.5.2.6 (2012/05/25) protected変数を、private化したため、getterメソッドで取得するように変更
    136         * @og.rev 5.5.7.4 (2012/10/25) OBJ_NAME,SEQNO を追加することで、SEQNO を振りなおします。
    137         * @og.rev 6.5.0.1 (2016/10/21) ErrorMessage をまとめるのと、直接 Throwable を渡します。
    138         *
    139         * @return 処理結果のDBTableModel
    140         */
    141        public DBTableModel execute() {
    142                final DBTableModel table = getDBTableModel();           // 5.5.2.6 (2012/05/25) インターフェースにgetterメソッド追加
    143
    144                final int size = KEYS.length;
    145                int[] clmNo = new int[size];
    146                for( int i=0; i<size; i++ ) {
    147                        final String clm = getValue( KEYS[i] );
    148                        clmNo[i]  = table.getColumnNo( clm,false );     // 存在しない場合は、-1
    149                        if( clmNo[i] < 0 ) {
    150                                final String errMsg = "検索結果に、[" + clm + "]を含めてください。" ;
    151                                throw new HybsSystemException( errMsg );
    152                        }
    153                }
    154
    155                String[] data  = null;
    156                final int rowCnt = table.getRowCount();
    157                final DBTableModel rtnTbl = table.newModel();
    158                String bkObjName = "";                                          // 5.5.7.4 (2012/10/25) SEQNO を振りなおすためのキーブレイク
    159                int    seqno     = 1 ;                                          // 5.5.7.4 (2012/10/25) SEQNO
    160                final String lang = getValue( "LANG" );
    161                final ResourceManager resource = ResourceFactory.newInstance( lang );
    162                for( int row=0; row<rowCnt; row++ ) {
    163                        try {
    164                                data = table.getValues( row );
    165                                final String text = data[clmNo[TEXT]] ;
    166                                final String[] temp = textSeparate( text );
    167                                if( temp != null ) {
    168                                        final String objName                    = data[clmNo[OBJ_NAME]];                // 5.5.7.4 (2012/10/25) SEQNO を振りなおす
    169                                        if( ! bkObjName.equals( objName ) ) {
    170                                                bkObjName = objName;
    171                                                seqno     = 1;
    172                                        }
    173
    174                                        data[clmNo[SEQNO]]              = String.valueOf( seqno++ );                    // 5.5.7.4 (2012/10/25) SEQNO を振りなおす
    175                                        data[clmNo[CLM]]                = temp[0];
    176                                        data[clmNo[CLS_NAME]]   = temp[1];
    177                                        data[clmNo[USE_LENGTH]] = temp[2];
    178                        //              data[clmNo[CLM_NAME]]   = resource.getLabel( temp[0] ) ;
    179
    180                                        final DBColumn dbClm = resource.getDBColumn( temp[0] );
    181                                        if( dbClm != null ) {
    182                                                data[clmNo[CLM_NAME]]   = dbClm.getLabel() ;
    183                                                final String len = data[clmNo[MAX_LENGTH]] ;
    184                                                if( len == null || len.isEmpty() ) {            // 6.1.0.0 (2014/12/26) refactoring
    185                                                        data[clmNo[MAX_LENGTH]] = dbClm.getMaxlength() ;
    186                                                }
    187                                        }
    188                        //              else {
    189                        //                      data[clmNo[CLM_NAME]]   = temp[0] ;     // ラベルが存在しない
    190                        //              }
    191                                        rtnTbl.addColumnValues( data );
    192                                }
    193                        }
    194                        catch( final RuntimeException ex ) {
    195                                // 6.5.0.1 (2016/10/21) ErrorMessage をまとめるのと、直接 Throwable を渡します。
    196                                makeErrorMessage( "TableFilter_DBARG Error",ErrorMessage.NG )
    197                                        .addMessage( row+1,ErrorMessage.NG,"DBARG"
    198                                                , StringUtil.array2csv( data )
    199                                        )
    200                                        .addMessage( ex );
    201                        }
    202                }
    203
    204                return rtnTbl;
    205        }
    206
    207        /**
    208         * ソースのテキスト部を分割します。
    209         *
    210         * ソースのテキスト部は、",NAME_JA VARCHAR2(100) " という形式のテキストになっています。
    211         * これを、カラム部、クラス名部、使用桁数部に分解します。上記の例では、
    212         * それぞれを、NAME_JA、VARCHAR2、100 に分解して、文字列配列に格納します。
    213         * また、これらのソースに、"--" や "/ * ･･･ * /" などのコメントが含まれるケースが
    214         * あります。"--" コメントは、それ以降を無視しますが、"/ *" コメントは、複数行に
    215         * またがる為、今回は処理対象から外します。
    216         * ソースのテキスト部には、それら以外に、OBJECT_NAME に相当する行や、");" などの
    217         * ソースの最初や最後の無効な部分があります。無効な部分は、null を返すことで
    218         * 登録処理から省いてください。
    219         *
    220         * @og.rev 5.5.7.4 (2012/10/25) カラムの大文字化と、桁数の 前0 削除
    221         * @og.rev 5.5.8.5 (2012/11/27) 桁数なしの場合の対応
    222         *
    223         * @param       text    ソースのテキスト部
    224         *
    225         * @return      分割後の文字列配列(CLM,CLS_NAME,USE_LENGTHの順)、無効なデータは null
    226         */
    227        private String[] textSeparate( final String text ) {
    228
    229                final int adrs = text.indexOf( "--" );
    230                final String text2 = adrs < 0 ? text : text.substring( 0,adrs ) ;
    231
    232                String[] rtnTxt = null ;
    233                final Matcher mt = PTN1.matcher( text2 );
    234                if( mt.lookingAt() ) {
    235                        String clm = mt.group( 1 );             // カラムの名称:パターンとして、空白は含まない
    236                        String cls = mt.group( 2 );             // クラスの名称(VARCHAR2|NUMBER)
    237                        String len = mt.group( 3 );             // 桁数:パターンとして、前後に空白を含む、()を含む、何もないなど
    238
    239                        // 5.5.8.5 (2012/11/27) 桁数なしの場合の対応
    240                        // 6.4.1.1 (2016/01/16) PMD refactoring. Avoid if (x != y) ..; else ..;
    241                        if( len == null ) {
    242                                len = "";
    243                        }
    244                        else {
    245                                final int st = len.indexOf( '(' );
    246                                final int ed = len.indexOf( ')' );
    247                                if( st >= 0 && ed >= 0 ) {
    248                                        len = len.substring( st+1,ed );
    249                                        len = len.trim().replaceFirst("^0+", "");                                               // 5.5.7.4 (2012/10/25) 先頭の 0 を削除する。
    250                                }
    251                                else {
    252                                        len = "";
    253                                }
    254                        }
    255
    256                        if( clm != null && cls != null ) {
    257                                clm = clm.toUpperCase(Locale.JAPAN);                                                            // 5.5.7.4 (2012/10/25) 大文字化
    258                                cls = cls.toUpperCase(Locale.JAPAN);                                                            // 5.5.7.4 (2012/10/25) 大文字化
    259                                rtnTxt = new String[] { clm,cls,len };
    260                        }
    261                }
    262
    263                // マッチしない または 条件を満たさない場合は、null
    264                return rtnTxt ;
    265        }
    266}