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.fukurou.business; 017 018import org.opengion.fukurou.model.DataModel; 019import org.opengion.fukurou.model.NativeType; 020 021import java.util.Map; 022import java.util.HashMap; 023import java.util.Arrays; 024 025/** 026 * 業務ロジックを処理するためのテーブルモデルです。 027 * 028 * このテーブルモデルでは、オブジェクト生成時に、カラム配列、値配列を元に、内部データを生成し、 029 * その後は、行の追加や値の変更はできません。 030 * 031 * @og.rev 5.1.1.0 (2009/12/01) 新規作成 032 * @og.group 業務ロジック 033 * 034 * @version 5.0 035 * @author Hiroki Nakamura 036 * @since JDK1.6, 037 */ 038public class ArrayTableModel implements DataModel<String> { 039 private static final String CR = System.getProperty("line.separator"); // 5.6.7.0 (2013/07/27) 追加 040 041 private final String[] names; 042 private final String[][] vals; 043 private final String[] modTypes; 044 045 private Map<Integer,String[]> rtnMap = null; // 5.6.0.3 (2012/01/24) 変更された値を、書き戻すためのMap<インデックス,値配列> 046 047 /** 048 * 引数に名前配列、値配列を指定したコンストラクター 049 * 050 * @param nms 名前配列 051 * @param vs 値2重配列 052 * @throws IllegalArgumentException 引数の配列が不正な場合 053 */ 054 public ArrayTableModel( final String[] nms, final String[][] vs ) { 055 this( nms, vs, null ); 056 } 057 058 /** 059 * 引数に名前配列、値配列、変更区分配列を指定したコンストラクター 060 * 061 * @og.rev 5.6.7.0 (2013/07/27) エラーメッセージを判りやすくする。 062 * @og.rev 5.7.2.3 (2014/01/31) vsのチェック条件を戻す 063 * @og.rev 5.7.3.1 (2014/02/14) nmsのチェック条件も戻す 064 * 065 * @param nms 名前配列 066 * @param vs 値2重配列 067 * @param ms 変更区分の配列 068 * @throws IllegalArgumentException 引数の配列が不正な場合 069 */ 070 public ArrayTableModel( final String[] nms, final String[][] vs, final String[] ms ) { 071 if( nms == null || nms.length == 0 ) { 072 String errMsg = "引数の名前配列に、null は設定できません。"; 073 throw new IllegalArgumentException( errMsg ); 074 } 075 // 5.6.7.0 (2013/07/27) エラーメッセージを判りやすくする。 076 // 5.7.2.3 (2014/01/31) 結果0行でlength=0で通るようなのでvsのエラーチェック条件を戻す。 077 if( vs == null ) { 078// if( vs == null || vs.length == 0 || vs[0] == null || vs[0].length == 0 ) { 079 String errMsg = "引数の値配列に、null は設定できません。"; 080 throw new IllegalArgumentException( errMsg ); 081 } 082 // 5.7.3.1 (2014/02/14) 5.7.2.3での戻しでは不十分だったのでこちらも戻す 083 if( vs.length > 0 ) { 084 if( vs[0] == null || vs[0].length == 0 || nms.length != vs[0].length ) { 085// if( nms.length != vs[0].length ) { 086// String errMsg = "名前配列と値配列のカラム数が異なります。" ; 087 String errMsg = "名前配列と値配列のカラム数が異なります。" + CR 088 + " nms =" + Arrays.toString( nms ) + CR 089 + " vs[0] =" + Arrays.toString( vs[0] ) ; 090 throw new IllegalArgumentException( errMsg ); 091 } 092 } 093 094 int cols = nms.length; 095 names = new String[cols]; 096 System.arraycopy( nms, 0, names, 0, cols ); 097 098 int rows = vs.length; 099 vals = new String[rows][cols]; 100 for( int i = 0; i < rows; i++ ) { 101 System.arraycopy( vs[i], 0, vals[i], 0, cols ); 102 } 103 104 if( ms != null && ms.length > 0 ) { 105 if( vs.length == ms.length ) { 106 modTypes = new String[rows]; 107 System.arraycopy( ms, 0, modTypes, 0, rows ); 108 } 109 else { 110 // 5.6.7.0 (2013/07/27) エラーメッセージを判りやすくする。 111// String errMsg = "変更区分を指定する場合、値配列の行数と一致する必要があります。"; 112 String errMsg = "変更区分を指定する場合、値配列の行数と一致する必要があります。" + CR 113 + " 変更区分 行数 =" + ms.length + CR 114 + " 値配列 行数 =" + vs.length ; 115 throw new IllegalArgumentException( errMsg ); 116 } 117// if( vs.length != ms.length ) { 118// String errMsg = "変更区分を指定する場合、値配列の行数と一致する必要があります。"; 119// throw new IllegalArgumentException( errMsg ); 120// } 121// else { 122// modTypes = new String[rows]; 123// System.arraycopy( ms, 0, modTypes, 0, rows ); 124// } 125 } 126 else { 127 modTypes = null; 128 } 129 } 130 131 /** 132 * rowで指定された行番号(インデックス番号)に行を追加します。 133 * 134 * 値配列をセットする場合は、以下の条件を満たす必要があります。 135 * 1.行番号は、0〜(rowCount-1) の範囲 136 * 2.値配列は、not null、 かつ 1件以上 137 * 3.値配列の個数は、内部カラム数と同じ 138 * 139 * ここで登録した値は、内部の値配列と別管理されますので、セット後に、再びゲットしても 140 * ここでセットした値を取り出すことはできません。 141 * また、同じ行番号でセットした場合は、後でセットした値が有効です。 142 * 143 * ※ インデックス(row)とは、このArrayTableModel に持つ vals 配列の行のインデックスです。 144 * よって、オリジナルのDBTableModelの行番号ではありません。 145 * 146 * @og.rev 5.6.0.3 (2012/01/24) 変更された値を、書き戻す機能を追加します。 147 * 148 * @param vals 配列値 149 * @param row 追加するインデックス 150 * @throws IllegalArgumentException 引数が1,2,3の条件を満たさない場合。 151 */ 152 public void setValues( final String[] vals, final int row ) { 153// throw new RuntimeException( "このクラスでは、setValuesメソッドはサポートされていません" ); 154 if( row < 0 || row > getRowCount() ) { 155 String errMsg = "引数のインデックスは、0〜" + (getRowCount()-1) + " の間で指定してください。index=[" + row + "]"; 156 throw new IllegalArgumentException( errMsg ); 157 } 158 else if( vals == null || vals.length == 0 ) { 159 String errMsg = "引数の値配列に、null、または 0件配列は指定できません。index=[" + row + "]"; 160 throw new IllegalArgumentException( errMsg ); 161 } 162 else if( vals.length != names.length ) { 163 String errMsg = "引数の値配列の個数と、内部カラム数が一致しません。" 164 + " index=[" + row + "] : 引数個数=[" + vals.length + "] != 内部カラム数=[" + names.length + "]"; 165 throw new IllegalArgumentException( errMsg ); 166 } 167 168 if( rtnMap == null ) { rtnMap = new HashMap<Integer,String[]>(); } 169 170 int cols = vals.length; 171 String[] newVals = new String[cols]; 172 System.arraycopy( vals, 0, newVals, 0, cols ); 173 174 rtnMap.put( Integer.valueOf( row ) , newVals ); 175 } 176 177 /** 178 * BizLogicで、データが変更された場合は、このMapで値の配列を返します。 179 * Mapのキーは、インデックス(row)のIntegerオブジェクトです。値は、設定された String配列です。 180 * なにも変更がされていなければ、null を返します。 181 * 182 * ※ インデックス(row)とは、このArrayTableModel に持つ vals 配列の行のインデックスです。 183 * よって、オリジナルのDBTableModelの行番号ではありません。 184 * 185 * @og.rev 5.6.0.3 (2012/01/24) 変更された値を、書き戻すためのMap<インデックス,値配列> を返します。 186 * 187 * @return 書き戻すためのMap<インデックス,値配列> 188 * @see AbstractBizLogic#isRequireTable() 189 */ 190 public Map<Integer,String[]> getModifyVals() { 191 return rtnMap; 192 } 193 194 /** 195 * カラム名に対応する カラム番号を返します。 196 * 197 * 特殊なカラムが指定された場合は、負の値を返します。 198 * 例えば、[KEY.カラム名]、[I]、[ROW.ID] など、特定の負の値を返します。 199 * また、カラム名が元のデータモデルに存在しない場合も、負の値か、 200 * Exception を返します。負の値なのか、Exception なのかは、 201 * 実装に依存します。 202 * 203 * @param columnName 値が参照されるカラム名 204 * 205 * @return 指定されたセルのカラム番号。存在しなければ、-1 206 * @throws IllegalArgumentException 引数のカラム名が null の場合 207 */ 208 public int getColumnNo( final String columnName ) { 209 if( columnName == null ) { 210 String errMsg = "引数のカラム名に、null は設定できません。"; 211 throw new IllegalArgumentException( errMsg ); 212 } 213 214 int address = -1; 215 for( int i = 0; i < names.length; i++ ) { 216 if( columnName.equalsIgnoreCase( names[i] ) ) { 217 address = i; 218 break; 219 } 220 } 221 222 return address; 223 } 224 225 /** 226 * カラム名配列に対応する カラム番号配列を返します。 227 * 228 * これは、#getColumnNo( String ) に対する 複数のカラム名を検索した 229 * 場合と同じです。 230 * 231 * @param clmNms 値が参照されるカラム名配列 232 * 233 * @return 指定されたセルのカラム番号配列。 234 */ 235 public int[] getColumnNos( final String[] clmNms ) { 236 if( clmNms == null ) { return new int[0]; } 237 238 int[] clmNos = new int[clmNms.length]; 239 for( int j = 0; j < clmNms.length; j++ ) { 240 int address = -1; 241 for( int i = 0; i < names.length; i++ ) { 242 if( clmNms[j].equalsIgnoreCase( names[i] ) ) { 243 address = i; 244 break; 245 } 246 } 247 clmNos[j] = address; 248 } 249 250 return clmNos; 251 } 252 253 /** 254 * カラム名配列を返します。 255 * 256 * @return カラム名配列 257 */ 258 public String[] getNames() { 259 return names.clone(); 260 } 261 262 /** 263 * row にあるセルの属性値を配列で返します。 264 * 265 * @param row 値が参照される行 266 * 267 * @return 指定されたセルの属性値配列 268 */ 269 public String[] getValues( final int row ) { 270 return vals[row].clone(); 271 } 272 273 /** 274 * row および clm にあるセルの属性値をStringに変換して返します。 275 * 276 * @param row 値が参照される行 277 * @param clm 値が参照される列 278 * 279 * @return 指定されたセルの値 280 * 281 */ 282 public String getValue( final int row, final int clm ) { 283 return vals[row][clm]; 284 } 285 286 /** 287 * row および clm にあるセルの属性値をStringに変換して返します。 288 * 289 * @param row 値が参照される行 290 * @param clm 値が参照される列(キー) 291 * 292 * @return 指定されたセルの値 293 * 294 */ 295 public String getValue( final int row, final String clm ) { 296 return vals[row][getColumnNo( clm )]; 297 } 298 299 /** 300 * データテーブル内の行の数を返します。 301 * 302 * @return モデルの行数 303 * 304 */ 305 public int getRowCount() { 306 return vals.length; 307 } 308 309 /** 310 * row 単位に変更されたタイプ(追加/変更/削除)を返します。 311 * タイプは始めに一度登録するとそれ以降に変更はかかりません。 312 * つまり、始めに 追加で作成したデータは、その後変更があっても追加のままです。 313 * なにも変更されていない場合は, ""(ゼロストリング)を返します。 314 * 315 * @param row 値が参照される行 316 * 317 * @return 変更されたタイプの値 318 */ 319 public String getModifyType( final int row ) { 320 return modTypes == null ? "" : modTypes[row]; 321 } 322 323 /** 324 * clm のNativeタイプを返します。 325 * Nativeタイプはorg.opengion.fukurou.model.NativeTypeで定義されています。 326 * 327 * @og.rev 5.1.8.0 (2010/07/01) NativeType#getType(String) のメソッドを使用するように変更。 328 * 329 * @param clm 値が参照される列 330 * 331 * @return Nativeタイプ 332 * @see org.opengion.fukurou.model.NativeType 333 */ 334 public NativeType getNativeType( final int clm ) { 335// return StringUtil.getNativeType( vals[0][clm] ); 336 return NativeType.getType( vals[0][clm] ); 337 } 338 339 /** 340 * このオブジェクトの文字列表記を返します。 341 * デバッグ用です。 342 * 343 * @og.rev 5.6.7.0 (2013/07/27) 新規追加 344 * 345 * @return 文字列表現 346 * @see java.lang.Object#toString() 347 */ 348 @Override 349 public String toString() { 350 StringBuilder buf = new StringBuilder(); 351 352 buf.append( "NAMES=" ).append( Arrays.toString( names ) ).append( CR ) 353 .append( " COL_LEN=" ).append( (names != null) ? names.length : -1 ).append( CR ) 354 .append( " ROW_LEN=" ).append( (vals != null) ? vals.length : -1 ).append( CR ) ; 355 356 return buf.toString(); 357 } 358}