2009年11月11日水曜日

JCR 2.0/Jackrabbit 2.0/galileo

10/30 にリリースされた Apache Jackrabbit 2.0 beta1 を使ってみる。 JCR (Content repository API for Java) は、ツリー状に構成されたデータを保管するAPI。データ構造の雰囲気は Windows のレジストリとそっくりだけど、XML のようなドキュメントも直に扱えて XPath 式なんかも普通に使える。データの読み書きに加えてバージョニングやトランザクションも Java 標準として提供している。 (個人的には、例えばログインユーザごとに画面や操作をカスタマイズできるようなWebアプリで、カスタマイズ情報を管理する仕組みなんかに利用してみたい。よく RDB 前提で一からテーブル設計したりするけど、ちょっといかがなものかと思ったりする。) Jackrabbit はその実装で、最新の正式リリースは 8月にリリースされた1.6だけど、開発中の2.0のベータ版も先月末にリリースされたらしい。これを Eclipse 環境で試してみる。 とりあえず JCR 1.0/Jackrabbit1.6用に書かれたチュートリアル「First Hops」の"Hop 2"を元ネタにして、最新プロダクトを動かしてみる。 環境は Eclipse 3.5(Galileo)、m2eclipse(Maven 2.2.1)、JUnitプラグイン(JUnit 4)。 ■ プロジェクト作成
  • Eclipse で Maven Project を作る。アーキタイプは maven-archetype-quickstart。
  • [Add Libraries...] で JUnit 4を追加する。
  • pom.xml の dependencies を以下のようにする。
    <dependencies>
      <dependency>
        <groupId>javax.jcr</groupId>
        <artifactId>jcr</artifactId>
        <version>2.0</version>
      </dependency>
      <dependency>
        <groupId>org.apache.jackrabbit</groupId>
        <artifactId>jackrabbit-core</artifactId>
        <version>2.0-beta1</version>
      </dependency>
      <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.5.5</version>
      </dependency>
    </dependencies>
    slf4j-log4j12 バージョンは1.5.5 が限界で、1.5.6 以上になると実行時に例外が発生する。org.slf4j.impl.StaticLoggerBinder クラスの"SINGLETON"フィールドのvisibility が、public からprivate になったため
■ 動かしてみる JUnitは、ここでは単に共通の前処理・後処理つきのエントリポイントとして利用する。正しい作法ではないけど、気にしない。 で、以下のようなテストコードを書いて、テストメソッドを一個ずつ実行してみる。
package xad.yasuabe.studies.standards1.jcr_study1;

import javax.jcr.Node;
import javax.jcr.PathNotFoundException;
import javax.jcr.Repository;
import javax.jcr.Session;
import javax.jcr.SimpleCredentials;

import org.apache.jackrabbit.core.TransientRepository;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;

public class AppTest {
   private static final String USERNAME = "username";
   private static final char[] PASSWORD = "password".toCharArray();

   private Session session;
   private Node root; 
      
   @Before
   public void setup() throws Exception {
        Repository repository = new TransientRepository();
        session = repository.login(
                new SimpleCredentials(USERNAME, PASSWORD));
        root = session.getRootNode();
   }
   
   @After
    public void tearDown() {   
        session.logout();
   }

   @Test
   public void storeContent() throws Exception {
        Node hello = root.addNode("hello");
        Node world = hello.addNode("world");
        world.setProperty("message", "Hello, World!");

        session.save();
   }
   @Test
   public void retrieveContent() throws Exception {
        Node node = root.getNode("hello/world");

        assertEquals("/hello/world", node.getPath());
        assertEquals("Hello, World!", 
              node.getProperty("message").getString());
   }
   @Test
   public void removeContent() throws Exception {
        root.getNode("hello").remove();
        session.save();
   }
   @Test
   public void verifyContentRemoved() throws Exception {
      boolean failed = false;
      try {
         assertNull(root.getNode("hello"));
      } catch (PathNotFoundException e) {
         failed = true;
      }
      assertTrue(failed);
   }
}
※ メソッドごとに個別に実行するやり方は、Outlineビューから実行したいメソッドの右クリから[Run As]->[JUnit Test]。
StoreContent()
ルート直下に hello、その下に world というノードを作って、message という名前のプロパティに値"Hello, World!"を設定する。
retrieveContent()
ルート下で、xpath式 "hello/world"で表されるノードを得る。フルパスとプロパティ"message"の値を確認する。
removeContent()
ルート直下のノード"hello"を削除する。
verifyContentRemoved()
ルート直下でノード"hello"の取得を試みる。例外が出るのを確認する。
実行してみると、期待通りに動くのがわかる。 また、Eclipse の Package explorer か Navigator から、プロジェクトの右クリで [Refresh] を実行するとツリーが更新され、プロジェクトディレクトリ直下に repository フォルダとrepository.xml ファイルが生成されているのが分かる。repository 直下には.lock ファイルがあって、session が生きている間、排他してるらしい。 今回は JCR 1.0(JSR 170) レベルの事しかやっていないが、Jackrabbit 2.0 から JCR 2.0 API(JSR 283) がフルサポートされたので、次はその辺りを調べてみたい。

0 件のコメント:

コメントを投稿