Qi4j を使ったコンポジット指向プログラミング

Qi4j を使ったコンポジット指向プログラミングでは、複数のオブジェクトを組み合わせた(mixin)、コンポジットを作成し、実行時に決定されるレイヤーやモジュールという構成内でコンポジットを扱えるようになっている。

今回は、以下のような手順で Qi4j アプリケーションを試してみた。

  1. Maven2 でプロジェクト作成
  2. pom.xml に Qi4j用のリモートリポジトリと依存設定追加
  3. ドメインインターフェース作成
  4. ドメインインターフェースの実装クラス(Mixin クラス)作成
  5. コンポジットの定義
  6. 実行クラスの作成と動作確認

Maven2 でプロジェクト作成

今回は Java アプリケーションで動作確認するため、Maven2archetype:create を使った一般的なプロジェクトを作成。

プロジェクト作成例
>mvn archetype:create -DgroupId=fits.sample -DartifactId=sample1

pom.xml に Qi4j用のリモートリポジトリと依存設定追加

自動生成された pom.xml ファイルに以下のような設定を行い、Qi4j を使用できるようにする。

  • Qi4j のリポジトリ設定追加
  • 使用する Qi4j の API に応じた依存ライブラリ設定を追加
  • Java 1.5 でコンパイルする設定の追加(Qi4j は Java SE 5 の機能を使用)

リポジトリの設定は以下の通り。

リポジトリ設定
<repository>
  <id>org.qi4j</id>
  <name>Qi4j Repository</name>
  <url>http://repository.ops4j.org/maven2/</url>
</repository>

今回は基本的な API を試すだけなので以下の依存ライブラリ設定のみ追加。

依存ライブラリ設定
<dependency>
  <groupId>org.qi4j.core</groupId>
  <artifactId>qi4j-core-runtime</artifactId>
  <version>0.7</version>
</dependency>

動作確認用に Java の指定クラスを実行するプラグインの設定を追加し、最終的に以下のような pom.xml ファイルを用意した。

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>fits.sample</groupId>
  <artifactId>qi4jsample1</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>qi4jsample1</name>
  <dependencies>
    <dependency>
      <groupId>org.qi4j.core</groupId>
      <artifactId>qi4j-core-runtime</artifactId>
      <version>0.7</version>
    </dependency>
  </dependencies>
  <repositories>
    <repository>
      <id>org.qi4j</id>
      <name>Qi4J Repository</name>
      <url>http://repository.ops4j.org/maven2/</url>
    </repository>
  </repositories>
  <build>
    <plugins>
      <!-- Java 1.5 用にコンパイルするための設定 -->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>1.5</source>
          <target>1.5</target>
        </configuration>
      </plugin>
      <!-- mvn exec:java で指定のクラスを実行するプラグイン -->
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>exec-maven-plugin</artifactId>
        <configuration>
          <executable>java</executable>
          <mainClass>fits.sample.App</mainClass>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

ドメインインターフェース作成

Qi4j では、コンポジットの構成要素とする機能毎にドメインインターフェースを用意し、ドメインインターフェースの実装クラス(Mixin クラス)をコンポジットに組み込むような作り方をするので、まずドメインインターフェースを作成する。
ドメインインターフェースは普通の Java インターフェースを用意するだけ。

Sample.java
package fits.sample;

public interface Sample {
    String hello(String msg);
}

ドメインインターフェースの実装クラス(Mixin クラス)作成

ドメインインターフェースの実装クラスを作成する。こちらも特別な事をする必要はない。

package fits.sample;

public class SampleMixin implements Sample {
    public String hello(String msg) {
        return "hello, " + msg;
    }
}

コンポジットの定義

コンポジットはドメインインターフェースと Composite インターフェースを継承したインターフェースとして定義し、@Mixins アノテーションで実装クラス(Mixin クラス)を指定する。(実際は複数のドメインインターフェースと Mixin クラスを設定してコンポジットを定義する事になる)

SampleComposite.java
package fits.sample;

import org.qi4j.api.composite.Composite;
import org.qi4j.api.mixin.Mixins;

@Mixins({SampleMixin.class})
public interface SampleComposite extends Sample, Composite {
}

実行クラスの作成と動作確認

今回は、単一レイヤーの単一モジュールで Qi4j アプリケーションを構成する SingletonAssembler を使って動作確認を実施した。

App.java
package fits.sample;

import org.qi4j.api.composite.CompositeBuilderFactory;
import org.qi4j.bootstrap.SingletonAssembler;
import org.qi4j.bootstrap.ModuleAssembly;
import org.qi4j.bootstrap.AssemblyException;

public class App {
    public static void main( String[] args ) {
        SingletonAssembler ass = new SingletonAssembler() {
            public void assemble(ModuleAssembly module) throws AssemblyException {
                module.addComposites(SampleComposite.class);
            }
        };

        CompositeBuilderFactory factory = ass.compositeBuilderFactory();
        //コンポジットの作成
        Sample sample = factory.newComposite(Sample.class);

        System.out.println(sample.hello("test"));
    }
}
動作確認
>mvn compile
>mvn exec:java
・・・
hello, test
・・・