The Apache Jakarta Project Jakarta HiveMind Project
 
   

Bootstrapping the Registry

アプリケーションのモジュール・デプロイ記述子に定義されているコンフィグ・ポイントやサービスにアクセスする事が可能となる前に、レジストリが必要となります:ここでは、どのようにレジストリを組み立てるかについて記述していきます。

ここでキーとなるクラスは、RegistryBuilderです。これはに、モジュール・デプロイ記述子の場所確認と解析を行うコード、及び、バインディングデータからレジストリを組み立てる為のコードが含まれています。記述子は全てクラスパスの中から探し出されます:アプリケーションのJAR 群にパッケージ化された記述子と共に、HiveMind 自身の記述子をも含んでいます

Note
HiveMind が人気となるにつれ、HiveMind モジュールのデプロイ記述子が第三者のフレームワークにバンドルされているのを見る事から始めてもいいかもしれません。がしかし、まだ時期尚早かもしれません。

どのように全て成り立つか調べてみます。プロジェクトのレイアウトは以下のとおりです。

[Project Layout]

サービス・インタフェースと実装

まず始めのステップで、サービス・インタフェースを定義します:

package hivemind.examples;

public interface Adder
{
    public int add(int arg0, int arg1);
} 

次に、このサービス用の実装が必要になります:

package hivemind.examples.impl;

import hivemind.examples.Adder;

public class AdderImpl implements Adder
{

  public int add(int arg0, int arg1)
  {
    return arg0 + arg1;
  }

} 

この例では、さらに3つのインタフェースとそれに対応する実装が追加されています:Subtracter・Multiplier・Dividerそして最後に全部を纏めるCalculatorです:

package hivemind.examples;


public interface Calculator extends Adder, Subtracter, Multiplier, Divider
{

}    

このCalculatorの実装は結合の為の配線工事が必要です:他の4つのサービス(Adder・, Substracter・Multiplier・Divider)が差し込まれます:

package hivemind.examples.impl;

import hivemind.examples.Adder;
import hivemind.examples.Calculator;
import hivemind.examples.Divider;
import hivemind.examples.Multiplier;
import hivemind.examples.Subtracter;

public class CalculatorImpl implements Calculator
{
  private Adder _adder;
  private Subtracter _subtracter;
  private Multiplier _multiplier;
  private Divider _divider;

  public void setAdder(Adder adder)
  {
    _adder = adder;
  }

  public void setDivider(Divider divider)
  {
    _divider = divider;
  }

  public void setMultiplier(Multiplier multiplier)
  {
    _multiplier = multiplier;
  }

  public void setSubtracter(Subtracter subtracter)
  {
    _subtracter = subtracter;
  }

  public int add(int arg0, int arg1)
  {
    return _adder.add(arg0, arg1);
  }

  public int subtract(int arg0, int arg1)
  {
    return _subtracter.subtract(arg0, arg1);
  }

  public int multiply(int arg0, int arg1)
  {
    return _multiplier.multiply(arg0, arg1);
  }

  public int divide(int arg0, int arg1)
  {
    return _divider.divide(arg0, arg1);
  }
}

モジュール・デプロイ記述子

最後に、HiveMind モジュール・デプロイ記述子であるhivemodule.xml が必要となります。

このモジュール記述子は、インタフェースと実装に関して各々のサービスを作成します。

<?xml version="1.0"?>
<module id="hivemind.examples" version="1.0.0">
  <service-point id="Adder" interface="hivemind.examples.Adder">
    <create-instance class="hivemind.examples.impl.AdderImpl"/>
    <interceptor service-id="hivemind.LoggingInterceptor"/>
  </service-point>
  
  <service-point id="Subtracter" interface="hivemind.examples.impl.SubtracterImpl">
    <create-instance class="hivemind.examples.impl.AdderImpl"/>
    <interceptor service-id="hivemind.LoggingInterceptor"/>
  </service-point>
  
  <service-point id="Multiplier" interface="hivemind.examples.Multipler">
    <create-instance class="hivemind.examples.impl.MultiplierImpl"/>
    <interceptor service-id="hivemind.LoggingInterceptor"/>
  </service-point>
  
  <service-point id="Calculator" interface="hivemind.examples.Calculator">
    <invoke-factory>
      <!-- Autowires service properties based on interface! -->
      <constuct class="hivemind.examples.impl.CalculatorImpl"/>
    </invoke-factory>
    <interceptor service-id="hivemind.LoggingInterceptor"/>
  </service-point>  
  
</module>

ここで、module id hivemind.examples がパッケージの名前と一致するよう選びましたが、絶対的に必須であるわけではありません。

興味深い点は、hivemind.BuilderFactory をCalculatorサービスのコンストラクトのために使い、他の4つのサービスとつなぎ合わせるためにも使っている、という点です。

レジストリのビルド

あらゆるサービス(あるいはコンフィグ・ポイント)にアクセスできるようになる前に、Registry がコンストラクトされなければなりません:Registry は、HiveMind によって管理されるサービスや設定のゲートウェイです。

package hivemind.examples;

import org.apache.hivemind.Registry;
import org.apache.hivemind.impl.RegistryBuilder;

public class Main
{

  public static void main(String[] args)
  {
    int arg0 = Integer.parseInt(args[0]);
    int arg1 = Integer.parseInt(args[1]);

    Registry registry = RegistryBuilder.constructDefaultRegistry();

    Calculator c =
      (Calculator) registry.getService(Calculator.class);

    System.out.println("Inputs " + arg0 + " and " + arg1);

    System.out.println("Add   : " + c.add(arg0, arg1));
    System.out.println("Subtract: " + c.subtract(arg0, arg1));
    System.out.println("Multiply: " + c.multiply(arg0, arg1));
    System.out.println("Divide  : " + c.divide(arg0, arg1));
  }
}
 

RegistryBuilder には、Registry をコンストラクトする為の、殆どの場面に見合った static メソッドが含まれています。

そして、レジストリを有する事になりましたので、Calculator インタフェースを Calculator の実装を探すためのキーとして使う事が出来るようになったわけです。実際のアプリケーションでは、同じインタフェースを実装する複数のサービスがある事がよくありますので、完全修辞のサービスIDを指定する事も必要となるでしょう。

Calculator サービスへのリファレンスを使う事で、漸くadd()subtract()multiply()divide()メソッドを invoke する事が出来るようになりました。

サンプルのビルド

Ant を使ってサンプルをビルド・実行するのはいともたやすい事です:詳細は、build.xmlの中に全てあります:

<?xml version="1.0"?>

<project name="HiveMind Adder Example" default="jar">

  <property name="java.src.dir" value="src/java"/>
  <property name="test.src.dir" value="src/test"/>
  <property name="conf.dir" value="src/conf"/>
  <property name="descriptor.dir" value="src/descriptor"/>
  <property name="target.dir" value="target"/>
  <property name="classes.dir" value="${target.dir}/classes"/>
  <property name="test.classes.dir" value="${target.dir}/test-classes"/>
  <property name="example.jar" value="${target.dir}/hivemind-examples.jar"/>
  <property name="lib.dir" value="lib"/>
  <property name="junit.temp.dir" value="${target.dir}/junit-temp"/>
  <property name="junit.reports.dir" value="${target.dir}/junit-reports"/>

  <path id="build.class.path">
    <fileset dir="${lib.dir}">
      <include name="*.jar"/>
    </fileset>
  </path>
      
  <path id="test.build.class.path">
    <path refid="build.class.path"/>
    <path location="${classes.dir}"/>
  </path>
        
  <path id="run.class.path">
    <path refid="build.class.path"/>
    <pathelement location="${classes.dir}"/>
    <pathelement location="${descriptor.dir}"/>
    <pathelement location="${conf.dir}"/>
  </path>
  
  <path id="test.run.class.path">
    <path refid="run.class.path"/>
    <path location="${test.classes.dir}"/>
  </path>  
  
  <target name="clean" description="Delete all derived files.">
    <delete dir="${target.dir}" quiet="true"/>
  </target>
  
  <target name="compile" description="Compile all Java code.">  
    <mkdir dir="${classes.dir}"/>    
    <javac srcdir="${java.src.dir}" destdir="${classes.dir}" classpathref="build.class.path"/>
  </target>
  
  <target name="compile-tests" description="Compile test classes." depends="compile">
    <mkdir dir="${test.classes.dir}"/>
    <javac srcdir="${test.src.dir}" destdir="${test.classes.dir}" classpathref="test.build.class.path"/>
  </target>
  
  <target name="run-tests" description="Run unit tests." depends="compile-tests">
  
    <mkdir dir="${junit.temp.dir}"/>
    <mkdir dir="${junit.reports.dir}"/>

    <junit haltonfailure="off" failureproperty="junit-failure" tempdir="${junit.temp.dir}">    
      <classpath refid="test.run.class.path"/>
    
      <formatter type="xml"/>
      <formatter type="plain"/>
      <formatter type="brief" usefile="false"/>
    
      <batchtest todir="${junit.reports.dir}">
        <fileset dir="${test.classes.dir}">
          <include name="**/Test*.class"/>
        </fileset>
      </batchtest>
    </junit>

    <fail if="junit-failure" message="Some tests failed."/>

  </target>
  
  <target name="jar" description="Construct the JAR file." depends="compile,run-tests">
    <jar destfile="${example.jar}">
      <fileset dir="${classes.dir}"/>
    <fileset dir="${descriptor.dir}"/>
    </jar>
  </target>
  
  <target name="run" depends="compile" description="Run the Adder service.">
    <java classname="hivemind.examples.Main" classpathref="run.class.path" fork="true">
      <arg value="11"/>
      <arg value="23"/>
    </java>
  </target>

</project>

JAR の中に HiveMind モジュール・デプロイ記述子とクラスファイルの両方をパッケージかして入れておく、というが重要なポイントです。

その他、唯一変わった点としては、src/conf をランタイムのクラスパスに追加する、という点が挙げられるでしょうか:log4j.properties という設定ファイルを追加するためです:さもないと、Log4J が設定ミスに関するコンソールのエラーメッセージを吐き出すでしょう。

サンプルの実行

bash-2.05b$ ant run
Buildfile: build.xml

compile:
    [mkdir] Created dir: C:\workspace\hivemind-example\target\classes
    [javac] Compiling 15 source files to C:\workspace\hivemind-example\target\classes

run:
     [java] Inputs 11 and 23
     [java] Add     : 34
     [java] Subtract: -12
     [java] Multiply: 253
     [java] Divide  : 0



BUILD SUCCESSFUL
Total time: 3 seconds