ナビゲーション・リンクをスキップ

JP1/AJS2 Unitdef 2.7.0-RELEASE API

JP1/AJS2ユニット定義をパースし、問合せ、加工するためのJava API.

参照先: 説明

パッケージ 
パッケージ 説明
org.unclazz.jp1ajs2.unitdef  
org.unclazz.jp1ajs2.unitdef.builder  
org.unclazz.jp1ajs2.unitdef.parameter  
org.unclazz.jp1ajs2.unitdef.parser  
org.unclazz.jp1ajs2.unitdef.query  
org.unclazz.jp1ajs2.unitdef.util  
JP1/AJS2ユニット定義をパースし、問合せ、加工するためのJava API.

このライブラリは、日立ソリューションズの製造・販売するJP1/AJS2の定義情報をパースし、 JavaオブジェクトとしてアクセスするためのAPIを提供するものである。 APIを構成するモジュールやそれらのモジュールが提供する機能を使用するサンプルコードは src/test/javaディレクトリ配下のorg.unclazz.jp1ajs2.sampleパッケージに含まれている。

使用例

まずリリース一覧 からjarファイルを取得してプロジェクトのビルドパスに含める。 もしあなたのプロジェクトがMavenを使用しているのであれば、アーティファクトはGithub上の Mavenリポジトリから取得できる。 そのための設定はpom.xmlに以下のコード断片を追加するだけである:

<repositories>
    ...
    <repository>
        <id>unclazz-mvn-repo</id>
        <url>https://raw.github.com/unclazz/mvn-repo/master/</url>
        <snapshots>
            <enabled>true</enabled>
            <updatePolicy>always</updatePolicy>
        </snapshots>
    </repository>
</repositories>
<dependencies>
    ...
    <dependency>
        <groupId>org.unclazz.jp1ajs2</groupId>
        <artifactId>unclazz-jp1ajs2-unitdef</artifactId>
        <version>X.X.X-RELEASE</version>
    </dependency>
<dependencies>

そしてビジネスロジックをコーディングする:

import static org.unclazz.jp1ajs2.unitdef.query.Queries.*;

final String sampleDef = ""
        + "unit=XXXX0000,,,;\r\n"
        + "{\r\n"
        + " ty=n;\r\n"
        + " el=XXXX0001,g,+80 +48;\r\n" 
        + " el=XXXX0002,g,+240 +144;\r\n"
        + " ar=(f=XXXX0001,t=XXXX0002);\r\n" 
        + " cm=\"これはコメントです。\";\r\n"
        + " fd=30;\r\n"
        + " unit=XXXX0001,,,;\r\n"
        + " {\r\n"
        + "     ty=pj;\r\n"
        + "     sc=\"hello.exe\";\r\n"
        + " }\r\n"
        + " unit=XXXX0002,,,;\r\n"
        + " {\r\n"
        + "     ty=pj;\r\n" 
        + "     sc=\"bonjour.exe\";\r\n"
        + " }\r\n"
        + "}\r\n";

// ユニット定義を文字列から読み取る
// Units.from...系メソッドは文字列・ストリーム・ファイルに対応している
final Unit u0 = Units.fromCharSequence(sampleDef).get(0);

// Unitオブジェクトはユニット定義情報にアクセスするローレベルのAPIを提供する
u0.getName(); // => "XXXX0000"
u0.getType(); // => "JOBNET"
u0.getSubUnits().size(); // => 2

// Query<T>とそのユーティリティを使ってユニットから各種の情報を取得できる
// arパラメータ(下位ユニット間の実行順序関係を示す)を遅延評価Iterableのかたちで取得
final Iterable<AnteroposteriorRelationship> ars = u0.query(ar());
// elパラメータ(下位ユニットの種別とマップ上の配置を示す)を正格評価Listのかたちで取得
final Iterable<Element> els = u0.query(el().list());
// fdパラメータ(実行所要時間を示す)を1つ取得
final FixedDuration fd0 = u0.query(fd().one());
// scパラメータ(PCジョブの実行ファイル名を示す)が"hello"で始まるユニットを遅延評価Iterableのかたちで取得
final Iterable<Unit> us = u0.query(descendants()
        .hasParameter("sc").startsWith("hello"));

Unit/Unitsオブジェクト

UnitはJP1/AJS2のユニット定義をあらわすインターフェースである。 クライアント・コードはこのインターフェースを通じてユニット定義に含まれる情報 ──ユニット名やその他のユニット属性パラメータや、 sz・cm・fdといったユニット定義パラメータ、 そして下位ユニットの情報──にアクセスすることができる。

final Unit u = ...;
u.getName(); // => ユニット名
u.getFullQualifiedName(); // => ユニット完全名
u.getAttributes(); // => ユニット属性パラメータ
u.getSubUnits(); // => 下位ユニットのリスト

UnitsUnitオブジェクトのファクトリ/ユーティリティ・クラスである。 Units.fromStream(InputStream)とその同系統のメソッドは、各種の入力ソースから ユニット定義情報を読み取って Unitオブジェクトを返す。

final List<Unit> us = Units.fromCharSequence("unit=FOO,,,;{" +
    "ty=g;cm=\"This is a jobnet-group unit named #\"FOO#\".\";}");
final Unit u = us.get(0);
u.getName(); // => "FOO"

一方serialize()Units#writeToStream(Unit,OutputStream)メソッドは その名前の通りUnitオブジェクトの文字列化を行う。

Parameter/ParameterValue

JP1/AJS2のユニット定義は、ユニットをノードとする木構造と そのノードに紐づく1つ以上のユニット定義パラメータ (名前の重複が許容されるものとそうでないものがある)、 そしてそのパラメータに紐づく1つ以上の値という部品を中心として成り立っている。

このうちユニット、つまりUnitについてはすでに紹介した。 そのgetParameters()メソッドを呼び出すと ユニット定義パラメータをあらわすParameterインターフェースのリストが得られる。 そしてgetValues()メソッドを呼び出すと パラメータ値をあらわすParameterValueインターフェースが得られる。

ParameterValueには3つの値のかたち ──文字シーケンス、 二重引用符で囲われた文字シーケンス、そしてタプル──のいずれかをとる。 ParameterValueが 提供するメソッドを通じてこれらのデータにアクセスすることができる。

Query

UnitParameterParameterValueという3つのインターフェースを通じた 木構造のトラバースは もっとも基本的でローレベルの操作となる。 これに対してQueryインターフェースを中核とした より生産性の高いAPIが用意されている。

例えばユニット定義パラメータszの情報を読み取るには次のようにする:

import static org.unclazz.jp1ajs2.unitdef.Queries.*;
...
final Unit u = ...;
final Iterable<MapSize> szs = u.query(sz()); // sz() = Queries.sz()

何かしらの条件を満たすサブユニット(子ユニット)や子孫ユニットを取得するには次のようにする:

import static org.unclazz.jp1ajs2.unitdef.Queries.*;
...
final Unit u = ...;

// サブユニット(子ユニット)を問合せる
final Iterable<Unit> cs0 = u.query(children());

// サブユニットを持つサブユニットを問合せる
final Iterable<Unit> cs1 = u.query(children.hasChildren());

// サブユニットの完全名を問合せる
final Iterable<FullQualifiedName> cs2 = u.query(children().theirFqn());

// 子孫ユニットを問合せる
final Iterable<Unit> ds0 = u.query(descendants());

// ユニット種別がPCジョブである子孫ユニットを問合せる
final Iterable<Unit> ds1 = u.query(descendants().typeIs(UnitType.PC_JOB));

// ユニット種別がPCジョブでユニット名が"..."で始まる子孫ユニットを問合せる
final Iterable<Unit> ds2 = u.query(descendants().typeIs(UnitType.PC_JOB).nameStartsWith("..."));

定義済みのクエリはQueriesというユーティリティ・クラスを通じて得られる。 サンプルコードにもあるように、定義済みクエリを利用する場合はこれらのクラスの静的メンバを適宜インポートしておこう。 ユーティリティは以下のような定義済みクエリを提供している(このうちいくつかはサンプルコードにも登場している):

children()
問合せ対象ユニットの子ユニット(直接の下位ユニット)を問合せるクエリ。
descendants()
問合せ対象ユニットの子孫ユニット(直接・間接の下位ユニット)を問合せるクエリ。
itSelfAndDescendants()
問合せ対象ユニットそれ自身とその子孫ユニット)を問合せるクエリ。
parameters()
問合せ対象ユニットのユニット定義パラメータを問合せるクエリ。
parameter()
問合せ対象ユニット定義パラメータのパラメータ値を問合せるクエリ。
ar()fd()sz()など
問合せ対象ユニットのユニット定義パラメータをその各パラメータ固有のインターフェースに変換するクエリ。

イミュータブルかつスレートレス

定義済みクエリの実装はイミュータブルでありステートレスであるので、複雑な条件を設定したインスタンスの参照を保持しておくことで、 複数の異なるユニットに対して繰り返し問合せを行うことができる。

Query<Unit,Iterable<Unit>> q0 = children().hasChildren();
Query<Unit,Iterable<Unit>> q1 = q0.typeIs(UnitType.PC_JOB);
Query<Unit,Iterable<Unit>> q2 = q1.hasParameter("cm").anyValue();
Query<Unit,Iterable<Unit>> q3 = q2.hasParameter("sc").endsWith(".exe");
Iterable<Unit> us0 = u.query(q1); // cmパラメータを持つこと という条件は付かない
Iterable<Unit> us1 = u.query(q2); // scパラメータ値が".exe"で終わることという条件は付かない

遅延評価と正格評価

定義済みクエリのうち問合せ結果としてIterableを返すものは処理方式として遅延評価を採用している。 つまりこれらのクエリのqueryFrom(Object) メソッドから返えされるIterableはそれが生成された時点ではまだ問合せ結果を内包していない。 問合せ処理の起動は可能な限り遅らせられるので、仮に要素を1つ取得するだけでIterableインスタンスを破棄したとしても、 そのために消費されるCPUとメモリのコストは当該の1ユニットを問合せるのに必要な分だけである。

なおこのように問合せ結果のうち最初の1つだけを取得したい場合は、 one() メソッドもしくはそのオーバーロードを呼び出して OneQueryのインスタンスを得ると便利である。 また問合せ結果として遅延評価Iterableの代わりに正格評価Listを取得したい場合は、 list() メソッドを呼び出してクエリListQueryのインスタンスを得るとよい。

Unit u2 = u.query(children().one());
List<Unit> ul = u.query(children().list());

パラメータの変更

JP1/AJS2のユニット定義ではスケジュールルールに関する設定のパラメータのほか多くの箇所でデフォルト値の省略が行われている。 このため定義情報のファイルサイズは節約されるかもしれないが、その読み取りロジックはしばしば煩雑なものとなってしまう。 このような状況をさけ、ロジックのコーディングを可能な限りアプリケーションの主な関心のためのものとするため、 ParameterConditionalModifier インターフェースを利用することができる。

このインターフェースを実装したクエリはchildren().theirParameters()descendants().theirParameters()parameters()そしてparameter()などから得られる。 いずれもQueriesユーティリティ・クラスが直接・間接に提供しているものだ。 これらのクエリは例えば以下のようにして使う:

final Unit u = ...;

// ユニット定義パラメータsdを問合せる
// ただし各パラメータについてパラメータ値の数が1つであれば先頭に省略された"1"を補う
final Iterable<Parameter> sds = u.query(parameters("sd")
                                        .whenValueCount(1).thenPrepend("1"));

// ユニット定義パラメータctfdを問合せる
// ただし各パラメータについてその1番目の値が"no"・"be"・"af"のいずれかなら先頭に省略された"1"を補う
final Iterable<Parameter> ctfds = u.query(parameters("ctfd")
                                        .whenValueAt(0).equalsAnyOf("no", "be", "af")
                                        .thenPrepend("1"));

JP1/AJS2製造・販売元との関係

JP1/AJS2製造・販売元に対する本プロジェクト開発者の立場は単なる「ユーザー」である。 したがって、本プロジェクトで開発・配布するコードは製造・販売元とは一切関わりがない。

本プロジェクトで開発・配布するコードは、製造・販売元で公開している 定義情報リファレンスに基づき、 これを参考にして、定義ファイルのパースや各種パラメータのアクセサのロジックを実装しているものの、 同リファレンスの誤読もしくはリファレンスとJP1/AJS2間の実装齟齬などにより、実際の動作に差異が存在する可能性がある。

ナビゲーション・リンクをスキップ

Copyright © 2016. All rights reserved.