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.db;
017
018import java.io.File;
019import java.net.URL;
020import java.util.ArrayList;
021import java.util.Arrays;
022import java.util.Comparator;
023import java.util.LinkedHashMap;
024import java.util.List;
025import java.util.Locale;
026import java.util.Map;
027
028import org.opengion.fukurou.util.StringUtil;
029import org.opengion.fukurou.util.FileUtil;
030import org.opengion.fukurou.util.LogWriter;
031import org.opengion.fukurou.xml.DomParser;
032import org.w3c.dom.Document;
033import org.w3c.dom.Element;
034import org.w3c.dom.Node;
035import org.w3c.dom.NodeList;
036
037/**
038 * DB設定XMLの内容をJAXBを利用してロードする
039 * Driverをロードする
040 * 上記2つの機能を備えたクラスです
041 *
042 * 外部からはgetDbidメソッドを利用してDB設定(ExpandedDbid型)を取得します。
043 * DB設定情報が無い場合にXMLを読みにいきます。
044 * このDBIDを決めるキーは、内部取り込み字に、大文字変換されますので、大文字・
045 * 小文字の区別はありません。
046 *
047 * @og.rev 4.0.0.0 (2007/10/25) 新規作成
048 * @og.rev 5.1.7.0 (2010/06/01) org.opengion.fukurou.xml.jaxb.dbid 関係 廃止
049 * @og.group 初期化
050 *
051 * @version  4.0
052 * @author 高橋正和
053 * @since   JDK6.0,
054 */
055public class DatabaseConfig {
056
057        // fukurou内で完結させるため、HybsDataからは読み込まずにここに書く
058        private static final String DEFAULT_DRIVER       = "oracle.jdbc.OracleDriver";
059
060        // XMLファイル関連
061//      private transient final String XmlFilename;
062//      private final String XmlFilename;
063        private final String xmlFilename;                               // 5.7.2.2 (2014/01/24)
064//      private static final String SCHEMA_FILENAME = "DBConfig.xsd";//xsdはfukurou.xml.jaxb.dbidパッケージに置く
065
066//      private transient final Map<String, EDbid> dbidMap = new HashMap<String, EDbid>();
067//      private transient List<String> driverList = new ArrayList<String>();
068//      private Map<String, EDbid> dbidMap = new HashMap<String, EDbid>();
069        private Map<String, EDbid> dbidMap = new LinkedHashMap<String, EDbid>();            // 5.6.7.0 (2013/07/27)
070//      private List<String> driverList = new ArrayList<String>();
071        private List<String> driverList = new ArrayList<String>();
072
073        // 5.6.7.0 (2013/07/27) プルダウンメニュー用の情報の、キャッシュ用変数。
074        private String codeKeyVal = null;               // 初めて要求されたときに、セットします。
075
076//      private static final String CR = System.getProperty( "line.separator" );
077
078        /* DBIDのキーの一覧を管理します。5.1.9.0 (2010/08/01) */
079        // 5.5.2.0 (2012/05/01) property追加
080//      private static final String[] DBID_INFO_KEYS
081//                              = { "dbidKey", "url", "user", "password", "readonly"
082//                                      , "mincount", "maxcount", "pooltime", "applicationInfo" };
083//      private static final String[] DBID_INFO_KEYS
084//                              = { "dbidKey", "url", "user", "password", "readonly"
085//                                      , "mincount", "maxcount", "pooltime", "applicationInfo","property" };
086        // 5.6.6.0 (2013/07/05) 表題(title)属性を追加
087        private static final String[] DBID_INFO_KEYS
088                                = { "dbidKey", "title", "url", "user", "password", "readonly"
089                                        , "mincount", "maxcount", "pooltime", "applicationInfo","property" };
090
091        /* DBDRIVERのキーのを管理します。5.1.9.0 (2010/08/01) */
092        private static final String DBDRIVER_CLASS_KEY = "class";
093
094        /**
095         * 初期値を使ってXMLを読み込む
096         * xmlFilenameの初期値は../DBConfig.xml
097         *
098         * @og.rev 4.3.1.1 (2008/08/23) 自分のコンストラクターを呼ぶように修正
099         */
100        public DatabaseConfig() {
101                this( "../DBConfig.xml" );
102        }
103
104        /**
105         * XMLファイルの名前を指定して読み込む
106         *
107         * @og.rev 5.1.9.0 (2010/08/01) クラスローダー外からでもDBConfig.xmlを取得できるようにする
108         * @og.rev 5.6.7.0 (2013/07/27) オブジェクト作成時に初期化も行っておきます。
109         * @og.rev 5.6.8.2 (2013/09/20) Tomcat8で、クラスローダーが変更されているのでその対応
110         * @og.rev 5.7.2.2 (2014/01/24) WEB-INF/classes フォルダがないと、xmlURL がnull になる対応。
111         * @og.rev 5.7.2.3 (2014/01/31) ファイルの存在チェックを追加します。
112         *
113         * @param       xmlfile XMLファイルの名前
114         */
115        public DatabaseConfig( final String xmlfile ) {
116//              xmlFilename = xmlfile;
117                String fileName = null;
118
119                ClassLoader clsl        = getClass().getClassLoader();
120                URL xmlURL                      = clsl.getResource( xmlfile );
121
122                if( xmlURL != null ) {
123                        fileName = xmlURL.getFile();
124                        // 5.7.2.3 (2014/01/31) ファイルの存在チェックを追加します。
125                        if( ! new File( fileName ).exists() ) { fileName = null; }
126                }
127                // 5.6.8.2 (2013/09/20) Tomcat8で、xmlURL が取得できなくなっている・・・ようだ。
128                else {
129                        xmlURL = clsl.getResource( "/" );               // クラスパスのベースURL
130                        // 5.7.2.2 (2014/01/24) Tomcat7で、WEB-INF/classes フォルダがないと、xmlURL がnull になる。
131                        if( xmlURL != null ) {
132                                File temp = new File( xmlURL.getPath() , xmlfile );
133                                if( temp.exists() ) { fileName = temp.getAbsolutePath(); }
134                        }
135                }
136
137                // 5.1.9.0 (2010/08/01)  クラスローダー外からでもDBConfig.xmlを取得できるようにする
138                if( fileName == null && new File( xmlfile ).exists() ) {
139                        fileName = xmlfile;
140                }
141
142                if( fileName == null ) {
143                        // 5.5.7.2 (2012/10/09) コメント追加
144                        String errMsg = "DBConfig.xmlが見つかりません。File=[" + xmlfile + "]\n" 
145                                                                + " WEB-INF/classes フォルダがないと、相対パスで見つけることができません。" ;
146                        throw new RuntimeException( errMsg );
147//                      throw new RuntimeException( "DBConfig.xmlが見つかりません。File=[" + xmlfile + "]" );
148                }
149
150                xmlFilename                     = fileName;
151//              System.out.println( xmlFilename );
152
153                init();                 // 5.6.7.0 (2013/07/27)
154        }
155
156        /**
157         * dbidKeyをキーにしてExpandedDbid型でマップの内容を返す。
158         * 存在しない場合はNULLを返します。
159         * キーが無い場合に初期化を行う。
160         *
161         * @og.rev 4.0.0.1 (2007/12/04) EDbid#clone() 廃止
162         * @og.rev 5.6.7.0 (2013/07/27) synchronized メソッドにします。
163         *
164         * @param key XMLで登録したdbidKey
165         *
166         * @return EDbid型オブジェクト
167         */
168        public synchronized EDbid getDbid( final String key ) {
169//              synchronized ( dbidMap ) {
170//                      if( dbidMap.isEmpty() ) {
171//                              init();
172//                      }
173
174                        return dbidMap.get( key.toUpperCase( Locale.JAPAN ) ) ;
175//              }
176        }
177
178        /**
179         * マップをクリアします。
180         * XMLファイルを再読み込みする場合に使用します。
181         *
182         * @og.rev 5.1.9.0 (2010/08/01) ドライバーのリストもクリアする。
183         * @og.rev 5.6.7.0 (2013/07/27) synchronized メソッドにします。
184         */
185        public synchronized void reload() {
186//              synchronized ( dbidMap ) {
187                        dbidMap.clear();
188//              }
189//              synchronized ( driverList ) {
190                        driverList.clear();
191//              }
192                init();
193        }
194
195        /**
196         * 初期化処理
197         *
198         * DB設定XMLファイル(DBConfig.xml)を読み込みます。
199         * このファイルから、ドライバーリストの取得、DBIDのオブジェクトマップの作成を
200         * 行います。
201         * EDbidオブジェクト は、環境変数で、共通の初期値を定義しておくことが可能です。
202         * 項目として、REALM_URL、REALM_NAME、REALM_PASSWORD が設定可能です。
203         *
204         * ドライバーリストの取得後、Class.forName で、ドライバの登録も行います。
205         *
206         * @og.rev 5.1.7.0 (2010/06/01) org.opengion.fukurou.xml.jaxb.dbid 関係 廃止
207         * @og.rev 5.6.7.0 (2013/07/27) dbidMap,driverList を書き込むのではなく、作成します。
208         */
209        private void init() {
210                Document doc = DomParser.read( new File(xmlFilename) ) ;
211                Element firstRoot = doc.getDocumentElement();
212
213//              List<String> driverList = getDriverList( firstRoot );
214//              driverList = getDriverList( firstRoot );
215                makeDriverList( firstRoot );                            // 5.6.7.0 (2013/07/27)
216
217                // 5.6.7.0 (2013/07/27) を、かけておきます。
218                synchronized ( this ) {
219                        for( String dr : driverList ) {
220                                try {
221                                        Class.forName( dr );
222                                } catch ( ClassNotFoundException ex ) {
223                                        String errMsg = "ドライバクラスが見つかりません。[" + dr + "]" ;
224                                        LogWriter.log( errMsg );
225                                        LogWriter.log( ex );
226                                }
227                        }
228                }
229
230                EDbid defDdbid = new EDbid();           // 初期値
231                defDdbid.setUrl(                System.getenv( "REALM_URL" ) );
232                defDdbid.setUser(               System.getenv( "REALM_NAME" ) );
233                defDdbid.setPassword(   System.getenv( "REALM_PASSWORD" ) );
234
235//              dbidMap = getDbidMap( firstRoot,defDdbid );
236                makeDbidMap( firstRoot,defDdbid );                              // 5.6.7.0 (2013/07/27)
237        }
238
239        /**
240         * ドライバーリストを取得します。
241         *
242         * DB設定XMLファイル(DBConfig.xml)の、class タグを取り込みます。
243         * このファイルから、ドライバーリストを取得します。
244         *
245         * 内部的に3段階の処理が実行されます。
246         * 第1Step:DBConfig.xml から、ドライバーリストを取得
247         * 第2Step:ドライバーリストが存在しない場合、環境変数の REALM_DRIVER からドライバーを取得
248         * 第3Step:それでも存在しない場合、このクラスの DEFAULT_DRIVER 定数 からドライバーを取得
249         *
250         * @og.rev 5.1.7.0 (2010/06/01) org.opengion.fukurou.xml.jaxb.dbid 関係 廃止
251         * @og.rev 5.1.9.0 (2010/08/01) ドライバ一覧のListをオブジェクト変数化
252         * @og.rev 5.6.7.0 (2013/07/27) driverList を書き込むのではなく、作成します。
253         * @og.rev 5.6.7.0 (2013/07/27) synchronized メソッドにします。
254         *
255         * @param       element DB設定XMLファイルのElementオブジェクト
256         */
257//      private static List<String> getDriverList( final Element element ) {
258        private void makeDriverList( final Element element ) {
259//              List<String> dList = new ArrayList<String>();
260
261                NodeList list = element.getElementsByTagName( "class" ) ;
262                int num = list.getLength();
263                for (int i = 0; i < num; i++) {
264                        Element cls = (Element)list.item(i);
265//                      dList.add( cls.getTextContent() );
266                        driverList.add( cls.getTextContent() );
267                }
268
269//              if( dList.isEmpty() ) {
270                if( driverList.isEmpty() ) {
271                        String realmDriver = System.getenv( "REALM_DRIVER" );
272                        if( realmDriver != null && realmDriver.length() > 0 ) {
273//                              dList.add( realmDriver );
274                                driverList.add( realmDriver );
275                        }
276                }
277
278//              if( dList.isEmpty() ) { dList.add( DEFAULT_DRIVER ); }
279                if( driverList.isEmpty() ) { driverList.add( DEFAULT_DRIVER ); }
280
281//              return dList ;
282        }
283
284        /**
285         * EDbidオブジェクトのマップを取得します。
286         *
287         * DB設定XMLファイル(DBConfig.xml)の、dbid タグを取り込みます。
288         * このファイルから、EDbidオブジェクトの属性情報を取得し、オブジェクトを構築します。
289         *
290         * EDbidオブジェクト は、初期値をコピーして、作成していきます。
291         * EDbidオブジェクトをマップから取り出すキーとなる、dbidKey は、大文字化して設定します。
292         *
293         * @og.rev 5.1.7.0 (2010/06/01) org.opengion.fukurou.xml.jaxb.dbid 関係 廃止
294         * @og.rev 5.1.9.0 (2010/08/01) Mapを返すように変更
295         * @og.rev 5.5.2.0 (2012/05/01) property追加
296         * @og.rev 5.6.6.0 (2013/07/05) 表題(title)属性の取得
297         * @og.rev 5.6.7.0 (2013/07/27) 内部MapをDBConfig.xmlの読み込み順に変更。
298         * @og.rev 5.6.7.0 (2013/07/27) dbidMap を書き込むのではなく、作成します。
299         * @og.rev 5.6.7.0 (2013/07/27) synchronized メソッドにします。
300         * @og.rev 5.6.7.1 (2013/08/09) DEFAULT と、RESOURCE の DBIDキーがなければ、内部的に作成します。
301         * @og.rev 5.6.8.0 (2013/09/06) RESOURCE の DBIDキーを内部作成時に、title も設定します。
302         *
303         * @param  element DB設定XMLファイルのElementオブジェクト
304         * @param  defDdbid 初期情報の設定された、EDbidオブジェクト
305         */
306//      private void makeDbidMap( final Element element , EDbid defDdbid ) {
307//      private static Map<String,EDbid> getDbidMap( final Element element , EDbid defDdbid ) {
308        private void makeDbidMap( final Element element , EDbid defDdbid ) {
309//              Map<String,EDbid> dMap = new HashMap<String,EDbid>();               // 5.6.7.0 (2013/07/27)
310
311                NodeList list = element.getElementsByTagName( "dbid" ) ;
312                int num = list.getLength();
313                for (int i = 0; i < num; i++) {
314                        Element ele = (Element)list.item(i);
315                        NodeList childs = ele.getChildNodes();
316                        int numChild = childs.getLength();
317//                      EDbid dbid = new EDbid();
318                        EDbid dbid = defDdbid.clone();          // 初期値をコピーして、作成
319                        for (int j = 0; j < numChild; j++) {
320                                Node nd = childs.item(j);
321                                if( nd.getNodeType() == Node.ELEMENT_NODE ) {
322                                        Element el = (Element)nd;
323                                        String tag = el.getTagName();
324                                        // dbidKey は、toUpperCase して、大文字のみとする。
325                                        if( "dbidKey".equals( tag ) )   {
326                                                String dbidKey = el.getTextContent();
327                                                if( dbidKey != null && dbidKey.length() > 0 ) {
328                                                        dbid.setDbidKey( dbidKey.toUpperCase( Locale.JAPAN ) );
329                                                }
330                                        }
331                                        else if( "title".equals( tag ) )        { dbid.setTitle(        el.getTextContent() ); }                // 5.6.6.0 (2013/07/05) 表題(title)属性の取得
332                                        else if( "url".equals( tag ) )          { dbid.setUrl(          el.getTextContent() ); }
333                                        else if( "user".equals( tag ) )         { dbid.setUser(         el.getTextContent() ); }
334                                        else if( "password".equals( tag ) ) { dbid.setPassword( el.getTextContent() ); }
335                                        else if( "readonly".equals( tag ) ) { dbid.setReadonly( el.getTextContent() ); }
336                                        else if( "mincount".equals( tag ) ) { dbid.setMincount( el.getTextContent() ); }
337                                        else if( "maxcount".equals( tag ) ) { dbid.setMaxcount( el.getTextContent() ); }
338                                        else if( "pooltime".equals( tag ) ) { dbid.setPooltime( el.getTextContent() ); }
339                                        else if( "applicationInfo".equals( tag ) ) { dbid.setApplicationInfo( el.getTextContent() ); }
340                                        else if ("property".equals( tag ) ) { dbid.addProp( el.getTextContent() ); } // 5.5.2.0 (2012/05/01)
341                                        else {
342                                                System.err.println( "警告:dbid に新しい属性が、追加されています。" );
343                                        }
344                                }
345                        }
346//                      dbidMap.put( dbid.getDbidKey(), dbid );
347//                      dMap.put( dbid.getDbidKey(), dbid );
348                        dbidMap.put( dbid.getDbidKey(), dbid );         // 5.6.7.0 (2013/07/27) 復活
349                }
350
351                // 5.6.7.1 (2013/08/09) DEFAULT と、RESOURCE の DBIDキーがなければ、内部的に作成します。
352                EDbid dbid_D = dbidMap.get( "DEFAULT" );                // DEFAULT が存在するか確認する。
353                if( dbid_D == null ) {
354                        dbid_D = defDdbid.clone();                                      // 初期値をコピー
355                        dbid_D.setDbidKey( "DEFAULT" );
356                        dbidMap.put( "DEFAULT", dbid_D );
357                }
358
359                EDbid dbid_R = dbidMap.get( "RESOURCE" );               // RESOURCE が存在するか確認する。
360                if( dbid_R == null ) {
361                        dbid_R = dbid_D.clone();                                        // DEFAULT の DBIDをコピー(必ず存在するはず)
362                        dbid_R.setDbidKey( "RESOURCE" );
363                        dbid_R.setTitle( "RESOURCE" );                          // 5.6.8.0 (2013/09/06) title も設定します。
364                        dbidMap.put( "RESOURCE", dbid_R );
365                }
366
367//              return dMap;
368        }
369
370        /* ------------------------------------------------------------------------------------
371         *
372         * 以下は、DBConfig.xml編集用のメソッドです。
373         * 編集用のメソッドでは、オブジェクト化されたDBID及びDBDRIVERの情報は使用せずに、
374         * DBConfig.xmlからその情報を再度読み出して、SET/GETしています。
375         * (オブジェクトとして依存しているのは、DBConfig.xmlのファイル名のみです)
376         *
377         * -------------------------------------------------------------------------------------
378         */
379        /**
380         * DBIDとして管理している項目のキーの一覧を配列形式で返します。
381         *
382         * @og.rev 5.1.9.0 (2010/08/01) 新規作成
383         *
384         * @return 項目のキー一覧
385         */
386        public static String[] getDbidInfoKeys() {
387//              return DBID_INFO_KEYS;
388                return DBID_INFO_KEYS.clone();
389        }
390
391        /**
392         * 全てのDBIDの属性情報のリスト(配列)で返します。
393         *
394         * 値の順番については、{@link #getDbidInfoKeys()}で返されるキーの一覧と同じです。
395         *
396         * @og.rev 5.1.9.0 (2010/08/01) 新規作成
397         * @og.rev 5.5.2.1 (2012/05/07) propertiesを出力
398         * @og.rev 5.6.6.0 (2013/07/05) 表題(title)属性を追加
399         * @og.rev 5.6.7.0 (2013/07/27) 内部MapをDBConfig.xmlの読み込み順に変更。
400         *
401         * @return 全てのDBIDの属性情報のリスト(配列)
402         * @see #getDbidInfoKeys()
403         */
404        public synchronized String[][] getDbidInfo() {
405//              Element ele = DomParser.read( new File(xmlFilename) ).getDocumentElement();
406//              Map<String,EDbid> dMap = getDbidMap( ele , new EDbid() );
407//              String[][] dbidInfo = new String[dMap.size()][DBID_INFO_KEYS.length];
408
409                String[][] dbidInfo = new String[dbidMap.size()][DBID_INFO_KEYS.length];
410                int idx = 0;
411//              for( EDbid dbid : dMap.values() ) {
412                for( EDbid dbid : dbidMap.values() ) {
413                        dbidInfo[idx][0] = dbid.getDbidKey();
414                        dbidInfo[idx][1] = dbid.getTitle();                             // 5.6.6.0 (2013/07/05) 表題(title)属性を追加
415                        dbidInfo[idx][2] = dbid.getUrl();
416                        dbidInfo[idx][3] = dbid.getUser();
417                        dbidInfo[idx][4] = dbid.getPassword();
418                        dbidInfo[idx][5] = String.valueOf( dbid.isReadonly() );
419                        dbidInfo[idx][6] = String.valueOf( dbid.getMincount() );
420                        dbidInfo[idx][7] = String.valueOf( dbid.getMaxcount() );
421                        dbidInfo[idx][8] = String.valueOf( dbid.getPooltime() );
422                        dbidInfo[idx][9] = String.valueOf( dbid.isApplicationInfo() );
423                        dbidInfo[idx][10]= String.valueOf( dbid.getProps().toString() ); // 5.5.2.1 (2012/05/07)
424                        idx++;
425                }
426                // 5.6.7.0 (2013/07/27) 内部MapをDBConfig.xmlの読み込み順に変更(なので、廃止)。
427//              dbidSort( dbidInfo );
428                return dbidInfo;
429        }
430
431        /**
432         * 全てのDBIDの属性情報のリスト(配列)をセットします。
433         *
434         * このメソッドを呼び出すと、DBConfig.xmlで定義されているDBID情報一覧を"一旦削除し"、
435         * その上で、引数のDBID情報一覧をDBConfig.xmlに書き込みます。
436         *
437         * 値の順番については、{@link #getDbidInfoKeys()}で返されるキーの一覧と同じです。
438         *
439         * 書き込みの直前に、同じフォルダにタイムスタンプを付加したバックアップファイルを作成します。
440         *
441         * @og.rev 5.1.9.0 (2010/08/01) 新規作成
442         * @og.rev 5.6.7.0 (2013/07/27) 内部MapをDBConfig.xmlの読み込み順に変更。
443         *
444         * @param dbidVals 全てのDBIDの属性情報のリスト(配列)
445         * @see #getDbidInfoKeys()
446         */
447        public void setDbidInfo( final String[][] dbidVals ) {
448                FileUtil.copy( xmlFilename, xmlFilename + "_" + System.currentTimeMillis() );
449
450                Document doc = DomParser.read( new File(xmlFilename) ) ;
451                Element firstRoot = doc.getDocumentElement();
452                deleteChildElements( firstRoot, "dbid" );
453
454                if( dbidVals != null && dbidVals.length > 0 ) {
455                        // 5.6.7.0 (2013/07/27) 内部MapをDBConfig.xmlの読み込み順に変更(なので、廃止)。
456//                      dbidSort( dbidVals );
457                        for( int i=0; i<dbidVals.length; i++ ) {
458                                Element newEle = doc.createElement( "dbid" );
459                                for( int j=0; j<dbidVals[i].length; j++ ) {
460                                        Element newChEle = doc.createElement( DBID_INFO_KEYS[j] );
461                                        newChEle.setTextContent( dbidVals[i][j] );
462                                        newEle.appendChild( newChEle );
463                                }
464                                firstRoot.appendChild( newEle );
465                                firstRoot.appendChild( doc.createTextNode( "\n\n" ) );
466                        }
467                }
468
469                DomParser.write( new File(xmlFilename), doc );
470
471                reload();               // 5.6.7.0 (2013/07/27) DBIDの属性情報のリストを更新後、初期化します。
472        }
473
474        /**
475         * DBIDの配列をソートします。
476         * ソートの方法としては、
477         *  @DEFAULTのDBIDは一番初め
478         *  ADEFAULT以外は、DBID順
479         * となります。
480         *
481         * @og.rev 5.6.7.0 (2013/07/27) 内部MapをDBConfig.xmlの読み込み順に変更(なので、廃止)。
482         *
483         * @param dbidVals 全てのDBIDの属性情報のリスト(配列)
484         */
485//      private static void dbidSort( final String[][] dbidVals ) {
486//              Arrays.sort( dbidVals, new Comparator<String[]>() {
487//                       public int compare( String[] s1, String[] s2 ) {
488//                               if( "DEFAULT".equals( s1[0] ) ) {
489//                                       return -1;
490//                               }
491//                               else if( "DEFAULT".equals( s2[0] ) ) {
492//                                       return 1;
493//                               }
494//                               return s1[0].compareTo( s2[0] );
495//                       }
496//              }
497//              );
498//      }
499
500        /**
501         * DBドライバーの属性キーを返します。
502         *
503         * @og.rev 5.1.9.0 (2010/08/01) 新規作成
504         *
505         * @return      DBドライバーの属性キー
506         */
507        public static String getDriverKey() {
508                return DBDRIVER_CLASS_KEY;
509        }
510
511        /**
512         * DBドライバーのリスト(配列)を返します。
513         *
514         * @og.rev 5.1.9.0 (2010/08/01) 新規作成
515         * @og.rev 5.6.7.0 (2013/07/27) driverList を書き込むのではなく、作成します。
516         *
517         * @return      DBドライバーリスト(配列)
518         */
519        public synchronized String[] getDriverList() {
520//              Element ele = DomParser.read( new File(xmlFilename) ).getDocumentElement();
521//              String [] rtn = getDriverList( ele ).toArray( new String[0] );
522
523                String [] rtn = driverList.toArray( new String[driverList.size()] );
524//              driverSort( rtn );
525                return rtn;
526        }
527
528        /**
529         * DBドライバーのリスト(配列)をセットします。
530         *
531         * このメソッドを呼び出すと、DBConfig.xmlで定義されているclass一覧を"一旦削除し"、
532         * その上で、引数のDBドライバー一覧をDBConfig.xmlに書き込みます。
533         *
534         * 書き込みの直前に、同じフォルダにタイムスタンプを付加したバックアップファイルを作成します。
535         *
536         * @og.rev 5.1.9.0 (2010/08/01) 新規作成
537         * @og.rev 5.6.7.0 (2013/07/27) DBドライバーのリストを更新後、初期化します。
538         *
539         * @param drivers DBドライバーのリスト(配列)
540         */
541        public void setDriverList( final String[] drivers ) {
542                FileUtil.copy( xmlFilename, xmlFilename + "_" + System.currentTimeMillis() );
543
544                Document doc = DomParser.read( new File(xmlFilename) );
545                Element firstRoot = doc.getDocumentElement();
546
547                Element parent = (Element)firstRoot.getElementsByTagName( "dbDriver" ).item( 0 );
548                deleteChildElements( parent, "class" );
549
550                if( drivers != null && drivers.length > 0 ) {
551//                      driverSort( drivers );
552                        for( int i=0; i<drivers.length; i++ ) {
553                                Element newEle = doc.createElement( "class" );
554                                newEle.setTextContent( drivers[i] );
555                                parent.appendChild( newEle );
556                        }
557                }
558
559                DomParser.write( new File(xmlFilename), doc );
560
561                reload();               // 5.6.7.0 (2013/07/27) DBドライバーのリストを更新後、初期化します。
562        }
563
564
565        /**
566         * DBID情報のキーとタイトルから、プルダウンメニューを作成するための情報を取得します。
567         *
568         * このメソッドを呼び出すと、DBConfig.xmlで定義されている dbidKey と、 title 属性から、
569         * 「key1:val1 key2:val2 ・・・」という文字列を作成します。
570         * これを利用すれば、プルダウンメニューが簡単に作成できます。
571         *
572         * @og.rev 5.6.7.0 (2013/07/27) プルダウンメニュー用の情報を作成します。
573         * @og.rev 5.6.7.1 (2013/08/09) 表題(title)属性のスペース対策
574         *
575         * @return プルダウンメニューを作成するための情報
576         */
577        public synchronized String getCodeKeyVal() {
578                if( codeKeyVal == null ) {
579                        StringBuilder buf = new StringBuilder();
580                        for( EDbid dbid : dbidMap.values() ) {
581                                String key = dbid.getDbidKey();
582                                String lbl = StringUtil.nval( dbid.getTitle() , key );
583//                              buf.append( " " ).append( key ).append( ":" ).append( lbl );
584                                if( lbl.indexOf( ' ' ) >= 0 ) {                                                                      // 5.6.7.1 (2013/08/09) スペース対策
585                                        buf.append( " " ).append( key ).append( ":\"" ).append( lbl ).append( "\"" );
586                                }
587                                else {
588                                        buf.append( " " ).append( key ).append( ":" ).append( lbl );
589                                }
590                        }
591
592                        codeKeyVal = buf.substring( 1 );                // 先頭のスペースを削除
593                }
594
595                return codeKeyVal;
596        }
597
598        /**
599         * DBドライバーの配列をソートします。
600         * ソートの方法としては、
601         *  @DEFAULT_DRIVERのDBは一番初め
602         *  ADEFAULT以外は、DBID順
603         * となります。
604         *
605         * @og.rev 5.6.7.0 (2013/07/27) 内部ListをDBConfig.xmlの読み込み順に変更(なので、廃止)。
606         *
607         * @param drivers 全てのDBIDの属性情報のリスト(配列)
608         */
609//      private static void driverSort( final String[] drivers ) {
610//              Arrays.sort( drivers, new Comparator<String>() {
611//                       public int compare( String s1, String s2 ) {
612//                               if( DEFAULT_DRIVER.equals( s1 ) ) {
613//                                       return -1;
614//                               }
615//                               else if( DEFAULT_DRIVER.equals( s2 ) ) {
616//                                       return 1;
617//                               }
618//                               return s1.compareTo( s2 );
619//                       }
620//              }
621//              );
622//      }
623
624        /**
625         * 親要素を基点として、引数で指定されたタグ名を持つ子要素を削除します。
626         *
627         * @og.rev 5.6.7.0 (2013/07/27) staticメソッド を イスタンスメソッドに変更
628         *
629         * @param parent 親要素
630         * @param childTagName 削除する子要素のタグ名
631         */
632//      private static void deleteChildElements( final Element parent, final String childTagName ) {
633        private void deleteChildElements( final Element parent, final String childTagName ) {
634                Node child = parent.getFirstChild();
635                boolean isDel = false;
636                while ( child != null ) {
637                        // エレメント間の改行Cも削除するため、次の異なる要素が来るまでは削除し続けます。
638                        if( child.getNodeType() == Node.ELEMENT_NODE ) {
639//                              if( ((Element)child).getTagName().equals( childTagName ) ) {
640                                if( ((Element)child).getTagName().equalsIgnoreCase( childTagName ) ) {
641                                        isDel = true;
642                                }
643                                else {
644                                        isDel = false;
645                                }
646                        }
647
648                        Node next = child.getNextSibling();
649                        if( isDel ) {
650                                parent.removeChild( child );
651                        }
652                        child = next;
653                }
654        }
655}