12 カスタム・フィルタ、フォーマッタおよびハンドラの開発
12.1 イベントのフィルタリング
デフォルトでは、すべてのトランザクション、操作およびメタデータ・イベントがDataSourceListenerイベント・ハンドラに渡されます。イベント・フィルタを実装して、ハンドラに送信するイベントをフィルタできます。たとえば、フィルタで、特定の列値を含む特定の表に対する特定の操作を選択できます。
フィルタは相加的です。複数のフィルタがハンドラに設定されている場合、イベントがハンドラに渡されるには、すべてのフィルタがtrueを返す必要があります。
フィルタは、Javaアプリケーション・プロパティ・ファイルを使用して構成できます。
# handler "foo" only receives certain events gg.handler.one.type=jms gg.handler.one.format=mytemplate.vm gg.handler.one.filter=com.mycompany.MyFilter
フィルタをアクティブにするには、フィルタを記述し、ハンドラに設定します。追加のロジックを特定のハンドラに追加する必要はありません。
12.2 カスタム・フォーマット
次のようにして、組込みハンドラの出力フォーマットをカスタマイズできます。
-
Javaでのカスタム・フォーマッタの記述。または
-
Velocityテンプレートの使用
12.2.1 Javaでのカスタム・フォーマッタのコーディング
前述の例では、同じフォーマッタ(com.mycompany.MyFormatter)を使用するJMSハンドラとファイル出力ハンドラを示しています。次の例は、このフォーマッタの実装方法の例です。
例12-1 カスタム・フォーマットの実装
package com.mycompany.MyFormatter;
import oracle.goldengate.datasource.DsOperation;
import oracle.goldengate.datasource.DsTransaction;
import oracle.goldengate.datasource.format.DsFormatterAdapter;
import oracle.goldengate.datasource.meta.ColumnMetaData;
import oracle.goldengate.datasource.meta.DsMetaData;
import oracle.goldengate.datasource.meta.TableMetaData;
import java.io.PrintWriter;
public class MyFormatter extends DsFormatterAdapter { public MyFormatter() { }
@Override
public void formatTx(DsTransaction tx,DsMetaData meta, PrintWriter out)
{ out.print("Transaction: " );
out.print("numOps=\'" + tx.getSize() + "\' " );
out.println("ts=\'" + tx.getStartTxTimeAsString() + "\'");
for(DsOperation op: tx.getOperations()) {
TableName currTable = op.getTableName();
TableMetaData tMeta = dbMeta.getTableMetaData(currTable);
String opType = op.getOperationType().toString();
String table = tMeta.getTableName().getFullName();
out.println(opType + " on table \"" + table + "\":" );
int colNum = 0;
for(DsColumn col: op.getColumns())
{ColumnMetaData cMeta = tMeta.getColumnMetaData( colNum++ ); out.println( cMeta.getColumnName() + " = " + col.getAfterValue() ); }
}
@Override
public void formatOp(DsTransaction tx,DsOperation op, TableMetaData tMeta, PrintWriter out)
{// not used...
}
}
フォーマッタは、トランザクション全体のフォーマット(コミット後)、または各操作のフォーマット(受信後、コミット前)の方法を定義します。フォーマッタが操作モードの場合、formatOp(...)がコールされます。そうではない場合、トランザクション・コミット時にformatTx(...)がコールされます。
このカスタム・フォーマッタをコンパイルして使用するには、Java用Oracle GoldenGate JARをクラスパスに含め、コンパイルした.classファイルをgg_install_dir/dirprmに配置します。
javac -d gg_install_dir/dirprm
-classpath ggjava/ggjava.jar MyFormatter.java
結果のクラス・ファイルは、resources/classesに(正しいパッケージ構造で)配置されます。
gg_install_dir/dirprm/com/mycompany/MyFormatter.class
あるいは、カスタム・クラスをJARに含めることもできます。この場合、JARファイルをユーザー・イグジット・プロパティを使用してJVMクラスパスに含める(jvm.bootoptionsプロパティでjava.class.pathを使用)か、Javaアプリケーション・プロパティ・ファイルを設定してカスタムJARを含めます。
# set properties on 'one' gg.handler.one.type=file gg.handler.one.format=com.mycompany.MyFormatter gg.handler.one.file=output.xml gg.classpath=/path/to/my.jar,/path/to/directory/of/jars/*
12.2.2 Velocityテンプレートの使用
Velocityテンプレートは、カスタム・フォーマット用のJavaコードを記述するかわりの方法として、フォーマッタのプロトタイプを簡単に作成するよい代替方法です。たとえば、次のテンプレートをJMSまたはファイル・ハンドラの形式として指定します。
Transaction: numOps='$tx.size' ts='$tx.timestamp' #for each( $op in $tx ) operation: $op.sqlType, on table "$op.tableName": #for each( $col in $op ) $op.tableName, $col.meta.columnName = $col.value #end #end
テンプレートの名前がsample.vmとすると、次のようにクラスパスに配置します。
gg_install_dir/dirprm/sample.vm
テンプレートを使用するようJavaアプリケーション・プロパティ・ファイルを更新します。
# set properties on 'one' gg.handler.one.type=file gg.handler.one.format=sample.vm gg.handler.one.file=output.xml
テンプレートを変更する場合、Javaソースを再コンパイルする必要はありません。テンプレートを保存してJavaアプリケーションを再実行するのみです。アプリケーションを実行すると、次の出力が生成されます(表の名前はSCHEMA.SOMETABLEで、列はTESTCOLAおよびTESTCOLBとします)。
Transaction: numOps='3' ts='2008-12-31 12:34:56.000' operation: UPDATE, on table "SCHEMA.SOMETABLE": SCHEMA.SOMETABLE, TESTCOLA = value 123 SCHEMA.SOMETABLE, TESTCOLB = value abc operation: UPDATE, on table "SCHEMA.SOMETABLE": SCHEMA.SOMETABLE, TESTCOLA = value 456 SCHEMA.SOMETABLE, TESTCOLB = value def operation: UPDATE, on table "SCHEMA.SOMETABLE": SCHEMA.SOMETABLE, TESTCOLA = value 789 SCHEMA.SOMETABLE, TESTCOLB = value ghi
12.3 Javaでのカスタム・ハンドラのコーディング
カスタム・ハンドラは、次の例で示すように、AbstractHandlerを拡張することで実装できます。
import oracle.goldengate.datasource.*;
import static oracle.goldengate.datasource.GGDataSource.Status;
public class SampleHandler extends AbstractHandler {
@Override
public void init(DsConfiguration conf, DsMetaData metaData) {
super.init(conf, metaData);
// ... do additional config...
}
@Override
public Status operationAdded(DsEvent e, DsTransaction tx, DsOperation op) { ... }
@Override
public Status transactionCommit(DsEvent e, DsTransaction tx) { ... }
@Override
public Status metaDataChanged(DsEvent e, DsMetaData meta) { .... }
@Override
public void destroy() { /* ... do cleanup ... */ }
@Override
public String reportStatus() { return "status report..."; }
@Override
public Status ddlOperation(OpType opType, ObjectType objectType, String objectName, String ddlText) }
AbstractHandler内のメソッドは、抽象的ではなく、それどころか本体があります。本体では、それは、メタデータ・オブジェクトをダーティとマークすることで、キャッシュ済メタデータの無効化を実行します。また、ddlOperationメソッドが指定されている場合は、DDLイベントのTRACEレベル・ロギングを提供します。カスタム・ハンドラの実装では、このメソッドをオーバーライドできます。AbstractHandler内の機能が実行されることを確認するために、カスタム処理の前にスーパー・メソッドを必ずコールする必要があります。
トランザクションがExtractから処理される際、ハンドラへのコール順序は次のようになります。
-
初期化:
-
まず、ハンドラが構築されます。
-
次に、インスタンスでプロパティ・ファイルの値を使用してすべてのセッターがコールされます。
-
最後に、ハンドラが初期化されます。トランザクションを受信する前に
init(...)メソッドがコールされます。init(...)メソッドでsuper.init(...)をコールして基底クラスを適切に初期化することが重要です。
-
-
その後、メタデータが受信されます。Javaモジュールが、この実行時にまだ出現していない表での操作を処理する場合、メタデータ・イベントが発行され、
metadataChanged(...)メソッドがコールされます。通常は、このメソッドを実装する必要はありません。DsMetaDataは、新規データ・ソース・メタデータが受信されると自動的に更新されます。 -
トランザクションが開始されます。トランザクション・イベントが発行され、ハンドラで
transactionBegin(...)メソッドが呼び出されます(これについては記載していません)。この時点ではトランザクションに操作がないため、これは通常使用されません。 -
操作が順次トランザクションに追加されます。これによって、各操作の追加のたびにハンドラで
operationAdded(...)メソッドがコールされます。処理済のすべての表メタデータを含むデータ・ソース・メタデータとともに、これを含むトランザクションもメソッドに渡されます。トランザクションはまだコミットされておらず、コミットが受信される前に異常終了される可能性があります。各操作には、トランザクションから得た列値が含まれます(Extractが圧縮更新を処理する場合、変更された値のみの可能性があります)。列値には、ビフォア値とアフター値の両方が含まれることがあります。
ddlOperationメソッドの場合、オプションは次のとおりです。-
opType- 出現しているDDL操作タイプ(CREATE、ALTERなど)を特定する列挙値です。 -
objectType- DDLのターゲットのタイプ(TABLE、VIEWなど)を特定する列挙値です。 -
objectName- 完全修飾ソース・オブジェクト名です。一般には、完全修飾表名です。 -
ddlText- ソース・リレーショナル・データベースで実行された未加工のDDLテキストです。
-
-
トランザクションがコミットされます。これによって、
transactionCommit(...)メソッドがコールされます。 -
定期的に
reportStatusがコールされます。プロセスの停止時にもコールされます。通常、これによって処理の統計が表示されます(処理された操作とトランザクションの数、およびその他の詳細)。
単純なプリンタ・ハンドラの例を次に示します。これは、単にトランザクション、操作およびメタデータについて非常に基本的なイベント情報を出力します。ハンドラには、出力ファイル名を設定するためのプロパティmyoutputもあります。これは、Javaアプリケーション・プロパティ・ファイルで次のように設定できます。
gg.handlerlist=sample # set properties on 'sample' gg.handler.sample.type=sample.SampleHandler gg.handler.sample.myoutput=out.txt
カスタム・ハンドラを使用するには、次のようにします。
-
クラスをコンパイルします
-
クラスをアプリケーション・クラスパスに含めます。
-
Javaアプリケーション・プロパティ・ファイルのアクティブ・ハンドラのリストにハンドラを追加します。
ハンドラをコンパイルするには、Java用Oracle GoldenGate JARをクラスパスに含め、コンパイルした.classファイルをgg_install_dir/javaue/resources/classesに配置します。
javac -d gg_install_dir/dirprm
-classpath ggjava/ggjava.jar SampleHandler.java
結果のクラス・ファイルは、次のようにresources/classesに(正しいパッケージ構造で)配置されます。
gg_install_dir/dirprm/sample/SampleHandler.classノート:
サンプルhello world以外のJavaアプリケーションの開発では、AntまたはMavenを使用してアプリケーションをコンパイル、テストおよびパッケージ化します。javacを示した例は、例示目的のみです。
あるいは、カスタム・クラスをJARに含め、クラスパスに含めることができます。Javaプロパティを使用してカスタムJARファイルをJVMクラスパスに含める(jvm.bootoptionsプロパティでjava.class.pathを使用)か、Javaアプリケーション・プロパティ・ファイルを設定してカスタムJARを含めます。
# set properties on 'one' gg.handler.one.type=sample.SampleHandler gg.handler.one.myoutput=out.txt gg.classpath=/path/to/my.jar,/path/to/directory/of/jars/*
任意のハンドラで、追加の個別JAR、ディレクトリ(リソースまたは抽出したクラス・ファイルを含む)またはJARのディレクトリ全体を含めるようクラスパス・プロパティを設定できます。JARのディレクトリ全体を含めるには、Java 6形式の構文を使用します。
c:/path/to/directory/* (or on UNIX: /path/to/directory/* )
ワイルドカード*のみ指定できます。ファイル・パターンは使用できません。これは、.jar接尾辞で終わるディレクトリ内のすべてのファイルに自動的に一致します。複数のJARまたは複数のディレクトリを含めるには、システム固有のパス・セパレータ(UNIXではコロン、Windowsではセミコロン)を使用するか、前述の例で示したようにプラットフォームに依存しないカンマを使用します。
ハンドラに多数のプロパティを設定する必要がある場合、パラメータ・ファイルにプロパティを含めるだけで、ハンドラの対応するセッターがコールされます。次に例を示します。
gg.handler.one.type=com.mycompany.MyHandler gg.handler.one.myOutput=out.txt gg.handler.one.myCustomProperty=12345
前述の例では、カスタム・ハンドラ内の次のメソッドが起動されます。
public void setMyOutput(String s) {// use the string...
} public void setMyCustomProperty(int j) {// use the int...
}
int、long、String、booleanなど、任意の標準Javaデータ型を使用できます。カスタム・データ型の場合、カスタム・プロパティ・エディタを作成して、Stringをカスタムのデータ型に変換することができます。
12.4 追加リソース
Java APIにはJavadocが用意されています。Javadocは、カスタマイズおよび拡張に有用なインタフェースおよびクラスのみを配布するために、コア・パッケージ、クラスおよびインタフェースのセットに意図的に縮小されています。
各パッケージでは、わかりやすくするために一部のクラスが意図的に省略されています。重要なクラスは次のとおりです。
-
oracle.goldengate.datasource.DsTransaction: データベース・トランザクションを表します。トランザクションには、0個以上の操作が含まれます。 -
oracle.goldengate.datasource.DsOperation: データベース操作(挿入、更新、削除)を表します。操作には、データ変更イベントを表す0個以上の列値が含まれます。列索引は、Java APIで0でオフセットされます。 -
oracle.goldengate.datasource.DsColumn: 列値を表します。列値は、ビフォア値とアフター値のコンポジットです。列値は存在する(値があるかnull)場合も欠落している(ソース証跡に含まれていない)場合もあります。-
oracle.goldengate.datasource.DsColumnCompositeは、コンポジットです -
oracle.goldengate.datasource.DsColumnBeforeValueは、操作前の列値です(これはオプションで、操作に含まれていない場合があります)。 -
oracle.goldengate.datasource.DsColumnAfterValueは、操作後の値です
-
-
oracle.goldengate.datasource.meta.DsMetaData: 出現するすべてのデータベース・メタデータを表します。オブジェクトは最初空です。DsMetaDataには、TableNameをキーとして使用するTableMetaDataの0個以上のインスタンスのハッシュ・マップが含まれます。 -
oracle.goldengate.datasource.meta.TableMetaData: 1つの表のすべてのメタデータを表します。0個以上のColumnMetaDataを含みます。 -
oracle.goldengate.datasource.meta.ColumnMetaData: データベースまたはOracle GoldenGateソース定義ファイルに定義されている列名およびデータ型を含みます。
詳細は、Javadocを参照してください。