D XMLおよび複合ファイル・ドライバの事前/事後処理サポート
この付録の内容は次のとおりです。
概要
データを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>