    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.db.AbstractTableFilter;
    019import org.opengion.hayabusa.db.DBTableModel;
    020
    021import org.opengion.fukurou.util.ErrorMessage;
    022import org.opengion.fukurou.util.StringUtil;
    023
    024import java.util.Map;
    025import java.util.HashMap;
    026
    027/**
    028 * TableFilter_KEY_BREAK は、TableFilter インターフェースを継承した、DBTableModel 処理用の
    029 * 実装クラスです。
    030 *
    031 * ここでは、指定のカラムに対して、キーブレイクが発生したときのデータのみ、残します。
    032 * キーブレイクは、グループキーと、ブレークキーがあります。
    033 * グループキーは、一塊のレコードを管理し、グループキーごとに、キーブレイクを判定します。
    034 * つまり、グループキーの並び順に依存しない形で、キーブレイク可能です。
    035 * 例：機種と日付と、状況Fがあったとして、日付、機種、状況F でソートし、機種をグループキー、
    036 * 状況Fをブレイクキーとすれば、日付の順に、機種の中で、状況Fがブレークしたときのみ、
    037 * データを残す、ということが可能になります。
    038 *
    039 * GRP_KEY  : グループの判定を行うカラムを、CSV形式で設定します。
    040 * BRK_KEY  : キーブレイクの判定を行うカラムを、CSV形式で設定します。
    041 * USE_LAST : キーブレイクと関係なく、グループの最後のデータを登録するかどうかを指定します。(初期値:false 登録しない)
    042 *
    043 * パラメータは、tableFilterタグの keys, vals にそれぞれ記述するか、BODY 部にCSS形式で記述します。
    044 *
    045 * @og.formSample
    046 * ●形式：
    047 *      ① &lt;og:tableFilter classId="KEY_BREAK"
    048 *                              keys="GRP_KEY,BRK_KEY,USE_LAST"
    049 *                              vals='"CLM1,CLM2....","CLM5,CLM6....",true' /&gt;
    050 *
    051 *      ② &lt;og:tableFilter classId="KEY_BREAK" &gt;
    052 *               {
    053 *                   GRP_KEY  : CLM1,CLM2....   ;
    054 *                   BRK_KEY  : CLM5,CLM6....   ;
    055 *                   USE_LAST : true            ;
    056 *               }
    057 *         &lt;/og:tableFilter&gt;
    058 *
    059 * @og.rev 6.7.9.1 (2017/05/19) 新規追加
    060 *
    061 * @version  6.7  2017/05/19
    062 * @author   Kazuhiko Hasegawa
    063 * @since    JDK1.8,
    064 */
    065public class TableFilter_KEY_BREAK extends AbstractTableFilter {
    066        /** このプログラムのVERSION文字列を設定します。   {@value} */
    067        private static final String VERSION = "6.7.9.1 (2017/05/19)" ;
    068
    069        /**
    070         * デフォルトコンストラクター
    071         *
    072         * @og.rev 6.7.9.1 (2017/05/19) 新規追加
    073         */
    074        public TableFilter_KEY_BREAK() {
    075                super();
    076                initSet( "GRP_KEY"      , "グループの判定を行うカラムを、CSV形式で設定します。" );
    077                initSet( "BRK_KEY"      , "キーブレイクの判定を行うカラムを、CSV形式で設定します。" );
    078                initSet( "USE_LAST"     , "キーブレイクと関係なく、グループの最後のデータを登録するかどうかを指定します。(初期値:false 登録しない)"            );
    079        }
    080
    081        /**
    082         * DBTableModel処理を実行します。
    083         *
    084         * @og.rev 6.7.9.1 (2017/05/19) 新規追加
    085         *
    086         * @return 処理結果のDBTableModel
    087         */
    088        public DBTableModel execute() {
    089                final String[]  grpClms = StringUtil.csv2Array( getValue( "GRP_KEY" ) );
    090                final String[]  brkClms = StringUtil.csv2Array( getValue( "BRK_KEY" ) );
    091
    092                final boolean   useLast = StringUtil.nval( getValue( "USE_LAST"  ), false ) ;
    093
    094                final DBTableModel table  = getDBTableModel();
    095        //      final DBTableModel rtnTbl = table.newModel();
    096
    097                final int[]    grpClmNo = new int[grpClms.length];              // グループキーカラムの番号
    098                final int[]    brkClmNo = new int[brkClms.length];              // ブレイクキーカラムの番号
    099
    100                for( int i=0; i<grpClms.length; i++ ) {
    101                        grpClmNo[i] = table.getColumnNo( grpClms[i],false );    // カラムが存在しなければ、-1
    102                }
    103
    104                for( int i=0; i<brkClms.length; i++ ) {
    105                        brkClmNo[i] = table.getColumnNo( brkClms[i],false );    // カラムが存在しなければ、-1
    106                }
    107
    108                final int rowCnt = table.getRowCount();
    109
    110                final Map<String,String> brkKeysMap = new HashMap<>() ;         // グループキー単位の最後のブレークキー
    111
    112                String[] data    = null;        // エラー時に表示するため。
    113                for( int row=0; row<rowCnt; row++ ) {
    114                        try {
    115                                data = table.getValues( row );
    116
    117                                final String grpKeys    = getKeys( grpClmNo , data );   // グループキー
    118                                final String oldBlkKeys = brkKeysMap.getOrDefault( grpKeys , "" );              // Mapにキーが無い場合は、空文字列
    119
    120                                final String brkKeys = getKeys( brkClmNo , data );      // ブレークキー
    121                                if( oldBlkKeys.equalsIgnoreCase( brkKeys ) ) {
    122                                        table.rowDelete( row );                                 // キーが同じなので、削除ﾌﾗｸﾞを立てる。(論理削除)
    123                                }
    124                                else {
    125                                        brkKeysMap.put( grpKeys , brkKeys );    // キーが異なるので、Mapにｾｰﾌﾞします。
    126                                }
    127                        }
    128                        catch( final RuntimeException ex ) {
    129                                // 6.5.0.1 (2016/10/21) ErrorMessage をまとめるのと、直接 Throwable を渡します。
    130                                makeErrorMessage( "TableFilter_KEY_BREAK Error",ErrorMessage.NG )
    131                                        .addMessage( row+1,ErrorMessage.NG,"KEY_BREAK"
    132                                                , StringUtil.array2csv( data )
    133                                        )
    134                                        .addMessage( ex );
    135                        }
    136                }
    137
    138                // レコードを削除するので、逆順に行います。
    139                for( int row=rowCnt-1; row>=0; row-- ) {
    140                        final String modType = table.getModifyType( row );
    141                        if( DBTableModel.DELETE_TYPE.equals( modType ) ) {                      // 削除対象 (DELETE_TYPE は、fukurou.model.DataModel で定義
    142                                if( useLast ) {                                                                                 // 若干複雑
    143                                        data = table.getValues( row );
    144                                        final String grpKeys = getKeys( grpClmNo , data );      // グループキー
    145                                        if( brkKeysMap.containsKey( grpKeys ) ) {                       // brkKeysMap を流用。useLast の場合、逆順で
    146                                                brkKeysMap.remove( grpKeys );                                   // 最後のグループキーのデータは、
    147                                                continue;                                                                               // 削除しないので、continue する。
    148                                        }
    149                                }
    150                                table.removeValue( row );       // 物理削除
    151                        }
    152                }
    153
    154                if( useLast ) { table.resetModify(); }  // useLast 使用時には、DELETEが残るため、一応クリアしておきます。
    155
    156                return table;
    157        }
    158
    159        /**
    160         * キーの配列ｱﾄﾞﾚｽと、１行分のデータ配列から、キーとなる文字列を作成します。
    161         *
    162         * @og.rev 6.7.9.1 (2017/05/19) 新規追加
    163         *
    164         * @param clms キーの配列ｱﾄﾞﾚｽ
    165         * @param rowData １行分のデータ配列
    166         * @return キーとなる文字列
    167         */
    168        private String getKeys( final int[] clms , final String[] rowData ) {
    169                final StringBuilder buf = new StringBuilder();
    170                for( int i=0; i<clms.length; i++ ) {
    171                        if( clms[i] >= 0 ) {
    172                                buf.append( rowData[clms[i]] ).append( ':' );
    173                        }
    174                }
    175                return buf.toString();
    176        }
    177}