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 * ① <og:tableFilter classId="KEY_BREAK" 048 * keys="GRP_KEY,BRK_KEY,USE_LAST" 049 * vals='"CLM1,CLM2....","CLM5,CLM6....",true' /> 050 * 051 * ② <og:tableFilter classId="KEY_BREAK" > 052 * { 053 * GRP_KEY : CLM1,CLM2.... ; 054 * BRK_KEY : CLM5,CLM6.... ; 055 * USE_LAST : true ; 056 * } 057 * </og:tableFilter> 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 * キーの配列アドレスと、1行分のデータ配列から、キーとなる文字列を作成します。 161 * 162 * @og.rev 6.7.9.1 (2017/05/19) 新規追加 163 * 164 * @param clms キーの配列アドレス 165 * @param rowData 1行分のデータ配列 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}