D XMLおよび複合ファイル・ドライバの事前/事後処理サポート

データをXMLドライバと複合ファイル・ドライバに提供する方法はカスタマイズ可能です。中間処理ステージを設定して、Oracle Data Integratorを使用して外部エンドポイントから取得されるデータを処理したり、データを外部エンドポイントに書き出すことができます。

この付録の内容は次のとおりです。

概要

データをXMLおよび複合ファイル・ドライバに提供する方法をカスタマイズできるようになりました。中間処理ステージを設定して、Oracle Data Integratorを使用して外部エンドポイントから取得されるデータを処理したり、データを外部エンドポイントに書き出すことができます。

1つのターミナル・ステージおよびゼロ以上のジャンクション・ステージを構成できます。ターミナル・ステージは外部エンドポイントからデータを読み取り、データを外部エンドポイントに書き込みます。ターミナル・ステージは外部エンドポイントからソース・データを読み取り、処理用にジャンクション・ステージに渡します。ジャンクション・ステージを構成して、ターミナル・ステージから渡されたデータを処理できます。

ソース・データに任意の形式を指定できます。XMLドライバまたは複合ファイル・ドライバに達するまで必ずしもXMLまたは複合ファイルである必要はありません。ただし、データが最終的にXMLドライバまたは複合ファイル・ドライバに渡される場合、データを必要な形式にする必要があります。つまり、データがXMLドライバに渡される場合、データ・サーバーに構成されているXSDに準拠する有効なXMLである必要があります。同様に、データが複合ファイル・ドライバに渡される場合、データがnXSDファイルで定義されているパターンと完全に一致する必要があります。

処理ステージの構成

XMLファイル形式のODI JDBCドライバに対する中間処理ステージの完全な構成。構成XMLファイルのXSDも含める必要があります。

入力パイプライン構成の場合、最初のステージは最初に入力を処理します。最後のステージはデータをドライバに提供します。この最後のステージは、XMLまたは複合ファイル・ドライバで想定される形式に準拠する出力である必要があります。

出力パイプライン構成の場合、最後のステージは出力を書き出します。最初のステージはドライバからデータを受け入れます。このデータは、データサーバーのXSDと同じ形状です。

構成を含むXMLファイルを作成した後、XMLドライバまたは複合ファイル・ドライバのpipeline_config_fileまたはpcfプロパティがXMLファイルの絶対ファイル位置を指していることを確認します。

例D-1に、サンプルの構成XMLファイルを示します。

例D-1 サンプルの構成XMLファイル

<?xml version="1.0" encoding="UTF-8"?>
<pipeline xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:noNamespaceSchemaLocation="pre-post.xsd">
 
   <input-stages>
      <io-stage name="restInput">
         <codeDefinition>
            <javaClass>com.company.org.InputProcessor</javaClass>
         </codeDefinition>
         <debugOutput>http://tempuri.org</debugOutput>
      </io-stage>
      <stage name="BufferInputStage">
         <codeDefinition>
            <javaClass>com.company.org.BufferingClass</javaClass>
         </codeDefinition>
         <props>
            <property name="bufferSizeBytes">2340</property>
         </props>
      </stage>
      <stage name="UnzipStage">
         <codeDefinition>
            <code>[Groovy text in Base64 encoded form]</code>
         </codeDefinition>
      </stage>
   </input-stages>
   <output-stages>
      <io-stage name="restOut">
         <codeDefinition>
            <javaClass>com.company.org.OutputProcessor</javaClass>
         </codeDefinition>
         <debugOutput>http://tempuri.org</debugOutput>
      </io-stage>
      <stage name="SevenZipOutputStage">
         <codeDefinition>
            <code>[Groovy text in Base64 encoded form]</code>
         </codeDefinition>
      </stage>
      <stage name="BufferOutputStage">
         <codeDefinition>
            <javaClass>com.company.org.PushOutput</javaClass>
         </codeDefinition>
         <debugOutput>/scratch/jsmith/view_storage/tmp/bufferout.txt</debugOutput>
      </stage>
   </output-stages>
</pipeline>

処理ステージの実装

XMLドライバおよび複合ファイル・ドライバの事前または事後のデータ処理サポートは、3つの異なる方法で実装される可能性があります。

  • Groovyコード

    Groovyコードを構成XMLファイルに直接指定します。このGroovyコードはデータサーバー構成の一部で、再利用できません。Base64でエンコードされた文字列またはCDATAセクション内のプレーン・テキスト文字列としてGroovyコードを指定できます。

    例は、「例: 構成XMLファイルに組み込まれたGroovyコード」を参照してください。

  • Javaクラス

    Javaクラスの完全修飾名を指定します。このJavaクラスは、実行時にODIエージェントのクラスパスで使用できる必要があります。

    ODI Studioの場合、JARで作成され、USER_HOME/odi/oracledi/userlibディレクトリに配置される可能性があります。

    スタンドアロンまたはコロケート・エージェントの場合、このJARをDOMAIN_HOME/libディレクトリに配置するか、スクリプトのいずれかを使用してクラスパスにコード化する必要があります。

    JEEエージェントの場合、共有ライブラリとしてデプロイする必要があり、ODIエージェント・アプリケーションはこの共有ライブラリに依存する必要があります。

    例は、「例: 認証を必要とするHTTPソースからデータを読み取るためのJavaクラス」を参照してください。

  • Groovyスクリプト

    Groovyスクリプトの名前を指定します。Javaクラスのすべての要件は、このGroovyスクリプトにも適用されます。例外として、MyGroovySource.groovyなどのスクリプトの名前を指定するか、/home/groupuser/name/MyCustomGroovy.groovyなどのスクリプトへの絶対パスを指定する場合があります。

    前者の場合、ClassLoaderを使用してJavaクラス・リソースとしてスクリプトを参照します。クラス・リソースの通常のロケータ・パターンは、これに適用されます。たとえば、ファイルがJARにない場合、ファイル名を/MyGroovySource.groovyとして指定する必要があります。JARのサブディレクトリにある場合、ロケータは/com/foo/MyGroovySource.groovyになります。絶対パスを使用する場合、GroovyスクリプトはプレーンJavaファイルとしてアクセスされます。

    例は、次の項を参照してください。

注意:

次の事項に注意してください。

  • XMLドライバ・スキーマがドロップされないかぎり、組み込まれたGroovyコードまたは絶対パスを介して配置されたGroovyスクリプト・ファイルの変更は選択されません。Javaクラスまたはクラスパスを介して配置されたGroovyスクリプト・ファイルの場合、JVMを再起動して変更を選択する必要があります。

  • インラインGroovyコード、GroovyスクリプトまたはJavaクラスは、パブリックAPIに示されているようにすべてJavaインタフェースに準拠する必要があります。ODIドライバは構成に設定されている順序で結果コードのチェーンを適用し、データが構成されているように複数のステージに流れます。

例: ZIPファイル内からXMLデータを読み取るためのGroovyスクリプト

ZIPファイル内からXMLデータを読み取るためのGroovyスクリプトの例は、次のとおりです。

例D-2 Groovyスクリプト: ZIPファイル内からのXMLデータの読取り

import java.io.IOException
import java.io.InputStream;
import java.util.Properties;
import java.util.logging.Logger;
import oracle.odi.jdbc.drivers.common.pipeline.api.Stage;
import oracle.odi.jdbc.drivers.common.pipeline.api.TerminalStreamInputStage;

class FileFromZip extends TerminalStreamInputStage {

   public FileFromZip(Properties pStageProperties, String pDataserverUrl,
			     Properties pDataserverProperties, String pJavaEncoding,
     Logger pLogger, String pDebugLocation, String pDebugEncoding, String pStageName) {

   super(pStageProperties, pDataserverUrl, pDataserverProperties,
    pJavaEncoding, pLogger, pDebugLocation, pDebugEncoding, pStageName);
   }

   @Override
   public InputStream readSource() throws IOException {
     def zipFile = new java.util.zip.ZipFile(new File(getStageProperties().get("ZIP_FILE")))
     def zipEntry = zipFile.entries().find { !it.directory && getStageProperties().get("XML_FILE").equalsIgnoreCase(it.name)}
     return zipFile.getInputStream(zipEntry)
   }

   @Override
   public void close() throws IOException {
     // TODO Auto-generated method stub

   }

}

例: XMLデータを変換して異なる形式に書き込むためのGroovyスクリプト

XMLデータを変換して異なる形式に書き出すためのGroovyスクリプトの例は、次のとおりです。

例D-3 Groovyスクリプト: XMLデータの変換および異なる形式への書込み

package oracle.odi.jdbc.driver
 
import groovy.xml.MarkupBuilder;
 
import java.io.IOException;
import java.io.OutputStream
import java.util.Properties;
import java.util.logging.Logger;

import oracle.odi.jdbc.drivers.common.pipeline.api.JunctionStreamOutputStage;
import oracle.odi.jdbc.drivers.common.pipeline.api.Stage;
 
class TransformXmlOutput extends JunctionStreamOutputStage {
 
  	private OutputStream output
	
  public TransformXmlOutput(Properties pStageProperties, String pDataserverUrl,
  	Properties pDataserverProperties, String pJavaEncoding, Logger pLogger, String pDebugLocation,
  	String pDebugEncoding, String pStageName) {
   		super(pStageProperties, pDataserverUrl, pDataserverProperties, pJavaEncoding, pLogger,
   		pDebugLocation, pDebugEncoding, pStageName);
  	}

  @Override
  	public OutputStream writeOutput(OutputStream out) {
   		System.out.println("In TransformXmlOutput writeOutput")
   		def Writer w = new BufferedWriter(new OutputStreamWriter(out))
   		System.out.println("Created writer")
   		output = pipeInput { input ->
     			// Perform transformation
    			System.out.println("Piping")
    			def builder = new MarkupBuilder (w);
    			def cars = new XmlSlurper().parse(input)
 
    			System.out.println("Parsed XML")
 
    			builder.mkp.xmlDeclaration(version: "1.0", encoding: "utf-8")
 
    			builder.html(xmlns:"http://www.w3.org/1999/xhtml") {
     				head {
      					title "Cars collection"
     				}
     				body {
      					h1("Cars")
      					ul(){
       						cars.car.each{car ->
        							li(car.@name.toString() + "," + car.country + "," + car.description + ", Age: " + (2012 - car.@year.toInteger()) + " years")
       						}
      					}
     				}
			    }
    			w.flush()
    			System.out.println("Closing connectedStage")
    			closeConnectedStage();
   		}
  	}
 
  	@Override
  	public void close() throws IOException {
   		System.out.println("Closing TransformXmlOutput")
   		if(output!= null) {
    			output.flush();
    			output.close()
   		}
  	}
 
  	public static OutputStream pipeInput(Closure read) {
 
   		PipedInputStream input = new PipedInputStream()
   		PipedOutputStream output = new PipedOutputStream(input)
   		getThreadsSource.submit {
    			try{
     				read(input)
    			} catch (Exception e) {
     				System.out.println("Exception in thread")
     				e.printStackTrace();
     				throw e;
    			} finally {
     				output.flush()
    			}
		   }
   		return output
	  }
}

例: 認証を必要とするHTTPソースからデータを読み取るためのJavaクラス

認証を必要とするHTTPソースからデータを読み取るためのJavaクラスの例は、次のとおりです。

例D-4 Javaクラス: 認証を必要とするHTTPソースからのデータの読取り

/**
 * 
 */
package oracle.odi.jdbc.driver.xml;
 
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.Properties;
import java.util.logging.Logger;
 
import oracle.odi.jdbc.drivers.common.pipeline.api.TerminalStreamInputStage;
 
/**
 * @author jsmith	
 *
 */
public class FromHttpBasicAuthJava extends TerminalStreamInputStage {
 
   /**
    * @param pStageProperties
    * @param pDataserverUrl
    * @param pDataserverProperties
    * @param pJavaEncoding
    * @param pLogger
    * @param pDebugLocation
    * @param pDebugEncoding
    * @param pStageName
    */
    public FromHttpBasicAuthJava(Properties pStageProperties, String pDataserverUrl,
            Properties pDataserverProperties, String pJavaEncoding,
            Logger pLogger, String pDebugLocation, String pDebugEncoding,
            String pStageName) {
        super(pStageProperties, pDataserverUrl, pDataserverProperties,
                pJavaEncoding, pLogger, pDebugLocation, pDebugEncoding,
                pStageName);
    }
 
    /* (non-Javadoc)
     * @see oracle.odi.jdbc.drivers.common.pipeline.api.TerminalStreamInputStage#readSource()
     */
    @Override
    public InputStream readSource() throws IOException {
        String username = (String)(getStageProperties().get("username"));
        String password = (String)(getStageProperties().get("password"));
        byte[] credential = org.apache.commons.codec.binary.Base64.encodeBase64(
                (username + ":" + password).getBytes());
 
        //pass encoded user name and password as header
        URL url = new URL ("http://localhost:18000/get");
        URLConnection conn = url.openConnection();
        conn.setRequestProperty ("Authorization", "Basic " + new String(credential));
        urlStream = conn.getInputStream();
        StringBuilder result = new StringBuilder();
        byte[] read;
        int bytesRead;
        while(true) {
            read = new byte[1024];
            if((bytesRead = urlStream.read(read)) == -1) {
                break;
            } else
                result.append(new String(read, 0, bytesRead));
        }
        
        return new ByteArrayInputStream(result.toString().getBytes());
    }
 
    /* (non-Javadoc)
     * @see oracle.odi.jdbc.drivers.common.pipeline.api.Stage#close()
     */
    @Override
    public void close() throws IOException {
        if(urlStream != null)
            urlStream.close();
    }
 
    private InputStream urlStream = null;
}

例: 構成XMLファイルに組み込まれたGroovyコード

Base64文字列として組み込まれたGroovyコードを使用した構成XMLの例は、次のとおりです。

例D-5 Base64文字列として組み込まれたGroovyコードを使用した構成XMLファイル

<?xml version="1.0" encoding="UTF-8"?>
 
<pipeline xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:noNamespaceSchemaLocation="pre-post.xsd">
 
  <input-stages>
    <io-stage name="fromZip">
      <codeDefinition>
<code>
CgppbXBvcnQgamF2YS5pby5JT0V4Y2VwdGlvbgppbXBvcnQgamF2YS5pby5JbnB1dFN0cmVhbTsKaW1wb3J0IGphdmEudXRpbC5Qcm9wZXJ0aWVzOwppbXBvcnQgamF2YS51dGlsLmxvZ2dpbmcuTG9nZ2VyOwoKaW1wb3J0IG9yYWNsZS5vZGkuamRiYy5kcml2ZXJzLmNvbW1vbi5waXBlbGluZS5hcGkuU3RhZ2U7CmltcG9ydCBvcmFjbGUub2RpLmpkYmMuZHJpdmVycy5jb21tb24ucGlwZWxpbmUuYXBpLlRlcm1pbmFsU3RyZWFtSW5wdXRTdGFnZTsKCmNsYXNzIEZpbGVGcm9tRnJvbVppcCBleHRlbmRzIFRlcm1pbmFsU3RyZWFtSW5wdXRTdGFnZSB7CgoJcHVibGljIEZpbGVGcm9tRnJvbVppcChQcm9wZXJ0aWVzIHBTdGFnZVByb3BlcnRpZXMsIFN0cmluZyBwRGF0YXNlcnZlclVybCwKCQkJUHJvcGVydGllcyBwRGF0YXNlcnZlclByb3BlcnRpZXMsIFN0cmluZyBwSmF2YUVuY29kaW5nLAoJCQlMb2dnZXIgcExvZ2dlciwgU3RyaW5nIHBEZWJ1Z0xvY2F0aW9uLCBTdHJpbmcgcERlYnVnRW5jb2RpbmcsIFN0cmluZyBwU3RhZ2VOYW1lKSB7CgkJc3VwZXIocFN0YWdlUHJvcGVydGllcywgcERhdGFzZXJ2ZXJVcmwsIHBEYXRhc2VydmVyUHJvcGVydGllcywKCQkJCXBKYXZhRW5jb2RpbmcsIHBMb2dnZXIsIHBEZWJ1Z0xvY2F0aW9uLCBwRGVidWdFbmNvZGluZywgcFN0YWdlTmFtZSk7Cgl9CgoJQE92ZXJyaWRlCglwdWJsaWMgSW5wdXRTdHJlYW0gcmVhZFNvdXJjZSgpIHRocm93cyBJT0V4Y2VwdGlvbiB7CgkJZGVmIHppcEZpbGUgPSBuZXcgamF2YS51dGlsLnppcC5aaXBGaWxlKG5ldyBGaWxlKGdldFN0YWdlUHJvcGVydGllcygpLmdldCgiWklQX0ZJTEUiKSkpCgkJZGVmIHppcEVudHJ5ID0gemlwRmlsZS5lbnRyaWVzKCkuZmluZCB7ICFpdC5kaXJlY3RvcnkgJiYgZ2V0U3RhZ2VQcm9wZXJ0aWVzKCkuZ2V0KCJYTUxfRklMRSIpLmVxdWFsc0lnbm9yZUNhc2UoaXQubmFtZSl9CgkJcmV0dXJuIHppcEZpbGUuZ2V0SW5wdXRTdHJlYW0oemlwRW50cnkpCgl9CgoJQE92ZXJyaWRlCglwdWJsaWMgdm9pZCBjbG9zZSgpIHRocm93cyBJT0V4Y2VwdGlvbiB7CgkJLy8gVE9ETyBBdXRvLWdlbmVyYXRlZCBtZXRob2Qgc3R1YgoKCX0KCn0K
</code>
      </codeDefinition>
      <props>
        <property name="ZIP_FILE">/home/myuser/files/personal.zip</property>
        <property name="XML_FILE">personal.xml</property>
      </props>
    </io-stage>
  </input-stages>
</pipeline>