TANGOSOL Coherence

仕事ネタも日記にしてしまいましょう.(^^;
Coherenceというのは,米TANGOSOL社の製品です.オープンソースではなく,いい値段のする商品(1995$/CPU〜)なのですが,評価版をダウンロードすることが出来ます.
このCoherenceを使うと何が出来るかというと,JVM間でメモリのレプリケーションを行ってくれるんですね.Coherenceというのは一貫性とかそういう意味を持つ単語です.この業界(どこ?)でよく耳にするところでは,SGIIBMのサーバに使われているCC-NUMA(Chache Coherent-Non Uniform Memory Access)というのがありますね.これは,分割された(不均一な)メモリ間でキャッシュの一貫性を保つというアーキテクチャです.CoherenceはこれのJava版といった感じです.もっと身近なところだと,OracleRACに使われているキャッシュ・フュージョンも似ているかな.
ということで,Coherenceもキャッシュの実装クラスを用意してくれています.このキャッシュは,他のJVMとネットワークを越えて内容の一貫性を維持してくれます.つまり,分散キャッシュなんですね.その実装方法(フルレプリケーションとかマスタースレーブとか)やポリシー(悲観的ロックとか楽観的ロックとか)は何種類か用意されていて,必要に応じて選択することが出来るようです.おもしろいことに,この分散キャッシュに対するJCAが提供されていて,分散トランザクションに参加することも出来るのだとか.分散システム全体でトランザクショナルに共有できるキャッシュなんてものが実現できる? 素晴らしいかも!
詳しく調べるのはこれからなのですが,Coherenceに単純なサンプルがついているので眺めてみました.このサンプルはコマンドライン・インタフェースを持っていて,分散キャッシュの内容を表示したり変更したりすることが出来ます.そのコードを見ると,使い方はとても簡単なんですね.
まずは初期化のところで分散キャッシュのインスタンスを取得します.

        NamedCache cache = CacheFactory.getCache("VirtualCache");

NamedCacheクラスは,java.util.Mapimplementsしています.ですから,後はget(Object)put(Object, Object)なんかを使えばいいだけなんですね.超簡単!*1
このサンプル,後はコマンドラインから命令を読み込んでキャッシュ(Map)を操作するだけです.ということで,動かしてしまいしょう.
サンプルを実行すると,コピーライトなどの表示の後に

Command: 

と聞いてくるので,まずはコマンドの一覧を確認.

Command: help

clear
get <key>
keys
info
put <key> <value>
quit
remove <key>

Command: 

楽勝っぽい.
では,キャッシュの内容が空なのを確認した上でエントリを追加してみましょう.

Command: keys


Command: put name koichik

>> Put Complete

Command: keys

>> name

Command: get name

>> Value is koichik

Command: 

キャッシュに値が入りました.
ここで,もう一つのプロセスを起動して,キャッシュの内容を確認します.

Command: keys

>> name

Command: get name

>> Value is koichik

Command: 

おぉ,ちゃんと共有できていますね.こちらからもエントリを追加してみます.

Command: put birthday 08/18

>> Put Complete

Command: 

そして元のプロセスで確認.

Command: keys

>> name
>> birthday

Command: get birthday

>> Value is 08/18

Command: 

いい感じ.
なお,この分散キャッシュはレプリケーションで共有されているので,サーバプロセスは不要です(サーバを使う構成も出来るようです).プロセスが一つでも生きていれば,内容は保持されます.ということで,最初のプロセスを終了してから2番目のプロセスでキャッシュを確認.

Command: keys

>> name
>> birthday

Command: get name

>> Value is koichik

Command: get birthday

>> Value is 08/18

Command: 

アイディア次第でいろいろな使い方が出来そうです.幸か不幸か来期の予算に含められているらしいので,なんとか使いこなしたいと思います.
でも連載は無理です... たぶん.

*1:名前空間がどうなってるとか,名前解決はどうなっている? ルータ超えられる? なんて疑問は当然ありますが,ともかく簡単に使えるのはいいことです.

Spring Framework 入門記 Contextその2 MessageSource

Contextパッケージの2回目です.前回BeanFactoryの代わりにApplicationContextを使いました.今回は,BeanFactoryにはない,ApplicationContext特有の機能を使ってみます.
まずは「3.10.1. Using the MessageSource」です.
ApplicationContextは,MessageSourceインタフェースもextendsしています.MessageSourceは,国際化(i18n)対応のメッセージを提供するためのインタフェースらしいです.苦手なんですよね,国際化.いやその,日本語化も苦手なんですけどね...
それでその,MessageSourceには次の3つのメソッドがあります.

  • getMessage(String code, Object[] args, Locale loc)
  • getMessage(String code, Object[] args, String default, Locale loc)
  • getMessage(MessageSourceResolvable resolvable, Locale locale)

最初の2つのメソッドの第1引数codeはリソースバンドルで言うところのキーで,java.text.MessageFormatで扱うパターン(フォーマット)文字列を得るために使われます.第2引数argsはそのMessageFormatに渡される引数ですね.
3番目のメソッドのMessageSourceResolvableは,2番目のメソッドの引数であるcodeargsdefaultを取得するgetterをメソッドして持つインタフェースです.つまり,このインタフェースをimplementsしたクラスは,ごく普通のBeanとして扱えるようなクラスです.こちらを使うと,メッセージに含める引数などもBean定義XMLファイルで様々に定義できるため,より柔軟性を高めることが出来るということでしょう.
さて,ApplicationContextMessageSourceimplementsしているわけですが,だからといってFileSystemXmlApplicationContext*1は直接MessageSourceの機能を実装しているわけではないようです.本物のMessageSource実装クラスに委譲するだけなんですね.ではその本物の実装は? というと,StaticMessageSourceResourceBundleMessageSourceの2つが用意されています.このうち前者はプログラマティック*2にメッセージを設定するというもので,あまりうれしくない実装です.一方後者はおなじみのリソースバンドルを使うタイプです.うん,この方が素敵(キラッ).
ちょっと意外だったのが,ApplicationContextMessageSourceの実装を入手する手段です.どうやら,messageSourceという名前のBeanが定義されていれば,それを使ってくれるのだとか.ふーん,コンテナが予約しているも同然の名前があるってことですね.ちなみにmessageSourceという名前のBeanが見つからない場合はApplicationContextが空のStaticMessageSourceを作成します.
国際化に対応したアプリケーションを作るなら,こういうものは必須なのでしょうね.国際化するわけではなくても,エラーメッセージやロギングのメッセージがそこら中のソースに散らばってしまうと大変です.でもこれ,ApplicationContextの機能なんですよね.ということは,これを使うとそのクラスはApplicationContextに依存してしまいます.うーん,あちら立てればこちらたたず.今回はあくまでもApplicationContextの学習がメインなので,その問題には触れずにいくことにしましょう.えっ? 逃げてるわけじゃありませんよっ(ドキドキ).
とにもかくにもですね,この機能を使うにはApplicationContextを入手しなければいけません.大体予想がつきますね.一貫性っていいなぁ.そうです,ApplicationContextAwareインタフェースをimplementsすればいいのです.BeanFactoryを入手するのにBeanFactoryAwareを使ったのと同じですね.
ということで,例によって実験コーナーの始まりです.
せっかくなので(何が?),MessageSource第3のメソッドを使ってみることにします.
まずは,MessageSourceResolvableimplementsした単純なクラスを用意します.

package study;
import org.springframework.context.MessageSourceResolvable;

public class Headline implements MessageSourceResolvable {
    private Object arguments;
    private String codes;
    private String defaultMessage;

    public Object getArguments() {
        return arguments;
    }
    public void setArguments(Object objects) {
        arguments = objects;
    }
    public String getCodes() {
        return codes;
    }
    public void setCodes(String strings) {
        codes = strings;
    }
    public String getDefaultMessage() {
        return defaultMessage;
    }
    public void setDefaultMessage(String string) {
        defaultMessage = string;
    }
}

これで,様々なメッセージフォーマットのキーとそのパラメータをBeanとして扱うことが出来ます.
次に,このHeadlineをプロパティとして持ち,ApplicationContextにフォーマットしてもらって出力するdisplay()メソッドを持つクラスを作ります.

package study;
import java.util.Locale;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.MessageSourceResolvable;

public class Billboard implements ApplicationContextAware {
    private ApplicationContext context;
    private MessageSourceResolvable headline;

    public void setApplicationContext(ApplicationContext context) throws BeansException {
        this.context = context;
    }
    public MessageSourceResolvable getHeadline() {
        return headline;
    }
    public void setHeadline(MessageSourceResolvable resolvable) {
        headline = resolvable;
    }
    public void display() {
        System.out.println(context.getMessage(headline, Locale.getDefault()));
    }
}

次に,これらのクラスを定義したXMLファイルを作成します(<bean>要素のみ抜粋).

    <bean name="headline" class="study.Headline">
        <property name="codes"><value>headline</value></property>
        <property name="defaultMessage"><value>Spring is commig.</value></property>
    </bean>
    <bean name="billboard" class="study.Billboard">
        <property name="headline"><ref bean="headline"/></property>
    </bean>

次に実行用のクラス.いつものとあまり変わりません.

package study;
import org.springframework.context.support.FileSystemXmlApplicationContext;

public class Main {
    public static void main(String args) {
        try {
            FileSystemXmlApplicationContext context =
                new FileSystemXmlApplicationContext(
                    new String { "factory.xml", "beans.xml" });

            Billboard billboard = (Billboard) context.getBean("billboard");
            billboard.display();

            context.close();
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }
}

これを実行すると,次のようになります.

Spring is commig.

おかしいですねぇ,もう春は来てるのに.
... すみません,わざとです.ごめんなさい.
これは,messageSourceというBeanを定義していないため,空のStaticMessageSourceが使われ,そこにはメッセージはまったく登録されていないのでデフォルトのメッセージが出力されたわけですね.
ということで,ResourceBundleMessageSourceをBean定義XMLに組み込みましょう(<bean>要素のみ抜粋).

    <bean name="messageSource" 
        class="org.springframework.context.support.ResourceBundleMessageSource"
    >
        <property name="basenames">
            <list>
                <value>headline</value>
            </list>
        </property>
    </bean>

ResourceBundleMessageSourceは,リソースバンドルのベース名のリストを受け取るのですが,ここでは一つ(headline)だけ指定しています.
そしてリソースバンドルを日本語用と英語用にそれぞれ作成します.
まず日本語用(headline_ja.properties).native2ascii済みです.

headline=\u6625\u304c\u6765\u305f\uff0e

それから英語用(headline_en.properties).

headline=Spring is here.

これを普通に(ロケールを指定しないで)実行すると,次のようになります(日本語環境だもん).

春が来た.

来てます!
次に,-Duser.language=en -Duser.country=USを付けて実行すると,次のようになります.

Spring is here.

いいねぇ!

*1:クラス名も長ければいいって訳じゃないですよね

*2:前回からのお気に入りフレーズ