第4章 検証

Smooks では、ルールという言葉は一般的な概念を意味します。特定のカートリッジに固有なものではありません。
他のコンポーネントより RuleProvider を設定および参照できます。

注記

検証カートリッジは、ルール機能を使用する唯一のカートリッジです。
ルールは ruleBases より中央的に定義されます。単一の Smooks 設定は複数の ruleBase 定義を参照できます。ruleBase 設定には名前、ルール src、およびルールプロバイダーがあります。
ルールソースの形式はプロバイダー実装に全体的に依存します。参照できるようにするため、各ルールに一意な名前 (単一ソースのコンテキスト内) を付けることのみが必要になります。
ruleBase 設定の例は次の通りです。
<?xml version="1.0"?>
<smooks-resource-list  xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd"  xmlns:rules="http://www.milyn.org/xsd/smooks/rules-1.0.xsd">
 
    <rules:ruleBases>
        <rules:ruleBase name="regexAddressing" src="/org/milyn/validation/address.properties" provider="org.milyn.rules.regex.RegexProvider" />
        <rules:ruleBase name="order" src="/org/milyn/validation/order/rules/order-rules.csv" provider="org.milyn.rules.mvel.MVELProvider"/>
    </rules:ruleBases>
 
</smooks-resource-list>
rules:ruleBase 設定要素の設定オプションは次の通りです。
  • name: このルールを参照するために他のコンポーネントが使用します。必須のオプションです。
  • src: ファイルまたは RuleProvider にとって意味のあるものになります。必須のオプションです。
  • provider: 使用したい実際のプロバイダー実装になります。ここで異なる技術が実行されます。 上記の設定では、 1 つの RuleProvider が正規表現を使用しますが、 複数の ruleBase 要素を指定でき、これらの ruleBase は必要な数の RuleProviders を持つことができます。必須のオプションです。
ルールプロバイダは org.milyn.rules.RuleProvider インターフェースを実装します。
Smooks には 2 つの RuleProvider 実装が事前設定されています。
  • RegexProvider
  • MVELProvider
独自の RuleProvider 実装を作成することも可能です。
名前の通り、 RegexProvider は正規表現を使用できるようにします。 フィルタされたメッセージの選択されたデータフィールドの形式に固有する低レベルなルールを定義できるようにします。たとえば、電子メールアドレスの正しい構文が含まれていることを検証するため、特定のフィールドに適用されることがあります。
次のコードは Regex ruleBase の設定方法を表しています。
<?xml version="1.0"?>
<smooks-resource-list  xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd"  xmlns:rules="http://www.milyn.org/xsd/smooks/rules-1.0.xsd">
 
    <rules:ruleBases>
        <rules:ruleBase name="customer" src="/org/milyn/validation/order/rules/customer.properties" provider="org.milyn.rules.regex.RegexProvider"/>
    </rules:ruleBases>
 
</smooks-resource-list>
正規表現は標準の .properties ファイル形式で定義されます。 以下は customer.properties の正規表現ルール定義ファイル (上記の例より) の一例になります。
# Customer data rules...
customerId=[A-Z][0-9]{5}
customerName=[A-Z][a-z]*, [A-Z][a-z]
MVEL プロバイダは、ルールを MVEL 表現として定義できるようにします。これらの表現は Smooks Javabean コンテキストの内容上で実行されます。そのため、 Smooks Bean コンテキストの Java オブジェクトにデータ (フィルタリングされたメッセージから) をバインドする必要があります。
これは、 メッセージ断片でさらに複雑なルールを定義できるようにします (例: ターゲットされた注文商品断片の製品は、注文ヘッダー詳細に指定された顧客の年齢資格制限内であるか)。
このコードは MVEL ruleBase の設定方法を表しています。
<?xml version="1.0"?>
<smooks-resource-list  xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd"  xmlns:rules="http://www.milyn.org/xsd/smooks/rules-1.0.xsd">
 
    <rules:ruleBases>
        <rules:ruleBase name="order" src="/org/milyn/validation/order/rules/order-rules.csv" provider="org.milyn.rules.mvel.MVELProvider"/>
    </rules:ruleBases>
 
</smooks-resource-list>
MVEL ルールを CSV ファイルに保存する必要があります。これらのファイルを編集する最も簡単な方法は、LibreOffice CalcGnumeric などのスプレッドシートアプリケーションを使用することです。各ルールレコードには、以下で構成される 2 つのフィールドが含まれます。
  • ルール名
  • MVEL 表現
コメントヘッダーの行を追加するには、 最初のフィールドの前にハッシュマーク(#) を追加します。
Smooks 検証カートリッジはルールカートリッジによって提供される機能によって構築され、ルールベースの断片検証を提供します。
これにより、メッセージ断片上で詳細な検証を実行できるようになります。Smooks の他の機能と同様に、検証機能はサポート対象の全データ形式で使用可能です。そのため、XML データだけでなく EDI や JSON、CSV などにも強固な検証を実行することができます。
検証の設定は http://www.milyn.org/xsd/smooks/validation-1.0.xsd 設定名前空間によって定義されます。
Smooks は複数のルールプロバイダ タイプをサポートし、検証カートリッジはこれらのタイプを使用できます。各ルールプロバイダタイプは異なるレベルの検証を提供しますが、すべて全く同じように設定されます。Smooks の検証カートリッジはルールプロバイダを抽象リソースと見なし、メッセージ断片を検証するためメッセージ断片を目指します。
検証ルールの設定には以下を指定する必要があります。
  • executeOn: ルールが実行される断片です。
  • excecuteOnNS: executeOn が属する断片名前空間です。
  • name: 適用されるルールの名前です。 ドット区切り形式の ruleBase と ruleName の組み合わせ (ruleBaseName.ruleName) を参照する複合ルール名です。
  • onFail: 適合の失敗の深刻度を判断します。
検証ルールの設定例は次の通りです。
<validation:rule executeOn="order/header/email" name="regexAddressing.email" onFail="ERROR" />
Smooks フィルター操作ごとの検証最大失敗数を設定できます。最大値を越えると例外がスローされます。OnFail.FATALに設定された検証は常に例外をスローし、 処理を停止することに注意してください。
最大検証失敗数を設定するには、次のコードを Smooks の設定に追加します。
<params>
    <param name="validation.maxFails">5</param>
</params>
検証設定の onFail 属性は実行するアクションを指定しました。これは、検証の失敗をどのように報告するかを決定します。
使用できるオプションは次の通りです。
  • OK: これを使用して検証を okay として保存します。 ValidationResults.getOks を呼び出すとすべての検証警告が返されます。コンテンツベースのルーティングを使用する場合に便利なオプションです。
  • WARN: 検証を warning として保存します。 ValidationResults.getWarnings を呼び出すとすべての検証警告が返されます。
  • ERROR: 検証を error として保存します。 ValidationResults.getErrors を呼び出すとすべての検証エラーが返されます。
  • FATAL: 検証の失敗が発生した直後に ValidationException をスローします。 ValidationResults.getFatal を呼び出すと致命的な検証失敗が表示されます。
ルールベースには次の形式の複合ルール名を使用します。
<ruleProviderName>.<ruleName>
  • ruleProviderName はルールプロバイダを識別し、 ruleBase 要素の name 属性へマッピングします。
  • ruleName はルールプロバイダの認識する特定ルールを識別します。src ファイルに定義されるルールである場合もあります。
Smooks.filterSource は検証の結果をキャプチャします。 filterSource メソッドが返される時、ValidationResult インスタンスにはすべての検証データが含まれます。
次のコードは Smooks がメッセージ断片の検証をどのように実行するかを表しています。
ValidationResult validationResult = new ValidationResult();
 
smooks.filterSource(new StreamSource(messageInStream), new StreamResult(messageOutStream), validationResult);
 
List<OnFailResult> errors = validationResult.getErrors();
List<OnFailResult> warnings = validationResult.getWarnings();
上記のコードでは、 個別の警告とエラーの検証結果が OnFailResult インスタンスの形式で ValidationResult オブジェクトより使用できるようになります。 各 OnFailResult インスタンスは障害の詳細を提供します。
検証カートリッジを使用すると、検証の失敗に関連する現地語化メッセージを指定することもできます。 現地語化メッセージは標準の Java ResourceBundleファイルに定義します (.properties 形式を使用)。

注記

検証メッセージバンドルのベース名はルールソース (src) が基になります。 ルールソースのファイル拡張子を省略し、 i18n という名前のフォルダーを追加します。たとえば、 /org/milyn/validation/order/rules/order-rules.csv の MVEL ruleBase ソースの場合、対応する検証メッセージバンドルのベース名は /org/milyn/validation/order/rules/i18n/order-rules になります。
検証カートリッジを使用すると、FreeMarker テンプレートを現地語化メッセージに適応できるため、Bean コンテキストからのコンテキストデータや、実際に発生したルールの失敗に関するデータがメッセージに含まれるようにすることが可能です。FreeMarker ベースのメッセージの前には ftl: を付ける必要があり、標準の FreeMarker の表記法を使用してコンテキストデータを参照する必要があります。Bean コンテキストからの Bean は直接参照することが可能ですが、RuleEvalResult とルールの失敗のパスは ruleResult および path Bean を介して参照することが可能です。
RegexProvider ルールを使用する例は次の通りです。
customerId=ftl:Invalid customer number '${ruleResult.text}' at '${path}'.  Customer number must match pattern '${ruleResult.pattern}'.
この例は Smooks を使用してメッセージ断片データを検証する方法を表しています。 2 種類の検証ルールを使用して 2 種類の検証を実行します。
  • .properties ファイル RuleBase に定義された正規表現を使用したメッセージフィールド値/形式の検証。たとえば、フィールドを有効な電子メールアドレスとして検証することが可能です。
  • .csv file RuleBase に定義された MVEL 表現を使用したビジネスルールの検証。たとえば、ある注文の注文商品の合計価格 (価格に数量をかけた値) が事前定義されたビジネスルールに違反しないかどうかを検証することができます。
このルールを実行するには、ルートフォルダーの例に移動し、以下を実行します。
  • mvn clean install
  • mvn exec:java
次の例では、注文商品が複数含まれた XML メッセージが存在します (この機能は、Smooks によってサポートされる他のデータ形式すべてに対して同様に動作します)。
<Order>
    <header>
        <orderId>A188127</orderId>
        <username>user1</username>
        <name>
            <firstname>Harry</firstname>
            <lastname>Fletcher</lastname>
        </name>
        <email>harry.fletcher@gmail.</email>
        <state>South Dakota</state>
    </header>
    <order-item>
        <quantity>1</quantity>
        <productId>364b</productId>
        <title>The 40-Year-Old Virgin</title>
        <price>29.98</price>
    </order-item>
    <order-item>
        <quantity>2</quantity>
        <productId>299</productId>
        <title>Pulp Fiction</title>
        <price>29.99</price>
    </order-item>
</Order>
注文メッセージデータに複数の検証を実行します。
提供されたユーザー名が、大文字の後に5 つ数字が続く (S12345 や G54321 など) 形式に従うことを確認します。この検証を実行するには、正規表現を使用する必要があります。
次に、提供された電子メールアドレスが有効な形式であることを確認する必要があります。ここでも正規表現を使用して確認を行います。
さらに、各注文商品の productId フィールドの形式 が 3 つの数字 (123 や 321 など) であることを確認する必要があります。ここでも正規表現を使用します。
最後に、各注文商品の合計が 50.00 を越えない (価格と数量を掛けた値が 50.00 を越えない) ことを確認する必要があります。この検証には MVEL 表現を使用します。
この検証を実行するには、正規表現ルールを分割し、個別の 2 つの .properties ファイルに置きます。
ここで、これらのファイルを例の rules ディレクトリに移動します。
MVEL 表現を .csv ファイルと rules ディレクトリに置きます。
customer.properties ファイルに格納される顧客関係の正規表現ルールは次のようになります。
# Customer data rules...
customerId=[A-Z][0-9]{5}
 
# Email address...
email=^[\\w-\\.]+@([\\w-]+\\.)+[\\w-]{2,4}$
product.properties ファイルに格納される商品関係の正規表現ルールは次のようになります。
# Product data rules...
productId=[0-9]{3}
注文商品の合計をチェックする MVEL 表現は order-rules.csv ファイルに格納されます。

注記

OpenOffice.org CalcGnumeric などの表計算アプリケーションを使用すると、最も簡単に .cvs ファイルを編集できます。
ここで、各ルールソースファイルに対してリソースバンドルの .properties ファイルを作成します。

注記

これらのファイルの名前は、対応するルールファイルの名前を基にしていることに注意してください。
rules/customer.properties に定義されるルールのメッセージバンドルは、 rules/i18n/customer.properties ファイルにあります。
customerId=ftl:Invalid customer number '${ruleResult.text}' at '${path}'.  
<!--  Customer number must begin with an uppercase character, followed by 5 digits. -->
email=ftl:Invalid email address '${ruleResult.text}' at '${path}'.  
<!--  Email addresses match pattern '${ruleResult.pattern}'. -->
rules/product.properties に定義されるルールのメッセージバンドルは rules/i18n/product.properties ファイルにあります。
# Product data rule messages...
productId=ftl:Invalid product ID '${ruleResult.text}' at '${path}'. 
<!--  Product ID must match pattern '${ruleResult.pattern}'. -->
rules/order-rules.csv に定義されるルールのメッセージバンドルは rules/i18n/order-rules.properties ファイルにあります。
# <!--  Order item rule messages. The "orderDetails" and "orderItem" beans are populated by Smooks bindings - see config in following section. -->
order_item_total=ftl:Order ${orderDetails.orderId} 
<!-- contains an order item for product ${orderItem.productId} with a quantity of ${orderItem.quantity} and a unit price of ${orderItem.price}. This exceeds the permitted per order item total. -->
これらの検証ルールを適用するために使用する必要がある設定は次の通りです。
<?xml version="1.0"?>
<smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd"
                      xmlns:rules="http://www.milyn.org/xsd/smooks/rules-1.0.xsd"
                      xmlns:validation="http://www.milyn.org/xsd/smooks/validation-1.0.xsd"
                      xmlns:jb="http://www.milyn.org/xsd/smooks/javabean-1.2.xsd">
 
    <params>
        <!-- Generate a ValidationException if we get more than 5 validation failures... -->
        <param name="validation.maxFails">5</param>
    </params>
 
    <!-- Define the ruleBases that are used by the validation rules... -->
    <rules:ruleBases>
        <!-- Field value rules using regex... -->
        <rules:ruleBase name="customer" src="rules/customer.properties" provider="org.milyn.rules.regex.RegexProvider"/>
        <rules:ruleBase name="product" src="rules/product.properties" provider="org.milyn.rules.regex.RegexProvider"/>
 
        <!-- Order business rules using MVEL expressions... -->
        <rules:ruleBase name="order" src="rules/order-rules.csv" provider="org.milyn.rules.mvel.MVELProvider"/>
    </rules:ruleBases>
 
    <!-- Capture some data into the bean context - required by the business rule validations... -->
    <jb:bean BeanId="orderDetails" class="java.util.HashMap" createOnElement="header">
        <jb:value data="header/*"/>
    </jb:bean>
    <jb:bean BeanId="orderItem" class="java.util.HashMap" createOnElement="order-item">
        <jb:value data="order-item/*"/>
    </jb:bean>
 
    <!-- Target validation rules... -->
    <validation:rule executeOn="header/username" name="customer.customerId" onFail="ERROR"/>
    <validation:rule executeOn="email" name="customer.email" onFail="WARN"/>
    <validation:rule executeOn="order-item/productId" name="product.productId" onFail="ERROR"/>
 
    <validation:rule executeOn="order-item" name="order.order_item_total" onFail="ERROR"/>
 
</smooks-resource-list>
例の Main クラスより実行するためのコードは次の通りです。
protected static ValidationResult runSmooks(final String messageIn) throws IOException, SAXException, SmooksException {
    // Instantiate Smooks with the config...
    final Smooks smooks = new Smooks("smooks-config.xml");
 
    try {
        // Create an exec context - no profiles....
        final ExecutionContext executionContext = smooks.createExecutionContext();
        final ValidationResult validationResult = new ValidationResult();
 
        // Configure the execution context to generate a report...
        executionContext.setEventListener(new HtmlReportGenerator("target/report/report.html"));
 
        // Filter the input message...
        smooks.filterSource(executionContext, new StringSource(messageIn), validationResult);
 
        return validationResult;
    }
    finally {
        smooks.close();
    }
}