Webアプリ開発エンジニアのための技術情報サイト「テックスコア」

3. 基本的な開発の概要

2007.05.16 株式会社四次元データ 鈴木 圭

※本記事は Buri のバージョン 0.3.1 を対象としていますが、新しいバージョン 0.3.2 がリリースされました(リリースの告知は seasar-user メーリングリストで行われました)。

前回は Buri に付属しているサンプルプログラムを実行することで、Buri による開発の全体的な流れを説明しました。今回は、実際に開発を行うために必要な情報として、ワークフローを記述する XPDL ファイルの作成と、高水準インタフェースである BAO の作成について解説します。

本章では簡単なサンプルプログラムの作成を通して、Buri による開発の基本的な手順を解説します。サンプルプログラムでは、データベースとして Apache Derby、プロジェクトの管理には Apache Maven を使用します。これらについては基本的な知識があることを前提とします。

3.1. サンプルプログラムの概要

ワークフロー

作成するサンプルプログラムとして、文書管理を行うプログラムを考えます。ワークフローとしては上図のような「登録→公開→公開終了」という単純な流れのものを作成します。その過程で Buri の開発に必要な情報を順次解説していきます。

そして、作成の途中でワークフローを下図のように変更します:

ワークフロー

通常、このような仕様変更に対応するには、データベースの定義から見直さなければなりません。しかし、Buri を使用していれば、データベースの定義を一切変更することなく、仕様変更に対応することができます。

今回は文書管理のシステム全体を完成させるのではなく、Buri によって文書オブジェクトのワークフローを扱う部分だけを作成します。動作確認には前回のように単体テストによって行います。完成したサンプルプログラム は以下のリンクからダウンロードすることができますので、必要に応じて参照してください:

サンプルプログラムで扱う文書データには、{ 文書 ID,文書のタイトル,文書の内容 } の三つの情報を持たせることにします:

+----------+----------------+
|    id    | 文書 ID        |
+----------+----------------+
|   title  | 文書のタイトル |
+----------+----------------+
|  content | 文書の内容     |
+----------+----------------+

これを元にデータベースのテーブルや DAO の設計を行います。

開発の流れは、以下の順番で行います:

それでは、開発に入りましょう。

3.2. データベースの準備

Buri は S2Dao を利用しているため、S2Dao が対応しているデータベースであれば、どれでも使用することができます。Buri の配布ファイルには、Buri 自身が使用するテーブルを作成するための SQL ファイルが含まれています。現状では Apache Derby 用と PostgreSQL 用の二種類が含まれているため、データベースには Apache Derby か PostgreSQL を使用することが簡単です。今回作成するサンプルプログラムでは Apache Derby を使用します。

サンプルプログラムで使用するテーブルの作成は、Derby 付属の ij ツールで以下の SQL を実行します:

ij> CREATE TABLE Document
(
    -- 文書 ID (値は 1 から始まる連番を自動生成).
    id INTEGER GENERATED BY DEFAULT AS IDENTITY
           (START WITH 1, INCREMENT BY 1) PRIMARY KEY,

    -- 文書のタイトル.
    title VARCHAR(64) NOT NULL,

    -- 文書の内容.
    content VARCHAR(1024) NOT NULL
);

また、Buri 自身が使用するテーブルは以下の SQL 文で作成します:

ij> run 'createdb_derby.sql';

(※ここでは Buri の解説の範疇から外れてしまうので、Apache Derby の導入に関する説明は割愛します。「3.1. サンプルプログラムの概要」で配布しているサンプルプログラムには作成済みのデータベースファイルが含まれています。)

3.3. プロジェクトの作成

プロジェクトは Apache Maven によって管理します(Maven を利用すると、必要なライブラリを自動取得することや、コマンドひとつでコンパイルや単体テストを行うことができます)。Maven についての詳細は別途こちらの記事を参照してください。

プロジェクトの作成は groupId=com.example.docmanage、artifactId=docmanage として作成します:

mvn archetype:create -DgroupId=com.example.docmanage -DartifactId=docmanage

プロジェクトの作成に成功したら、docmanage ディレクトリの pom.xml を開いて以下に示す項目(強調表示の部分)を追加します:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.example.docmanage</groupId>
  <artifactId>docmanage</artifactId>
  <packaging>jar</packaging>
  <version>1.0</version>
  <name>docmanage</name>

  <repositories>
    <repository>
      <id>maven.seasar.org</id>
      <name>The Seasar Foundation Maven2 Repository</name>
      <url>http://maven.seasar.org/maven2</url>
    </repository>
  </repositories>

  <build>
    ...
  </build>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.apache.derby</groupId>
      <artifactId>derbyclient</artifactId>
      <version>10.2.2.0</version>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>geronimo-spec</groupId>
      <artifactId>geronimo-spec-j2ee</artifactId>
      <version>1.4-rc4</version>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>1.2.14</version>
    </dependency>
    <dependency>
      <groupId>org.seasar.buri</groupId>
      <artifactId>s2-buri</artifactId>
      <version>0.3.1</version>
    </dependency>
  </dependencies>
</project>

ここでは Seasar Foundation が提供しているリモートリポジトリの設定と、サンプルプログラムに必要なライブラリの情報を追加しています。なお、プロジェクトの作成時に自動生成される docmanage/src/main/java/com/example/docmanage/App.java 及び docmanage/src/test/java/com/example/docmanage/AppTest.java は不要なので削除します。

ここからは実際にプログラムを書く作業になります。今回は作成するクラスは多くありませんので、全て com.example.docmanage パッケージに配置することにします。また、DTO(Data Transfer Object)と DAO(Data Access Object)の作成に関しては、S2Dao を利用して開発する場合と基本的に同じ作業になります。BAO の作成は Buri のルールに則って作成を行います。

3.4. DTO クラスの作成

今回は文書管理を行うプログラムなので、「文書」を表す DTO として DocumentDto クラスを作成します。DocumentDto にはデータベースに作成した Document テーブルに対応したフィールドを含めます(com.example.docmanage.DocumentDto.java):

package com.example.docmanage;

public class DocumentDto
{
    public static final String TABLE = "Document";
    public static final String id_ID = "sequence, sequenceName=documentID";

    private long id;
    private String title;
    private String content;

    public DocumentDto()
    {
        // BLANK.
    }

    public DocumentDto(String title, String content)
    {
        this.title    = title;
        this.content  = content;
    }

    ... Getter, Setter など.
}

3.5. DAO インタフェースの作成

DAO インタフェースは DocumentDao という名前で作成します。また、DocumentDao には検索(select)、挿入(insert)、更新(update)、削除(delete)のためのメソッドを持たせます (com.example.docmanage.DocumentDao.java):

package com.example.docmanage;

public interface DocumentDao
{
    public static final Class BEAN = DocumentDto.class;

    public DocumentDto select(long id);
    public static final String select_QUERY = "id=?";

    public void insert(DocumentDto document);
    public void update(DocumentDto document);
    public void delete(DocumentDto document);
}

各メソッドには任意の名前をつけることができますが、select、insert、update、delete という名前の場合は、次に行う XPDL の作成における設定項目を省略することができるので、ここでは select、insert、update、delete という名前にしてください。他の名前を使用する場合の XPDL での設定については機会を改めて説明します。

3.6. XPDL の作成

JaWE (Java Workflow Editor) の導入

XPDL ファイルの作成は JaWE というワーフクローエディタを使用します。JaWE を使用することで、グラフィカルインタフェースでワークフローのモデリングを行い、それを XPDL 形式(Buri が扱う形式)で保存することができます。JaWE は以下のサイトから入手することができます:

ObjectWeb Forge: Project Info- Enhydra JaWE

ここでは JaWE のコミュニティ版をダウンロードします(ダウンロードは無料ですが「氏名」と「メールアドレス」を登録する必要があります)。セットアップ形式をダウンロードすると簡単です。

[Tips] 圧縮ファイルをダウンロードした場合は、それを適当な場所に展開します。展開先のディレクトリを JAWE_HOME とした場合、JAWE_HOME に build.xml がありますので、Apache Ant でビルドします。デフォルトのターゲットを実行すると JAWE_HOME/bin に起動スクリプト(Windows ならば run.bat)が作成されます。作成された起動スクリプトを実行することで JaWE が起動します。

(※JaWE と操作性の似ている JPEd というワークフローエディタもあるようです。こちらは起動時に一定時間待たされることはありません。)

モデリングを行う

それでは実際に JaWE でモデリングを開始しましょう。

[Tips] JaWE のコミュニティ版では、起動時に表示されるダイアログボックスがしばらく(10 秒程度)表示され続けるという制限があります。10 秒程度経過すると、[OK] ボタンが有効になるので、クリックしてダイアログボックスを閉じましょう。

(1) パッケージの作成

まずやるべきことは、パッケージ(新しい XPDL ファイル)の作成です。パッケージとは XPDL の最上位要素であり、アプリケーション全体を表します。パッケージを作成するには [File] メニューの [New] を選択します:

パッケージの作成

作成されたパッケージはウィンドウの左側に表示されます。次に作成されたパッケージを右クリックし、表示されるメニューから [Properties] を選択します:

パッケージのプロパティ

表示されるパッケージのプロパティウィンドウで、パッケージに関する情報を入力します。まずは [General] タブの [Name:] でパッケージの名前を指定します。ここでは「文書管理パッケージ」とします(id は特に変更する必要はありません)。なお、変更の適用はウィンドウの左上のチェックマークをクリックするか、エディットボックス内で [Enter] キーを押します:

パッケージのプロパティ

(2) プロセスの作成

パッケージの作成の次は、プロセスを作成します。今回は文書オブジェクトのためのプロセスをひとつだけ作成します。以下のように [Package] メニューの [Insert new process] を選択します:

プロセスの作成

作成されたプロセスは、画面左側のパッケージの子要素として追加されます。追加されたプロセスを右クリックし、表示されるメニューから [Properties] を選択します:

プロセスのプロパティ

表示されるプロセスのプロパティウィンドウで、プロセスに関する情報を入力します。まずは [General] タブの [Name:] でプロセスの名前を指定します。ここでは「文書管理プロセス」とします(id は特に変更する必要はありません):

プロセスのプロパティ

(3) プロセスのモデリング

ここからは「ワークフロー」の厳密な表現である「プロセス」という言葉を使用します(XPDL ではプロセスという言葉を使用します)。プロセスの作成で始めに行うべきことは、プロセスの実行者の配置です。下図のように [Insert new participant] を選択し、作業領域上でクリックします:

プロセスのモデリング

そして、配置した Participant のプロパティを開きます:

プロセスのモデリング

プロパティには [Name:] に「文書管理担当」を設定します:

プロセスのモデリング

次に「3.1. サンプルプログラムの概要」で示したワークフローと同じようにプロセス内の項目を配置します。配置する項目は左側の一覧から選択します:

プロセスのモデリング

[Tips]「アクティビティ(処理を持たない)」と「アクティビティ(処理を持つ)」の違いは、フローがそのアクティビティに巡ってきたときに実行する処理を設定できるかできないか、という違いがあります。ここでは処理を持たないアクティビティだけを使用します。

それでは、以下の図と同じように注意しながらアクティビティおよびトランジションを配置してください:

プロセスのモデリング

配置した項目をダブルクリックすることで、その項目のプロパティを選ぶことができます。プロパティでは [Name:] にアクティビティの名前を指定します。[Performer:] は「文書管理担当」となっていることを確認します。[Start mode] は「Automatic」とします。[Finish mode] はアクティビティに状態遷移したあとに、自動的に次のアクティビティに遷移するかどうかの指定です。この値は [登録] アクティビティと [公開終了] アクティビティについては「Automatic」、[公開中] アクティビティについては「Manual」とします。(つまり、文書が「登録」されたら自動的に「公開中」状態となり、明示的に「公開終了」とした場合 に、文書オブジェクト(DocumentDto)はプロセスでのライフサイクルを終える、ということになります)。

プロセスのモデリング

モデリングに関してはこれで終了です。作成したものは docmanage.xpdl という名前で、Maven で作成したプロジェクトの src/main/resources ディレクトリに保存しておきましょう(ディレクトリがなければ作成します)。

3.7. BAO インタフェースの作成

XPDL の次は BAO インタフェースを作成します。BAO インタフェースには、XPDL の作成のときに設定した情報を定数アノテーションとして埋め込みます。(定数アノテーションとは、J2SE 5.0 から導入されたアノテーションと同じ目的の機能で、public static フィールドとして作成する定数によってメタデータを指定するものです。S2Dao でも採用されている手法です)。

BAO の作成にはいくつかのルールがありますが、まずは以下に示す実装を見てください(com.example.docmanage.DocumentBao.java):

package com.example.docmanage;

import java.util.List;

public interface DocumentBao
{
    public static final Class TARGETDTO = DocumentDto.class;
    public static final String PROCESS = "文書管理パッケージ.文書管理プロセス";

    /** 文書を登録する. */
    public void register(DocumentDto document);
    public static final String register_ACTIVITY = "登録";

    /** 公開中の文書を取得する. */
    public List<DocumentDto> getPublishings();
    public static final String getPublishings_ACTIVITY = "公開中";

    /** 文書の公開を終了する. */
    public void finishPublishing(DocumentDto document);
}

この中に含まれている定数アノテーションは TARGETDTO、PROCESS、register_ACTIVITY、getPublishings_ACTIVITY の四つです。TARGETDTO 以外の値は、先ほど作成した XPDL(docmanage.xpdl)の中で設定した値と対応していることに注意してください。ここで指定している定数アノテーションは、それぞれ次 の意味を持っています:

  • TARGETDTO ... 扱う DTO クラスの Class オブジェクト。
  • PROCESS ... 実行するプロセス(XPDL で指定したもの)の名前。
  • register_ACTIVITY ... register() メソッドの実行対象のアクティビティ名。
  • getPublishings_ACTIVITY ... getPublishings() メソッドの実行対象のアクティビティ名。

ここで使用したアノテーションを含め、Buri で使用可能なアノテーションに関する詳細は、本章の最後に解説します。

3.8. 設定ファイルの準備

作成したサンプルプログラムを実際に動かすには、必要な設定ファイルを準備する必要があります。準備する設定ファイルは、作成しているサンプルプログラムの src/main/resources に次のファイルを準備します:

  • jdbc.dicon
  • buri/dicon/buri-user.dicon
  • app.dicon

(1) jdbc.dicon の変更

Buri の配布ファイルの src/test/resources/jdbc.dicon をコピーします。コピー後、jdbc.dicon を開き、「<component name="xaDataSource"」(複数ありますがコメントアウトされていないもの)の部分で、データベースの設定を記述します(強調表示部分が変更箇所です):

Buri の配布ファイルの src/test/resources/jdbc.dicon をコピーします。コピーした jdbc.dicon を開き、次の変更を行います:

  1. jdbc-extension.dicon を include している行を削除する(今回は Uuji や Kuina-Dao を使用しないため)。
  2. 「<component name="xaDataSource"」(複数ありますがコメントアウトされていないもの)にデータベースの設定を記述する。

以下に変更箇所に強調表示で示します:

<components namespace="jdbc">
    <include path="jta.dicon"/>
    <include path="jdbc-extension.dicon"/>

    ...

    <component name="xaDataSource"
        class="org.seasar.extension.dbcp.impl.XADataSourceImpl">
        <property name="driverClassName">
            "org.apache.derby.jdbc.EmbeddedDriver"
        </property>
        <property name="URL">
            "jdbc:derby:db/docmanage"
        </property>
    </component>

(2) buri/dicon/buri-user.dicon の変更

Buri の配布ファイルの src/test/resources/buri/dicon/buri-user.dicon をコピーします。このファイルでは使用する XPDL ファイルの指定などを行う、基本的な設定ファイルです。buri-user.dicon は Buri を使用する場合は必ず変更することになるので覚えておいてください。

buri-user.dicon の中を見ると、「<!-- ここからはテスト用なので実際は削除する -->」とコメントされている部分が見つかります。コメントで指示されている通り、「<!-- ここからはテスト用なので実際は削除する -->」から「<!-- ここからはテスト用なので実際は削除する -->」までの内容を削除します(コメントアウトでも構いません)。

次に、「<component name="BuriEngineConfig"」の内側にサンプルプログラムで使用する XPDL ファイルの指定を行います:

    ...
    <component name="BuriEngineConfig" class="org.seasar.buri.engine.impl.BuriEngineConfigImpl">
        <!-- ParticipantProviderを使う場合はここに記述する。引数はResourceのファイル名,パッケージ名,ParticipantProvider -->
            <initMethod name="addResourceConfig">
            <arg>"docmanage.xpdl"</arg>
        <arg>"文書管理パッケージ"</arg>
    </initMethod>
    ...

(3) app.dicon の作成

app.dicon は、今回作成しているサンプルプログラムで使用する dicon ファイルです。以下の内容で新しく作成してください:

<?xml version="1.0" encoding="Shift_JIS" ?>
<!DOCTYPE components PUBLIC
  "-//SEASAR//DTD S2Container 2.3//EN"
  "http://www.seasar.org/dtd/components23.dtd">

<components>
  <include path="dao.dicon" />
  <include path="buri/dicon/bao.dicon" />

  <component name="DocumentDao" class="com.example.docmanage.DocumentDao">
    <aspect>j2ee.requiredTx</aspect>
    <aspect>dao.interceptor</aspect>
  </component>

  <component name="DocumentBao" class="com.example.docmanage.DocumentBao">
    <aspect>j2ee.requiredTx</aspect>
    <aspect>bao.interceptor</aspect>
  </component>
</components>

ここでは、DocumentDao と DocumentBao をコンポーネントとして登録しています。buri/dicon/bao.dicon をインクルードし、BAO インタフェースである DocumentBao のアスペクトに bao.interceptor を指定します。

これで設定ファイルの準備は終了です。

3.9. 単体テストの作成と実行

ここまでの内容で、実行に必要な準備は整いましたので、単体テストを作成して実際に動作させてみましょう。

単体テストは S2TestCase を継承して、DocumentBaoTestCase という名前で作成します (src/test/java/com/example/docmanage/DocumentBaoTestCase.java)。単体テストの内容 は、文書の登録から公開、公開終了までの一連の流れが実行できるかを確かめるために、以下の内容で作成しました:

[Tips] S2TestCase は名前が Tx で終わるメソッドをトランザクションとして実行し、メソッドの終了時にロールバックします。これによってデータベースに不要なデータが残らないので、単体テストを繰り返し実行するときに便利です。

package com.example.docmanage;

import org.seasar.extension.unit.S2TestCase;

public class DocumentBaoTest extends S2TestCase
{
    private static final String DICON_PATH = "app.dicon";

    private DocumentBao documentBao;

    @Override
    protected void setUp() throws Exception
    {
        super.setUp();
        include(DICON_PATH);
    }

    public void testTx()
    {
        DocumentDto document1 = new DocumentDto("文書A", "文書Aです。");
        DocumentDto document2 = new DocumentDto("文書B", "文書Bです。");
        DocumentDto document3 = new DocumentDto("文書C", "文書Cです。");

        // document1 を登録.
        documentBao.register(document1);

        // 公開中=1 になっているはず.
        assertTrue(documentBao.getPublishings().size()==1);
        System.out.println(documentBao.getPublishings());

        // document2, document3 を登録.
        documentBao.register(document2);
        documentBao.register(document3);

        // 公開中=3 になっているはず.
        assertEquals(documentBao.getPublishings().size(), 3);
        System.out.println(documentBao.getPublishings());

        // document1 の公開を終了.
        documentBao.finishPublishing(document1);

        // 公開中=2 になっているはず.
        assertEquals(documentBao.getPublishings().size(), 2);
        System.out.println(documentBao.getPublishings());

        // document2, document3 の公開を終了.
        documentBao.finishPublishing(document2);
        documentBao.finishPublishing(document3);

        // 公開中=0 になっているはず.
        assertEquals(documentBao.getPublishings().size(), 0);
        System.out.println(documentBao.getPublishings());
    }
}

実行すると以下のような出力が得られます(長くなる行があるので「」によって折り返しています):

[[id=29, title=文書A, content=文書Aです。]]
[[id=29, title=文書A, content=文書Aです。], [id=30, title=文書B, content=
文書Bです。], [id=31, title=文書C, content=文書Cです。]]
[[id=30, title=文書B, content=文書Bです。], [id=31, title=文書C, content=
文書Cです。]]
[]

※プログラムの実行でエラーが出てしまった場合は、XPDL や BAO の定数アノテーションの指定などにミスがないか、もう一度確認してみてください(「3.1. サンプルプログラムの概要」でサンプルプログラムをダウンロードすることもできるので、そちらも参考にしてください)。

3.10. ワークフローの変更

オブジェクトの状態管理を行うことがワークフローエンジンである Buri の特徴の一つであると前述しました。これは、オブジェクトの取り得る状態の数が増えた場合にも柔軟に対応できることを意味しています。実際に Buri ではデータベースのテーブルに一切変更を加えることなくワークフローの変更に対応することができます。ここではそのような仕様変更があったと仮定して、 ワークフローに変更を加えてみましょう。

docmanage.xpdl の変更

作成した XPDL(docmanage.xpdl)では、文書オブジェクトを「登録」すると自動的に「公開中」アクティビティに遷移するという流れになっていまし た。ここに仕様変更として、「登録」した文書オブジェクトは一旦「公開待機中」になり、その後明示的に「公開」することで「公開中」に遷移する、という流 れに変更します。以下に変更前と変更後のワークフロー(XPDL のプロセス)を示します:

[変更前]
変更前

[変更後]
変更後

それでは docmanage.xpdl を JaWE で開き、内容を変更しましょう。「公開待機中」アクティビティと「公開」アクティビティを新しく加え、トランジション(矢印)を正しく繋ぎ変えます。「公 開待機中」アクティビティの [Finitsh mode] は「Manual」に、「公開」アクティビティの [Finish mode] は「Automatic」とすることに注意してください。

DocumentBao の変更

次に新しい XPDL に対応するために BAO の変更を行います。変更後の DocumentBao の内容を以下に示します(強調表示されている部分が変更点です):

package com.example.docmanage;

import java.util.List;

public interface DocumentBao
{
    public static final Class TARGETDTO = DocumentDto.class;
    public static final String PROCESS = "文書管理パッケージ.文書管理プロセス";

    /** 文書を登録する. */
    public void register(DocumentDto document);
    public static final String register_ACTIVITY = "登録";

    /** 公開待機中の文書を取得する. */
    public List<DocumentDto> getWaitForPublishings();
    public static final String getWaitForPublishings_ACTIVITY = "公開待機中";

    /** 文書を公開する. */
    public void publish(DocumentDto document);

    /** 公開中の文書を取得する. */
    public List<DocumentDto> getPublishings();
    public static final String getPublishings_ACTIVITY = "公開中";

    /** 文書の公開を終了する. */
    public void finishPublishing(DocumentDto document);
}

仕様変更というとプログラム全体の大掛かりな修正を予想してしまいますが、実際の修正箇所は XPDL と BAO の二箇所だけで済みました。

(※処理系のメソッドについては _ACTIVITY アノテーションを省略することも可能です。上記サンプルでは全体をシンプルにするために全ての処理系メソッドに _ACTIVITY アノテーションを省略しています。実際には _ACTIVITY アノテーションを付加するほうが、プログラミングミスの場合などにエラーとなるため、通常は全ての処理系メソッドに _ACTIVITY アノテーションを付加しましょう。)

単体テストの変更と実行

    public void testTx()
    {
        DocumentDto document1 = new DocumentDto("文書A", "文書Aです。");
        DocumentDto document2 = new DocumentDto("文書B", "文書Bです。");
        DocumentDto document3 = new DocumentDto("文書C", "文書Cです。");

        // document1 を登録.
        documentBao.register(document1);

        // 公開待機中=1, 公開中=0 となっているはず.
        assertEquals(documentBao.getWaitForPublishings().size(), 1);
        assertEquals(documentBao.getPublishings().size(), 0);
        System.out.println(documentBao.getWaitForPublishings());
        System.out.println(documentBao.getPublishings());

        // document2, document3 を登録.
        documentBao.register(document2);
        documentBao.register(document3);

        // 公開待機中=3, 公開中=0 となっているはず.
        assertEquals(documentBao.getWaitForPublishings().size(), 3);
        assertEquals(documentBao.getPublishings().size(), 0);
        System.out.println(documentBao.getWaitForPublishings());
        System.out.println(documentBao.getPublishings());

        // document1, document2 を公開.
        documentBao.publish(document1);
        documentBao.publish(document2);

        // 公開待機中=1, 公開中=2 となっているはず.
        assertEquals(documentBao.getWaitForPublishings().size(), 1);
        assertEquals(documentBao.getPublishings().size(), 2);
        System.out.println(documentBao.getWaitForPublishings());
        System.out.println(documentBao.getPublishings());

        // document3 を公開.
        documentBao.publish(document3);

        // 公開待機中=0, 公開中=3 となっているはず.
        assertEquals(documentBao.getWaitForPublishings().size(), 0);
        assertEquals(documentBao.getPublishings().size(), 3);
        System.out.println(documentBao.getWaitForPublishings());
        System.out.println(documentBao.getPublishings());

        // document1, document2, document3 の公開を終了.
        documentBao.finishPublishing(document1);
        documentBao.finishPublishing(document2);
        documentBao.finishPublishing(document3);

        // 公開待機中=0, 公開中=0 となっているはず.
        assertEquals(documentBao.getWaitForPublishings().size(), 0);
        assertEquals(documentBao.getPublishings().size(), 0);
        System.out.println(documentBao.getWaitForPublishings());
        System.out.println(documentBao.getPublishings());
    }

変更後の単体テストの実行結果は以下の通りです:

[[id=8, title=文書A, content=文書Aです。]]
[]
[[id=8, title=文書A, content=文書Aです。], [id=9, title=文書B, content=
文書Bです。], [id=10, title=文書C, content=文書Cです。]]
[]
[[id=10, title=文書C, content=文書Cです。]]
[[id=8, title=文書A, content=文書Aです。], [id=9, title=文書B, content=
文書Bです。]]
[]
[[id=8, title=文書A, content=文書Aです。], [id=9, title=文書B, content=
文書Bです。], [id=10, title=文書C, content=文書Cです。]]
[]
[]

3.11. Buri の定数アノテーション

最後に Buri で定義されている定数アノテーションについて解説します。

Buri で定義されている定数アノテーションには二つの種類があります。ひとつは BAO インタフェースに対して指定する定数アノテーション、もうひとつは BAO の持つメソッドに対して指定する定数アノテーションです。「3.7. BAO インタエースの作成」 で作成した DocumentBao では、TARGETDTO と PROCESS が前者、register_ACTIVITY と getPublishings_ACTIVITY が後者になります。定数アノテーションはどちらも、public static なフィールドとして作成します。

BAO インタフェースに指定する定数アノテーション

BAO インタフェースに指定することができる定数アノテーションを以下に示します:

TARGETDTO(Class 型)
BAO が扱う対象の DTO クラスの Class オブジェクトを指定します。例えば、SampleDto を扱う BAO では次のように指定します:
public static final Class TARGETDTO = DocumentDto.class;
PROCESS(String 型)
実行するプロセスを「<パッケージ名>.<プロセス名>」という形式で指定します。<パッケージ名> と <プロセス名> にはそれぞれ XPDL ファイルで指定したパッケージ名とプロセス名を指定します。例えば、「通信販売」パッケージの「注文」プロセスを指定する場合は次のようになります:
public static final String PROCESS = "通信販売.注文";
CONVERTER(BuriConvert[] 型)
値の自動変換(id から DTO への変換など)の方法を指定します。例えば Long 型の値(主キー)が渡されたときに、対応する DTO へ自動変換させるには次のように指定します:
public static final BuriConvert CONVERTER[] = new BuriConvert[]
{
    new BuriConvert(Long.class, "DocumentDao.select(#data)")
};
USERINFO(String 型)
S2Container からユーザ情報を自動取得させる場合に使用します。以下に使用例を示します:
public static final String USERINFO = "loginUser";

BAO のメソッドに指定する定数アノテーション

<メソッド名>_ACTION(String 型)
XPDL の中(OGNL 式の中)で #action として参照することができるパラメータを指定します。通常は分岐のあるプロセスに対して、分岐先を決めるための情報を渡します。例えば、次のような「承認/非承認」という分岐を持つプロセスがあるとして:
分岐のあるフロー
「非承認」に分岐させるメソッド reject に対して次のように定数アノテーションを指定します:
public static final String reject_ACTION = "REJECT";
そして、"REJECT" という値は #action として参照することができるので、「非承認」に進むトランジション(矢印)の条件式に「#action=="REJECT"」を指定することで分岐先を決定する、という使い方をします。
<メソッド名>_CONVERTER(String 型)
BAO インタフェースに指定する CONVERTER と同じですが、メソッドごとに変換の仕方を変更したい場合に使用します。以下に使用例を示します:
public void cancel(Long documentId);
public static final String cancel_CONVERTER = "DocumentDao.select(#data)";
<メソッド名>_RESULT(String 型)
メソッドの戻り値として取得する値を表す OGNL 式を指定します。例えば、何らかの処理をキャンセルするメソッド cancel の戻り値として #cancelStatus の値を受け取る場合は以下のように記述します:
public String cancel(DocumentDto document);
public static final String cancel_RESULT = "#cancelStatus";
#cancelStatus には XPDL 中の cancel メソッドに対応するアクティビティの中で値を設定します。
<メソッド名>_ARGS(String 型)
メソッドの引数を指定します。値としては次のものが指定可能です:
  • "data" ... DTO などのデータを渡す場合。
  • "userData" ... ユーザ情報を持つオブジェクトを渡す場合。
  • "datas" ... データ数を取得するメソッドに DTO のリストを渡す場合。(渡した DTO のリストの中で、対象のアクティビティに存在するオブジェクトの数を返します)。
以下に、「公開中」アクティビティにある DocumentDto の数を返すメソッドの例を示します:
public int countPublishings(List<DocumentDto> documentList);
public static final String countPublishings_ACTIVITY = "公開中";
public static final String countPublishings_ARGS = "datas";
<メソッド名>_ACTIVITY(String 型)
対象のアクティビティを指定します。プロセスの最初のアクティビティとデータ取得系のメソッド(あるアクティビティに位置するデータなどを取得す るメソッド)に対応するメソッドに対して使用します。例えば、公開中の文書(DocumentDto)の一覧を取得するメソッド getPublishings に対して、「公開中」アクティビティを指定する場合は次のようにします:
public List<DocumentDto> getPublishings();
public static final String getPublishings_ACTIVITY = "公開中";

まとめ

今回は Buri による開発の具体的な流れを説明しました。もう一度まとめると、以下の手順で開発を行いました:

  1. データベースの準備(Apache Derby)
  2. プロジェクトの作成(Apache Maven)
  3. DTO, DAO の作成(S2Dao と同じ手順)
  4. XPDL の作成(JaWE)
  5. BAO の作成

BAO というインタフェースがあることで、その裏側で動作しているワークフローエンジンの存在をほとんど意識することなく開発を行うことができます。また、「3.10. ワークフローの変更」では、DocumentDto の取り得る状態が増えるという仕様変更があったにも関わらず、データベースを一切変更することなく対応できた点は Buri を導入したことによる大きなメリットと言えるでしょう。

さて、次回からは Buri がサポートしてる他の機能に関する解説を行います。



前のページへ TECHSCOREのTOPページへ
TECHSCORE PR
PR
PR
PR
PR
PR

techscore(トップページへ)
TECHSCORE書店
TECHSCOREトップページJavaSQLXMLリッチクライアントモデリングセマンティックWebその他技術Tuigwaa