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 java.util.HashMap; 019import java.util.Map; 020 021import org.opengion.fukurou.util.StringUtil; 022import org.opengion.hayabusa.db.AbstractTableFilter; 023import org.opengion.hayabusa.db.DBColumn; 024import org.opengion.hayabusa.db.DBColumnConfig; 025import org.opengion.hayabusa.db.DBTableModel; 026import org.opengion.hayabusa.db.DBTableModelUtil; 027import org.opengion.hayabusa.resource.ResourceManager; 028 029/** 030 * TableFilter_ROTATE は、TableFilter インターフェースを継承した、DBTableModel 処理用の 031 * 実装クラスです。 032 * 033 * ここではテーブルの回転、及びその逆回転を行います。 034 * 035 * パラメータは、tableFilterタグの keys, vals にそれぞれ記述するか、BODY 部にCSS形式で記述します。 036 * 【パラメータ】 037 * { 038 * KEY_CLM : キーカラム(複数指定可) 039 * ROTATE_CLM : 回転するカラム 040 * VALUE_CLM : 回転カラムの値 041 * REVERSE : 回転(false)・逆回転(true) (任意指定 初期値:false) 042 * MUST_CLM : 必須属性を定義するカラム (任意指定 初期値:false) 043 * DEF_CLM : 初期値を定義するカラム (任意指定) 044 * } 045 * 046 * ※ それぞれに指定されたカラム名が存在しない場合は、処理されませんのでご注意下さい。 047 * 048 * @回転 049 * キーカラムに指定された値が同じN行を1行として回転します。 050 * (キーカラムの値がブレイクしたタイミングで、行を変更します) 051 * このN行に含まれる回転カラムの値がカラム名に、回転カラム値が各カラムの値になります。 052 * キーカラムは、カンマ区切りで複数指定可能です。 053 * 054 * 生成されたテーブルモデルのカラムは、始めのMカラムがキーカラムに、その後ろのNカラムが 055 * 回転されたカラムになります。 056 * 057 * また、元テーブルにMUST_CLMにより、各カラムの必須属性を定義することが 058 * できます。(MUST属性は、'1'又は'true'の場合に必須になります。) 059 * 060 * A逆回転 061 * 回転時の逆の挙動になります。 062 * "キーカラムに指定されたカラム以外"を回転カラムで指定されたカラムの値として分解します。 063 * 各回転カラムの値は、回転カラム値に指定されたカラムに格納されます。 064 * 065 * 分解後のカラム数は、キーカラム数 + 2 (回転カラム、回転カラム値)になります。 066 * また、行数は、(分解前の行数) x (回転カラム数)になります。 067 * 068 * @og.formSample 069 * ●形式: 070 * @ <og:tableFilter classId="ROTATE" keys="KEY_CLM,REVERSE" vals='"AA,BB,CC",true' /> 071 * 072 * A <og:tableFilter classId="ROTATE" > 073 * { 074 * KEY_CLM : キーカラム(複数指定可) 075 * ROTATE_CLM : 回転するカラム 076 * VALUE_CLM : 回転カラムの値 077 * REVERSE : 回転(false)・逆回転(true) (任意指定 初期値:false) 078 * MUST_CLM : 必須属性を定義するカラム (任意指定 初期値:false) 079 * DEF_CLM : 初期値を定義するカラム (任意指定) 080 * } 081 * </og:tableFilter> 082 * 083 * @og.rev 5.6.6.0 (2013/07/05) keys の整合性チェックを追加 084 * 085 * @version 0.9.0 2000/10/17 086 * @author Hiroki Nakamura 087 * @since JDK1.1, 088 */ 089public class TableFilter_ROTATE extends AbstractTableFilter { 090 // * このプログラムのVERSION文字列を設定します。 {@value} */ 091 private static final String VERSION = "5.6.6.1 (2013/07/12)" ; 092 093 /** 094 * keys の整合性チェックを行うための初期設定を行います。 095 * 096 * @og.rev 5.6.6.1 (2013/07/12) keys の整合性チェック対応 097 * 098 * @param keysMap keys の整合性チェックを行うための Map 099 */ 100 @Override 101 protected void init( final Map<String,String> keysMap ) { 102 keysMap.put( "KEY_CLM" , "キーカラム(複数指定可)" ); 103 keysMap.put( "ROTATE_CLM" , "回転するカラム" ); 104 keysMap.put( "VALUE_CLM" , "回転カラムの値" ); 105 keysMap.put( "REVERSE" , "回転(false)/逆回転(true) (初期値:false)" ); 106 keysMap.put( "MUST_CLM" , "必須属性を定義するカラム (初期値:false)" ); 107 keysMap.put( "DEF_CLM" , "初期値を定義するカラム" ); 108 } 109 110 private DBTableModel table = null; // 5.5.2.6 (2012/05/25) 共通に使うため、変数定義 111 private ResourceManager resource = null; // 5.5.2.6 (2012/05/25) 共通に使うため、変数定義 112 113 /** 114 * DBTableModel処理を実行します。 115 * 116 * @og.rev 4.3.7.4 (2009/07/01) 新規追加 117 * @og.rev 5.5.2.6 (2012/05/25) protected変数を、private化したため、getterメソッドで取得するように変更 118 * 119 * @return 処理結果のDBTableModel 120 */ 121 public DBTableModel execute() { 122 boolean reverse = StringUtil.nval( getValue( "REVERSE" ), false ); 123 124 table = getDBTableModel(); // 5.5.2.6 (2012/05/25) インターフェースにgetterメソッド追加 125 resource = getResource(); // 5.5.2.6 (2012/05/25) インターフェースにgetterメソッド追加 126 127 // 逆回転 128 if ( reverse ) { 129 return getRecoverdTable(); 130 } 131 // 回転 132 else { 133 return getRotateTable(); 134 } 135 } 136 137 /** 138 * 回転後のDBTableModelを返します。 139 * 140 * @og.rev 5.1.8.0 (2010/07/01) メソッド名変更(setDefValue ⇒ setDefault) 141 * 142 * @return 回転後のDBTableModel 143 */ 144 private DBTableModel getRotateTable() { 145 String[] keyClm = StringUtil.csv2Array( getValue( "KEY_CLM" ) ); 146 int rotateNo = table.getColumnNo( getValue( "ROTATE_CLM" ), false ); 147 int valNo = table.getColumnNo( getValue( "VALUE_CLM" ), false ); 148 149 if ( keyClm == null || keyClm.length == 0 || rotateNo < 0 || valNo < 0 ) { 150 return table; 151 } 152 153 int mustNo = table.getColumnNo( getValue( "MUST_CLM"), false ); 154 int defNo = table.getColumnNo( getValue( "DEF_CLM"), false ); 155 156 int clmCount = 0; // 回転後のカラム数 157 // キーカラムのカラム番号を求め、カラム数としてカウントします。 158 Map<String, Integer> clmMap = new HashMap<String, Integer>(); 159 int[] keyNos = new int[keyClm.length]; 160 for ( int i = 0; i < keyNos.length; i++ ) { 161 keyNos[i] = table.getColumnNo( keyClm[i], false ); 162 if ( keyNos[i] < 0 ) { 163 return table; 164 } 165 clmMap.put( keyClm[i], clmCount ); 166 clmCount++; 167 } 168 169 int rowCount = 0; // 回転後の行数 170 // 回転カラムの値から回転後のカラム数を求めます。 171 // また同時に、キーカラムの値のブレイク数により行数を求めます。 172 Map<String, Integer> rowMap = new HashMap<String, Integer>(); 173 Map<String, Boolean> mustMap = new HashMap<String, Boolean>(); 174 Map<String, String> defaultMap = new HashMap<String, String>(); 175 for ( int i = 0; i < table.getRowCount(); i++ ) { 176 String clmKey = table.getValue( i, rotateNo ); 177 if ( clmMap.get( clmKey ) == null ) { 178 clmMap.put( clmKey, clmCount ); 179 clmCount++; 180 } 181 // 必須カラム抜き出し 182 if( mustNo > -1 && StringUtil.nval( table.getValue( i, mustNo ), false ) ) { 183 mustMap.put( clmKey, true ); 184 } 185 // デフォルト値を書き換えるカラムの抜き出し 186 if( defNo > -1 && table.getValue( i, defNo ) != null && table.getValue( i, defNo ).length() > 0 ) { 187 defaultMap.put( clmKey, table.getValue( i, defNo ) ); 188 } 189 190 String rowKey = getSeparatedValue( i, keyNos ); 191 if ( rowKey != null && rowKey.length() > 0 ) { 192 if ( rowMap.get( rowKey ) == null ) { 193 rowMap.put( rowKey, rowCount ); 194 rowCount++; 195 } 196 } 197 } 198 199 // 回転後のカラム一覧よりDBTableModelを初期化します。 200 String names[] = new String[clmMap.size()]; 201 for ( Map.Entry<String, Integer> entry : clmMap.entrySet() ) { 202 names[entry.getValue()] = entry.getKey(); 203 } 204 DBTableModel nTable = DBTableModelUtil.newDBTable(); 205 nTable.init( names.length ); 206 for ( int i = 0; i < names.length; i++ ) { 207 if( mustMap.get( names[i] ) != null ) { 208 table.addMustType( i, "must" ); 209 } 210 DBColumn column = resource.makeDBColumn( names[i] ); 211 if( defaultMap.get( names[i] ) != null ) { 212 DBColumnConfig dbConfig = column.getConfig(); 213// dbConfig.setDefValue( defaultMap.get( names[i] ) ); 214 dbConfig.setDefault( defaultMap.get( names[i] ) ); // 5.1.8.0 (2010/07/01) 215 column = new DBColumn( dbConfig ); 216 } 217// nTable.setDBColumn( i, resource.makeDBColumn( names[i] ) ); 218 nTable.setDBColumn( i, column ); // 5.1.8.0 (2010/07/01) 219 } 220 221 // 値の一覧を作成し、DBTableModelに値をセットします。 222 if( rowCount > 0 ) { 223 String[][] vals = new String[rowCount][names.length]; 224 for ( int i = 0; i < table.getRowCount(); i++ ) { 225 int row = rowMap.get( getSeparatedValue( i, keyNos ) ); 226 int clm = clmMap.get( table.getValue( i, rotateNo ) ); 227 228 for ( int j = 0; j < keyNos.length; j++ ) { 229 vals[row][j] = table.getValue( i, keyNos[j] ); 230 } 231 vals[row][clm] = table.getValue( i, valNo ); 232 } 233 for ( int i = 0; i < vals.length; i++ ) { 234 nTable.addColumnValues( vals[i] ); 235 } 236 } 237 238 return nTable; 239 } 240 241 /** 242 * 各行のキーとなるキーカラムの値を連結した値を返します。 243 * 244 * @param row 行番号 245 * @param clmNo カラム番号配列 246 * 247 * @return 各行のキーとなるキーカラムの値を連結した値 248 */ 249 private String getSeparatedValue( final int row, final int[] clmNo ) { 250 StringBuilder buf = new StringBuilder(); 251 for ( int i = 0; i < clmNo.length; i++ ) { 252 String val = table.getValue( row, clmNo[i] ); 253 if( val != null && val.length() > 0 ) { 254 if( i > 0 ) { 255 buf.append( "__" ); 256 } 257 buf.append( val ); 258 } 259 } 260 return buf.toString(); 261 } 262 263 /** 264 * 逆回転後のDBTableModelを返します。 265 * 266 * @return 逆回転後のDBTableModel 267 */ 268 private DBTableModel getRecoverdTable() { 269 String[] keyClm = StringUtil.csv2Array( getValue( "KEY_CLM" ) ); 270 String rotateClm = getValue( "ROTATE_CLM" ); 271 String valClm = getValue( "VALUE_CLM" ); 272 273 if ( keyClm == null || keyClm.length == 0 || rotateClm == null || rotateClm.length() == 0 274 || valClm == null || valClm.length() == 0 ) { 275 return table; 276 } 277 278 // キーカラムのカラム番号を求めます。 279 int[] keyNos = new int[keyClm.length]; 280 for ( int i = 0; i < keyNos.length; i++ ) { 281 keyNos[i] = table.getColumnNo( keyClm[i], false ); 282 if ( keyNos[i] < 0 ) { 283 return table; 284 } 285 } 286 287 // キーカラム以外(回転カラム以外)のカラム番号を求めます。 288 int clmIdx = 0; 289 int[] clmNos = new int[table.getColumnCount() - keyNos.length]; 290 for ( int i = 0; i < table.getColumnCount(); i++ ) { 291 boolean isClm = true; 292 for ( int j = 0; j < keyNos.length; j++ ) { 293 if ( i == keyNos[j] ) { 294 isClm = false; 295 } 296 } 297 if ( isClm ) { 298 clmNos[clmIdx] = i; 299 clmIdx++; 300 } 301 } 302 303 // テーブルモデルを初期化します。 304 DBTableModel nTable = DBTableModelUtil.newDBTable(); 305 nTable.init( keyNos.length + 2 ); 306 for ( int i = 0; i < keyNos.length; i++ ) { 307 nTable.setDBColumn( i, resource.makeDBColumn( keyClm[i] ) ); 308 } 309 nTable.setDBColumn( keyNos.length, resource.makeDBColumn( rotateClm ) ); 310 nTable.setDBColumn( keyNos.length + 1, resource.makeDBColumn( valClm ) ); 311 312 // 各行を作成し、DBTableModelに登録します。 313 for ( int i = 0; i < table.getRowCount(); i++ ) { 314 for ( int j = 0; j < clmNos.length; j++ ) { 315 String[] vals = new String[keyNos.length + 2]; 316 for ( int k = 0; k < keyNos.length; k++ ) { 317 vals[k] = table.getValue( i, keyNos[k] ); 318 } 319 vals[keyNos.length] = table.getColumnName( clmNos[j] ); 320 vals[keyNos.length + 1] = table.getValue( i, clmNos[j] ); 321 nTable.addColumnValues( vals ); 322 } 323 } 324 325 return nTable; 326 } 327 328}