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