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     */
016    package org.opengion.hayabusa.taglib;
017    
018    import org.opengion.hayabusa.common.HybsSystem;
019    import org.opengion.hayabusa.common.HybsSystemException;
020    import org.opengion.hayabusa.db.DBTableModel;
021    import org.opengion.hayabusa.db.TableFilter;
022    import org.opengion.fukurou.db.Transaction;
023    import org.opengion.fukurou.db.TransactionReal;
024    import org.opengion.fukurou.util.ErrorMessage;
025    import org.opengion.fukurou.util.StringUtil;
026    import static org.opengion.fukurou.util.StringUtil.nval ;
027    
028    import java.io.ObjectOutputStream;
029    import java.io.ObjectInputStream;
030    import java.io.IOException;
031    import java.util.Map;
032    
033    /**
034     * TableFilter のサブクラスをCALLしてDBTableModelにアクセスするタグです?
035     *
036     * DBTableModel ?TableFilter のサブクラス(classIdで??に渡して処?実行します?
037     * クラスを作?する場合?、org.opengion.hayabusa.db.TableFilter インターフェースを継承した
038     * クラスにする?があります?また?classId 属?には、シス?リソース で
039     * 設定し?TableFilter.XXXX の XXXX を指定します?
040     *
041     * BODY部??、SQLを記述する為?に使って?したが?CSS定義形式?書式で、keys,vals を記述
042     * できるようにします?
043     * これは、下記?ようなパラメータを?keys="KEY,KEY2,KEY3" vals='AAAA,"BB,CC,DD",EE' のような記述形式と
044     *   {
045     *        KEY1 : AAAA ;
046     *        KEY2 : BB,CC,DD ;
047     *        KEY3 : EE ;
048     *        ・・・・・・
049     *   }
050     * のような、CSS形式に類似の形式でも記述できるようにしました?
051     * keys,vals と CSS定義形式パラメータを同時に?した?合?、両方とも有効です?
052     * ただし?キーが重?た?合?、不定と?てください?
053     * 現時点では、CSS定義形式パラメータが優先されますが、これ?、単に?パラメータMapへの
054     * 登録?、CSS定義形式パラメータが後?為、上書きされるためです?
055     *
056     * ※ こ?タグは、Transaction タグの対象です?
057     *
058     * @og.formSample
059     * ●形式?lt;og:tableFilter classId="…" />
060     * ●body?あ?EVAL_BODY_BUFFERED:BODYを評価し?{@XXXX} を解析しま?
061     *
062     * ●Tag定義??
063     *   <og:tableFilter
064     *       classId          ○?TAG】データベ?ス処?実行するクラスパスを指定しま???)?
065     *       tableId            【TAG?通常は使?せん)DBTableModel sessionに登録されて?キーを指定しま?
066     *       modifyType         【TAG】データ処??方?A:追?C:更新 D:削除)を指定しま?
067     *       keys               【TAG】リンク先に渡すキーを指定しま?
068     *       vals               【TAG】keys属?に対応する?をCSV形式で??しま?
069     *       selectedAll        【TAG】データを?件選択済みとして処?るかど?[true/false]を指定しま?初期値:false)
070     *       stopZero           【TAG】検索結果が0件のとき??続行するかど?[true/false]を指定しま?初期値:false[続行する])
071     *       scope              【TAG】キャ?ュする場合?スコープ[request/page/session/applicaton]を指定しま?初期値:session)
072     *       dbid               【TAG?通常は使?せん)Queryオブジェクトを作?する時?DB接続IDを指定しま?
073     *       debug              【TAG】デバッグ??を?力するかど?[true/false]を指定しま?初期値:false)
074     *   >   ... Body ...
075     *   </og:tableFilter>
076     *
077     * ●使用?
078     *    ・引数/プロシジャーを直接書く??
079     *    【entry.jsp?
080     *        <og:tableFilter
081     *            classId     = "WL_LOGICSET"         :TableFilter のサブクラス(実行クラス)
082     *            tableId     = "WL0000"              :登録??DBTableModelのsession/request変数??取得キー
083     *            keys        = "AA,BB,CC"            :実行クラスへの引数のキー
084     *            vals        = "{@AA},{@BB},{@CC}"   :実行クラスへの引数の値
085     *            selectedAll = "false/true"          :処?象の行を全行選択するかど?(初期値:false)
086     *            modifyType  = "A/C/D"               :処??方?A:追?C:更新 D:削除)を指定します?初期値は自動です?
087     *        />
088     *
089     *    ・BODY部?、CSS形式?パラメータ??eys,vals?を記述する?
090     *
091     *        <og:tableFilter
092     *            classId     = "WL_LOGICSET"         :TableFilter のサブクラス(実行クラス)
093     *            tableId     = "WL0000"              :登録??DBTableModelのsession/request変数??取得キー
094     *            selectedAll = "false/true"          :処?象の行を全行選択するかど?(初期値:false)
095     *            modifyType  = "A/C/D"               :処??方?A:追?C:更新 D:削除)を指定します?初期値は自動です?
096     *        >
097     *               {
098     *                   AA    :  {@AA}
099     *                   BB    :  {@BB}
100     *                   CC    :  {@CC}
101     *               }
102     *        </og:tableFilter>
103     *
104     * @og.group そ??
105     * @og.rev 3.8.5.0 (2006/03/20) 新規作?
106     *
107     * @version  0.9.0  2000/10/17
108     * @author   Kazuhiko Hasegawa
109     * @since    JDK1.1,
110     */
111    public class TableFilterTag extends CommonTagSupport {
112            //* こ?プログラ??VERSION??を設定します?       {@value} */
113            private static final String VERSION = "5.7.6.2 (2014/05/16)" ;
114    
115            private static final long serialVersionUID = 576220140516L ;
116    
117            private static final String errMsgId    = HybsSystem.ERR_MSG_KEY;
118            private transient DBTableModel  table   = null;
119    
120            private String          tableId         = HybsSystem.TBL_MDL_KEY;
121            private String          classId         = null;
122            private String          modifyType      = null;
123            private String[]        keys            = null;
124            private String[]        vals            = null;
125    
126            private   String        dbid            = null ; // 4.2.4.0 (2008/06/23)
127            private   String        sql                     = null ; // 5.6.5.2 (2013/06/21) bodyからSQL??みを?り?す?
128            private   Map<String,String>  paramMap = null;    // 5.6.5.2 (2013/06/21) bodyからparamMapを取りだし?
129    
130            private boolean         selectedAll     = false;
131            private boolean         stopZero        = false;        // 5.7.6.2 (2014/05/16) stopZero属?追?
132    
133            /**
134             * Taglibの開始タグが見つかったときに処??doStartTag() ?オーバ?ライドします?
135             *
136             * @return      後続????( EVAL_BODY_BUFFERED )
137             */
138            @Override
139            public int doStartTag() {
140                    table = (DBTableModel)getObject( tableId );
141    
142                    if( keys != null && vals != null && keys.length != vals.length ) {
143                            String errMsg = "keys と vals の設定?の数が異なります?: " + HybsSystem.CR
144                                                    + "keys.length=[" + keys.length + "] , "
145                                                    + "keys.length=[" + StringUtil.array2line( keys,"," ) + "]"
146                                                    + HybsSystem.CR
147                                                    + "vals.length=[" + vals.length + "] , "
148                                                    + "vals.length=[" + StringUtil.array2line( vals,"," ) + "]";
149                            throw new HybsSystemException( errMsg );
150                    }
151    
152                    startQueryTransaction( tableId );
153                    return EVAL_BODY_BUFFERED ;             // Body を評価する
154            }
155    
156            /**
157             * Taglibのタグ本体を処??doAfterBody() ?オーバ?ライドします?
158             *
159             * @og.rev 5.6.5.2 (2013/06/21) bodyローカル化?sql、paramMap 追?
160             *
161             * @return      後続????(SKIP_BODY)
162             */
163            @Override
164            public int doAfterBody() {
165                    String body = nval( getBodyString(),null );
166    
167                    // paramMapの取り出?
168                    paramMap = StringUtil.cssParse( body );
169    
170                    // SQL???出?classId="DBSELECT" の場合?みの処?
171                    if( "DBSELECT".equalsIgnoreCase( classId ) && body != null ) {
172                            int ad1 = body.indexOf( '{' );
173                            int ad2 = body.indexOf( '}' );
174    
175                            if( ad1 >= 0 && ad2 >= 0 ) {
176                                    sql = body.substring( 0,ad1 ).trim() + body.substring( ad2+1 ).trim();
177                            }
178                            else {
179                                    sql = body.trim();
180                            }
181                    }
182    
183                    return SKIP_BODY ;
184            }
185    
186            /**
187             * Taglibの終?グが見つかったときに処??doEndTag() ?オーバ?ライドします?
188             *
189             * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得?為,ApplicationInfoオブジェクトを設?
190             * @og.rev 4.2.3.0 (2008/06/23) DBIDとボディー部??記述を下位クラスに渡す用に修正
191             * @og.rev 4.3.7.4 (2009/07/01) Resouceオブジェクトを下位クラスに渡す用に修正
192             * @og.rev 5.1.9.0 (2010/08/01) Transaction 対?
193             * @og.rev 5.2.1.0 (2010/10/01) debugPrint() メソ?の処?件見直?
194             * @og.rev 5.3.7.0 (2011/07/01) TransactionReal の引数変更 、Transaction対応で、close処?入れる?
195             * @og.rev 5.6.5.2 (2013/06/21) bodyローカル化?sql、paramMap 追?
196             * @og.rev 5.7.6.2 (2014/05/16) table件数が変わる?合?"DB.COUNT" キーでリクエストに再セ?する?
197             *
198             * @return      後続????
199             */
200            @Override
201            public int doEndTag() {
202                    // ??時には、オブジェクト?部??を表示する?
203                    debugPrint();   // 5.2.1.0 (2010/10/01) debugPrint() メソ?自体に、isDebug() が?込まれて??
204                    int rtnCode = EVAL_PAGE;        // try ??finally の関係で、変数化しておく
205    
206                    int[] rowNo = getParameterRows();
207    
208                    // 5.1.9.0 (2010/08/01) Transaction 対?
209                    Transaction tran = null;
210                    final TableFilter filter ;
211                    // 5.3.7.0 (2011/07/01) Transaction対応で、close処?入れる?
212                    try {
213                            TransactionTag tranTag = (TransactionTag)findAncestorWithClass( this,TransactionTag.class );
214                            if( tranTag == null ) {
215                                    tran = new TransactionReal( getApplicationInfo() );             // 5.3.7.0 (2011/07/01) 引数変更
216                            }
217                            else {
218                                    tran = tranTag.getTransaction();
219                            }
220    
221                            // 5.7.6.2 (2014/05/16) table件数が変わる?合?"DB.COUNT" キーでリクエストに再セ?する?
222                            int rowCnt1 = table == null ? -1 : table.getRowCount();
223    
224                            String cls = HybsSystem.sys( "TableFilter_" + classId );
225                            filter = (TableFilter)HybsSystem.newInstance( cls );
226    
227                            filter.setDBTableModel( table );
228                            filter.setParameterRows( rowNo );
229                            filter.setModifyType( modifyType );
230                            filter.setKeysVals( keys,vals );
231            //              filter.setApplicationInfo( getApplicationInfo() );      // 3.8.7.0 (2006/12/15)
232                            filter.setTransaction( tran );                                          // 5.1.9.0 (2010/08/01) Transaction 対?
233                            filter.setDebug( isDebug() );
234                            filter.setDbid( dbid );                                 // 4.2.4.0 (2008/06/23)
235                            filter.setSql( sql );                                   // 5.6.5.2 (2013/06/21) sql 追?
236                            filter.setParamMap( paramMap );                 // 5.6.5.2 (2013/06/21) paramMap 追?
237                            filter.setResource( getResource() );    // 4.3.7.4 (2009/07/01)
238    
239                            table = filter.execute();
240    
241                            // 5.7.6.2 (2014/05/16) table件数が変わる?合?"DB.COUNT" キーでリクエストに再セ?する?
242                            int rowCnt2 = table == null ? -1 : table.getRowCount();
243                            if( rowCnt1 != rowCnt2 ) {
244                                    setRequestAttribute( "DB.COUNT" , String.valueOf( rowCnt2 ) );
245                            }
246    
247                            int errCode = filter.getErrorCode();
248                            ErrorMessage errMessage = filter.getErrorMessage();
249    
250                            if( errCode >= ErrorMessage.NG )  {  // 異常
251                                    rtnCode = SKIP_PAGE;
252                            }
253    
254                            // 5.7.6.2 (2014/05/16) 件数?件(また?、table==null)かつ stopZero = true
255                            if( rowCnt2 <= 0 && stopZero ) { return SKIP_PAGE; }
256    
257                            String err = TaglibUtil.makeHTMLErrorTable( errMessage,getResource() );
258                            if( err != null && err.length() > 0 ) {
259                                    jspPrint( err );
260                                    setSessionAttribute( errMsgId,errMessage );
261                            }
262                            else {
263                                    removeSessionAttribute( errMsgId );
264                            }
265                    }
266                    finally {
267                            if( tran != null ) { tran.close(); }
268                    }
269    
270                    if( table != null && ! commitTableObject( tableId, table ) ) {
271                            rtnCode = SKIP_PAGE ;
272                    }
273    
274                    return rtnCode ;
275            }
276    
277            /**
278             * タグリブオブジェクトをリリースします?
279             * キャ?ュされて再利用される?で、フィールド?初期設定を行います?
280             *
281             * @og.rev 5.6.5.2 (2013/06/21) body?、sql、paramMap 追?
282             * @og.rev 5.7.6.2 (2014/05/16) stopZero属?追?
283             */
284            @Override
285            protected void release2() {
286                    super.release2();
287                    table           = null;
288                    tableId         = HybsSystem.TBL_MDL_KEY;
289                    classId         = null;
290                    modifyType      = null;
291                    keys            = null;
292                    vals            = null;
293                    selectedAll     = false;
294                    stopZero        = false;        // 5.7.6.2 (2014/05/16) stopZero属?追?
295                    dbid            = null;         // 4.2.4.0 (2008/06/23)
296                    sql                     = null;         // 5.6.5.2 (2013/06/21) bodyからSQL??みを?り?す?
297                    paramMap        = null;         // 5.6.5.2 (2013/06/21) bodyからparamMapを取りだす?
298            }
299    
300            /**
301             * 表示??タの HybsSystem.ROW_SEL_KEY を?に?ばれた 行を処??対象とします?
302             *
303             * @return      選択行?配?
304             */
305            @Override
306            protected int[] getParameterRows() {
307                    final int[] rowNo ;
308                    if( selectedAll ) {
309                            int rowCnt = table.getRowCount();
310                            rowNo = new int[ rowCnt ];
311                            for( int i=0; i<rowCnt; i++ ) {
312                                    rowNo[i] = i;
313                            }
314                    } else {
315                            rowNo = super.getParameterRows();               // 4.0.0 (2005/01/31)
316                    }
317                    return rowNo;
318            }
319    
320            /**
321             * 【TAG】データベ?ス処?実行するクラスパスを指定します?
322             *
323             * @og.tag
324             * ここで?するクラスIDは、シス?リソース にて TableFilter の
325             * サブクラス(インターフェース継承)として?する?があります?
326             *
327             * クラス自身は、org.opengion.hayabusa.db.TableFilter インターフェースを継承して??があります?
328             * {@og.doc03Link tableFilter TableFilter_**** クラス}
329             *
330             * @param       id TableFilter インターフェースを継承して?実クラスの ID
331             * @see         org.opengion.hayabusa.db.TableFilter  TableFilter インターフェース
332             */
333            public void setClassId( final String id ) {
334                    classId = nval( getRequestParameter( id ),classId );
335            }
336    
337            /**
338             * 【TAG?通常は使?せん)結果のDBTableModelを?sessionに登録するとき?キーを指定しま?
339             *              (初期値:HybsSystem#TBL_MDL_KEY[={@og.value org.opengion.hayabusa.common.HybsSystem#TBL_MDL_KEY}])?
340             *
341             * @og.tag
342             * 検索結果より、DBTableModelオブジェクトを作?します?これを?下流?viewタグ等に
343             * 渡す?合に??常は、session を利用します?そ?場合?登録キーです?
344             * query タグを同時に実行して、結果を求める?合?同?モリに配置される為?
345             * こ? tableId 属?を利用して、メモリ空間を?ます?
346             *              (初期値:HybsSystem#TBL_MDL_KEY[={@og.value org.opengion.hayabusa.common.HybsSystem#TBL_MDL_KEY}])?
347             *
348             * @param       id sessionに登録する時? ID
349             */
350            public void setTableId( final String id ) {
351                    tableId = nval( getRequestParameter( id ),tableId );
352            }
353    
354            /**
355             * 【TAG】データを?件選択済みとして処?るかど?[true/false]を指定しま?初期値:false)?
356             *
357             * @og.tag
358             * 全ての??タを選択済み??タとして扱って処?ます?
359             * 全件処?る?合に、指定します?(true/false)
360             * ?ォル?false です?
361             *
362             * @param  all ??タを?件選択済み [true:全件選択済み/false:通常]
363             */
364            public void setSelectedAll( final String all ) {
365                    selectedAll = nval( getRequestParameter( all ),selectedAll );
366            }
367    
368            /**
369             * 【TAG】検索結果が0件のとき??続行するかど?[true/false]を指定しま?初期値:false[続行する])?
370             *
371             * @og.tag
372             * 初期値は、false(続行す?です?
373             *
374             * @og.rev 5.7.6.2 (2014/05/16) 新規追?
375             *
376             * @param  cmd 検索結果が0件のとき?[true:処?中止する/false:続行する]
377             */
378            public void setStopZero( final String cmd ) {
379                    stopZero = nval( getRequestParameter( cmd ),stopZero );
380            }
381    
382            /**
383             * 【TAG】データ処??方?A:追?C:更新 D:削除)を指定します?
384             *
385             * @og.tag
386             * 通常は、DBTableModel に自動設定されて? modifyType を?に、データ処?法を
387             * 選別します?(A:追?C:更新 D:削除)
388             * こ?場合?行単位で modifyType の値を取得して判別する?がありますが、?には
389             * 処?象は、?件おな?modifyType である可能性が高いです?
390             * また?selectedAll などで強制?全件処?象とする場合?、modifyType に値?
391             * 設定さて?せん。その様な場合に外部より modifyType を指定します?
392             * 初期値は、?動判?です?
393             *
394             * @param  type ??タ処??方?A:追?C:更新 D:削除)
395             */
396            public void setModifyType( final String type ) {
397                    modifyType = nval( getRequestParameter( type ),modifyType );
398    
399                    if( modifyType != null && !"A".equals( modifyType ) && !"C".equals( modifyType ) && !"D".equals( modifyType ) ) {
400                            String errMsg = "modifyType は A:追?C:更新 D:削除 のどれかを指定してください? " + HybsSystem.CR
401                                                    + "modifyType=[" + modifyType + "]";
402                            throw new HybsSystemException( errMsg );
403                    }
404            }
405    
406            /**
407             * 【TAG】リンク先に渡すキーを指定します?
408             *
409             * @og.tag
410             * 戻る時に、検索時?キャ?ュに?した引数以外に?したり、別の値に置き換えた?
411             * する場合?キーを設定できます?カンマ区?で??できます?
412             * vals 属?には、キーに対応する?を?設定してください?
413             * ?方法?、CSV変数を?に?してから、getRequestParameter で値を取得します?
414             * こうしな???タ自身にカンマを持って?場合に?をミスる為です?
415             *
416             * @param       key リンク先に渡すキー
417             */
418            public void setKeys( final String key ) {
419                    keys = getCSVParameter( key );
420            }
421    
422            /**
423             * 【TAG】names属?に対応する?をCSV形式で??します?
424             *
425             * @og.tag
426             * キーに設定した?を?カンマ区??で?して出来ます?
427             * ??序?、キーと同じにしておいて下さ??
428             * ?方法?、CSV変数を?に?してから、getRequestParameter で値を取得します?
429             * こうしな???タ自身にカンマを持って?場合に?をミスる為です?
430             *
431             * @param       val names属?に対応する?
432             */
433            public void setVals( final String val ) {
434                    vals = getCSVParameter( val );
435            }
436    
437            /**
438             * 【TAG?通常は使?せん)Queryオブジェクトを作?する時?DB接続IDを指定します?
439             *
440             * @og.tag
441             * Queryオブジェクトを作?する時?DB接続IDを指定します?
442             * これは、シス?リソースで、DEFAULT_DB_URL 等で?して? ??タベ?ス接続?
443             * ??に、XX_DB_URL を定義することで?dbid="XX" とすると、この 接続?を使用して
444             * ??タベ?スにアクセスできます?
445             *
446             * @param       id ??タベ?ス接続ID
447             */
448            public void setDbid( final String id ) {
449                    dbid = nval( getRequestParameter( id ),dbid );
450            }
451    
452            /**
453             * シリアライズ用のカスタ?リアライズ書き込みメソ?
454             *
455             * @og.rev 4.0.0.0 (2006/09/31) 新規追?
456             * @serialData ?のオブジェクト?、シリアライズされません?
457             *
458             * @param       strm    ObjectOutputStreamオブジェク?
459             * @throws IOException  入出力エラーが発生した??
460             */
461            private void writeObject( final ObjectOutputStream strm ) throws IOException {
462                    strm.defaultWriteObject();
463            }
464    
465            /**
466             * シリアライズ用のカスタ?リアライズ読み込みメソ?
467             *
468             * ここでは、transient 宣?れた?変数の??初期化が?なフィールド?み設定します?
469             *
470             * @og.rev 4.0.0.0 (2006/09/31) 新規追?
471             * @serialData ?のオブジェクト?、シリアライズされません?
472             *
473             * @param       strm    ObjectInputStreamオブジェク?
474             * @see #release2()
475             * @throws IOException  シリアライズに関する入出力エラーが発生した??
476             * @throws ClassNotFoundException       クラスを見つけることができなかった??
477             */
478            private void readObject( final ObjectInputStream strm ) throws IOException , ClassNotFoundException {
479                    strm.defaultReadObject();
480            }
481    
482            /**
483             * こ?オブジェクト???表現を返します?
484             * 基本???目?使用します?
485             *
486             * @return こ?クラスの??表現
487             */
488            @Override
489            public String toString() {
490                    return org.opengion.fukurou.util.ToString.title( this.getClass().getName() )
491                                    .println( "VERSION"                     ,VERSION                )
492                                    .println( "tableId"                     ,tableId                )
493                                    .println( "classId"                     ,classId                )
494                                    .println( "modifyType"          ,modifyType             )
495                                    .println( "selectedAll"         ,selectedAll    )
496                                    .println( "keys"                        ,keys                   )
497                                    .println( "vals"                        ,vals                   )
498                                    .println( "dbid"                        ,dbid                   ) // 4.2.4.0 (2008/06/23)
499                                    .println( "sql"                         ,sql                    ) // 5.6.5.2 (2013/06/21)
500                                    .fixForm().toString() ;
501            }
502    }