第12章 一般的なユースケース

Smooks v1.0 より導入された主な機能の 1 つが巨大なメッセージ (数ギガバイト) を処理する機能です。Smooks は以下の巨大メッセージの処理をサポートします。
  • 1 対 1 のトランスフォーメーション: ソースの形式 (XML など) からターゲットの形式 (EDI、CSV、XML など) へ巨大サイズのメッセージを変換する処理になります。
  • 分割とルーティング: 巨大サイズのメッセージを、小さい (消費しやすい) 任意形式 ( (EDI、XML、Java など) のメッセージに分割し、 複数の宛先 (ファイル、 JMS、 データベースなど) へルーティングします。
  • 永続性: 巨大なメッセージのコンポーネントをデータベースへ永続化し、巨大メッセージのコンポーネントのクエリや処理を容易にします。Smooks 内では、分割とルーティング (データベースへのルーティング) の 1 つとして考慮されます。
上記の方法はすべてコードを書かずに (宣言的に対応するなどして) 実現することが可能です。一般的に、上記のいずれかの方法を処理するには、比較的大きく難解/維持不可能なコードを書く必要があります。また、巨大なメッセージが小型のメッセージに分割され (ステージ 1)、小型のメッセージがそれぞれ永続化やルーティングなどのために処理される(ステージ 2) マルチステージ処理として実装されている場合もあります。これは、難解で維持不可能なコードを若干維持しやすく再使用できるようにするために行います。Smooks では、これらのユースケースのほとんどはコードを書かずに対応することが可能です。さらに、ソースメッセージ上の単一のパスで処理し、分割とルーティングを平行して行うことも可能です (異なる形式で異なるタイプの複数の宛先へルーティングも可能)。

注記

パフォーマンス上のヒント: Smooks で巨大なメッセージを処理する場合、SAX フィルターを使用するようにしてください。
別形式の単一メッセージに変換して巨大なメッセージを処理する必要がある場合、 複数の FreeMarker テンプレートをソースメッセージのイベントストリームに適用し、 Smooks.filterSource の結果ストリームへ出力するのが Smooks における最も簡単なメカニズムになります。
適切なモデルのタイプによりますが、FreeMarker のテンプレートを用いてこれを行う方法は 2 つあります。
  • モデルに FreeMarker + NodeModels を使用します。
  • モデルに対して FreeMarker と Java Object モデルを使用します。 Javabean カートリッジを使用して、メッセージのデータよりモデルを構築できます。
ユースケースにおけるトレードオフが妥当である場合、最初のオプションを使用するとよいでしょう。詳細は FreeMarker のテンプレートに関するドキュメントを参照してください。
メッセージに order-item 要素が含まれる場合を想定してみてください。 このような場合に Smooks と FreeMarker (NodeModel 使用) を用いて巨大サイズのメッセージを処理するのは複雑ではありません。 メッセージが大変大きいため、 ランタイム時のメモリフットプリントをできるだけ小さくするよう複数の NodeModel をメッセージ内に指定する必要があります。 メモリーに保持するには大きすぎるため、 単一のモデルを使用してメッセージを処理することはできません。 order メッセージの場合、 メインの order データのモデルと order-item データのモデルの 2 つのモデルがあります。
このケースでは、 メモリに存在するほとんどの情報はメインの注文データとなり、注文商品が 1 つだけ存在するようになります。 NodeModels はネストされているため、 Smooks は注文データの NodeModels に注文商品の NodeModels の情報が含まれないようにします。 また、 Smooks はメッセージをフィルタリングするため、 注文商品の NodeModels は注文商品ごとに上書きされます (未収集の場合など)。 詳細は「 Smooks で DOM モデルと SAX モデルを混合する」の項を参照してください。
FreeMarker テンプレートによって使用される複数の NodeModels をキャプチャするよう Smooks を設定するには、各モデルのルートノードをターゲットにするよう DomModelCreator を設定します。Smooks は SAX フィルタリングもこの機能を使用できるようにします (巨大メッセージを処理する秘訣となります)。次の Smooks 設定は、巨大なメッセージに対して NodeModels を作成します。
<?xml version="1.0"?>
<smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd" 
                      xmlns:core="http://www.milyn.org/xsd/smooks/smooks-core-1.3.xsd"
                      xmlns:ftl="http://www.milyn.org/xsd/smooks/freemarker-1.1.xsd">
 
    <!--
    Filter the message using the SAX Filter (i.e. not DOM, so no
    intermediate DOM for the "complete" message - there are "mini" DOMs
    for the NodeModels below)....
    -->
    <core:filterSettings type="SAX" defaultSerialization="false" />
 
    <!--
    Create 2 NodeModels. One high level model for the "order"
    (header etc) and then one for the "order-item" elements...
    -->
    <resource-config selector="order,order-item">
        <resource>org.milyn.delivery.DomModelCreator</resource>
    </resource-config>
 
    <!-- FreeMarker templating configs to be added below... -->
ここで FreeMarker のテンプレートを追加する必要があります。合計で 3 つのテンプレートを適用する必要があります。
  • 注文商品まで (注文商品は含まない) の注文「ヘッダー」詳細を出力するテンプレート。
  • salesorder の item 要素を生成するために必要な各注文商品のテンプレート。
  • メッセージを閉じるテンプレート。
Smooks では、2 つの FreeMarker テンプレートを定義してこれを実装します。テンプレートの 1 つは上記の 1 と 3 に対応する (組み合わせる) ようにし、2 つ目のテンプレートは item 要素に対応するようにします。
1 つ目の FreeMarker テンプレートは order-items 要素を目的とし、 次のようになるはずです。
<ftl:freemarker applyOnElement="order-items">
        <ftl:template><!--<salesorder>
    <details>
        <orderid>${order.@id}</orderid>
        <customer>
            <id>${order.header.customer.@number}</id>
            <name>${order.header.customer}</name>
        </customer>
    </details>
    <itemList>
    <?TEMPLATE-SPLIT-PI?> 
    </itemList>
</salesorder>-->
        </ftl:template>
    </ftl:freemarker>
次の存在に気が付くはずです。
?TEMPLATE-SPLIT-PI?
?TEMPLATE-SPLIT-PI? の処理命令はテンプレートを分割する場所を Smooks に知らせ、order-items の始めにテンプレートの最初の部分を出力し、残りの部分を order-items 要素の最後に出力します。item 要素テンプレート (2 つ目のテンプレート) はこの 2 つの出力の間に出力されます。
2 つ目の FreeMarker テンプレートは大変単純です。ソースメッセージにある各 order-item 要素の最後に item 要素を出力するだけです。
<ftl:freemarker applyOnElement="order-item">
        <ftl:template><!-- <item>
    <id>${.vars["order-item"].@id}</id>
    <productId>${.vars["order-item"].product}</productId>
    <quantity>${.vars["order-item"].quantity}</quantity>
    <price>${.vars["order-item"].price}</price>
</item>-->
        </ftl:template>
    </ftl:freemarker>
</smooks-resource-list>
2 つ目のテンプレートは order-item 要素の最後にファイアします。
?TEMPLATE-SPLIT-PI?
そのため、最初のテンプレートの上記の処理命令がある場所に出力を効率的に生成します。2 つ目のテンプレートは order NodeModel のデータも参照した可能性があることに注意してください。これは、チュートリアルの実行可能な例として使用可能です。
メモリーにあるオブジェクトは、常に注文ヘッダー詳細と現在の注文商品詳細 (仮想オブジェクトモデルにおける) のみであるため、巨大なメッセージの 1 対 1 のトランスフォーメーションを実行するこの方法が適用できます。トランスフォーメーションが不明瞭で、 ソースメッセージにあるすべてのデータへの完全アクセスが常に必要になるような場合では動作しません (メッセージで注文商品すべてを逆順にしたりソートする必要がある場合など)。 このような場合、 注文詳細と商品をデータベースへルーティングした後にデータベースのストレージ、クエリ、および呼び出し機能を使用してトランスフォーメーションを実行することが可能です。
大型/巨大メッセージを処理する方法としては、独立して処理できる小型なメッセージに分割する方法も一般的です。分割とルーティングは、 巨大メッセージのみを処理する方法ではなく、小さいメッセージを処理するために必要となることもよくあります (メッセージの大きさは関係ない場合もあります)。 たとえば、 注文メッセージの注文商品を分割し、 異なる部署や関連企業へルーティング (内容を基にしたルーティング) して処理する必要がある場合などがあります。このような場合、以下のように宛先に応じて異なるメッセージ形式が必要となる場合があります。
  • "destination1" はファイルシステムより XML が必要。
  • "destination2" は JMS キューを介して Java オブジェクトが必要。
  • "destination3" はデータベースなどのテーブルよりメッセージを取得。
  • "destination4" は JMS キューを介して EDI メッセージが必要。
Smooks では上記すべてが可能です。メッセージ上の単一パスで、 複数の宛先 (異なるタイプ) へ分割とルーティングの操作を複数実行することができます。
基本の概念はシンプルです。 Smooks よりメッセージをストリームすると、 以下が実行されます。
  • ルーティングされる断片のスタンドアロンメッセージ (分割) が繰り返し作成されます。
  • 固有の beanId で分割メッセージが Bean コンテキストへ繰り返しバインドされます。
  • 必要なエンドポイント (ファイル、 DB、 JMS、 ESB) へ分割メッセージが繰り返しルーティングされます。
注文メッセージの各 orderItem など、ソースメッセージにある分割メッセージの各インスタンスに対してこれらの操作が発生する点を強調するため、上記では「繰り返し」という表現を使用しました。
上記の最初の 2 項目では、 Smooks は分割メッセージを作成する方法を提供します。
  • 基本的 (非変換/非リッチ化) な断片の分割とバインド。 これは大変シンプルな設定で、 メッセージ断片を XML 形式へ繰り返しシリアライズし、 文字列として Bean コンテキストに保存します。
  • Java バインディングとテンプレーティングカートリッジを使用するより複雑な方法。Smooks を設定してソースメッセージからデータを抽出し、Bean コンテキスト (jb:bean 設定を使用) へ挿入します。また、任意でテンプレートを適用して分割メッセージを作成します。この方法は前述の方法よりも複雑ですが、 次の利点があります。
    • 分割断片を変換できます (基本的な方法とは異なり、 XML 以外にも対応します)。
    • メッセージをリッチ化できます。
    • 複数のソース断片からのデータを各分割メッセージへ結合できるようにし、 複雑な分割が可能です (たとえば、orderItem 断片だけでなく、 注文ヘッダー情報も統合できます)。
    • Java オブジェクトを分割メッセージとして分割およびルーティングできます (JMS 上など)。
複雑な方法について上記で説明しましたが、 巨大サイズのメッセージを処理する秘訣は (基本的な方法では問題になりませんが)、 少量のメモリフットプリントを常に維持することです。 これには、常に最も関連性の高いメッセージデータのみをバインドし (Bean コンテキストへ)、Javabean カートリッジを使用するようにします。 後続の項の例は、 すべて注文メッセージからの注文商品の分割とルーティングが基になっています。 Smooks の Javabean カートリッジのバインディング設定は、 メインの注文詳細 (注文ヘッダーなど) と「現在の」注文商品詳細のみがデータとしてメモリに保持されるよう実装されるため、 巨大メッセージ対するすべての作業が解決法に掲載されています。
前述の通り、 メッセージの断片を分割しルーティングする最も簡単な方法は、 ルーティングカートリッジより基本的な frag:serialize コンポーネントと *:router コンポーネント (jms:router、file:router など) を使用することです。 http://www.milyn.org/xsd/smooks/fragment-routing-1.2.xsd 名前空間に frag:serialize コンポーネント独自の設定があります。
以下は、SOAP メッセージボディーの内容をシリアライズし、「soapBody」の BeanId 下にある Bean コンテキストに保存する例になります。
<?xml version="1.0"?>
<smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd" xmlns:frag="http://www.milyn.org/xsd/smooks/fragment-routing-1.2.xsd">
 
    <frag:serialize fragment="Envelope/Body" bindTo="soapBody" childContentOnly="true"/>
 
</smooks-resource-list>
これを実行するための Smooks のコードは次の通りです。
Smooks smooks = new Smooks(configStream);
JavaResult javaResult = new JavaResult();
 
smooks.filterSource(new StreamSource(soapMessageStream), javaResult);
 
String bodyContent = javaResult.getBean("soapBody").toString().trim();
プログラムを用いて実行することも可能です (XML 設定は不必要) 。
Smooks smooks = new Smooks();
 
smooks.addVisitor(new FragmentSerializer().setBindTo("soapBody"), "Envelope/Body");
 
JavaResult javaResult = new JavaResult();
smooks.filterSource(new StreamSource(soapMessageStream), javaResult);
 
String bodyContent = javaResult.getBean("soapBody").toString().trim();
上記のコードスニペットは、 分割メッセージを作成し、 アクセスできる Bean コンテキストへバインドする方法のみを表しています。 処理のためにこれらの分割メッセージを別のエンドポイントへルーティングする場合はどうなるでしょうか。 この場合でも簡単です。 後続の項に概説されているルーティングコンポーネントの 1 つを使用すればよいだけです。
次の例は、処理のために分割メッセージ (ここでは order-item 断片) を JMS の宛先へルーティングする設定を表す簡単な例になります。
<?xml version="1.0"?>
<smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd" xmlns:frag="http://www.milyn.org/xsd/smooks/fragment-routing-1.2.xsd" xmlns:jms="http://www.milyn.org/xsd/smooks/jms-routing-1.2.xsd">
 
    <!-- Create the split messages for the order items... -->
    <frag:serialize fragment="order-items/order-item" bindTo="orderItem" />
 
    <!-- Route each order items split mesage to the orderItem JMS processing queue... -->
    <jms:router routeOnElement="order-items/order-item" BeanId="orderItem" destination="orderItemProcessingQueue" />
 
</smooks-resource-list>
上記の例の JMS ルーティングに関する詳細は、 JMS ルーターのドキュメント (下記) を参照してください。 jms:router は他のルーターに置き換えることができます。 例えば、 JBoss ESB を使用している場合は、 esbr:routeBean 設定を使用して ESB エンドポイントへ分割メッセージをルーティングできます。
ファイルベースのルーティングは、http://www.milyn.org/xsd/smooks/file-routing-1.1.xsd 設定名前空間から file:outputStream 設定を介して実行されます。
本項では、以下の Smooks の機能を組み合わせ、ファイルシステムでメッセージを小さなメッセージに分割する方法を説明します。
メッセージからデータを抽出し、 Bean コンテキスト内の変数に保持するための Javabean カートリッジ。この場合、DOM NodeModel を使用してテンプレーティングデータモデルとして使用する注文と注文商品のデータをキャプチャすることもできます。
ファイルシステムストリーム (命名、開閉、スロットルの作成など) を管理するルーティングカートリッジの file:outputStream 設定。
Java Bean カートリッジ (前述の最初の項目参照) によって Bean コンテキストにバインドされるデータより個別の分割メッセージを生成するテンプレーティングカートリッジ。テンプレートの結果はファイル出力ストリーム (前述の 2 番目の項目参照) へ書き込まれます。
次の例では、巨大な注文メッセージを処理し、 個別の注文商品詳細をファイルへルーティングします。 分割メッセージには注文商品断片からのデータが含まれるだけでなく、 order-header 要素や root 要素からの情報も含まれます。
これを Smooks で実現するには、次の Smooks 設定をアセンブルします。
<?xml version="1.0"?>
<smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd"
                      xmlns:core="http://www.milyn.org/xsd/smooks/smooks-core-1.3.xsd"
                      xmlns:jb="http://www.milyn.org/xsd/smooks/javabean-1.4.xsd"
                      xmlns:file="http://www.milyn.org/xsd/smooks/file-routing-1.1.xsd"
                      xmlns:ftl="http://www.milyn.org/xsd/smooks/freemarker-1.1.xsd">
 
        <!--
        Filter the message using the SAX Filter (i.e. not DOM, so no
        intermediate DOM, so we can process huge messages...
        -->
        <core:filterSettings type="SAX" />
 
        <!-- Extract and decode data from the message. Used in the freemarker template (below).
               Note that we could also use a NodeModel here... -->
(1)     <jb:bean BeanId="order" class="java.util.Hashtable" createOnElement="order">
            <jb:value property="orderId" decoder="Integer" data="order/@id"/>
            <jb:value property="customerNumber" decoder="Long" data="header/customer/@number"/>
            <jb:value property="customerName" data="header/customer"/>
            <jb:wiring property="orderItem" BeanIdRef="orderItem"/>
        </jb:bean>
(2)     <jb:bean BeanId="orderItem" class="java.util.Hashtable" createOnElement="order-item">
            <jb:value property="itemId" decoder="Integer" data="order-item/@id"/>
            <jb:value property="productId" decoder="Long" data="order-item/product"/>
            <jb:value property="quantity" decoder="Integer" data="order-item/quantity"/>
            <jb:value property="price" decoder="Double" data="order-item/price"/>
        </jb:bean>
 
        <!-- Create/open a file output stream. This is writen to by the freemarker template (below).. -->
(3)     <file:outputStream openOnElement="order-item" resourceName="orderItemSplitStream">
            <file:fileNamePattern>order-${order.orderId}-${order.orderItem.itemId}.xml</file:fileNamePattern>
            <file:destinationDirectoryPattern>target/orders</file:destinationDirectoryPattern>
            <file:listFileNamePattern>order-${order.orderId}.lst</file:listFileNamePattern>
 
            <file:highWaterMark mark="10"/>
        </file:outputStream>
 
        <!--
        Every time we hit the end of an <order-item> element, apply this freemarker template,
        outputting the result to the "orderItemSplitStream" OutputStream, which is the file
        output stream configured above.
        -->
(4)     <ftl:freemarker applyOnElement="order-item">
            <ftl:template>target/classes/orderitem-split.ftl</ftl:template>
            <ftl:use>
                <!-- Output the templating result to the "orderItemSplitStream" file output stream... -->
                <ftl:outputTo outputStreamResource="orderItemSplitStream"/>
            </ftl:use>
        </ftl:freemarker>
 
</smooks-resource-list>
Smooks リソース設定の (1) と (2) は、注文ヘッダー情報 (1) と注文商品情報 (2) を抽出する Java バインディングを定義します。 常に現在の注文商品のみがメモリに存在するようにすることが巨大メッセージを処理する秘訣となります。 Smooks の Javabean カートリッジは、これらをすべて管理し、order-item 断片が処理されると orderItem Bean を作成および再作成します。
設定 (3) の file:outputStream 設定は、ファイルシステムでファイルの生成を管理します。設定から見た通り、ファイル名は Bean コンテキストのデータより動的に作成することが可能です。また、highWaterMark 設定パラメータを介してファイルの作成をスロットルすることができます。これにより、ターゲットのファイルシステムが圧倒されないようにファイル作成の管理を行えるようにします。
Smooks リソース設定 (4) は、file:outputStream (3) によって作成された分割メッセージへ書き込みするために使用される FreeMarker テンプレートリソースを定義します。(4) がどのように file:outputStream リソースを参照するか注目してください。FreeMarker のテンプレートは次のようになります。
<orderitem id="${.vars["order-item"].@id}" order="${order.@id}">
    <customer>
        <name>${order.header.customer}</name>
        <number>${order.header.customer.@number}</number>
    </customer>
    <details>
        <productId>${.vars["order-item"].product}</productId>
        <quantity>${.vars["order-item"].quantity}</quantity>
        <price>${.vars["order-item"].price}</price>
    </details>
</orderitem>
JMS ルーティングは、http://www.milyn.org/xsd/smooks/jms-routing-1.2.xsd 設定名前空間より jms:router 設定を介して実行されます。
orderItem_xml bean を smooks.exampleQueue というJMS キューへルーティングする (「ファイルへのルーティング」の例も読み取ります) jms:router の例は次の通りです。
<?xml version="1.0"?>
<smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd"
                      xmlns:core="http://www.milyn.org/xsd/smooks/smooks-core-1.3.xsd"
                      xmlns:jms="http://www.milyn.org/xsd/smooks/jms-routing-1.2.xsd"
                      xmlns:ftl="http://www.milyn.org/xsd/smooks/freemarker-1.1.xsd">
 
        <!--
        Filter the message using the SAX Filter (i.e. not DOM, so no
        intermediate DOM, so we can process huge messages...
        -->
        <core:filterSettings type="SAX" />
 
(1)     <resource-config selector="order,order-item">
            <resource>org.milyn.delivery.DomModelCreator</resource>
        </resource-config>
 
(2)     <jms:router routeOnElement="order-item" BeanId="orderItem_xml" destination="smooks.exampleQueue">
            <jms:message>
                <!-- Need to use special FreeMarker variable ".vars" -->
                <jms:correlationIdPattern>${order.@id}-${.vars["order-item"].@id}</jms:correlationIdPattern>
            </jms:message>
            <jms:highWaterMark mark="3"/>
        </jms:router>
 
(3)     <ftl:freemarker applyOnElement="order-item">
            <!--
            Note in the template that we need to use the special FreeMarker variable ".vars"
            because of the hyphenated variable names ("order-item"). See http://freemarker.org/docs/ref_specvar.html.
            -->
            <ftl:template>/orderitem-split.ftl</ftl:template>
            <ftl:use>
                <!-- Bind the templating result into the bean context, from where
                it can be accessed by the JMSRouter (configured above). -->
                <ftl:bindTo id="orderItem_xml"/>
            </ftl:use>
        </ftl:freemarker>
 
</smooks-resource-list>
この例では、 FreeMarker 操作の結果が JMS キューへルーティングされます (文字列としてなど)。 完全オブジェクトモデルをルーティングした可能性もありますが、 この場合はシリアライズされた ObjectMessage としてルーティングされます。
データベースへのルーティングは比較的簡単です。「ファイルへのルーティング」の項を読んでからこの項を読むようにしてください。
前述のファイルルーティングの例と同じ状況であることを仮定しますが、ここでは注文および注文商品データをデータベースにルーティングします。
最初に、データストリームより注文および注文商品データを抽出する Java バインディングのセットを定義します。
<?xml version="1.0"?>
<smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd" 
                      xmlns:jb="http://www.milyn.org/xsd/smooks/javabean-1.4.xsd">
 
    <!-- Extract the order data... -->
    <jb:bean BeanId="order" class="java.util.Hashtable" createOnElement="order">
        <jb:value property="orderId" decoder="Integer" data="order/@id"/>
        <jb:value property="customerNumber" decoder="Long" data="header/customer/@number"/>
        <jb:value property="customerName" data="header/customer"/>
    </jb:bean>
 
    <!-- Extract the order-item data... -->
    <jb:bean BeanId="orderItem" class="java.util.Hashtable" createOnElement="order-item">
        <jb:value property="itemId" decoder="Integer" data="order-item/@id"/>
        <jb:value property="productId" decoder="Long" data="order-item/product"/>
        <jb:value property="quantity" decoder="Integer" data="order-item/quantity"/>
        <jb:value property="price" decoder="Double" data="order-item/price"/>
    </jb:bean>
 
</smooks-resource-list>
次に、 データソースの設定と、そのデータソースを使用して Java オブジェクトモデルへバインドされたデータをデータベースへ挿入する複数の db:executor 設定を定義します。
直接のデータベース接続を読み出すデータソースの設定 (名前空間 http://www.milyn.org/xsd/smooks/datasource-1.3.xsd)
<?xml version="1.0"?>
<smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd" xmlns:ds="http://www.milyn.org/xsd/smooks/datasource-1.3.xsd">
 
    <ds:direct bindOnElement="#document"
            datasource="DBExtractTransformLoadDS"
            driver="org.hsqldb.jdbcDriver"
            url="jdbc:hsqldb:hsql://localhost:9201/milyn-hsql-9201"
            username="sa"
            password=""
            autoCommit="false" />
 
</smooks-resource-list>
データベース接続の読み出しに JNDI データソースを使用することも可能です。
<?xml version="1.0"?>
<smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd" xmlns:ds="http://www.milyn.org/xsd/smooks/datasource-1.3.xsd">
 
    <!-- This JNDI datasource can handle JDBC and JTA transactions or 
           it can leave the transaction managment to an other external component.
           An external component could be an other Smooks visitor, the EJB transaction manager
           or you can do it your self. -->
    <ds:JNDI
        bindOnElement="#document"
        datasource="DBExtractTransformLoadDS"
        datasourceJndi="java:/someDS"
        transactionManager="JTA"
        transactionJndi="java:/mockTransaction"
        targetProfile="jta"/>
 
</smooks-resource-list>
データソーススキーマはデータソースの設定方法を説明します。
db:executor の設定 (名前空間 http://www.milyn.org/xsd/smooks/db-routing-1.1.xsd)
<?xml version="1.0"?>
<smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd"
                      xmlns:db="http://www.milyn.org/xsd/smooks/db-routing-1.1.xsd">
 
    <!-- Assert whether it's an insert or update. Need to do this just before we do the insert/update... -->
    <db:executor executeOnElement="order-items" datasource="DBExtractTransformLoadDS" executeBefore="true">
        <db:statement>select OrderId from ORDERS where OrderId = ${order.orderId}</db:statement>
        <db:resultSet name="orderExistsRS"/>
    </db:executor>
 
    <!-- If it's an insert (orderExistsRS.isEmpty()), insert the order before we process the order items... -->
    <db:executor executeOnElement="order-items" datasource="DBExtractTransformLoadDS" executeBefore="true">
        <condition>orderExistsRS.isEmpty()</condition>
        <db:statement>INSERT INTO ORDERS VALUES(${order.orderId}, ${order.customerNumber}, ${order.customerName})</db:statement>
    </db:executor>
 
    <!-- And insert each orderItem... -->
    <db:executor executeOnElement="order-item" datasource="DBExtractTransformLoadDS" executeBefore="false">
        <condition>orderExistsRS.isEmpty()</condition>
        <db:statement>INSERT INTO ORDERITEMS VALUES (${orderItem.itemId}, ${order.orderId}, ${orderItem.productId}, ${orderItem.quantity}, ${orderItem.price})</db:statement>
    </db:executor>
 
    <!-- Ignoring updates for now!! -->
 
</smooks-resource-list>