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.process;
017
018import java.util.Arrays;
019
020import org.opengion.fukurou.system.OgRuntimeException ;         // 6.4.2.0 (2016/01/29)
021import org.opengion.fukurou.model.DataModel;
022import org.opengion.fukurou.model.NativeType;
023import org.opengion.fukurou.util.StringUtil;
024import static org.opengion.fukurou.system.HybsConst.CR;                         // 6.1.0.0 (2014/12/26) refactoring
025import static org.opengion.fukurou.system.HybsConst.BUFFER_MIDDLE;      // 6.1.0.0 (2014/12/26) refactoring
026
027/**
028 * LineModel は、データの1行分を管理する為の TableModel と類似の実装クラスです。
029 *
030 * データの1行分を LineModel に割り当てます。
031 * カラム番号は、0 から始まります。カラム名よりカラム番号を求める場合に、
032 * 存在しない場合は、-1 を返します。
033 * カラム番号が -1 の場合は、処理を行いません。
034 *
035 * 注意:このクラスは、同期処理されていません。
036 *
037 * @version  4.0
038 * @author   Kazuhiko Hasegawa
039 * @since    JDK5.0,
040 */
041public class LineModel implements DataModel<Object> {           // 4.3.3.6 (2008/11/15) Generics警告対応
042        /** タブセパレータ */
043        private static final char TAB = '\t';           // 6.0.2.5 (2014/10/31) タブ区切り文字を char 化します。
044
045        private String[]        names   ;
046        private Object[]        data    ;
047        private int                     dtSize  ;
048        private int                     rowNo   = -1;
049
050        /**
051         * デフォルトコンストラクター
052         *
053         * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor.
054         */
055        public LineModel() { super(); }         // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
056
057        /**
058         * このオブジェクトを初期化します。
059         * 指定の引数分の内部配列を作成します。
060         *
061         * @param   columnCount カラム数
062         */
063        public void init( final int columnCount ) {
064                if( columnCount <= 0 ) {
065                        final String errMsg = "内部配列の数量が 0か、負です。count=[" + columnCount + "]";
066                        throw new OgRuntimeException( errMsg );
067                }
068                dtSize  = columnCount;
069                names   = new String[dtSize];
070                data    = new Object[dtSize];
071        }
072
073        /**
074         * カラム名配列を指定して、このオブジェクトを初期化します。
075         *
076         * @og.rev 8.5.3.2 (2023/10/13) JDK21対応。警告: [this-escape] サブクラスが初期化される前の'this'エスケープの可能性があります
077         * @og.rev 8.5.5.1 (2024/02/29) spotbugs CT_CONSTRUCTOR_THROW(コンストラクタで、Excweptionを出さない)
078         *
079         * @param   clmNms カラム名配列(可変長引数)
080         */
081//      public void init( final String... clmNms ) {
082        public LineModel( final String... clmNms ) {                    // 8.5.3.2 (2023/10/13) JDK21対応
083                // 8.5.5.1 (2024/02/29) spotbugs CT_CONSTRUCTOR_THROW(コンストラクタで、Excweptionを出さない)
084                if( clmNms == null || clmNms.length == 0 ) {            // 6.1.1.0 (2015/01/17) 可変長引数でもnullは来る。
085                        final String errMsg = "カラム名配列が、指定されていません。";
086//                      throw new OgRuntimeException( errMsg );
087                        System.out.println( errMsg );
088                }
089                else {
090                        dtSize  = clmNms.length;
091                        names   = new String[dtSize];
092                        System.arraycopy( clmNms,0,names,0,dtSize );
093                        data    = new Object[dtSize];
094                }
095        }
096
097        /**
098         * 名前をセットします。
099         * 指定のカラム番号が、-1 の場合は、なにもしません。
100         *
101         * @param   clmNo        値が変更されるカラム番号
102         * @param   key  新しい名前
103         */
104        public void setName( final int clmNo,final String key ) {
105                if( clmNo >= 0 ) { names[clmNo] = key; }
106        }
107
108        /**
109         * カラム番号に対するカラム名を取得します。
110         * 指定のカラム番号が、-1 の場合は、null を返します。
111         *
112         * @param   clmNo  カラム番号 最初のカラム番号は0、2番目のカラム番号は 1、などとする。
113         *
114         * @return  カラム名
115         */
116        public String getName( final int clmNo ) {
117                return clmNo >= 0 ? names[clmNo] : null ;                       // 6.0.2.5 (2014/10/31) refactoring
118        }
119
120        /**
121         * カラム名配列を返します。
122         * 配列オブジェクトは、clone されたコピーを返しますので、
123         * 内容を書き換えたい場合は、setName() メソッドを使用してください。
124         *
125         * @return      カラム名配列
126         * @og.rtnNotNull
127         */
128        @Override       // DataModel
129        public String[] getNames() {
130                return names.clone();
131        }
132
133        /**
134         * column に対応した 値を登録します。
135         * 指定のカラム番号が、-1 の場合は、なにもしません。
136         *
137         * @param   clmNo       値が変更されるカラム番号
138         * @param   value       新しい値(nullも可)
139         */
140        public void setValue( final int clmNo,final Object value ) {
141                if( clmNo >= 0 ) { data[clmNo] = value; }
142        }
143
144        /**
145         * column にあるセルの属性値をObjectに変換して返します。
146         * 指定のカラム番号が、-1 の場合は、null を返します。
147         *
148         * @param   clmNo  値が参照されるカラム番号
149         *
150         * @return  指定されたセルの値 Object
151         */
152        public Object getValue( final int clmNo ) {
153                return clmNo >= 0 ? data[clmNo] : null ;                        // 6.0.2.5 (2014/10/31) refactoring
154        }
155
156        /**
157         * row および clm にあるセルの属性値をStringに変換して返します。
158         *
159         * @og.rev 6.3.2.0 (2015/07/10) LineModelで、Formatter処理できるように、対応します。
160         *
161         * @param   rowNo     値が参照される行
162         * @param   clmNo     値が参照される列
163         *
164         * @return  指定されたセルの値
165         */
166        @Override       // DataModel
167        public Object getValue( final int rowNo, final int clmNo ) {
168                return getValue( clmNo ) ;              // 6.3.2.0 (2015/07/10)
169        }
170
171        /**
172         * 属性値配列をセットします。
173         * このメソッドでは、カラム名配列は更新しません。配列数が異なる場合や、
174         * 属性値配列が null の場合は設定できません。
175         * 設定は、配列オブジェクトのコピーをセットしますので、登録元の配列オブジェクトを
176         * 書き換えた場合でも、このオブジェクトの内部値は変更されませんので、
177         * 副作用を期待したコーディングは、行わないで下さい。
178         * 注意:値オブジェクト配列自身はコピーしますが、個々のオブジェクトそのものは、
179         * arraycopy しているだけです。個々のオブジェクトの状態変化に対しては、
180         * 各クライアント側で対応が必要です。
181         *
182         * @param       values  セットする値配列
183         * @param       rno             処理中の行番号
184         */
185        @Override       // DataModel
186        public void setValues( final Object[] values, final int rno ) {
187                if( values == null ) {
188                        final String errMsg = "値配列が、null です。row=[" + rno + "]";
189                        throw new OgRuntimeException( errMsg );
190                }
191                else if( names.length != values.length ) {
192                        final String errMsg = "カラム名配列と異なる要素の属性値配列は登録できません。" + CR
193                                                        + " names.length=[" + names.length + "],"
194                                                        + " values.length[" + values.length + "],"
195                                                        + " row=[" + rno + "]"  + CR
196                                                        + " names=" + StringUtil.array2csv( names )
197                                                        + " values=" + Arrays.toString( values ) ;              // 5.1.8.0 (2010/07/01) errMsg 修正
198                        throw new OgRuntimeException( errMsg );
199                }
200
201                rowNo = rno;
202                System.arraycopy( values,0,data,0,values.length );
203        }
204
205        /**
206         * 属性値を配列で返します。
207         * 配列オブジェクトは、clone されたコピーを返しますので、
208         * 内容を書き換えたい場合は、setValue() メソッドを使用してください。
209         *
210         * @return  指定されたセルの属性値
211         * @og.rtnNotNull
212         */
213        public Object[] getValues() {
214                return data.clone();
215        }
216
217        /**
218         * row にあるセルの属性値を配列で返します。
219         *
220         * @og.rev 6.3.2.0 (2015/07/10) LineModelで、Formatter処理できるように、対応します。
221         *
222         * @param   row     値が参照される行
223         *
224         * @return  指定されたセルの属性値
225         */
226        @Override       // DataModel
227        public Object[] getValues( final int row ) {
228                final String errMsg = "このクラスでは実装されていません。";
229                throw new UnsupportedOperationException( errMsg );
230        }
231
232        /**
233         * 行データモデル属性に、処理中の行番号情報を設定します。
234         * 一般に、setValue( int clm, Object value ) との併用時に使用します。
235         *
236         * @param       rno     処理中の行番号
237         */
238        public void setRowNo( final int rno ) {
239                rowNo = rno;
240        }
241
242        /**
243         * 行データモデル属性の、処理中の行番号情報を返します。
244         *
245         * @return  処理中の行番号
246         */
247        public int getRowNo() {
248                return rowNo;
249        }
250
251        /**
252         * columnName 名称に対応する カラム番号を返します。存在しない場合は、-1 を返します。
253         *
254         * @param   columnName  値が参照されるカラム番号
255         *
256         * @return  指定されたセルのカラム番号(存在しない場合は、-1)
257         */
258        @Override       // DataModel
259        public int getColumnNo( final String columnName ) {
260                int clmNo = -1;
261                if( columnName != null ) {
262                        for( int i=0; i<dtSize; i++ ) {
263                                if( columnName.equalsIgnoreCase( names[i] ) ) {
264                                        clmNo = i;
265                                        break;
266                                }
267                        }
268                }
269
270                return clmNo;
271        }
272
273        /**
274         * データテーブル内の列の数を返します。
275         *
276         * @return  モデルの列数
277         */
278        public int size() {
279                return dtSize ;
280        }
281
282        /**
283         * この内部データの名前配列を連結した文字列で、出力します。
284         *
285         * @return      内部データの名前配列を連結した文字列
286         */
287        public String nameLine() {
288                String rtn = "No Data";
289
290                if( dtSize > 0 ) {
291                        final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );
292                        buf.append( "#Name" );
293                        for( int clm=0; clm<dtSize; clm++ ) {
294                                // 8.5.4.2 (2024/01/12) PMD 7.0.0 ConsecutiveAppendsShouldReuse 対応
295                                buf.append( TAB )
296                                        .append( names[clm] );
297                        }
298                        rtn = buf.toString() ;
299                }
300                return rtn ;
301        }
302
303        /**
304         * この内部データの名前配列を連結した文字列で、出力します。
305         *
306         * @return      名前配列を連結した文字列
307         */
308        public String dataLine() {
309                String rtn = "No Data";
310
311                if( dtSize > 0 ) {
312                        final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );
313                        buf.append( rowNo );
314                        for( int clm=0; clm<dtSize; clm++ ) {
315                                // 8.5.4.2 (2024/01/12) PMD 7.0.0 ConsecutiveAppendsShouldReuse 対応
316                                buf.append( TAB )
317                                        .append( data[clm] );
318                        }
319                        rtn = buf.toString() ;
320                }
321                return rtn ;
322        }
323
324        /**
325         * この内部データを見える形で出力します。
326         *
327         * @return      内部データを見える形
328         * @og.rtnNotNull
329         */
330        @Override       // Object
331        public String toString() {
332                return nameLine() + CR + dataLine() ;
333        }
334
335        /**
336         * clm のNativeタイプを返します。
337         * Nativeタイプはorg.opengion.fukurou.model.NativeTypeで定義されています。
338         *
339         * @og.rev 4.1.1.2 (2008/02/28) 新規追加
340         * @og.rev 5.1.8.0 (2010/07/01) NativeType#getType(String) のメソッドを使用するように変更。
341         *
342         * @param  clm      値が参照される列
343         *
344         * @return Nativeタイプ
345         * @see org.opengion.fukurou.model.NativeType
346         */
347        @Override       // DataModel
348        public NativeType getNativeType( final int clm ) {
349                return NativeType.getType( data[clm].toString() );
350        }
351}