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     */
016    package org.opengion.fukurou.db;
017    
018    import org.opengion.fukurou.util.StringUtil;
019    import org.opengion.fukurou.util.ApplicationInfo;
020    import org.opengion.fukurou.util.Closer;
021    import org.opengion.fukurou.model.Formatter;
022    import org.opengion.fukurou.model.ArrayDataModel;
023    
024    import java.sql.Connection;
025    import java.sql.PreparedStatement;
026    import java.sql.ParameterMetaData;
027    import java.sql.SQLException;
028    
029    import java.util.Arrays;
030    
031    /**
032     * DBTableModel インターフェースを継承した TableModel の実?ラスです?
033     * sql? execute( query ) する事により,??タベ?スを検索した結果?
034     * DBTableModel に割り当てます?
035     *
036     * メソ?を宣?て??
037     * DBTableModel インターフェースは?データベ?スの検索結果(Resultset)をラ??する
038     * インターフェースとして使用して下さ??
039     *
040     * @og.rev 5.2.2.0 (2010/11/01) パッケージ移?hayabusa.db ?fukurou.db)
041     * @og.group ??/Shell制御
042     *
043     * @version  4.0
044     * @author   Kazuhiko Hasegawa
045     * @since    JDK5.0,
046     */
047    public class DBSimpleTable {
048    
049            /** シス?依存?改行記号をセ?します?     */
050            private static final String CR = System.getProperty("line.separator");
051    
052            private final String[]  names ;                         // ??タ配?に対応するカラ???names)
053            private String[]        keys            = null;         // 登録に使用するカラ?ー配?(keys)
054            private int[]           keysNo          = null;         // 登録に使用するカラ?ー配?番号
055            private String          table           = null;         // 登録??ブル?
056            private String          where           = null;         // where 条件式[カラ?]を含?
057            private int[]           whereNo         = null;         // [カラ?]に対応するデータ配?番号
058            private String[]        constrain       = null;         // key に対応した制?件
059    
060            private String          connID          = null;         // 登録に使用するコネクションID
061            private boolean         useWhere        = false;        // where が設定されると true にセ?されます?
062    
063            private Connection      conn            = null;
064            private PreparedStatement pstmt = null;
065            private ParameterMetaData pMeta = null;         // 5.1.2.0 (2010/01/01) setObject に、Type を渡す?(PostgreSQL対?
066            private String          query           = null;         // エラーメ?ージ用の変数
067            private int                     execCnt         = 0;
068            private ApplicationInfo appInfo  = null;        // 3.8.7.0 (2006/12/15)
069            private boolean useParamMetaData = false;       // 5.1.2.0 (2010/01/01) setObject に、Type を渡す?(PostgreSQL対?
070    
071            /**
072             * ??タ配?のカラ?称配?を指定してオブジェクトを構築します?
073             *
074             * @param       nm      カラ?称配?
075             * @throws RuntimeException tbl ?null の場?
076             */
077            public DBSimpleTable( final String[] nm ) {
078                    if( nm == null ) {
079                            String errMsg = "??タ配?のカラ?称に null は設定できません?;
080                            throw new RuntimeException( errMsg );
081                    }
082    
083                    names = new String[nm.length];
084                    System.arraycopy( nm,0,names,0,names.length );
085            }
086    
087            /**
088             * 登録に使用するカラ?ー配?(keys)を登録します?
089             *
090             * 引数のkey配??null の場合?、names と同じカラ?称配?(names)が使用されます?
091             * キー配?(keys)は、?しか登録できません。また?addConstrain等?メソ?
092             * 呼び出しを先に実行すると、カラ?称配?(names)が設定されてしま??
093             * そ?後にこ?メソ?を呼び出すとエラーが発生します?
094             *
095             * @param       key     登録カラ?称配?
096             * @see         #addConstrain( String ,String )
097             * @throws RuntimeException すでに キー配?(keys)が登録済み/作?済みの場?
098             */
099            public void setKeys( final String[] key ) {
100                    if( keys != null ) {
101                            String errMsg = "すでに キー配?(keys)が登録済みです?";
102                            throw new RuntimeException( errMsg );
103                    }
104    
105                    if( key != null ) {
106                            int size = key.length;
107                            keys = new String[size];
108                            System.arraycopy( key,0,keys,0,size );
109    
110                            constrain = new String[size];
111                            Arrays.fill( constrain,"?" );
112    
113                            keysNo = new int[size];
114                            for( int i=0; i<size; i++ ) {
115                                    int address = findAddress( names,keys[i] );
116                                    if( address >= 0 ) {
117                                            keysNo[i] = address;
118                                    }
119                                    else {
120                                            String errMsg = "?? key は、カラ???names)に存在しません"
121                                                                    + " key[" + i + "]=" + key[i]
122                                                                    + " names=" + StringUtil.array2csv( names ) ;
123                                            throw new RuntimeException( errMsg );
124                                    }
125                            }
126                    }
127            }
128    
129            /**
130             * カラ?称配?(names)と同じキー配?(keys)を作?します?
131             *
132             * これは、キー配?(keys) が作?されなかった?合?処?す?
133             * keys ?null の場合?み、??実行します?
134             *
135             * @see         #setKeys( String[] )
136             */
137            private void makeKeys() {
138                    // キー配?(keys) が未設定?場合?、カラ?称配?(names)が設定されます?
139                    if( keys == null ) {
140                            keys = names;
141                            int size = keys.length;
142    
143                            constrain = new String[size];
144                            Arrays.fill( constrain,"?" );
145    
146                            keysNo = new int[size];
147                            for( int i=0; i<size; i++ ) {
148                                    keysNo[i] = i;
149                            }
150                    }
151            }
152    
153            /**
154             * Insert/Update/Delete 時?登録する??ブル?
155             *
156             * @param       tbl     ??ブル?
157             * @throws RuntimeException tbl ?null の場?
158             */
159            public void setTable( final String tbl ) {
160                    if( tbl == null ) {
161                            String errMsg = "table に null は設定できません?;         // 5.1.8.0 (2010/07/01) errMsg 修正
162                            throw new RuntimeException( errMsg );
163                    }
164    
165                    table = tbl;
166            }
167    
168            /**
169             * ??タベ?スの接続?IDを設定します?
170             *
171             * @param       conn    接続?ID
172             */
173            public void setConnectionID( final String conn ) {
174                    connID = conn;
175            }
176    
177            /**
178             * アクセスログ取得?為,ApplicationInfoオブジェクトを設定します?
179             *
180             * @og.rev 3.8.7.0 (2006/12/15) 新規追?
181             *
182             * @param   appInfo アプリ??オブジェク?
183             */
184            public void setApplicationInfo( final ApplicationInfo appInfo ) {
185                    this.appInfo = appInfo;
186            }
187    
188            /**
189             * Insert/Update/Delete 時? PreparedStatement の引数(?)制?
190             *
191             * 制?件(val)は、そのまま引数に使用されます?通常? で表され?
192             * パラメータに、文字長を制限する?合?SUBSTRB( ?,1,100 ) と?
193             * val 変数を与えます?
194             * また?キー?に対して、?を?登録した??合にも?使用できます?
195             * 例えば、NVAL( ?,? ) のような場合?キー?に値?つを割り当てます?
196             * 値配?の並び??、キー配?(keys)に対する(?の個数)に対応します?
197             * 注意:カラ?称配?(names)ではありません。また?先にキー配?(keys)を登録
198             * しておかな?、キー配?登録時にエラーが発生します?
199             * 制?件は、??るQUERYに対して適用されます?で?
200             * key また?、val ?null の場合?、RuntimeException ?Throwします?
201             *
202             * @param       key     制?かけるキー
203             * @param       val     制?件?
204             * @see         #setKeys( String[] )
205             * @throws RuntimeException key また?、val ?null の場?
206             */
207            public void addConstrain( final String key,final String val ) {
208                    if( key == null || val == null ) {
209                            String errMsg = "key また?、val に null は設定できません?
210                                                    + " key=[" + key + "] , val=[" + val + "]" ;
211                            throw new RuntimeException( errMsg );
212                    }
213    
214                    // キー配?(keys)が未設?null)の場合?、カラ?称配?(names)を割り当てます?
215                    if( keys == null ) { makeKeys(); }
216    
217                    // 制?件のアドレスは、カラ?称配?(names)でなく?キー配?(keys)を使用します?
218                    int address = findAddress( keys,key );
219                    if( address >= 0 ) {
220                            constrain[address] = val;
221                    }
222                    else {
223                            String errMsg = "?? key は、キー配?(keys)に存在しません"
224                                                    + " key=[" + key + "] , val=[" + val + "]"
225                                                    + " keys=" + StringUtil.array2csv( keys ) ;
226                            throw new RuntimeException( errMsg );
227                    }
228            }
229    
230            /**
231             * Update/Delete 時?キーとなるWHERE 条件のカラ?を設定します?
232             *
233             * 通常の WHERE 句の書き方と同じで、カラ???names)に対応する設定?(values)の値?
234             * 割り当てたい?に[カラ?] を記述します???の場合?設定?をセ?する
235             * ときに、シングルコー??ションを使用しますが、[カラ?]で?する?合??
236             * そ?前後に?')シングルコー??ションは、不要です?
237             * WHERE条件は、登録に使用するキー配?(keys)に現れな?件で行を特定することがあります?で
238             * カラ?称配?(names)を?にカラ?のアドレスを求めます?
239             * [カラ?]は? に置き換えて、PreparedStatement として、実行される形式に変換されます?
240             * 例:FGJ='1' and CLM=[CLM] and SYSTEM_ID in ([SYSID],'**')
241             *
242             * @og.rev 4.3.4.0 (2008/12/01) キー配?(keys)が未設?null)の場合?、カラ?称配?(names)を割り当て?
243             * @og.rev 5.0.2.0 (2009/11/01) バグ修正(keysは??タセ?のキーなので、where句のカラ?含まれて入?わけではな?
244             *
245             * @param  wh WHERE条件のカラ?
246             * @throws RuntimeException [カラ?]がカラ???names)に存在しな???
247             */
248            public void setWhere( final String wh ) {
249    
250                    if( wh != null ) {
251                            // キー配?(keys)が未設?null)の場合?、カラ?称配?(names)を割り当てます?
252    //                      if( keys == null ) { makeKeys(); }
253    
254    //                      ArrayDataModel data = new ArrayDataModel( keys );
255                            // 5.0.2.0 (2009/11/01)
256                            ArrayDataModel data = new ArrayDataModel( names );
257                            Formatter format = new Formatter( data );
258                            format.setFormat( wh );
259                            where = format.getQueryFormatString();
260                            whereNo = format.getClmNos();
261    
262    //                      StringBuilder buf = new StringBuilder( wh.length() );
263    //
264    //                      // 注意:[ と ] が隣接したケースでは処?きません?
265    //                      String wh2 = wh.replace( '[',']' );
266    //                      CSVTokenizer token = new CSVTokenizer( wh2,']',false );
267    //                      int cnt = token.countTokens() / 2 ;
268    ////                    String format = null;
269    //                      whereNo = new int[ cnt ];
270    //                      for( int i=0; i<cnt; i++ ) {
271    ////                            format = token.nextToken();
272    ////                            buf.append( format);
273    //                              buf.append( token.nextToken() );        // format
274    //                              String clm = token.nextToken();
275    //                              // カラ?称配?(names)を?にカラ?のアドレスを求めます?
276    //                              int address = findAddress( names,clm );
277    //                              if( address >= 0 ) { whereNo[i] = address; }
278    //                              else {
279    //                                      String errMsg = "[" + clm + "]が?カラ???names)に存在しません? + CR
280    //                                                              + " names=" + StringUtil.array2csv( names );
281    //                                      throw new RuntimeException( errMsg );
282    //                              }
283    //                              buf.append( "?" );              // [カラ? ?? に置き換?
284    //                      }
285    ////                    format = token.nextToken();
286    ////                    buf.append( format );
287    //                      buf.append( token.nextToken() );        // format
288    //
289    //                      where = buf.toString();
290                    }
291                    else {
292                            where = null;
293                    }
294            }
295    
296            /**
297             * ??タをインサートする?合に使用するSQL?作?します?
298             *
299             * @return  インサー?QL
300             */
301            private String getInsertSQL() {
302                    // キー配?(keys)が未設?null)の場合?、カラ?称配?(names)を割り当てます?
303                    if( keys == null ) { makeKeys(); }
304    
305                    StringBuilder sql = new StringBuilder();
306                    sql.append( "INSERT INTO " ).append( table );
307                    sql.append( " ( " );
308                    sql.append( keys[0] );
309                    for( int i=1; i<keys.length; i++ ) {
310                            sql.append( "," ).append( keys[i] );
311                    }
312                    sql.append( " ) VALUES ( " );
313                    sql.append( constrain[0] );
314                    for( int i=1; i<keys.length; i++ ) {
315                            sql.append( "," ).append( constrain[i] );
316                    }
317                    sql.append( " )" );
318    
319                    useWhere = false;
320    
321                    return sql.toString();
322            }
323    
324            /**
325             * ??タをア????トする?合に使用するSQL?作?します?
326             *
327             * @return  ア?????QL
328             */
329            private String getUpdateSQL() {
330                    // キー配?(keys)が未設?null)の場合?、カラ?称配?(names)を割り当てます?
331                    if( keys == null ) { makeKeys(); }
332    
333                    StringBuilder sql = new StringBuilder();
334                    sql.append( "UPDATE " ).append( table ).append( " SET " );
335                    sql.append( keys[0] ).append( " = " ).append( constrain[0] );
336    
337                    for( int i=1; i<keys.length; i++ ) {
338                            sql.append( " , " );
339                            sql.append( keys[i] ).append( " = " ).append( constrain[i] );
340                    }
341    
342                    if( where != null && where.length() > 0 ) {
343                            sql.append( " WHERE " ).append( where );
344                            useWhere = true;
345                    }
346                    else {
347                            useWhere = false;
348                    }
349    
350                    return sql.toString();
351            }
352    
353            /**
354             * ??タをデリートする?合に使用するSQL?作?します?
355             *
356             * @og.rev 5.0.2.0 (2009/11/01) バグ修正(削除時?keysは?な?
357             *
358             * @return  ?ー?QL
359             */
360            private String getDeleteSQL() {
361                    // キー配?(keys)が未設?null)の場合?、カラ?称配?(names)を割り当てます?
362    //              if( keys == null ) { makeKeys(); }
363                    // 5.0.2.0 (2009/11/01)
364                    keys = new String[0];
365    
366                    StringBuilder sql = new StringBuilder();
367                    sql.append( "DELETE FROM " ).append( table );
368    
369                    if( where != null && where.length() > 0 ) {
370                            sql.append( " WHERE " ).append( where );
371                            useWhere = true;
372                    }
373                    else {
374                            useWhere = false;
375                    }
376    
377                    return sql.toString();
378            }
379    
380            /**
381             * Insert 処??開始を宣?ます?
382             * ??、コネクションを接続して、PreparedStatementオブジェクトを作?します?
383             * こ?メソ?と、close() メソ?は?セ?で処?てください?
384             *
385             * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得?為,ApplicationInfoオブジェクトを設?
386             * @og.rev 5.1.2.0 (2010/01/01) setObject に ParameterMetaData の getParameterType を渡す?(PostgreSQL対?
387             * @og.rev 5.3.8.0 (2011/08/01) useParamMetaData ?ConnectionFactory経由で取得?(PostgreSQL対?
388             *
389             * @throws SQLException Connection のオープンに失敗した??
390             */
391            public void startInsert() throws SQLException {
392                    execCnt = 0;
393                    query = getInsertSQL();
394                    conn  = ConnectionFactory.connection( connID,appInfo );
395                    pstmt = conn.prepareStatement( query );
396                    // 5.1.2.0 (2010/01/01) setObject に ParameterMetaData の getParameterType を渡す?(PostgreSQL対?
397    //              useParamMetaData = ApplicationInfo.useParameterMetaData( conn );
398                    useParamMetaData = ConnectionFactory.useParameterMetaData( connID );    // 5.3.8.0 (2011/08/01)
399                    if( useParamMetaData ) {
400                            pMeta = pstmt.getParameterMetaData();
401                    }
402            }
403    
404            /**
405             * Update 処??開始を宣?ます?
406             * ??、コネクションを接続して、PreparedStatementオブジェクトを作?します?
407             * こ?メソ?と、close() メソ?は?セ?で処?てください?
408             *
409             * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得?為,ApplicationInfoオブジェクトを設?
410             * @og.rev 5.1.2.0 (2010/01/01) setObject に ParameterMetaData の getParameterType を渡す?(PostgreSQL対?
411             * @og.rev 5.3.8.0 (2011/08/01) useParamMetaData ?ConnectionFactory経由で取得?(PostgreSQL対?
412             *
413             * @throws SQLException Connection のオープンに失敗した??
414             */
415            public void startUpdate() throws SQLException {
416                    execCnt = 0;
417                    query = getUpdateSQL();
418                    conn  = ConnectionFactory.connection( connID,appInfo );
419                    pstmt = conn.prepareStatement( query );
420                    // 5.1.2.0 (2010/01/01) setObject に ParameterMetaData の getParameterType を渡す?(PostgreSQL対?
421    //              useParamMetaData = ApplicationInfo.useParameterMetaData( conn );
422                    useParamMetaData = ConnectionFactory.useParameterMetaData( connID );    // 5.3.8.0 (2011/08/01)
423                    if( useParamMetaData ) {
424                            pMeta = pstmt.getParameterMetaData();
425                    }
426            }
427    
428            /**
429             * Delete 処??開始を宣?ます?
430             * ??、コネクションを接続して、PreparedStatementオブジェクトを作?します?
431             * こ?メソ?と、close() メソ?は?セ?で処?てください?
432             *
433             * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得?為,ApplicationInfoオブジェクトを設?
434             * @og.rev 5.1.2.0 (2010/01/01) setObject に ParameterMetaData の getParameterType を渡す?(PostgreSQL対?
435             * @og.rev 5.3.8.0 (2011/08/01) useParamMetaData ?ConnectionFactory経由で取得?(PostgreSQL対?
436             *
437             * @throws SQLException Connection のオープンに失敗した??
438             */
439            public void startDelete() throws SQLException {
440                    execCnt = 0;
441                    query = getDeleteSQL();
442                    conn  = ConnectionFactory.connection( connID,appInfo );
443                    pstmt = conn.prepareStatement( query );
444                    // 5.1.2.0 (2010/01/01) setObject に ParameterMetaData の getParameterType を渡す?(PostgreSQL対?
445    //              useParamMetaData = ApplicationInfo.useParameterMetaData( conn );
446                    useParamMetaData = ConnectionFactory.useParameterMetaData( connID );    // 5.3.8.0 (2011/08/01)
447                    if( useParamMetaData ) {
448                            pMeta = pstmt.getParameterMetaData();
449                    }
450            }
451    
452            /**
453             * ??タ配?を渡して実際のDB処?実行します?
454             *
455             * こ?処??前に、startXXXX をコールしておき、INSER,UPDATE,DELETEのどの
456             * 処?行うか?宣?ておく?があります?
457             * 戻り?は、この処?の処?数です?
458             * ?件数は、close( boolean ) 時に取得します?
459             *
460             * @og.rev 4.0.0.0 (2007/11/28) SQLException をきちんと伝播させます?
461             * @og.rev 5.1.2.0 (2010/01/01) setObject に ParameterMetaData の getParameterType を渡す?(PostgreSQL対?
462             * @og.rev 5.3.8.0 (2011/08/01) useParamMetaData 時? setNull 対?PostgreSQL対?
463             *
464             * @param       values  カラ???names) に対応する設定?配?
465             *
466             * @return      ここでの処?数
467             *
468             * @see    #close( boolean )
469             * @throws SQLException Connection のクロースに失敗した??
470             * @throws RuntimeException Connection DB処??実行に失敗した??
471             */
472            public int execute( final String[] values ) throws SQLException {
473                    final int cnt;
474                    try {
475                            int clmNo = 1;  // JDBC のカラ?号は?から始まる?
476    
477                            // 5.1.2.0 (2010/01/01) setObject に ParameterMetaData の getParameterType を渡す?(PostgreSQL対?
478                            if( useParamMetaData ) {
479                                    // keys に値を割り当てます?
480                                    for( int i=0; i<keys.length; i++ ) {
481                                            int type = pMeta.getParameterType( clmNo );
482                                            // 5.3.8.0 (2011/08/01) setNull 対?
483    //                                      pstmt.setObject( clmNo++,values[keysNo[i]],type );
484                                            String val = values[keysNo[i]];
485                                            if( val == null || val.isEmpty() ) {
486                                                    pstmt.setNull( clmNo++, type );
487                                            }
488                                            else {
489                                                    pstmt.setObject( clmNo++,val,type );
490                                            }
491                                    }
492    
493                                    // where 条件を使用する場合?、?を割り当てます?
494                                    if( useWhere ) {
495                                            for( int i=0; i<whereNo.length; i++ ) {
496                                                    int type = pMeta.getParameterType( clmNo );
497                                                    // 5.3.8.0 (2011/08/01) setNull 対?
498    //                                              pstmt.setObject( clmNo++,values[whereNo[i]],type );
499                                                    String val = values[whereNo[i]];
500                                                    if( val == null || val.isEmpty() ) {
501                                                            pstmt.setNull( clmNo++, type );
502                                                    }
503                                                    else {
504                                                            pstmt.setObject( clmNo++,val,type );
505                                                    }
506                                            }
507                                    }
508                            }
509                            else {
510                                    // keys に値を割り当てます?
511                                    for( int i=0; i<keys.length; i++ ) {
512                                            pstmt.setObject( clmNo++,values[keysNo[i]] );
513                                    }
514    
515                                    // where 条件を使用する場合?、?を割り当てます?
516                                    if( useWhere ) {
517                                            for( int i=0; i<whereNo.length; i++ ) {
518                                                    pstmt.setObject( clmNo++,values[whereNo[i]] );
519                                            }
520                                    }
521                            }
522    
523                            cnt = pstmt.executeUpdate();
524                            execCnt += cnt;
525                    }
526                    catch (SQLException ex) {
527                            Closer.stmtClose( pstmt );
528                            pMeta = null;           // 5.1.2.0 (2010/01/01)
529                            if( conn != null ) {
530                                    conn.rollback();
531                                    ConnectionFactory.remove( conn,connID );
532                                    conn = null;
533                            }
534                            String errMsg = "DB処??実行に失敗しました? + CR
535                                                    + " query=[" + query + "]" + CR
536                                                    + " values=" + StringUtil.array2csv( values );
537    //                      throw new RuntimeException( errMsg );
538                            throw new RuntimeException( errMsg ,ex );
539                    }
540                    return cnt;
541            }
542    
543            /**
544             * DB処?クロースします?
545             *
546             * 引数には、commit させる?合?、true を?rollback させる?合?、false をセ?します?
547             * 戻り?は、今まで処?れた合計データ件数です?
548             * こ?処??、SQLException を?部で RuntimeException に変換して?為、catch ??
549             * 不要ですが、? finally ?呼び出してください。そ?な?、リソースリークの
550             * 原因になります?
551             *
552             * @og.rev 5.1.2.0 (2010/01/01) pMeta のクリア
553             *
554             * @param  commitFlag コミットフラグ [true:commitする/false:rollbacする]
555             *
556             * @return      今までの合計??数
557             */
558            public int close( final boolean commitFlag ) {
559                    if( conn != null ) {
560                            try {
561                                    if( commitFlag ) {      conn.commit();  }
562                                    else {                          conn.rollback(); }
563                            }
564                            catch (SQLException ex) {
565                                    ConnectionFactory.remove( conn,connID );
566                                    conn = null;
567                                    String errMsg = "DB処?確?COMMIT)できませんでした? + CR
568                                                            + " query=[" + query + "]" + CR ;
569                                    throw new RuntimeException( errMsg,ex );
570                            }
571                            finally {
572                                    Closer.stmtClose( pstmt );
573                                    pMeta = null;           // 5.1.2.0 (2010/01/01)
574                                    ConnectionFactory.close( conn,connID );
575                                    conn = null;
576                            }
577                    }
578    
579                    return execCnt;
580            }
581    
582            /**
583             * ??配?中の値とマッチするアドレスを検索します?
584             * ??配?がソートされて??、バイナリサーチが使えません。よって?
585             * 総当りでループ検索して?す?
586             * 総数が多い場合??くなる為、???にセ?して使用することを検討く???
587             *
588             * @param       data    ターゲ?の??配?中
589             * @param       key     検索する??
590             *
591             * @return  ターゲ?の添え?存在しな??合??1)
592             */
593            private int findAddress( final String[] data,final String key ) {
594                    int address = -1;
595                    if( data != null && key != null ) {
596                            for( int i=0; i<data.length; i++ ) {
597                                    if( key.equalsIgnoreCase( data[i] ) ) {
598                                            address = i;
599                                            break;
600                                    }
601                            }
602                    }
603                    return address;
604            }
605    }