ワインと将棋とインターネット このページをアンテナに追加 RSSフィード

12月04日(木)

[] S2Vali-0.6.0 リリースしました!

http://code.google.com/p/s2vali/

Google Code にホスティングしてみました。

もう少し機能を追加しようかなあとも思ったが、ひとまずリリースしました。

MVCフレームワークで用意されているValidatorで手の届かない部分などで活用してもらえると有用なんではないかと思っています。

実際、自分の仕事でも既に使っていますし。

Seasarにはお世話になっているのでほんの少しでも恩返しができればと。

Google Code はなかなかいいですね。ちょっと字が小さくて見づらい気がするけど、何もセットアップせずに Wiki,SVN,IssueTrackerが使えるんですから。

Wikiの文法はTrac(python系)に似た形で自分の好きな形。

エンタープライズ版もほしいな。GoogleAppsに追加してくれないかな。。

11月24日(月)

[] JavaBeansをAOPで作成したい

s2valiを実践投入して試している中で1つ新しいニーズが出てきました。

commons-validator の validateメソッドには JavaBeansを渡すのですが、s2valiのメソッドとしては以下のようにチェックしたい値をパラメータに渡す形もサポートしたい。


  // JavaBeansを渡してValidate
  public String[] validateHoge(HogeDto dto);

  // パラメータ渡しでValidate 
  @ValidationParam({"name", "age", ...})
  public String[] validateHoge(String field1, int field2, ...);

これを実現するためには、以下の課題を解決する必要がありそうです。

  1. アノテーションを読み取る。
  2. InterTypeを使って、JavaBeansのクラスを動的に生成する
  3. クラスの生成をどのタイミングでやる??(メソッド呼び出しのたびにやるのではパフォーマンスが悪い)

アノテーションAOPは使う側では触れていたけれど、作る側の知識は持ち合わせていないのでこれから勉強しなければ。

「JavaBeansのクラスを動的に生成する」は、フィールドが定義されているクラスにgetter/setterを追加する PropertyInterType というのがseasarには用意されているようですが、フィールドも何も用意されていないところに追加する、もしくはクラス丸ごと作成する、みたいなことを javaasistでやればよいのかな。。

「クラスの生成をどのタイミングでやる??」は、s2valiコンポーネント生成時にアノテーションを読み取って、必要なBeanクラスを生成してコンポーネント登録する、みたいな感じか。

しかし、何をトリガーにすればよいのか。。

なかなか高いハードルですが、いい機会なので少しずつやってみようと思います。

11月22日(土)

[] S2Valiを作りながら提供側に必要な技術を学ぶ(4)

最近はもっぱら、Validatorのテストケースを書いています。Validatorはstruts-1.2.9とSAStrutsから移植してきたものですが、念のためテスト書いてます。

すでに自分の案件に投入もしているのでほぼ問題なく動きそうです。

その中で1つ発見した commons-validator の便利な機能が extends。

Javaのクラスを継承するような感覚で、

定義を継承できるんですね。

たぶん知ってる人には当たり前の機能なんですが、意外と便利です。

ところでS2Valiでサポートする戻り値(エラーの戻し方)は String[] に加えて、ErrorMessageという独自のクラスを配列で返すことにしました。

ErrorMessageは message と args[] をプロパティに持ったDTOです。

例えばTeedaを使ってる人は、


  ErrorMessage[] errors = paramValidator.validateHoge(hogeDto);
  for (ErrorMessage error: errors) {
    FacesMessageUtil.addErrorMessage(errors.getMessage(), errors.getArgs());
  }

のように使います。

[] 今日のはまり

maven2のdependencyのoptional

commons-validator が依存している oroがなぜかライブラリパスに追加されない。なぜだ、、、と悩んでいると、commons-validatorはoroに "optional" という設定で依存していた。

以下のエントリが詳しい。

http://d.hatena.ne.jp/waman/20070928/1190933910

maven2のコマンドラインからだとテストが通らない・・・

s2valiの開発を終え、maven2で mvn deploy しようと思ったら、テストが通らない。

commons.validator.ValidatorResourcesから、

Form 'form2' not found for locale 'ja'

というWarningが出ている。Localeの問題だということはわかったのだが、なぜだ・・・

はてな記法

ちっとも覚えられない・・・

11月08日(土)

[] S2Valiを作りながら提供側に必要な技術を学ぶ(3)

なかなか時間が取れないものですね。実装は最低限使える部分までは終わったのですがブログの更新が滞ってました。

ResourceBundle

前回はValidatorResourcesをコンポーネントに保有させるところまで行きました。

今日はResourceBundleです。

commons-validatorでは、

        <validator name="required"
                   classname="jp.honestyworks.s2vali.validator.DefaultValidator"
                   method="validateRequired"
                   methodParams="java.lang.Object, org.apache.commons.validator.Field"
                   msg="s2vali.required" />

のように validator毎に msg属性でエラーメッセージを指定できますが、このmsg属性にResourceBundleのkeyを入れておけばResourceBundleから取得したメッセージが使われるようにしたいのです。

またメッセージのArgs(「{0}を入力してください」の{0})も

           <field property="card_id" depends="required,length">
                <arg key="prompt.card_id" />
                <arg key="${var:minlength}" name="length" resource="false" />
                <arg key="${var:maxlength}" name="length" resource="false" />
             ....
           </field>

このように arg要素の key属性でResourceBundleのkeyを指定できます。

ResourceBundleのファイルを定義するdicon

作戦としてはValidatorResourcesと同じように ValidatorResourcesContainerのinitメソッドでResourceBundleを構築して保有しておくというやり方にしました。

まずは、使い手にResourceファイル名を指定してもらう仕組みです。

これは diconファイルにコンポーネントのプロパティとして設定してもらうことにします。

* s2valiConfig.dicon

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN"
    "http://www.seasar.org/dtd/components24.dtd">
<components namespace="s2vali">

    <component name="validatorConfig"
        class="jp.honestyworks.s2vali.ValidatorConfig">
        
        <property name="resourceBundleProperties">
            "testmessage"
        </property>
        
        <property name="validationRules">
            "s2vali-rules.xml"
        </property>
        
    </component>

</components>

ついでに validationRulesファイルも設定可能にしました。

ValidatorResourcesとResourceBundleの連携

validatorResourcesContainerに validatorConfigをinjectして initメソッドで ResourceBundleを取得します。そして、ValidatorResourcesに ResourceBundleを組み込もうと思っていろいろ調べてみたのですが、どうやらなさそうです。

僕のイメージでは ValidatorResourcesのコンストラクタとかに ResourceBundleを渡せばFieldやArgがResourceBundleを保持した形で構築され、

Field.getMsg() とかでResourceBundleから取得されたメッセージがとれるものかと想像していましたが、どうもそのようにはなっていないようです。

SAStrutsやStrutsの実装もさらっと見てみたのですが、SAStrutsではCreator(だったか)でResourceBundleを自力でsetしているような。。

仕方がないのでValidationの実行時にResourceBundleを自分で引くような形で実装しました。

これでもまったく問題なさそうです。

実装のことを文章で書くのはなかなか難しいものです。

今日はこのあたりまで。

SVN: http://my.honestyworks.jp/svn/open/s2vali/

Maven2: http://my.honestyworks.jp/maven2/

10月29日(水)

[] S2Valiを作りながら提供側に必要な技術を学ぶ(2)

毎朝2時間は仕事に直接関係ないことをやろうと決め、その枠組みでS2Valiを進めてます。(これも仕事に使うといえば使うのですが。。)

S2Valiでは s2vali-rules.xml (Struts等でおなじみのcommons-validatorの定義ファイル) を読込んでValidationを実行します。

しかしメソッド呼び出しのたびに毎回XMLファイルを読みに行くのはあり得ません。

そこでValidatorResourcesContainerというコンポーネントを作って、initMethodでファイルの読み込みからValidatorResources(commons-validatorのクラス)を生成するようにしました。

ファイルの読み込みはひとまず classpath直下にあるs2vali-rules.xml という名前固定でいきます。

リソースファイルはjar内にアーカイブされた状態でも読めないとだめです。

そこで、自分が[Seasar-user:15840] で指摘させていただいた問題(env.txtがjarから読めなかったという問題) のトラックレコードを見て先人の知恵を拝借することにしました。

※S2には便利なUtilクラスがたくさん含まれているのでそれらをうまく活用することは、フレームワークの使い手側にとっても非常に有益です。

env.txtの読み込みは以下のように行なわれていました。(途中略)

final URL url = ResourceUtil.getResourceNoException(filePath);
↓
file = ResourceUtil.getFile(url);
↓
if (file != null) {
    calcValue();
else {
    calcValue(url);
}

calcValue(url)の中では、 final InputStream is = URLUtil.openStream(url); のようにInputStreamを取得しています。

ResourceUtil,URLUtilといったseasarのUtilクラス群を使えば楽できるわけですね。

ところでなぜいったんfileから取得することを試みているのか?

これはもしかして jar外のものを優先して読み、無ければjar内から取得するためなのでしょうか。。

HotDeploy対応のためこのようになっているとのことです。

今日はJarファイルからリソースを取得できることを確認して、ひとまず終了。

SVN: http://my.honestyworks.jp/svn/open/s2vali/

10月27日(月)

[] S2Vali を作りながら、提供側に必要な技術を学ぶ(1)

S2Validator なるものを作ってみよう! - ワインと将棋とインターネット で書いたような仕様で S2Validator(改めS2Vali) を作り始めました。

S2Valiでは使い手に、

public interface CsvValidator {

    public String[] validateSomething(SomethingDto dto);

}

このようにインターフェースを定義してもらい、

	<component class="foo.bar.CsvValidator">
	   <aspect>s2ValiInterceptor</aspect>
	</component>

このようにコンポーネントにaspectを指定してもらうことで自動的にValidationを実行します。

まず最初にInterceptorの製作から。

上記のようにInterfaceにAspectをかけただけのコンポーネントをインスタンス化するためにこちら側で何か処理が必要かと思っていたのですが、実はs2-containerがよきに計らってくれるようで何もしなくてよさそう。

AbstractInterceptorを拡張してinvokeメソッドに実際のValidation処理を書くだけでよさそうです。

SVN: http://my.honestyworks.jp/svn/open/s2vali/

10月04日(土)

[] S2Validator なるものを作ってみよう!

Teeda,SAStruts,Cubbyなどはそれぞれ独自の入力値検証機能を持っていますが、例えば

  • アップロードしたCSVファイルの入力値検証
  • S2Axis2等で作るWebサービスAPIの入力値検証
  • バッチ処理プログラムの入力値検証

など、MVCフレームワークの入力値検証が使えない場面で役立つような汎用的なValidatorを作ってみようかな。

これまではCommons-Validationを使用してそのままロジック書いていたのでそれを少し発展させて、以下のような仕様にしてみよう。

使い方

  1. 入力値検証を定義するXMLファイルを書く。これはcommons-validatorの仕様どおり。みんなお馴染みの。 -> 将来的にはアノテーションにしてもいいかもしれないけれども、入力値検証の定義は設定ファイルでも良いと個人的には思ふ。
  2. インターフェースを定義する。クラス名は **Validator, メソッド名は validate***, 引数には検証対象のJavaBeansを取る。
  3. 戻り値にはエラーメッセージのリスト、検証OKの場合はnull.
public interface CsvValidator {

    public String[] validateSomething(SomethingDto dto);

}
  1. 使うクラスにDIする。
public class SomeAction {

    @Resource
    protected CsvValidator csvValidator;

}

エラーをどのように取得させるか、次の3通りが考えられますが、シンプルに1番目でよいかな。。

  • 戻り値でリスト(配列)を返す。
  • エラーを取得するメソッドを用意する。
  • Exceptionで返す。

仕様のロールモデルはS2Mai。Interceptorを使って簡単に作れそうな気がするけど、すでに同じようなものがありそうな気もするなあ。。

ところで、SeasarMVCファミリーは入力値検証の仕様ぐらいは統一感を出してもいいんじゃないかなあと思います。少なくとも僕は案件の特性に応じて使い分けていくのでアノテーションぐらいは統一されていたほうがわかりやすいかも。

Amazon検索

Amazon.co.jp のロゴ
日記の検索

番組表を検索してRDに予約