OSDN Git Service

Ver8.5.2.0
[opengion/opengionV8.git] / uap / webapps / gf / src / org / opengion / fukurou / business / ArrayTableModel.java
1 /*
2  * Copyright (c) 2009 The openGion Project.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13  * either express or implied. See the License for the specific language
14  * governing permissions and limitations under the License.
15  */
16 package org.opengion.fukurou.business;
17
18 import org.opengion.fukurou.model.DataModel;
19 import org.opengion.fukurou.model.NativeType;
20 import static org.opengion.fukurou.system.HybsConst.CR;                         // 6.1.0.0 (2014/12/26) refactoring
21 import static org.opengion.fukurou.system.HybsConst.BUFFER_MIDDLE;      // 6.1.0.0 (2014/12/26) refactoring
22
23 import java.util.concurrent.ConcurrentMap;                                                      // 6.4.3.3 (2016/03/04)
24 import java.util.concurrent.ConcurrentHashMap;                                          // 6.4.3.1 (2016/02/12) refactoring
25 import java.util.Arrays;
26
27 /**
28  * 業務ロジックを処理するためのテーブルモデルです。
29  *
30  * このテーブルモデルでは、オブジェクト生成時に、カラム配列、値配列を元に、内部データを生成し、
31  * その後は、行の追加や値の変更はできません。
32  *
33  * @og.rev 5.1.1.0 (2009/12/01) 新規作成
34  * @og.group 業務ロジック
35  *
36  * @version 5.0
37  * @author Hiroki Nakamura
38  * @since JDK1.6,
39  */
40 public class ArrayTableModel implements DataModel<String> {
41
42         private final String[] names;
43         private final String[][] vals;
44         private final String[] modTypes;
45
46         /** 6.4.3.1 (2016/02/12) PMD refactoring. HashMap → ConcurrentHashMap に置き換え。 */
47         private final ConcurrentMap<Integer,String[]> rtnMap = new ConcurrentHashMap<>() ;      // 6.4.3.3 (2016/03/04) final化で、初期から作成しておきます。
48
49         /**
50          * 引数に名前配列、値配列を指定したコンストラクター
51          *
52          * @param       nms     名前配列
53          * @param       vs      値2重配列
54          * @throws  IllegalArgumentException 引数の配列が不正な場合
55          */
56         public ArrayTableModel( final String[] nms, final String[][] vs ) {
57                 this( nms, vs, null );
58         }
59
60         /**
61          * 引数に名前配列、値配列、変更区分配列を指定したコンストラクター
62          *
63          * @og.rev 5.6.7.0 (2013/07/27) エラーメッセージを判りやすくする。
64          * @og.rev 5.7.2.3 (2014/01/31) vsのチェック条件を戻す
65          * @og.rev 5.7.3.1 (2014/02/14) nmsのチェック条件も戻す
66          *
67          * @param       nms     名前配列
68          * @param       vs      値2重配列
69          * @param       ms      変更区分の配列
70          * @throws  IllegalArgumentException 引数の配列が不正な場合
71          */
72         public ArrayTableModel( final String[] nms, final String[][] vs, final String[] ms ) {
73                 if( nms == null || nms.length == 0 ) {
74                         final String errMsg = "引数の名前配列に、null は設定できません。";
75                         throw new IllegalArgumentException( errMsg );
76                 }
77                 // 5.6.7.0 (2013/07/27) エラーメッセージを判りやすくする。
78                 // 5.7.2.3 (2014/01/31) 結果0行でlength=0で通るようなのでvsのエラーチェック条件を戻す。
79                 if( vs == null ) {
80                         final String errMsg = "引数の値配列に、null は設定できません。";
81                         throw new IllegalArgumentException( errMsg );
82                 }
83                 // 5.7.3.1 (2014/02/14) 5.7.2.3での戻しでは不十分だったのでこちらも戻す
84                 // 6.0.0.1 (2014/04/25) These nested if statements could be combined
85                 if( vs.length > 0 && ( vs[0] == null || vs[0].length == 0 || nms.length != vs[0].length ) ) {
86                         final String errMsg = "名前配列と値配列のカラム数が異なります。"    + CR
87                                                         + "   nms   =" + Arrays.toString( nms   )                       + CR
88                                                         + "   vs[0] =" + Arrays.toString( vs[0] ) ;
89                         throw new IllegalArgumentException( errMsg );
90                 }
91
92                 final int cols = nms.length;
93                 names = new String[cols];
94                 System.arraycopy( nms, 0, names, 0, cols );
95
96                 final int rows = vs.length;
97                 vals = new String[rows][cols];
98                 for( int i=0; i<rows; i++ ) {
99                         System.arraycopy( vs[i], 0, vals[i], 0, cols );
100                 }
101
102                 if( ms != null && ms.length > 0 ) {
103                         if( vs.length == ms.length ) {
104                                 modTypes = new String[rows];
105                                 System.arraycopy( ms, 0, modTypes, 0, rows );
106                         }
107                         else {
108                                 // 5.6.7.0 (2013/07/27) エラーメッセージを判りやすくする。
109                                 final String errMsg = "変更区分を指定する場合、値配列の行数と一致する必要があります。"   + CR
110                                                                         + "   変更区分 行数 =" + ms.length                + CR
111                                                                         + "   値配列   行数 =" + vs.length ;
112                                 throw new IllegalArgumentException( errMsg );
113                         }
114                 }
115                 else {
116                         modTypes = null;
117                 }
118         }
119
120         /**
121          * rowで指定された行番号(インデックス番号)に行を追加します。
122          *
123          * 値配列をセットする場合は、以下の条件を満たす必要があります。
124          *   1.行番号は、0~(rowCount-1) の範囲
125          *   2.値配列は、not null、 かつ 1件以上
126          *   3.値配列の個数は、内部カラム数と同じ
127          *
128          * ここで登録した値は、内部の値配列と別管理されますので、セット後に、再びゲットしても
129          * ここでセットした値を取り出すことはできません。
130          * また、同じ行番号でセットした場合は、後でセットした値が有効です。
131          *
132          * ※ ここでの更新時に、modifyType は、設定されません。
133          * 必要であれば、setModifyType メソッドで個別に設定してください。
134          *
135          * ※ インデックス(row)とは、このArrayTableModel に持つ vals 配列の行のインデックスです。
136          * よって、オリジナルのDBTableModelの行番号ではありません。
137          *
138          * @og.rev 5.6.0.3 (2012/01/24) 変更された値を、書き戻す機能を追加します。
139          * @og.rev 6.4.3.1 (2016/02/12) PMD refactoring. HashMap → ConcurrentHashMap に置き換え。
140          *
141          * @param   inVals  配列値
142          * @param   rowNo   追加するインデックス
143          * @throws      IllegalArgumentException 引数が1,2,3の条件を満たさない場合。
144          */
145         @Override       // DataModel
146         public void setValues( final String[] inVals, final int rowNo ) {
147                 if( rowNo < 0 || rowNo > getRowCount() ) {
148                         final String errMsg = "引数のインデックスは、0~" + (getRowCount()-1) + " の間で指定してください。index=[" + rowNo + "]";
149                         throw new IllegalArgumentException( errMsg );
150                 }
151                 else if( inVals == null || inVals.length == 0 ) {
152                         final String errMsg = "引数の値配列に、null、または 0件配列は指定できません。index=[" + rowNo + "]";
153                         throw new IllegalArgumentException( errMsg );
154                 }
155                 else if( inVals.length != names.length ) {
156                         final String errMsg = "引数の値配列の個数と、内部カラム数が一致しません。"
157                                                         + " index=[" + rowNo + "] : 引数個数=[" + inVals.length + "] != 内部カラム数=[" + names.length + "]";
158                         throw new IllegalArgumentException( errMsg );
159                 }
160
161                 // 6.4.3.1 (2016/02/12) PMD refactoring. HashMap → ConcurrentHashMap に置き換え。
162
163                 final int cols = names.length;
164                 final String[] newVals = new String[cols];
165                 System.arraycopy( inVals, 0, newVals, 0, cols );
166
167                 // 6.4.3.1 (2016/02/12) PMD refactoring. HashMap → ConcurrentHashMap に置き換え。初期化処理の場所も移動。
168                 rtnMap.put( Integer.valueOf( rowNo ) , newVals );
169         }
170
171         /**
172          * BizLogicで、データが変更された場合は、このMapで値の配列を返します。
173          * Mapのキーは、インデックス(row)のIntegerオブジェクトです。値は、設定された String配列です。
174          * なにも変更がされていなければ、空のConcurrentMapを返しましす。
175          *
176          * ※ インデックス(row)とは、このArrayTableModel に持つ vals 配列の行のインデックスです。
177          * よって、オリジナルのDBTableModelの行番号ではありません。
178          *
179          * @og.rev 5.6.0.3 (2012/01/24) 変更された値を、書き戻すためのMap&lt;インデックス,値配列&gt; を返します。
180          * @og.rev 6.4.3.1 (2016/02/12) PMD refactoring. HashMap → ConcurrentHashMap に置き換え。
181          * @og.rev 6.4.3.3 (2016/03/04) 変更が無い場合は、nulllではなく、空のConcurrentMapを返しましす。
182          *
183          * @return      書き戻すためのMap<インデックス,値配列>
184          * @see AbstractBizLogic#isRequireTable()
185          * @og.rtnNotNull
186          */
187         public ConcurrentMap<Integer,String[]> getModifyVals() {
188                 return rtnMap;
189         }
190
191         /**
192          * カラム名に対応する カラム番号を返します。
193          *
194          * 特殊なカラムが指定された場合は、負の値を返します。
195          * 例えば、[KEY.カラム名]、[I]、[ROW.ID] など、特定の負の値を返します。
196          * また、カラム名が元のデータモデルに存在しない場合も、負の値か、
197          * Exception を返します。負の値なのか、Exception なのかは、
198          * 実装に依存します。
199          *
200          * @param       columnName      値が参照されるカラム名
201          *
202          * @return  指定されたセルのカラム番号。存在しなければ、-1
203          * @throws  IllegalArgumentException 引数のカラム名が null の場合
204          */
205         @Override       // DataModel
206         public int getColumnNo( final String columnName ) {
207                 if( columnName == null ) {
208                         final String errMsg = "引数のカラム名に、null は設定できません。";
209                         throw new IllegalArgumentException( errMsg );
210                 }
211
212                 int address = -1;
213                 for( int i=0; i<names.length; i++ ) {
214                         if( columnName.equalsIgnoreCase( names[i] ) ) {
215                                 address = i;
216                                 break;
217                         }
218                 }
219
220                 return address;
221         }
222
223         /**
224          * カラム名配列に対応する カラム番号配列を返します。
225          *
226          * これは、#getColumnNo( String ) に対する 複数のカラム名を検索した
227          * 場合と同じです。
228          *
229          * @og.rev 6.8.6.0 (2018/01/19) 可変長引数から、通常配列に変更。
230          *
231          * @param       clmNms  値が参照されるカラム名配列(可変長引数)
232          *
233          * @return  指定されたセルのカラム番号配列。
234          * @og.rtnNotNull
235          */
236 //      public int[] getColumnNos( final String... clmNms ) {
237         public int[] getColumnNos( final String[] clmNms ) {
238                 if( clmNms == null || clmNms.length == 0 ) { return new int[0]; }       // 6.1.1.0 (2015/01/17) 可変長引数でもnullは来る。
239
240                 int[] clmNos = new int[clmNms.length];
241                 for( int j=0; j<clmNms.length; j++ ) {
242                         int address = -1;
243                         for( int i=0; i<names.length; i++ ) {
244                                 if( clmNms[j].equalsIgnoreCase( names[i] ) ) {
245                                         address = i;
246                                         break;
247                                 }
248                         }
249                         clmNos[j] = address;
250                 }
251
252                 return clmNos;
253         }
254
255         /**
256          * カラム名配列を返します。
257          *
258          * @return      カラム名配列
259          * @og.rtnNotNull
260          */
261         @Override       // DataModel
262         public String[] getNames() {
263                 return names.clone();
264         }
265
266         /**
267          * 指定のカラム名引数に相当するデータを2重配列で返します。
268          *
269          * @og.rev 6.8.5.0 (2018/01/09) 新規追加
270          *
271          * @param       clmNms  値が参照されるカラム名配列(可変長引数)
272          *
273          * @return  指定された名引数に相当するデータの2重配列
274          * @og.rtnNotNull
275          */
276         protected String[][] getValues( final String... clmNms ) {
277                 final int[] clmNos = getColumnNos( clmNms );
278
279                 final String[][] rtns = new String[vals.length][clmNos.length];
280
281                 for( int row=0; row<vals.length; row++ ) {
282                         for( int j=0; j<clmNos.length; j++ ) {
283                                 final int col = clmNos[j];
284                                 rtns[row][col] = vals[row][col];
285                         }
286                 }
287
288                 return rtns;
289         }
290
291         /**
292          * row にあるセルの属性値を配列で返します。
293          *
294          * @param   row     値が参照される行
295          *
296          * @return  指定されたセルの属性値配列
297          * @og.rtnNotNull
298          */
299         @Override       // DataModel
300         public String[] getValues( final int row ) {
301                 return vals[row].clone();
302         }
303
304         /**
305          * row および clm にあるセルの属性値をStringに変換して返します。
306          *
307          * @param   row     値が参照される行
308          * @param   clm     値が参照される列
309          *
310          * @return  指定されたセルの値
311          */
312         @Override       // DataModel
313         public String getValue( final int row, final int clm ) {
314                 return vals[row][clm];
315         }
316
317         /**
318          * row および clm にあるセルの属性値をStringに変換して返します。
319          *
320          * @param   row     値が参照される行
321          * @param   clm     値が参照される列(キー)
322          *
323          * @return  指定されたセルの値
324          *
325          */
326         public String getValue( final int row, final String clm ) {
327                 return vals[row][getColumnNo( clm )];
328         }
329
330         /**
331          * データテーブル内の行の数を返します。
332          *
333          * @return  モデルの行数
334          *
335          */
336         @Override       // DataModel
337         public int getRowCount() {
338                 return vals.length;
339         }
340
341         /**
342          * row 単位に変更されたタイプ(追加/変更/削除)を返します。
343          * タイプは始めに一度登録するとそれ以降に変更はかかりません。
344          * つまり、始めに 追加で作成したデータは、その後変更があっても追加のままです。
345          * なにも変更されていない場合は、""(ゼロストリング)を返します。
346          *
347          * @param   row     値が参照される行
348          *
349          * @return  変更されたタイプの値
350          */
351         @Override       // DataModel
352         public String getModifyType( final int row ) {
353                 return modTypes == null ? "" : modTypes[row];
354         }
355
356         /**
357          * row 単位に変更タイプ(追加/変更/削除)をセットします。
358          * このメソッドでは、データのバックアップは取りません。
359          * タイプは始めに一度登録するとそれ以降に変更はかかりません。
360          * なにも変更されていない場合は、""(ゼロストリング)の状態です。
361          *
362          * @og.rev 6.7.9.1 (2017/05/19) インターフェースの見直しにより、追加
363          *
364          * @param   row      値が参照される行
365          * @param   modType  変更タイプ(追加/変更/削除)
366          *
367          */
368         @Override       // DataModel
369         public void setModifyType( final int row , final String modType ) {
370                 if( modTypes[row].isEmpty() ) { modTypes[row] = modType; }
371         }
372
373         /**
374          * clm のNativeタイプを返します。
375          * Nativeタイプはorg.opengion.fukurou.model.NativeTypeで定義されています。
376          *
377          * @og.rev 5.1.8.0 (2010/07/01) NativeType#getType(String) のメソッドを使用するように変更。
378          *
379          * @param  clm      値が参照される列
380          *
381          * @return Nativeタイプ
382          * @see org.opengion.fukurou.model.NativeType
383          */
384         @Override       // DataModel
385         public NativeType getNativeType( final int clm ) {
386                 return NativeType.getType( vals[0][clm] );
387         }
388
389         /**
390          * このオブジェクトの文字列表記を返します。
391          * デバッグ用です。
392          *
393          * @og.rev 5.6.7.0 (2013/07/27) 新規追加
394          *
395          * @return 文字列表現
396          * @og.rtnNotNull
397          * @see java.lang.Object#toString()
398          */
399         @Override       // Object
400         public String toString() {
401                 final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );
402
403                 buf.append( "NAMES=" ).append( Arrays.toString( names ) ).append( CR )
404                         // 6.4.1.1 (2016/01/16) PMD refactoring. Avoid if (x != y) ..; else ..;
405                         .append( " COL_LEN=" ).append( names == null ? -1 : names.length ).append( CR )
406                         .append( " ROW_LEN=" ).append( vals  == null ? -1 : vals.length  ).append( CR ) ;
407
408                 return buf.toString();
409         }
410 }