SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

japan.internet.com翻訳記事

Jakarta Commonsを使ってJDKクラスを拡張する:パート3

Commons CLI/VFS/Configuration/Poolの利用

Configuration

 Commons Configurationは、プロパティファイルにアクセスするタイプの企業向けソフトウェアに役立つコンポーネントです。この機能によって、アプリケーションはさまざまな場所から読み込まれる設定情報を統一された方法で参照できます。

 このAPIには、他にも便利な機能があります。

  • 各種のソース(JNDI、データベース、テキストファイル、XMLファイル、メモリ、システムプロパティ、アプレット、サーブレット初期化プロパティなど)に格納されている設定プロパティへの透過的アクセス
  • リロードストラテジに基づくプロパティの自動リロード機能(このリロードストラテジはストラテジクラスの記述によってカスタマイズ可能)
  • 変更されたプロパティの自動保存機能
  • XPath風の構文を使ったXML設定情報へのアクセス

 アプリケーションのモジュールコンテキストにorg.apache.commons.configuration.Configurationのインスタンスへの参照が含まれている場合は、アプリケーションに必要なプロパティをそのモジュール内のすべてのクラスで簡単に利用することができます。

 Jakartaのサイトでは、このAPIが初歩的なサンプルと共にわかりやすく紹介されています。なお、プロパティを記憶域に自動保存する機能は、保存先がファイルの場合にのみサポートされます。

 今回紹介するサンプルアプリケーションは、リモートのSNTP(Simple Network Time Protocol)サーバーとの間でシステム時刻の同期をとるものです。ただし、実際にSNTPサーバーに対して同期処理を行うメソッドは実装されておらず、Commons Configurationのデモ用スケルトンコードになっています。このサンプルの完全なソースコードは「in.co.narayanan.commons.config」パッケージに含まれています。

 リスト10は、このサンプルアプリケーションで設定が必要なプロパティです。ここで、プロパティの内容を簡単に紹介しておきます。

  • syncintervalhours ― 同期の間隔を表す整数型プロパティ
  • enablesync ― 同期処理のオンオフを表す論理型プロパティ
  • <name> ― このツールが接続するSNTPサーバーの名前を表す文字列配列のプロパティ
  • lastsync ― 最後に成功した同期のタイムスタンプを表す文字列(同期完了のたびに記録される)
リスト10 サンプルアプリケーションで使用する設定ファイル
application.properties
syncintervalhours=12
enablesync=true
#This property is set after the first run
lastsync=<timestamp in milliseconds>

sntpservers.xml
<servers>
    <name>server1</name>
    <name>server2</name>
    <name>server3</name>
</servers>

 リスト11は、Commons Configurationを利用して、このサンプルアプリケーションの設定ファイルにアクセスするためのインターフェイスです。

リスト11 サンプルアプリケーションの設定情報にアクセスするためのインターフェイス
public interface IConfiguration {
    void setStringConfig(String nameSpace, String key, String value);
    String getStringConfig(String nameSpace, String key);
    String[] getStringArrayConfig(String nameSpace, String key);
    void setBooleanConfig(
        String nameSpace, String key, boolean value);
    boolean getBooleanConfig(String nameSpace, String key);
    void setIntConfig(String nameSpace, String key, int value);
    int getIntConfig(String nameSpace, String key);
}

 このインターフェイスによって、Commons Configuration APIの機能にアクセスしようとするアプリケーションのクラスを分離することができます。このインターフェイスには、文字列、整数型、論理型、文字列配列のプロパティを取得/設定するためのメソッドが用意されています。

 リスト12のコードは、このインターフェイスを実装したApplicationConfigurationクラスの一部です。

リスト12 Commons Configuration APIを用いたプロパティの読み込み
/**
 * Get the config property value from configuration storage. The
 * properties are loaded if it is not already loaded for the
 * given namespace.
 * 
 * @param nameSpace Name of the configuration group
 * @param key Unique key within the namespace
 * @return Sring value of the property. Null if the property
 *         is not found or if the configuration cannot be loaded
 */
public String getStringConfig(String nameSpace, String key) {
    Configuration config = getConfiguration(nameSpace);
    if(config != null) {
        return config.getString(key);
    }
    return null;
}
 
private synchronized Configuration getConfiguration
    (String nameSpace) {
    Configuration config = configs.get(nameSpace);
    if(config == null) {
        try {
            if("application".equals(nameSpace)) {
                config = new PropertiesConfiguration(
                    "application.properties");
            } else if("sntpservers".equals(nameSpace)) {
                config = 
                new XMLConfiguration(
                    getClass().getResource("sntpservers.xml"));
            }
            configs.put(nameSpace, config);
        } catch (ConfigurationException e) {
            System.out.println("Unable to load the configuration:"
                + e.getMessage());
        }
    }
    return config;
}

 太字の行は、取得メソッドが呼び出されたときにテキストファイルおよびXMLファイルからプロパティを読み込むコードです。Configurationオブジェクトは、nameSpaceごとに内部マップに格納されます。これによって、プロパティどうしを混同することなく、設定情報の読み込みと格納が独立して行われます。種類の異なるプロパティが別々の場所から読み込まれる可能性がある場合にはorg.apache.commons.configuration.CompositeConfigurationクラスを使用できます(詳細については、こちらを参照)。

 リスト13に、この設定を記憶域に再保存する方法を示します。

リスト13 テキストファイルへの設定の再保存
private synchronized void save(Configuration config) {
    if(config instanceof FileConfiguration) {
        try {
            // If reloading strategy is set, then the properties
            // doesn't get saved
        ((FileConfiguration)config).save();
        } catch (ConfigurationException e) {
            System.out.println("Config not saved. Error while saving."
                + e.getMessage());
        }
    } else {
        System.out.println("Config not saved. Not supported.");
    }
}
注意
 私の環境では、リロードストラテジをConfigurationのインスタンスに設定しているときに、プロパティをテキストファイルに保存すると問題が生じました(プロパティファイルの用法の詳細については、こちらを参照)。

 リスト14に、アプリケーションのクラス内でこのコンテキストを通して設定プロパティにアクセスする方法を示します。

リスト14 アプリケーションのコンテキストを用いた設定情報へのアクセス
void syncTime() {
    if(shouldSyncNow()) {
        context.getLogger().log(Level.INFO, "Sync started");
        sync();
        recordSyncTime();
    } else {
        context.getLogger().log(Level.INFO,
            "Sync skipped. Time not yet arrived");
    }
}

private boolean shouldSyncNow() {
    boolean enableSync = context.getConfiguration()
        .getBooleanConfig("application", "enablesync");
    context.getLogger().log(Level.INFO, "enablesync:" + enableSync);
    if(enableSync) {
        if(getCurrentTime() > readLastSync() + getInterval()) {
            return true;
        }
    }
    return false;
}

/**
 * Use SNTP API to sync the time.
 */
private void sync() {
    String servers[] = context.getConfiguration()
                      .getStringArrayConfig("sntpservers", "name");
    for(String server : servers) {
        context.getLogger().log(Level.INFO, "Time Server:" + server);
    }

    // Use the list of server to sync the system time.
    // sntp API for java can be used here
    context.getLogger().log(Level.INFO, "Syncing time..");
}

 このコードでは、必要なプロパティを取り出すために、ロガーへの参照とコンフィギュレーションクラスを取得しています。各プロパティの使い方については、in.co.narayanan.commons.config.SyncTimeクラスを調べるとよいでしょう。

 リスト15は、SyncTimeクラスの動作を確認するためのテストケースクラスです。

リスト15 SyncTimeクラスの動作を検証するテストケースクラス
public class TestSyncTime extends TestCase {
    public void testSyncTime() {
        Logger consoleLogger = Logger.getAnonymousLogger();
        ApplicationContext context = new ApplicationContext();
        context.setLogger(consoleLogger);
        context.setConfiguration(new ApplicationConfiguration());

        SyncTime sync = new SyncTime(context);
        sync.syncTime();
        sync.syncTime();
    }
}

 このテストケースクラスでは、Javaのロガーとコンフィギュレーションクラスを初期化し、これらをアプリケーションコンテキストにセットして、SyncTimeクラスに依存関係を与えています。

 Commons Configurationを使えば、さまざまな場所で提供されている外部プロパティにアクセスできます。これは確かに便利なコンポーネントですが、企業向けソフトウェアの場合は、JNDIやデータベースを利用するディレクトリサーバーにプロパティを自動保存する必要があるため、改良の余地があるでしょう。しかし、単純なテキストファイルやXMLファイル上でプロパティを扱うのであれば、このフレームワークの利用を検討する価値があります。

次のページ
Pool

この記事は参考になりましたか?

japan.internet.com翻訳記事連載記事一覧

もっと読む

この記事の著者

japan.internet.com(ジャパンインターネットコム)

japan.internet.com は、1999年9月にオープンした、日本初のネットビジネス専門ニュースサイト。月間2億以上のページビューを誇る米国 Jupitermedia Corporation (Nasdaq: JUPM) のニュースサイト internet.comEarthWeb.com からの最新記事を日本語に翻訳して掲載するとともに、日本独自のネットビジネス関連記事やレポートを配信。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

Narayanan A.R.(Narayanan A.R.)

テスト駆動開発、アジャイル方法論、Javaテクノロジ、およびデザインパターンの熱烈な擁護者。Javaテクノロジを使ったソフトウェアのデザインおよび開発に携わって数年になる。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/313 2006/04/11 19:10

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー