Bootstrapping the Registry |
アプリケーションのモジュール・デプロイ記述子に定義されているコンフィグ・ポイントやサービスにアクセスする事が可能となる前に、レジストリが必要となります:ここでは、どのようにレジストリを組み立てるかについて記述していきます。
ここでキーとなるクラスは、RegistryBuilderです。これはに、モジュール・デプロイ記述子の場所確認と解析を行うコード、及び、バインディングデータからレジストリを組み立てる為のコードが含まれています。記述子は全てクラスパスの中から探し出されます:アプリケーションのJAR 群にパッケージ化された記述子と共に、HiveMind 自身の記述子をも含んでいます
どのように全て成り立つか調べてみます。プロジェクトのレイアウトは以下のとおりです。
![[Project Layout]](images/Bootstrap-ProjectLayout.png)
サービス・インタフェースと実装
まず始めのステップで、サービス・インタフェースを定義します:
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

