D XMLおよび複合ファイル・ドライバの事前/事後処理サポート
この付録の内容は次のとおりです。
D.1 概要
データをXMLおよび複合ファイル・ドライバに提供する方法をカスタマイズできるようになりました。中間処理ステージを設定して、Oracle Data Integratorを使用して外部エンドポイントから取得されるデータを処理したり、データを外部エンドポイントに書き出すことができます。
1つのターミナル・ステージおよびゼロ以上のジャンクション・ステージを構成できます。ターミナル・ステージは外部エンドポイントからデータを読み取り、データを外部エンドポイントに書き込みます。ターミナル・ステージは外部エンドポイントからソース・データを読み取り、処理用にジャンクション・ステージに渡します。ジャンクション・ステージを構成して、ターミナル・ステージから渡されたデータを処理できます。
ソース・データに任意の形式を指定できます。XMLドライバまたは複合ファイル・ドライバに達するまで必ずしもXMLまたは複合ファイルである必要はありません。ただし、データが最終的にXMLドライバまたは複合ファイル・ドライバに渡される場合、データを必要な形式にする必要があります。つまり、データがXMLドライバに渡される場合、データ・サーバーに構成されているXSDに準拠する有効なXMLである必要があります。同様に、データが複合ファイル・ドライバに渡される場合、データがnXSDファイルで定義されているパターンと完全に一致する必要があります。
D.2 処理ステージの構成
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>
D.3 処理ステージの実装
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ドライバは構成に設定されている順序で結果コードのチェーンを適用し、データが構成されているように複数のステージに流れます。
D.4 例: 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
} }
D.5 例: 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 } }
D.6 例: 認証を必要とする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; }
D.7 例: 構成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>