第14章 Smooks の拡張


14.1. Smooks の API

API

既存のすべての Smooks 機能 (Java バインド、EDI 処理など) は、明確に定義された多くの API の拡張によって構築されています。

Smooks の主要な拡張ポイント/API は、リーダー API とビジター API です。
リーダー API
ソース/入力データ (リーダー) を処理して、すべてのメッセージフラグメントとサブフラグメントに明確に定義された一連の階層イベント (SAX イベントモデルに基づく) として他の Smooks コンポーネントによって消費できるようにするためのもの。
ビジター API
ソース/入力リーダーによって生成されたメッセージフラグメント SAX イベントを消費するためのもの。

14.2. Smooks コンポーネントの設定

すべての Smooks コンポーネントは、まったく同じ方法で設定されます。Smooks Core コードを使用する場合、すべての Smooks コンポーネントは、SmooksResourceConfiguration インスタンスを使用して設定された resources です。

14.3. namespace 固有の設定

Smooks は、コンポーネントの namespace (XSD) 固有の XML 設定を構成する機能を提供します。最も基本的な設定 (および SmooksResourceConfiguration クラスに直接マッピングされる設定) は、基本設定 namespace (http://www.milyn.org/xsd/smooks-1.1.xsd)。

14.4. namespace 固有の設定例

<smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd">

    <resource-config selector="">
        <resource></resource>
        <param name=""></param>
    </resource-config>

</smooks-resource-list>
Copy to Clipboard Toggle word wrap
  • selector 属性は、リソースを選択する機能です (たとえば、ビジター実装の XPath にすることができます)。
  • resource 要素は実際のリソースです。これは、Java クラス名またはテンプレートなどの他の形式のリソースにすることができます。このセクションの残りの部分では、リソースは Java クラス名であると想定されます。
  • param 要素は、resource 要素に定義されたリソースの設定パラメーターです。

14.5. ランタイム表現

Smooks は、リソースの実行時表現を作成するためのすべての詳細 (たとえば、リソース要素に指定されたクラスの構成) を処理し、すべての設定パラメーターを注入します。また、リソースタイプとは何か、およびそこからセレクターなどを解釈する方法も明らかにします。(たとえば、リソースがビジターインスタンスである場合は、ソースメッセージフラグメントを選択するセレクターが XPath であることを認識します。)

14.6. 設定アノテーション

コンポーネントが作成されたら、<param> 要素の詳細を設定する必要があります。これは、@ConfigParam および @Config アノテーションを使用すると、実行されます。

14.7. @ConfigParam アノテーション

@ConfigParam アノテーションは、アノテーション付きのプロパティ自身と同じ名前を持つ <param> 要素から名前付きパラメーターを反射的に注入します。名前は異なる場合がありますが、デフォルトの動作はコンポーネントプロパティーの名前に一致します。

14.8. @ConficParam の利点

このアノテーションにより、次の理由でコンポーネントから余分なコードが削除されます。
  • <param> 値をアノテーション付きのコンポーネントプロパティーに設定する前に、そのデコードを処理します。Smooks は、すべての主要な型 (int、Double、File、Enum など) に DataDecoder を提供しますが、すぐに使用できるデコーダーが特定のデコード要件をカバーしていない場合は、カスタム DataDecoder を実装および使用できます (例: @ConfigParam(decoder = MyQuirkyDataDecoder.class))。カスタムデコーダーが登録されている場合、Smooks はカスタムデコーダーを自動的に使用します (つまり、このアノテーションでデコーダープロパティーを定義する必要はありません)。Smooks が、特定のデータ型をデコードするために、DataDecoder 実装を自動的に見つけられるように、DataDecoder 実装を登録する方法の詳細については、DataDecoder Javadocs を参照してください。
  • config プロパティの choice 制約をサポートし、設定値が定義された選択値の 1 つではない場合、設定例外を生成します。たとえば、ONOFF の制約付きの値セットを持つプロパティーがあるとします。このアノテーションの Choice プロパティーを使用して、設定を制約したり、例外を発生させたりすることができます。(たとえば、@ConfigParam(choice = {"ON", "OFF"}) です。)
  • @ConfigParam(defaultVal = "true") など、デフォルトの設定値を指定できます。
  • @ConfigParam(use = Use.OPTIONAL) など、プロパティー設定値が必須かオプションかを指定できます。デフォルトでは、すべてのプロパティーは、REQUIRED ですが、defaultVal を設定すると、プロパティーは、OPTIONAL と暗黙的にマークされます。

14.9. @ConfigParam アノテーションの使用

この例は、アノテーション付きのコンポーネント DataSeeder とそれに対応する Smooks 設定を示しています。
public class DataSeeder 
{
   @ConfigParam
   private File seedDataFile;

   public File getSeedDataFile() 
   {
      return seedDataFile;
   }

   // etc...
}
Copy to Clipboard Toggle word wrap
<smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd">
   <resource-config selector="dataSeeder">
      <resource>com.acme.DataSeeder</resource>
         <param name="seedDataFile">./seedData.xml</param>
      </resource-config>
</smooks-resource-list>
Copy to Clipboard Toggle word wrap

14.10. @Config アノテーション

@Config アノテーションは、コンポーネントリソースに関連付けられた完全な SmooksResourceConfiguration インスタンスをアノテーション付きのコンポーネントプロパティに反射的に注入します。タイプ SmooksResourceConfiguration ではないコンポーネントプロパティーにこのアノテーションを追加すると、エラーが発生します。

14.11. @Config アノテーションの使用

public class MySmooksComponent 
{
    @Config
    private SmooksResourceConfiguration config;

    // etc...
Copy to Clipboard Toggle word wrap

14.12. @Initialize と @Uninitialize

場合によっては、コンポーネントに初期化コードを記述する必要がある複雑な設定が必要です。このために、Smooks は @Initialize アノテーションを提供しています。
同様に、関連する Smooks インスタンスが破棄される (ガベージコレクション) 際、初期化中に行った操作を元に戻す必要がある場合があります。たとえば、初期化中に取得したリソースを解放する場合などです。このために、Smooks は @Uninitialize アノテーションを提供しています。

14.13. 基本的な初期化/初期化解除シーケンス

これは、基本的な初期化/初期化解除シーケンスです。
smooks = new Smooks(..);

// Initialize all annotated components
@Initialize

// Use the smooks instance through a series of filterSource invocations...
smooks.filterSource(...);
smooks.filterSource(...);
smooks.filterSource(...);
... etc ...

smooks.close();

// Uninitialize all annotated components
@Uninitialize
Copy to Clipboard Toggle word wrap

14.14. @Initialize と @Uninitialize の使用

概要

この例では、初期化時にデータベースへの複数の接続を開いて、Smooks インスタンスを閉じる際、それらのデータベースリソースをすべて解放する必要があるコンポーネントがあるとします。

public class MultiDataSourceAccessor 
{
    @ConfigParam
    private File dataSourceConfig;

    Map<String, Datasource> datasources = new HashMap<String, Datasource>();

    @Initialize
    public void createDataSources() 
    {
        // Add DS creation code here....
        // Read the dataSourceConfig property to read the DS configs...
    }

    @Uninitialize
    public void releaseDataSources() 
    {
        // Add DS release code here....
    }

    // etc...
}
Copy to Clipboard Toggle word wrap
上記の @Initialize および @Uninitialize アノテーションを使用する場合は、次の点に注意する必要があります。
  • @Initialize および @Uninitialize メソッドは、引数なしのパブリックメソッドである必要があります。
  • @ConfigParam プロパティーは、最初の @Initialize メソッドが呼び出される前に、すべて初期化されます。したがって、@ConfigParam コンポーネントプロパティーを初期化プロセスへの入力として使用できます。
  • @Uninitialize メソッドは、すべて Smooks.close メソッドの呼び出しに応答して、呼び出されます。

14.15. カスタム設定 namespace の定義

Smooks は、コンポーネントのカスタム設定 namespace を定義する機能をサポートしています。これにより、<resource-config> 基本設定を使用して、検証可能なコンポーネントの XSD ベースのカスタム設定をすべて一般的な Smooks リソースとして扱うのではなく、サポートできます。

14.16. カスタム設定 namespace の使用

基本的なプロセスには、次の 2 つの手順が含まれます。
  1. 基本 http://www.milyn.org/xsd/smooks-1.1.xsd 設定 namespace を拡張するコンポーネントの設定 XSD を記述します。この XSD は、コンポーネントのクラスパスで提供する必要があります。/META-INF/ フォルダーに配置され、namespace URI と同じパスを持つ必要があります。たとえば、拡張 namespace URI が http://www.acme.com/schemas/smooks/acme-core-1.0.xsd の場合は、/META-INF/schemas/smooks/acme-core-1.0.xsd のクラスパスに物理 XSD ファイルを指定する必要があります。
  2. カスタム namespace 設定を SmooksResourceConfiguration インスタンスにマッピングする Smooks 設定 namespace マッピング設定ファイルを記述します。このファイルは、マッピングする namespace の名前に基づいて (慣例により)、名前を付ける必要があり、XSD と同じフォルダー内のクラスパスに物理的に配置する必要があります。上記の例を拡張すると、Smooks マッピングファイルは、/META-INF/schemas/smooks/acme-core-1.0.xsd-smooks.xml になります。-smooks.xml 接尾辞に注意してください。
注記
この機能に慣れるための最も簡単な方法は、Smooks コード自体の既存の拡張 namespace 設定を確認することです。すべての Smooks コンポーネント (Java バインド機能を含む) は、この機能を使用して、設定を定義します。Smooks Core 自体は、多くの拡張設定 namespace を定義します。

14.17. ソースリーダーの実装

カスタムデータ形式のソースリーダーを実装すると、Java バインド、テンプレート、保持、検証、分割、ルーティングなど、そのデータ形式に対するすべての Smooks 機能をすぐに開くことができます。Smooks の唯一の要件は、リーダーが、Java JDK からの標準の org.xml.sax.XMLReader インターフェイスを実装していることです。ただし、リーダー実装を設定できるようにする場合は、リーダーが、org.milyn.xml.SmooksXMLReader インターフェースを実装する必要があります。org.milyn.xml.SmooksXMLReaderorg.xml.sax.XMLReader の拡張です。既存の org.xml.sax.XMLReader 実装を使用することも、新しいものを実装することも簡単です。
詳細については、http://java.sun.com/j2se/1.5.0/docs/api/org/xml/sax/XMLReader.html を参照してください。

14.18. Smooks で使用するソースリーダーの実装

  1. 次のように、まず、基本的なリーダークラスを実装する必要があります。
     public class MyCSVReader implements SmooksXMLReader 
    {
       // Implement all of the XMLReader methods...
    }
    
    Copy to Clipboard Toggle word wrap
    特に興味深いものは、org.xml.sax.XMLReader インターフェイスの 2 つのメソッドです。
    1. setContentHandler(ContentHandler) は Smooks Core によって呼び出されます。リーダーの org.xml.sax.ContentHandler インスタンスを設定します。org.xml.sax.ContentHandler インスタンスメソッドは、parse(InputSource) メソッド内から呼び出されます。
    2. parse(InputSource): これは、ソースデータ入力ストリームを受け取り、解析し (つまり、この例の場合は、CSVストリーム)、setContentHandler(ContentHandler) メソッドで提供される org.xml.sax.ContentHandler インスタンスの呼び出しで SAX イベントストリームを生成するメソッドです。
    詳細については、http://download.oracle.com/javase/6/docs/api/org/xml/sax/ContentHandler.html を参照してください。
  2. CSV レコードに関連付けられたフィールドの名前を使用して、CSV リーダーを設定します。カスタムリーダー実装の設定は、いずれの Smooks コンポーネントでも同じです。以下の例を参照してください。
    public class MyCSVReader implements SmooksXMLReader 
    {
    
        private ContentHandler contentHandler;
    
        @ConfigParam
        private String[] fields; // Auto decoded and injected from the "fields" <param> on the reader config.
    
        public void setContentHandler(ContentHandler contentHandler) {
            this.contentHandler = contentHandler;
        }
    
        public void parse(InputSource csvInputSource) throws IOException, SAXException {
            // TODO: Implement parsing of CSV Stream...
        }
    
        // Other XMLReader methods...
    }
    
    Copy to Clipboard Toggle word wrap
  3. 基本的なリーダー実装スタブができると、単体テストの作成を開始して、新しいリーダー実装をテストできます。これを行うには、CSV 入力が必要です。names.csv という名前のファイル内の名前の単純なリストを特徴とする以下の例を確認してください。
    Tom,Jones
    Mike,Jones
    Mark,Jones
    Copy to Clipboard Toggle word wrap
  4. テスト Smooks 設定を使用して、MyCSVReader で Smooks を設定します。前述のとおり、Smooks では、すべてがリソースであり、基本的な <resource-config> 設定を行うことができます。これは、問題なく動作しますが、少し「うるさい」ため、Smooks は、特にリーダーを設定するために、基本的な <reader> 設定要素を提供しています。テストの設定は、mycsvread-config.xml で次のようになります。
    <smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd">
       <reader class="com.acme.MyCSVReader">
          <params>
             <param name="fields">firstname,lastname</param>
          </params>
       </reader>
    </smooks-resource-list>
    
    Copy to Clipboard Toggle word wrap
  5. JUnit テストクラスを実装します。
    public class MyCSVReaderTest extends TestCase 
    {
        
        public void test() {
            Smooks smooks = new Smooks(getClass().getResourceAsStream("mycsvread-config.xml"));
            StringResult serializedCSVEvents = new StringResult();
    
            smooks.filterSource(new StreamSource(getClass().getResourceAsStream("names.csv")), serializedCSVEvents);
    
            System.out.println(serializedCSVEvents);
    
            // TODO: add assertions etc
        }
    }
    
    Copy to Clipboard Toggle word wrap
  6. parse メソッドを実装します。
    public class MyCSVReader implements SmooksXMLReader 
    {
        private ContentHandler contentHandler;
    
        @ConfigParam
        private String[] fields; // Auto decoded and injected from the "fields" <param> on the reader config.
    
        public void setContentHandler(ContentHandler contentHandler) 
        {
            this.contentHandler = contentHandler;
        }
    
        public void parse(InputSource csvInputSource) throws IOException, SAXException 
        {
            BufferedReader csvRecordReader = new BufferedReader(csvInputSource.getCharacterStream());
            String csvRecord;
    
            // Send the start of message events to the handler...
            contentHandler.startDocument();
            contentHandler.startElement(XMLConstants.NULL_NS_URI, "message-root", "", new AttributesImpl());
    
            csvRecord = csvRecordReader.readLine();
            while(csvRecord != null) 
            {
                String[] fieldValues = csvRecord.split(",");
            
                // perform checks...
    
                // Send the events for this record...
                contentHandler.startElement(XMLConstants.NULL_NS_URI, "record", "", new AttributesImpl());
                for(int i = 0; i < fields.length; i++) 
                {
                    contentHandler.startElement(XMLConstants.NULL_NS_URI, fields[i], "", new AttributesImpl());
                    contentHandler.characters(fieldValues[i].toCharArray(), 0, fieldValues[i].length());
                    contentHandler.endElement(XMLConstants.NULL_NS_URI, fields[i], "");            
                }
                contentHandler.endElement(XMLConstants.NULL_NS_URI, "record", "");            
    
                csvRecord = csvRecordReader.readLine();    
            }
    
            // Send the end of message events to the handler...
            contentHandler.endElement(XMLConstants.NULL_NS_URI, "message-root", "");
            contentHandler.endDocument();
        }
    
        // Other XMLReader methods...
    }
    
    Copy to Clipboard Toggle word wrap
  7. 単体テストクラスを実行して、コンソールに次の出力を表示します (フォーマット済み)。
    <message-root>
        <record>
            <firstname>Tom</firstname>
            <lastname>Jones</lastname>
        </record>
        <record>
            <firstname>Mike</firstname>
            <lastname>Jones</lastname>
        </record>
        <record>
            <firstname>Mark</firstname>
            <lastname>Jones</lastname>
        </record>
    </message-root>
    
    Copy to Clipboard Toggle word wrap
    この後は、テストの拡張、リーダー実装コードの強化などのケースです。その後、リーダーを使用して、Smooks でサポートされているさまざまな操作を実行できます。

14.19. java-binding-config.xml を使用したリーダーの設定例

次の設定 (java-binding-config.xml) を使用すると、名前を PersonName オブジェクトのList にバインドできます。
<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">
    <reader class="com.acme.MyCSVReader">
        <params>
         <param name="fields">firstname,lastname</param>
        </params>
    </reader>
    <jb:bean beanId="peopleNames" class="java.util.ArrayList" createOnElement="message-root">
        <jb:wiring beanIdRef="personName" />
    </jb:bean>
    <jb:bean beanId="personName" class="com.acme.PersonName" createOnElement="message-root/record">
        <jb:value property="first" data="record/firstname" />
        <jb:value property="last" data="record/lastname" />
    </jb:bean>
</smooks-resource-list>
Copy to Clipboard Toggle word wrap
その設定のテストは次のとおりです。
public class MyCSVReaderTest extends TestCase 
{
    public void test_java_binding() 
    {
        Smooks smooks = new Smooks(getClass().getResourceAsStream("java-binding-config.xml"));
        JavaResult javaResult = new JavaResult();

        smooks.filterSource(new StreamSource(getClass().getResourceAsStream("names.csv")), javaResult);

        List<PersonName> peopleNames = (List<PersonName>) javaResult.getBean("peopleNames");

        // TODO: add assertions etc
    }
}
Copy to Clipboard Toggle word wrap

14.20. リーダーを使用するためのヒント

  • リーダーインスタンスが同時に使用されることはありません。Smooks Coreは、メッセージごとに新しいインスタンスを作成するか、readerPoolSizeFilterSettings プロパティに従って、インスタンスをプールおよび再利用します。
  • リーダーは、現在のフィルタリングコンテキストの Smooks ExecutionContext にアクセスする必要がある場合、org.milyn.xml.SmooksXMLReader インターフェイスを実装する必要があります。
  • ソースデータがバイナリーデータストリームである場合、リーダーは、org.milyn.delivery.StreamReader インターフェイスを実装する必要があります。
  • GenericReaderConfigurator インスタンスを使用して、ソースコード (単体テストなど) 内でリーダーを設定し、Smooks インスタンスに設定できます。
  • 基本的な <reader> 設定は問題ありませんが、カスタム CSV リーダー実装用にカスタム設定 namespace (XSD) を定義できます。このトピックは、ここでは扱いません。ソースコードを確認して、Smooks に付属するリーダー実装の拡張設定 namespace (EDIReaderCSVReaderJSONReader など) を確認します。これから、独自のカスタムリーダーでこれを行う方法を考え出すことができるはずです。

14.21. バイナリーソースリーダー

バイナリーソースリーダー はバイナリーデータソースのリーダーです。リーダーは、org.milyn.delivery.StreamReader インターフェイスを実装する必要があります。これは、InputStream が提供されるように、Smooks ランタイムに指示する単なるマーカーインターフェイスです。
バイナリーリーダーの実装は、非バイナリーリーダーの実装 (上記を参照) と本質的に同じですが、parse メソッドの実装が、InputSource からのInputStream を使用し (つまり、InputSource.getCharacterStream() ではなく、InputSource..getByteStream() を呼び出し)、デコードされたバイナリーデータから XML イベントを生成する必要がある点では異なります。

14.22. バイナリーソースリーダーの実装

  1. バイナリーソースリーダーを実装するには、次の parse メソッド実装を確認してください。
    public static class BinaryFormatXXReader implements SmooksXMLReader, StreamReader 
    {
        @ConfigParam
        private String xProtocolVersion;
    
        @ConfigParam
        private int someOtherXProtocolConfig;
    
        // etc...
    
        public void parse(InputSource inputSource) throws IOException, SAXException {
            // Use the InputStream (binary) on the InputSource...
            InputStream binStream = inputSource.getByteStream();
    
            // Create and configure the data decoder... 
            BinaryFormatXDecoder xDecoder = new BinaryFormatXDecoder();
            xDecoder.setProtocolVersion(xProtocolVersion);
            xDecoder.setSomeOtherXProtocolConfig(someOtherXProtocolConfig);
            xDecoder.setXSource(binStream);
    
            // Generate the XML Events on the contentHandler...
            contentHandler.startDocument();
    
            // Use xDecoder to fire startElement, endElement etc events on the contentHandler (see previous section)...
    
            contentHandler.endDocument();
        }
    
        // etc....
    }
    
    Copy to Clipboard Toggle word wrap
  2. 他のリーダーと同様、Smooks 設定に BinaryFormatXXReader リーダーを設定します。
    <smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd">
    
        <reader class="com.acme.BinaryFormatXXReader">
            <params>
             <param name="xProtocolVersion">2.5.7</param>
             <param name="someOtherXProtocolConfig">1</param>
                ... etc... 
            </params>
        </reader>
    
        ... Other Smooks configurations e.g. <jb:bean> configs for binding the binary data into Java objects... 
    
    </smooks-resource-list>
    
    Copy to Clipboard Toggle word wrap
  3. Smooks の実行コードを実行します (StreamSource に提供される InputStream に注意してください)。この場合、XML オブジェクトと Java オブジェクトの 2 つの結果が生成されます。
    StreamResult xmlResult = new StreamResult(xmlOutWriter);
    JavaResult javaResult = new JavaResult();
    
    InputStream xBinaryInputStream = getXByteStream();
    
    smooks.filterSource(new StreamSource(xBinaryInputStream), xmlResult, javaResult);
    
    // etc... Use the beans in the javaResult...
    
    Copy to Clipboard Toggle word wrap

14.23. ビジター実装

ビジター実装 は、Smooks の主要な機能です。Smooks のすぐに使える機能 (Java バインド、テンプレート、保持など) のほとんどは、1 つ以上のビジター実装を使用して、作成されました。ビジター実装は、多くの場合、ExecutionContext および ApplicationContext コンテキストオブジェクトでコラボレーションして、共通の目標を達成します。

14.24. サポート対象のビジター実装

  1. org.milyn.delivery.sax.SAXVisitor サブインターフェイスに基づく SAX ベースの実装。
  2. org.milyn.delivery.dom.DOMVisitor サブインターフェイスに基づく DOM ベースの実装。

14.25. SAX と DOM のビジター実装

実装は SAX と DOM の両方をサポートできますが、Red Hat は SAX のみのビジターを実装することを推奨します。通常、SAX ベースの実装は作成が簡単であり、実行も高速です。
重要
すべてのビジター実装は、ステートレスオブジェクトとして扱われます。1 つのビジターインスタンスは、複数のメッセージ、つまり Smooks.filterSource メソッドの複数の同時呼び出しで同時に使用できる必要があります。現在の Smooks.filterSource 実行に関連するすべての状態は、ExecutionContext に保存する必要があります。

14.26. SAX ビジター API

SAX ビジター API は多くのインターフェイスで構成されています。これらのインターフェイスは、SAXVisitor 実装が取得および処理できる org.xml.sax.ContentHandler SAX イベントに基づいています。SAXVisitor 実装によって解決されるユースケースに応じて、これらのインターフェイスの 1 つまたはすべてを実装する必要がある場合があります。

14.27. SAX ビジター API インターフェイス

org.milyn.delivery.sax.SAXVisitBefore
対象のフラグメント要素の startElement SAX イベントを取得します。
public interface SAXVisitBefore extends SAXVisitor 
{
    void visitBefore(SAXElement element, ExecutionContext executionContext) 
                                          throws SmooksException, IOException;
}
Copy to Clipboard Toggle word wrap
org.milyn.delivery.sax.SAXVisitChildren
対象のフラグメント要素の文字ベースの SAX イベント、および子フラグメント要素の startElement イベントに対応する Smooks 生成 (疑似) イベントを取得します。
public interface SAXVisitChildren extends SAXVisitor 
{
    void onChildText(SAXElement element, SAXText childText, ExecutionContext 
                        executionContext) throws SmooksException, IOException;

    void onChildElement(SAXElement element, SAXElement childElement, 
         ExecutionContext executionContext) throws SmooksException, IOException;
}
Copy to Clipboard Toggle word wrap
org.milyn.delivery.sax.SAXVisitAfter
対象のフラグメント要素の endElement SAX イベントを取得します。
 public interface SAXVisitAfter extends SAXVisitor 
{
    void visitAfter(SAXElement element, ExecutionContext executionContext) 
                                          throws SmooksException, IOException;
}
Copy to Clipboard Toggle word wrap

14.28. SAX ビジター API の例

XML を使用した API イベントの図解

これにより、3 つのインターフェイスが org.milyn.delivery.sax.SAXElementVisitor インターフェイス内で 1 つのインターフェイスにまとめられます。

<message>
    <target-fragment>      <!-- SAXVisitBefore.visitBefore -->
        Text!!             <!-- SAXVisitChildren.onChildText -->  
        <child>            <!-- SAXVisitChildren.onChildElement -->
        </child>
    </target-fragment>     <!-- SAXVisitAfter.visitAfter -->
</message>
Copy to Clipboard Toggle word wrap
上記は、XML としてのソースメッセージイベントストリームの図です。EDI、CSV、JSON、またはその他の形式の可能性があります。これは、読みやすいように、XML としてシリアル化されたソースメッセージイベントストリームであると考えてください。
上記の SAX インターフェイスからわかるように、org.milyn.delivery.sax.SAXElement タイプは、すべてのメソッド呼び出しで渡されます。このオブジェクトには、属性とその値を含む、対象のフラグメント要素に関する詳細が含まれています。また、テキストの蓄積を管理するためのメソッド、および Smooks.filterSource(Source, Result) メソッド呼び出しで渡された可能性がある StreamResult インスタンスに関連する Writer へのアクセスが含まれています。

14.29. SAX によるテキスト蓄積

SAX はストリームベースの処理モデルです。ドキュメントオブジェクトモデル (DOM) を作成したり、イベントデータを蓄積したりすることはありません。これが、巨大なメッセージストリームの処理に適した処理モデルである理由です。

14.30. org.milyn.delivery.sax.SAXElement

org.milyn.delivery.sax.SAXElement は、常に対象の要素に関連する属性データを含みますが、フラグメントの子テキストデータを含みません。SAX イベント (SAXVisitChildren.onChildText) が SAXVisitBefore.visitBefore イベントと SAXVisitAfter.visitAfter イベントの間に発生します。テキストイベントは、SAXElement に蓄積されません。その結果、パフォーマンスが大幅に低下する可能性があるためです。この欠点は、SAXVisitor 実装がフラグメントのテキストコンテンツにアクセスする必要がある場合、対象のフラグメントのテキストを蓄積するように、Smooks に明示的に指示する必要があることです。これは、SAXVisitorSAXVisitBefore.visitBefore メソッド実装内から SAXElement.accumulateText メソッドを呼び出すと、実行されます。

14.31. テキスト蓄積の例

public class MyVisitor implements SAXVisitBefore, SAXVisitAfter 
{
   public void visitBefore(SAXElement element, ExecutionContext executionContext)
                                             throws SmooksException, IOException 
   {
      element.accumulateText();
   }

   public void visitAfter(SAXElement element, ExecutionContext executionContext) 
                                             throws SmooksException, IOException 
   {
      String fragmentText = element.getTextContent();

      // ... etc ...
   }
}
Copy to Clipboard Toggle word wrap

14.32. @TextConsumer アノテーション

@TextConsumer アノテーションは、SAXVisitBefore.visitBefore メソッドを使用する代わりに、SAXVisitor 実装をアノテーションするために、使用することができます。

14.33. @TextConsumer の例

@TextConsumer
public class MyVisitor implements SAXVisitAfter 
{
   public void visitAfter(SAXElement element, ExecutionContext executionContext) 
                                             throws SmooksException, IOException 
   {
      String fragmentText = element.getTextContent();

        // ... etc ...
    }
}
Copy to Clipboard Toggle word wrap
注記
フラグメントテキストの全容は、SAXVisitAfter.visitAfter イベントの終了後、公開されます。

14.34. StreamResult の書き込み/シリアル化

概要

Smooks.filterSource(Source, Result) メソッドは、多くの異なる Result 型実装のうちの 1 つ以上を取ることができ、そのうちの 1 つが javax.xml.transform.stream.StreamResult クラスです。Smooks は、StreamResult インスタンスでソースを流入させ、再び流出させます。

デフォルトでは、Smooks は常に完全なソースイベントストリームを XML として、Smooks.filterSource(Source, Result) メソッドに提供される任意の StreamResult インスタンスにシリアル化します。Smooks.filterSource(Source, Result) メソッドに提供されたソースが XML ストリームであり、StreamResult インスタンスが Result インスタンスの 1 つとして提供された場合は、Smooks インスタンスが 1 つ以上のフラグメントを変更する 1 つ以上の SAXVisitor 実装で設定されていないかぎり、ソース XML は未変更の StreamResult に書き出されます。

14.35. StreamResult の書き込み/シリアル化の設定

  1. デフォルトのシリアル化動作をオンまたはオフにするには、フィルター設定にアクセスし、そのように設定します。
  2. メッセージフラグメントの 1 つのシリアル化された形式を変更するには、SAXVisitor を実装して、変換を実行し、XPath のような式を使用して、メッセージフラグメントをターゲットとします。
  3. メッセージフラグメントのシリアル化された形式を変更するには、提供されているテンプレートコンポーネントのいずれかを使用します。これらのコンポーネントは、SAXVisitor 実装でもあります。

14.36. SAXVisitor の実装

  1. フラグメントのシリアル化された形式を変換するための SAXVisitor を実装するには、SAXVisitor 実装が StreamResult に書き込まれるように、Smooks をプログラミングします。これは、Smooks が 1 つのフラグメントで複数の SAXVisitor 実装のターゲティングをサポートしているためですが、フラグメントごとに StreamResult に書き込むことができる SAXVisitor は、1 つだけです。
  2. 2 つ目の SAXVisitorStreamResult に書き込もうとすると、SAXWriterAccessException が発生し、Smooks 設定を変更する必要があります。
  3. 記述する StreamResult を指定するには、SAXVisitor が、StreamResult への Writer の所有権を取得する必要があります。これは、SAXVisitBefore.visitBefore メソッド実装内から、SAXElement.getWriter(SAXVisitor) メソッドを呼び出し、thisSAXVisitor パラメーターとして渡すと、実行されます。

14.37. SAXVisitor の実装例

public class MyVisitor implements SAXElementVisitor 
{
   public void visitBefore(SAXElement element, ExecutionContext executionContext) 
                                             throws SmooksException, IOException 
   {
      Writer writer = element.getWriter(this);

      // ... write the start of the fragment...
   }

   public void onChildText(SAXElement element, SAXText childText, 
                                    ExecutionContext executionContext) 
                                       throws SmooksException, IOException 
   {
      Writer writer = element.getWriter(this);

      // ... write the child text...
   }

   public void onChildElement(SAXElement element, SAXElement childElement, 
                                    ExecutionContext executionContext) 
                                       throws SmooksException, IOException 
   {
   
   }

   public void visitAfter(SAXElement element, ExecutionContext executionContext) 
                                             throws SmooksException, IOException 
   {
      Writer writer = element.getWriter(this);
      // ... close the fragment...
   }
}
Copy to Clipboard Toggle word wrap

14.38. SAXElement.setWriter

SAXElement.setWriter を使用すると、Writer インスタンスをリセットするために必要なサブフラグメントのシリアル化を制御できるため、サブフラグメントのシリアル化を流用できます。
シリアル化/変換しているターゲットフラグメントにサブフラグメントがまったくないことがわかっている場合があります。この状況では、Writer の所有権を獲得するための SAXElement.getWriter メソッドを呼び出すためだけに、SAXVisitBefore.visitBefore メソッドを実装することは非効率的です。このため、@StreamResultWriter アノテーションがあります。@TextConsumer アノテーションと組み合わせて使用すると、SAXVisitAfter.visitAfter メソッドを実装するだけで十分です。

14.39. StreamResultWriter の例

@StreamResultWriter
public class MyVisitor implements SAXVisitAfter 
{
   public void visitAfter(SAXElement element, ExecutionContext executionContext) 
                                                throws SmooksException, IOException 
   {
      Writer writer = element.getWriter(this);

      // ... serialize to the writer ...
   }
}
Copy to Clipboard Toggle word wrap

14.40. SAXToXMLWriter

Smooks は、SAXToXMLWriter クラスを提供します。SAXElement データを XML としてシリアル化するプロセスを簡素化します。このクラスでは、SAXVisitor 実装を記述できます。

14.41. SAXToXMLWriter の例

@StreamResultWriter
public class MyVisitor implements SAXElementVisitor 
{
   private SAXToXMLWriter xmlWriter = new SAXToXMLWriter(this, true);

   public void visitBefore(SAXElement element, ExecutionContext executionContext) 
                                             throws SmooksException, IOException 
   {
      xmlWriter.writeStartElement(element);
   }

   public void onChildText(SAXElement element, SAXText childText, ExecutionContext 
                              executionContext) throws SmooksException, IOException 
   {
      xmlWriter.writeText(childText, element);
   }

   public void onChildElement(SAXElement element, SAXElement childElement, 
      ExecutionContext executionContext) throws SmooksException, IOException 
   {
   
   }

   public void visitAfter(SAXElement element, ExecutionContext executionContext) 
                                             throws SmooksException, IOException 
   {
      xmlWriter.writeEndElement(element);
   }
}
Copy to Clipboard Toggle word wrap

14.42. SAXToXMLWriter の設定

  1. SAXToXMLWriterSAXVisitor 実装を記述する場合は、SAXToXMLWriter コンストラクターにブール値を設定します。encodeSpecialChars argであり、rewriteEntities フィルター設定に基づいて、設定する必要があります。
  2. @StreamResultWriter アノテーションをクラスから SAXToXMLWriter インスタンス宣言に移動します。この結果、Smooks は、SAXToXMLWriter インスタンスを作成し、関連する Smooks インスタンスの rewriteEntities フィルター設定で初期化されます。
    @TextConsumer
    public class MyVisitor implements SAXVisitAfter 
    {
       @StreamResultWriter
       private SAXToXMLWriter xmlWriter;
    
       public void visitAfter(SAXElement element, ExecutionContext executionContext) 
                                                 throws SmooksException, IOException 
       {
          xmlWriter.writeStartElement(element);
          xmlWriter.writeText(element);
          xmlWriter.writeEndElement(element);
       }
    }
    
    Copy to Clipboard Toggle word wrap

14.43. ビジター設定

SAXVisitor 設定は、テスト目的に役立ち、他の Smooks コンポーネントとまったく同様に機能します。Smooks ビジターインスタンスを設定する場合は、設定 selector は、XPath 式と同様に解釈されます。ビジターインスタンスは、Smooks インスタンスのプログラムコード内で設定できます。

14.44. ビジター設定の例

この例では、次のような SAXVisitor 実装を使用します。
@TextConsumer
public class ChangeItemState implements SAXVisitAfter 
{
   @StreamResultWriter
   private SAXToXMLWriter xmlWriter;

   @ConfigParam
   private String newState;

   public void visitAfter(SAXElement element, ExecutionContext executionContext) 
                                             throws SmooksException, IOException 
   {
      element.setAttribute("state", newState);

      xmlWriter.writeStartElement(element);
      xmlWriter.writeText(element);
      xmlWriter.writeEndElement(element);
   }
}
Copy to Clipboard Toggle word wrap
ステータスが OK の<order-item> フラグメントをトリガーするように、ChangeItemState を宣言的に設定すると、次のようになります。
<smooks-resource-list 
   xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd">
 
   <resource-config selector="order-items/order-item[@status = 'OK']">
      <resource>com.acme.ChangeItemState </resource>
      <param name="newState">COMPLETED</param>
   </resource-config>
 
</smooks-resource-list>
Copy to Clipboard Toggle word wrap
カスタム設定 namespace を使用すると、よりクリーンな厳密に型指定された設定を ChangeItemState コンポーネントに定義できます。カスタム設定 namespace コンポーネントは次のように設定されます。
<smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd" 
   xmlns:order="http://www.acme.com/schemas/smooks/order.xsd">
 
   <order:changeItemState itemElement="order-items/order-item[@status = 'OK']" 
      newState="COMPLETED" />
 
</smooks-resource-list>
Copy to Clipboard Toggle word wrap
このビジターは、次のように、ソースコードに設定することもできます。
Smooks smooks = new Smooks();

smooks.addVisitor(new ChangeItemState().setNewState("COMPLETED"), 
                                 "order-items/order-item[@status = 'OK']");

smooks.filterSource(new StreamSource(inReader), new StreamResult(outWriter));
Copy to Clipboard Toggle word wrap

14.45. ExecutionLifecycleCleanable

ExecutionLifecycleCleanable ライフサイクルインターフェイスを実装するビジターコンポーネントはポスト Smooks.filterSource ライフサイクル操作を実行できます。以下の例を参照してください。
public interface ExecutionLifecycleCleanable extends Visitor 
{
   public abstract void executeExecutionLifecycleCleanup(
                                          ExecutionContext executionContext);
}
Copy to Clipboard Toggle word wrap
基本的な呼び出しシーケンスは、次のように記述できます (executeExecutionLifecycleCleanup 呼び出しに注意)。
smooks = new Smooks(..);

smooks.filterSource(...);
// ** VisitorXX.executeExecutionLifecycleCleanup **
smooks.filterSource(...);
// ** VisitorXX.executeExecutionLifecycleCleanup **
smooks.filterSource(...);
// ** VisitorXX.executeExecutionLifecycleCleanup **
 ... etc ...
Copy to Clipboard Toggle word wrap
このライフサイクルメソッドでは、Smooks.filterSource 実行ライフサイクルの周囲にスコープされたリソースを関連する ExecutionContext のためにクリーンアップできます。

14.46. VisitLifecycleCleanable

VisitLifecycleCleanable ライフサイクルインターフェイスを実装するビジターコンポーネントはポスト SAXVisitAfter.visitAfter ライフサイクル操作を実行できます。
public interface VisitLifecycleCleanable extends Visitor 
{
   public abstract void executeVisitLifecycleCleanup(ExecutionContext executionContext);
}
Copy to Clipboard Toggle word wrap
基本的な呼び出しシーケンスは、次のように記述できます (executeVisitLifecycleCleanup 呼び出しに注意)。
smooks.filterSource(...);
    
    <message>
        <target-fragment>      < --- VisitorXX.visitBefore
            Text!!                       < --- VisitorXX.onChildText  
            <child>                      < --- VisitorXX.onChildElement
            </child>                 
        </target-fragment>     < --- VisitorXX.visitAfter
        ** VisitorXX.executeVisitLifecycleCleanup **
        <target-fragment>      < --- VisitorXX.visitBefore
            Text!!                       < --- VisitorXX.onChildText  
            <child>                      < --- VisitorXX.onChildElement
            </child>                 
        </target-fragment>     < --- VisitorXX.visitAfter
        ** VisitorXX.executeVisitLifecycleCleanup **
    </message>
    VisitorXX.executeExecutionLifecycleCleanup

smooks.filterSource(...);
    
    <message>
        <target-fragment>      < --- VisitorXX.visitBefore
            Text!!                       < --- VisitorXX.onChildText  
            <child>                      < --- VisitorXX.onChildElement
            </child>                 
        </target-fragment>     < --- VisitorXX.visitAfter
        ** VisitorXX.executeVisitLifecycleCleanup **
        <target-fragment>      < --- VisitorXX.visitBefore
            Text!!                       < --- VisitorXX.onChildText  
            <child>                      < --- VisitorXX.onChildElement
            </child>                 
        </target-fragment>     < --- VisitorXX.visitAfter
        ** VisitorXX.executeVisitLifecycleCleanup **
    </message>
    VisitorXX.executeExecutionLifecycleCleanup
Copy to Clipboard Toggle word wrap
このライフサイクルメソッドでは、SAXVisitor 実装の 1 つのフラグメント実行の周囲にスコープされたリソースを関連する ExecutionContext のためにクリーンアップできます。

14.47. ExecutionContext

ExecutionContext は状態情報を保存するためのコンテキストオブジェクトです。Smooks.filterSource メソッドの 1 回の実行に特化して、スコープされています。すべての Smooks ビジター実装は、1 つの Smooks.filterSource 実行のコンテキスト内でステートレスである必要があり、ビジター実装を Smooks.filterSource メソッドの複数の同時実行で使用できるようにします。ExecutionContext インスタンスに保存されているすべてのデータは、Smooks.filterSource 実行の完了時、失われます。ExecutionContext は、すべてのビジター API メッセージイベント呼び出しで提供されます。

14.48. ApplicationContext

ApplicationContext は状態情報を保存するためのコンテキストオブジェクトです。関連する Smooks インスタンスの周囲にスコープされます。つまり、1 つの Smooks インスタンスにつき、1 つの ApplicationContext インスタンスのみが存在します。このコンテキストオブジェクトは、複数の Smooks.filterSource 実行で維持およびアクセスする必要があるデータを保存するために、使用できます。コンポーネント (SAXVisitor コンポーネントを含む) は、ApplicationContext クラスプロパティを宣言し、@AppContext アノテーションを付けて、関連する ApplicationContext インスタンスにアクセスできます。以下の例を参照してください。
public class MySmooksComponent 
{
    @AppContext
    private ApplicationContext appContext;

    // etc...
}
Copy to Clipboard Toggle word wrap

トップに戻る
Red Hat logoGithubredditYoutubeTwitter

詳細情報

試用、購入および販売

コミュニティー

Red Hat ドキュメントについて

Red Hat をお使いのお客様が、信頼できるコンテンツが含まれている製品やサービスを活用することで、イノベーションを行い、目標を達成できるようにします。 最新の更新を見る.

多様性を受け入れるオープンソースの強化

Red Hat では、コード、ドキュメント、Web プロパティーにおける配慮に欠ける用語の置き換えに取り組んでいます。このような変更は、段階的に実施される予定です。詳細情報: Red Hat ブログ.

会社概要

Red Hat は、企業がコアとなるデータセンターからネットワークエッジに至るまで、各種プラットフォームや環境全体で作業を簡素化できるように、強化されたソリューションを提供しています。

Theme

© 2025 Red Hat