ガイド
Woolpackにおけるインタープリタ デザインパターンの考え方
Woolpackにおけるインタープリタ デザインパターンでは、 処理部品を組み立てるフェーズと処理部品を実行するフェーズを分離するところに特徴があります。 処理部品を組み立てるフェーズでは以下の例のように部品を組み立てていきます。
final Fn fn = new RegExpConverter(Pattern.compile("##(.+)##"), "$1");
処理部品に対し依存性が自然に注入されます(依存性の注入)。 またオブジェクトを生成する処理が処理部品の組み立てるフェーズに集中することにより 処理部品と組み立て処理の間で依存性が自然に逆転します(制御の逆転)。 既存のDI/IoCコンテナの代替としてインタープリタ デザインパターンを使用することができます。
処理部品を実行するフェーズでは以下の例のように処理を実行します。
final String result = fn.exec("mamo##hona##mimo");
assertEquals("mamohonamimo", result);
RegExpConverterクラスやPatternクラス、 変換元の正規表現や変換後の置き換えパターン「"$1"」に依存しない、 Fnインタフェースだけを知っている処理ブロックやクラスを設計することができ、 疎結合を維持することができます。
型推論とスタティックインポートの使いかた
Java5から導入された汎用型(Generics)には型推論とスタティックインポートの機能があります。 Woolpackでは各処理部品に対してそれらを生成するスタティックメソッドを用意しており、 これらを使用することにより組み立てフェーズにおける記述を簡略化することができます。
型推論を使わずにコンストラクタで処理部品を組み立てると以下の例のようになります。
final Fn<String, String, RuntimeException> fn = new JoinFn<String, String, String, RuntimeException>(
  new RegExpConverter<RuntimeException>(Pattern.compile("#@@([^@]+)@#"), "?$1?"),
  new RegExpConverter<RuntimeException>(Pattern.compile("#@([^@]+)@#"), "!$1!")
);
assertEquals("mamo?hona?piyo!maro!mimo", fn.exec("mamo#@@hona@#piyo#@maro@#mimo"));
型推論を使うと以下の例のようになります。
final Fn<String, String, RuntimeException> fn = FnUtils.join(
  ConvertUtils.convertRegExp(Pattern.compile("#@@([^@]+)@#"), "?$1?"),
  ConvertUtils.convertRegExp(Pattern.compile("#@([^@]+)@#"), "!$1!")
);
さらにスタティックインポートを使うと以下の例のようになります。
import static woolpack.fn.FnUtils.*;
import static woolpack.convert.ConvertUtils.*;
// ...
final Fn<String, String, RuntimeException> fn = join(
  convertRegExp(Pattern.compile("#@@([^@]+)@#"), "?$1?"),
  convertRegExp(Pattern.compile("#@([^@]+)@#"), "!$1!")
);
型推論を使用してMapインスタンスを以下の例のように組み立てることができます。
final Map<String, String> map = Utils.map("key0", "value0").map("key1", "value1");
assertEquals(2, map.size());
assertEquals("value0", map.get("key0"));
assertEquals("value1", map.get("key1"));
組み立てるMapインスタンスの各値の型が異なる場合は以下の例のように宣言します。
final Map<String, Number> map = Utils.<String, Number>map("key0", 3).map("key1", 3.1);
assertEquals(2, map.size());
assertEquals(Integer.valueOf(3), map.get("key0"));
assertEquals(Double.valueOf(3.1), map.get("key1"));
型推論を使用してListインスタンスを以下の例のように組み立てることができます。
final List<String> list = Utils.list("a").list("b");
assertEquals(Arrays.asList("a", "b"), list);
組み立てるListインスタンスの各値の型が異なる場合は以下の例のように宣言します。
final List<Number> list = Utils.<Number>list(3).list(3.1);
assertEquals(Arrays.asList((Number) 3, 3.1), list);
式言語部品の使いかた(woolpack.el)
Woolpackでは式言語のインタフェース「GettingEL」と「EL」を定義しており、 実装としてWoolpack実装とOGNLアダプタとJXPathアダプタを用意しています。
ELインタフェースは以下の例のように使います。
final EL el = null/* ... */;
final Map<String, String> map = Utils.map("key0", "value0");
final Object object = el.getValue(map);
assertEquals("value0", object);
el.setValue(map, "value1");
assertEquals("value1", map.get("key0"));
Woolpack実装は以下の例のように宣言します。
final EL el = new PathEL("key0");
Woolpack実装ではデフォルトで配列、コレクション、単純型、マップ(0.08予定)、Bean(0.08予定)をある程度自動的に変換します。
OGNLアダプタは以下の例のように宣言します。
final EL el = new OGE("key0");
OGNLを文字列で指定します。OGNLの文法は http://www.ognl.org/または http://s2container.seasar.org/ja/ognl.html が詳しいです。
JXPathアダプタは以下の例のように宣言します。
final EL el = new JXE("key0");
XPathを文字列で指定します。JXPathの文法は http://jakarta.apache.org/commons/jxpath/ が詳しいです。
Woolpackの式言語インタフェースは 処理部品を組み立てるフェーズと処理部品を実行するフェーズを分離するところに特徴があります。 式言語インタフェースのインスタンスを受け取って使っているクラスを一部紹介します。
クラスクラスの機能式言語インタフェースの使いかた
ActionDefMVCのひとつのアクション情報実行するPOJOのメソッドを指定する
AutoUpdaterコンポーネントのデータをDOMに流し込む処理部品データの取得先コンポーネントを指定する
DB処理部品の使いかた(woolpack.sql.fn)
Woolpackでは RDBメタ情報・クエリ生成・RDB値バインド・RDB値取得・トランザクション分離機構を 部品化しています。これらを組み立てて使用します。
入力のない更新系のクエリは以下の例のように宣言します。
final DataSource dataSource = null/* ... */;
final Fn<Object, Integer, Exception> fn = SqlFnUtils.inputStatement(
  dataSource,
  "create memory table my_table (" +
  "my_id integer, " +
  "my_seq integer, " +
  "my_string varchar, " +
  "my_int integer, " +
  "constraint MYTALBE0P primary key (my_id, my_seq))",
  SqlFnUtils.GET_COUNT);
assertEquals(Integer.valueOf(0), fn.exec(null));
入力のあるクエリは以下の例のように宣言します。
final DataSource dataSource = null/* ... */;
final Fn<Map<String, ?>, Integer, Exception> fn = SqlFnUtils.inputMap(
  dataSource,
  new PreparedStatementInfo(
    "insert into my_table (my_id, my_seq, my_string, my_int) values (?, ?, ?, ?)",
    Arrays.asList("myId", "mySeq", "myString", "myInt")),
  SqlFnUtils.GET_COUNT);
assertEquals(
  Integer.valueOf(1),
  fn.exec(Utils.<String, Object>map("myId", 0).map("mySeq", 1).map("myString", "c0").map("myInt", 2)));
入力と出力がひとつの項目だけであるクエリは以下の例のように宣言します。
final DataSource dataSource = null/* ... */;
final Fn<Object, Object, Exception> fn = SqlFnUtils.inputSingle(
  dataSource,
  "select my_string from my_table where my_id = ?",
  SqlFnUtils.getOne(SqlFnUtils.GET_SINGLE));
assertEquals("c0", fn.exec(0));
出力が複数の項目で複数レコードであるクエリは以下の例のように宣言します。
final DataSource dataSource = null/* ... */;
final Fn<Map<String, ?>, List<Map<String, Object>>, Exception> fn = SqlFnUtils.inputMap(
  dataSource,
  new PreparedStatementInfo(
    "select * from my_table where my_id = ? and my_seq = ?",
    Arrays.asList("myId", "mySeq")),
  SqlFnUtils.getList(SqlFnUtils.getMapResult()));
assertEquals(
  Utils.list(Utils.
    <String, Object>map("MY_ID", 0)
    .map("MY_SEQ", 1)
    .map("MY_STRING", "c0")
    .map("MY_INT", 2)),
  fn.exec(Utils.
    <String, Object>map("myId", 0)
    .map("mySeq", 1)));
出力がBeanであるクエリは以下の例のように宣言します。
final DataSource dataSource = null/* ... */;
final Fn<Object, TestBean, Exception> fn = SqlFnUtils.inputStatement(
    dataSource,
    "select * from my_table where my_id = 0 and my_seq = 1",
    SqlFnUtils.getOne(SqlFnUtils.getBeanResult(TestBean.class)));
assertEquals(2, fn.exec(null).getMyInt());
トランザクション制御部品の使いかた(woolpack.fn.tx)
Woolpackでは トランザクションを制御するDataSourceのプロキシと トランザクションが制御されたDataSourceのプロキシの組を生成するビルダーを用意しています。 これを使用することにより DataSourceを使用するDBアクセスクラスはそのままで 業務ロジックからトランザクション処理を分離することができます。
複数の更新クエリでトランザクションを制御する場合は以下の例のように宣言します。
final DataSource dataSource = null/* ... */;
final TxBuilder builder = new TxBuilder(dataSource);
final Fn<Map<String, ?>, Integer, Exception> fn = SqlTxUtils.tx(
  builder.getTxDataSource(),// トランザクションを制御するDataSourceのプロキシ
  FnUtils.seq(Utils.
    list(SqlFnUtils.inputMap(
      builder.getTmpDataSource(),// トランザクションが制御されたDataSourceのプロキシ
      new PreparedStatementInfo(
        "insert into your_table (my_int, your_string) values (?, ?)",
        Arrays.asList("myInt", "yourString")),
      SqlFnUtils.GET_COUNT))
    .list(
      SqlFnUtils.inputMap(
        builder.getTmpDataSource(),// トランザクションが制御されたDataSourceのプロキシ
        new PreparedStatementInfo(
          "insert into my_table (my_id, my_seq, my_string, my_int) values (?, ?, ?, ?)",
          Arrays.asList("myId", "mySeq", "myString", "myInt")),
        SqlFnUtils.GET_COUNT))));
fn.exec(Utils.<String, Object>
map("myId", 0)
.map("mySeq", 1)
.map("myString", "c0")
.map("myInt", 2)
.map("yourString", "y0"));
上の例ではトランザクションブロックである「SqlTxUtils.tx」の中にふたつのクエリを指定していますが、 「SqlTxUtils.tx」の委譲先には任意の「Fn」インスタンスを指定することができます。 特に、識別子で業務を分岐する処理を「SqlTxUtils.tx」の委譲先の中に指定することにより 業務に対し横断的にトランザクション制御を定義することができます。
RDBテーブル情報制御部品の使いかた(woolpack.sql.meta)
WoolpackではDatabaseMetaDataからテーブル定義のメタ情報(DDL)を取得することができます。
final DataSource dataSource = null/* ... */;
final List<TableInfo> result = TableInfoUtils.getTableInfoList(dataSource);
メタ情報を使用して簡単なCRUDクエリを生成することができます。
ひとつのテーブルからinsertクエリを生成するには以下の例のように使います。
final TableInfo tableInfo = null/* ... */;
final PreparedStatementInfo psInfo = SqlMetaUtils.INSERT_FACTORY.exec(tableInfo);
assertEquals(
  "INSERT INTO my_table(my_id, my_seq, my_string, my_int) VALUES (?, ?, ?, ?)",
  psInfo.getQuery());
assertEquals(
  Arrays.asList("my_id", "my_seq", "my_string", "my_int"),
  psInfo.getList());
主キーを検索条件とするselectクエリを生成するには以下の例のように宣言します。
final PreparedStatementInfo psInfo = SqlMetaUtils.SELECT_FACTORY.exec(tableInfo);
主キーを検索条件とするupdateクエリを生成するには以下の例のように宣言します。
final PreparedStatementInfo psInfo = SqlMetaUtils.UPDATE_FACTORY.exec(tableInfo);
主キーを検索条件とするdeleteクエリを生成するには以下の例のように宣言します。
final PreparedStatementInfo psInfo = SqlMetaUtils.DELETE_FACTORY.exec(tableInfo);
指定されたカラム名だけを指定するinsertクエリを生成するには以下の例のように宣言します。
final PreparedStatementInfo psInfo = SqlMetaUtils.INSERT_FACTORY_FACTORY.exec(tableInfo)
.exec(Arrays.asList("my_id", "my_seq", "my_int"));
指定されたカラム名だけを検索条件とするselectクエリを生成するには以下の例のように宣言します。
final PreparedStatementInfo psInfo = SqlMetaUtils.SELECT_FACTORY_FACTORY.exec(tableInfo)
.exec(Arrays.asList("my_id", "my_int"));
主キーの指定されたカラム名だけを検索条件として指定されたカラム名だけを更新するupdateクエリを生成するには以下の例のように宣言します。
final PreparedStatementInfo psInfo = SqlMetaUtils.UPDATE_FACTORY_FACTORY.exec(tableInfo)
.exec(Arrays.asList("my_id", "my_int"));
DDLからのクエリ生成とwoolpack.sql.fnの部品を組み合わせて宣言することができます。
静的なクエリとして組み合わせるには以下の例のように宣言します。
final DataSource dataSource = null/* ... */;
final TableInfo tableInfo = null/* ... */;
final Fn<Map<String, ?>, List<Map<String, Object>>, Exception> fn = SqlFnUtils.inputMap(
    dataSource,
    SqlMetaUtils.SELECT_FACTORY.exec(tableInfo),
    SqlFnUtils.getList(SqlFnUtils.getMapResult()));
assertEquals(
    Utils.list(Utils.map("MY_ID", (Object) 0).map("MY_SEQ", 1).map("MY_STRING", "c0").map("MY_INT", 2)),
    fn.exec(Utils.map("MY_ID", (Object) 0).map("MY_SEQ", 1)));
動的なクエリとして組み合わせるには以下の例のように宣言します。
final DataSource dataSource = null/* ... */;
final TableInfo tableInfo = null/* ... */;
final Fn<Map<String, ?>, List<Map<String, Object>>, Exception> fn = SqlFnUtils.inputMap(
  dataSource,
  FnUtils.join(
    ConvertUtils.<String>keySet(),
    SqlMetaUtils.SELECT_FACTORY_FACTORY.exec(tableInfo)),
    SqlFnUtils.getList(SqlFnUtils.getMapResult()));
assertEquals(
  Utils.list(Utils.map("MY_ID", (Object) 0).map("MY_SEQ", 1).map("MY_STRING", "c0").map("MY_INT", 2)),
  fn.exec(Utils.map("MY_ID", (Object) 0).map("MY_SEQ", 1)));
Webアプリケーション部品の使いかた(woolpack.ee)
WoolpackではWebアプリケーションの作成を支援するためにいくつかの部品を用意しています。 Servlet APIのrequest、session、applicationの各スコープをMapインタフェースで扱うためのアダプタを用意しています。 これらを利用することにより業務クラスがServlet APIに依存することを防止し、JUnitテストケースの実装と実行を容易にします。
final Map<String, Object> request = new ServletRequestAttributeMap(request);
final ConcurrentMap<String, Object> session = Utils.concurrentMap(new HttpSessionMap(
  request.getSession()),
  request.getSession());
final ConcurrentMap<String, Object> application = Utils.concurrentMap(new ServletContextMap(
  request.getSession().getServletContext()),
  request.getSession().getServletContext());
Webアプリケーションを作成するときはHttpServletを継承して以下の例のように作ります。
public class HelloServlet extends HttpServlet {
  public final transient Fn<EEContext, Void, Exception> fn;
  public HelloServlet() {
    super();
    // Fnを組み立てます。
    fn = null/* ... */;
  }
  @Override
  public void init(final ServletConfig servletConfig) throws ServletException {
    super.init(servletConfig);
    // ServletContextを使用する設定を行います。
    // ...
  }
  @Override
  protected void service(
      final HttpServletRequest request,
      final HttpServletResponse response)
  throws ServletException, IOException {
    // コンテキストを生成して設定します。
    final EEContext context = new EEContext();
    context.setId(request.getRequestURI());
    context.setInput(request.getParameterMap());
    context.setRequest(new ServletRequestAttributeMap(request));
    context.setSession(Utils.concurrentMap(new HttpSessionMap(
        request.getSession()), request.getSession()));
    context.setApplication(Utils.concurrentMap(new ServletContextMap(
        request.getSession().getServletContext()), request.getSession().getServletContext()));
    // Fnを実行します。
    fn.exec(context);
    
    // ブラウザに返すストリームをcontext.getId()から特定して生成します。
    // woolpack.xmlパッケージを使用することもできますが、
    // 他のServletにforwardすることもできます。
    // ...
  }
}
オブジェクトの生成を定義する方法(woolpack.container, woolpack.web)
Woolpackではオブジェクトの生成をフラット構造で定義する部品を用意しています。 生成したオブジェクトをWebアプリケーションの各スコープにキャッシュするように定義することもできます。
OGNLUtils.setting();
final Fn<? super ContainerContext<WebContext>, ?, Exception> fn =
  FnUtils.exec(FnUtils.join(
    ContainerUtils.getKey(),
    FnUtils.switching(Utils.<Object, Fn<? super ContainerContext<WebContext>, ?, ? extends Exception>>
      map("gyoumu0", WebUtils.request(FactoryUtils.newInstance(MyGyoumu0Bean.class)))
      .map("gyoumu1", WebUtils.session(FactoryUtils.newInstance(MyGyoumu1Bean.class)))
      .map("gyoumu2", WebUtils.application(FactoryUtils.newInstance(MyGyoumu2Bean.class)))
      .map("gyoumu3", FnUtils.fix(FactoryUtils.newInstance(MyGyoumu3Bean.class)))
      .map("gyoumu4", FactoryUtils.doEL(new OGE("new woolpack.gomi.MyGyoumu4Bean(gyoumu0, gyoumu2)")))
)));

final SimpleWebContext webContext = new SimpleWebContext();
webContext.setRequest(new HashMap<String, Object>());
webContext.setSession(Utils.concurrentMap(new HashMap<String, Object>(), new Object()));
webContext.setApplication(Utils.concurrentMap(new HashMap<String, Object>(), new Object()));

final ContainerContext<WebContext> context = new ContainerContext<WebContext>();
context.setSubContext(webContext);
context.setFn(fn);
webContext.setContainer(context);
{
  final Object result = context.visit("gyoumu4");
  assertTrue(result instanceof MyGyoumu4Bean);
}
OGNLを使用して以下の例のようにアクセスすることができます。
final EL el = new OGE("container.gyoumu4");
final Object result = el.getValue(webContext);
assertTrue(result instanceof MyGyoumu4Bean);
Webアプリケーションで使用するときは「ContainerContextSetter」クラスを使用して以下の例のように宣言します。
final Fn<WebContext, Void, RuntimeException> fn1 = WebUtils.setContainerContext(fn);
業務の分岐を定義するには(woolpack.id)
Woolpackでは業務の分岐を行うための部品を用意しています。
以下の例のようにして業務の分岐を宣言します。
final DataSource dataSource = null/* ... */;
final Fn<EEContext, Void, Exception> fn =
  FnUtils.seq(Utils.<Fn<? super EEContext, Void, ? extends Exception>>
    list(IdUtils.<Void, RuntimeException>convertId(ConvertUtils.convertRegExp(Pattern.compile("^.*/([^/]+)$"), "$1")))
    .list(FnUtils.exec(FnUtils.join(IdUtils.GET_ID, FnUtils.switching(
      Utils.<String, Fn<EEContext, Void, RuntimeException>>
      map("id0", new Gyoumu0Fn())
      .map("id1", new Gyoumu1Fn(dataSource))
      .map("id2", new Gyoumu2Fn(9))
      ,
      new DefaultFn()
    ))))
  );
想定されない識別子のためのデフォルトの委譲先を定義することも可能です。
Webアプリケーションに適用する時はURLなどから識別子を取得してコンテキストに設定します。
final EEContext context = new EEContext();
context.setId(request.getRequestURI());
fn.exec(context);
フォーマットの使いかた(woolpack.convert)
Woolpackではjava.text.Formatを利用した変換用部品を用意しています。
java.text.Formatのformat()メソッドを利用した変換器は以下の例のように宣言します。
assertEquals("3",
  ConvertUtils.format(ConvertUtils.formatFactory(new DecimalFormat()))
  .exec(Integer.valueOf(3)));
java.text.FormatのparseObject()メソッドを利用した変換器は以下の例のように宣言します。
final Fn<String, Object, Exception> fn =
  ConvertUtils.parse(ConvertUtils.formatFactory(new DecimalFormat()));
assertEquals(Long.valueOf(3), fn.exec("3"));
XML・HTML加工用部品の使いかた(woolpack.xml, woolpack.html)
WoolpackではDOMノードを加工する部品を用意しています。 HTMLとDOMに相互に変換することによりWebアプリケーションのビューを制御することができます。
JUnitテストケースなどで文字列とDOMノードを相互変換するには以下の例のように使います。
final Node node = XmlTransformerUtils.convert("<HTML><BODY><SPAN id=\"id0\"/></BODY></HTML>");
final String s = XmlTransformerUtils.convert(node);
DOMノードをストリームに変換するには以下の例のように使います。
final Node node = null/* ... */;
final Writer w = null/* ... */;
try {
  final XmlTransformerContext tc = new XmlTransformerContext();
  tc.setSource(new DOMSource(node));
  tc.setResult(new StreamResult(w));
  XmlTransformerUtils.TRANSFORMER.exec(tc);
} finally {
  w.close();
}
WebアプリケーションでリソースをDOMノードに変換するには以下の例のように宣言します。
final ServletConfig servletConfig = null/* .. */;
final Fn<String, Node, Exception> fn = FnUtils.join(
  ConvertUtils.convertRegExp(Pattern.compile("^(.*)$"), "/html/sample/hello/$1.html"),
  XmlUtils.nodeFactory(
    FactoryUtils.inputStreamReaderFactory(new ServletInputStreamFactory<IOException>(
      servletConfig.getServletContext()), "UTF-8"),
      XmlTransformerUtils.TRANSFORMER));
XPathを使用してノードを検索するには以下の例のように使います。
final Node node = null/* ... */;
final NodeList list = JXPUtils.list("//SPAN/@id").exec(node);
final Node result = JXPUtils.one("//SPAN/@id").exec(node);
ノードの検索結果を加工するには以下の例のように宣言します。
final Fn<NodeContext, Void, RuntimeException> fn = XmlUtils.findNode(JXPUtils.list("//*[@id=\"dummy\" or @name=\"dummy\"]"), XmlUtils.REMOVE_THIS);
Woolpackではコンポーネントのデータを特定の規約にしたがってDOMに流し込む処理部品「AutoUpdater」を用意しています。 コンポーネントのデータ構造に似た属性名マーカー付きDOMノードをテンプレートとして定義することにより、 データの流し込み処理を自動化することができます。 以下の例のように宣言します。
final Fn<NodeContext, Void, RuntimeException> fn = HtmlUtils.updateAuto(Arrays.asList("name", "id"), new PathEL("map"), null);
流し込み処理の動作例はサンプル main アプリケーションでみることができます。
MVC制御部品の使いかた(woolpack.action, woolpack.ee.ActionBuilder)
WoolpackではMVCを制御する部品を用意しています。 以下の例のように宣言します(woolpack.samples.crud.SampleServletから抜粋)。
final ActionBuilder actionBuilder = new ActionBuilder(
  new ActionInvoker(
    FnUtils.switching(new ActionDefMaker()
    .putForward("simple_error")
    .putForward("simple_errorValidate")
    .putForward("common_top")
    // 登録の指示画面にSampleBeanの初期値をそのまま流し込むための画面遷移定義です。
    .put(
      "user_registerInput",
      ELUtils.NULL,
      ELUtils.NULL,
      new OGE("container.userBean"))
    // 入力画面の入力値を確認画面にそのまま流し込むための画面遷移定義です。
    .putEcho("user_registerConfirm")
    // HTML hidden として送信されたリクエストの入力値を userBeanに設定し、
    // それを引数に userController.register に渡す画面遷移定義です。
    .put(
      "user_registerResult",
      new OGE("container.userBean"),
      new OGE("container.userController.register(container.userBean)"),
      ELUtils.NULL)
    .get()),
    // 各画面遷移定義でマッチしなかったアクション結果に対するデフォルトの遷移先定義です。
    new ForwardDef("simple_error", new PathEL("local"), FnUtils.fix(true))),
    // 自動的に画面に値を設定するための、更新対象の属性名の一覧の定義です。
    Arrays.asList("name", "id"));
Webアプリケーションとして利用するには以下の例のように宣言します。
final Fn<EEContext, Void, Exception> fn = FnUtils.seq(Utils.<Fn<? super EEContext, Void, ? extends Exception>>
  // ...
  list(actionBuilder.getActionExpression())
  // DOMノードを生成する処理など
  // ...
  .list(actionBuilder.getAutoUpdateExpression())
  // ...
);
入力値検証部品の使いかた(woolpack.validator, woolpack.ee.ValidatorBuilder)
Woolpackでは入力値検証を定義する部品を用意しています。 以下の例のように宣言します(woolpack.samples.crud.SampleServletから抜粋)。
final Fn<ValidatorContext, Boolean, RuntimeException> fn = BoolUtils.boolSeq(
  BoolUtils.<ValidatorContext, RuntimeException>andand(),
  Utils.<Fn<ValidatorContext, Boolean, RuntimeException>>
  // プロパティ「name」がパラメータに存在する場合はその長さをチェックします
  list(ValidatorUtils.branchByNameIfExists(
    Utils.<String, Fn<ValidatorContext, Boolean, RuntimeException>>
    map("name", BoolUtils.ifNot(
      FnUtils.join(ValidatorUtils.VALUE, ConvertUtils.TO_STRING, BoolUtils.checkMaxLength(40)),
      ValidatorUtils.message("validator.name.maxLength"))))
  )
  // 業務IDが正規表現「user_(register|update)(Confirm|Result)」に一致する場合に
  // プロパティ「name」プロパティ「name」の有無をチェックします
  .list(FnUtils.ifTrue(
    FnUtils.join(
      IdUtils.GET_ID,
      BoolUtils.checkRegExp(Pattern.compile("user_(register|update)(Confirm|Result)"))),
    ValidatorUtils.branchByName(
      Utils.<String, Fn<ValidatorContext, Boolean, RuntimeException>>
      map("name", BoolUtils.ifNot(
        FnUtils.join(ValidatorUtils.VALUE, BoolUtils.NOT_EMPTY),
        ValidatorUtils.message("validator.name.required")))
    ), FnUtils.fix(true)))
);
並行性制御部品の使いかた(woolpack.acquirable)
WoolpackではJava5から導入された並行性制御のインタフェース「Acquirable」を用意しています。 これを使用してセマフォやロックによる並行性制御を定義することができます。
以下の例のようにして宣言します。
final Fn<EEContext, Void, RuntimeException> fn = AcquirableUtils.acquire(
    FnUtils.fix(new TrySemaphore(new Semaphore(1, true))),
    new AllowFn(),
    new DenyFn());
ビジター応用部品の使いかた(woolpack.visitor)
WoolpackではMap・Bean・コレクション・配列・単純型で構造化されたオブジェクトを解析するためのビジター部品を用意しています。
構造化されたオブジェクトにヌルまたは空文字列の値の存在を検証するには以下の例のようにします。
final Visitor<List<Object>, RuntimeException> visitor = new Visitor<List<Object>, RuntimeException>();
visitor.setMap(VisitorAppUtils.CHECK_NOT_EMPTY);
visitor.setSubContext(new ArrayList<Object>());
try {
  visitor.visit(new String[]{"a", "", "b"});
  fail();
} catch (final IllegalStateException e) {
  System.out.println(visitor.getSubContext());
}
構造化されたオブジェクトをJavascript表現に変換するには以下の例のようにします。
final Visitor<StringBuilder, RuntimeException> visitor = new Visitor<StringBuilder, RuntimeException>();
visitor.setMap(VisitorAppUtils.JS);
visitor.setSubContext(new StringBuilder());
visitor.visit(new String[]{"a", "b"});
assertEquals("[\"a\",\"b\"]", visitor.getSubContext().toString());
履歴
  1. 20070212 新規作成。
  2. 20070217 コレクションの説明を変更。表記誤りを変更(parseからparseObject)。
  3. 20070228 Fnインタフェース変更に伴う変更。
トップに戻る
Copyright (C) 2006-2007 Takahiro Nakamura. All rights reserved.