この章では、Oracle Enterprise Schedulerを使用して、管理者とユーザーが後で使用できるように保存する必要があるジョブ・リクエスト・ログと出力を生成する方法について説明します。
ジョブ・リクエストによって生成されるログは、管理者が問題を診断したり、ジョブ固有の状態を確認するのに役立ちます。ログには、Fusion Middleware Controlからアクセスできます。さらに、一部のジョブでは、ジョブの完了後にユーザーが確認できるジョブ固有のデータに関するレポートなどの出力が、その作業の一環として生成されます。コードで、リクエスト・ログ情報およびリクエストの出力を作成および格納できます。
この章の内容は次のとおりです。
Oracle Enterprise Schedulerでは、ジョブがリクエストのロギングに使用できるAPIが提供されています。プロセス・ジョブを除くすべてのジョブ・タイプで、ロギングAPIが使用されます。また、Oracle Enterprise Schedulerは、コンテンツ・ストア内のリクエスト・ログを処理するAPIも提供します。
Oracle Enterprise Schedulerでは、リクエストごとに1つのログがサポートされます。このログにはREQUESTID.logという形式の名前が付けられます。ロギングAPIでは、コンテンツ・ストアに直接ログが記録され、ログ・コンテンツはロールバックできません。
Fusion Middleware Controlによるジョブ・リクエストの表示の詳細は、『Oracle Fusion Middleware Oracle Enterprise Schedulerの管理』のジョブ・リクエスト・ログの表示に関する項を参照してください。
APIによりメッセージが記録されるシステム・プロパティSYS_EXT_requestLogLevel制約は、リクエスト・ログに格納されます。
プロパティの値は、デフォルトでINFOに設定されます。有効な値の完全なセットは、SEVERE、WARNING、INFO、CONFIG、FINE、FINER、FINESTです。JavaおよびPL/SQL APIを使用して、リクエストのログ・レベルを検出します。
プロセス・ジョブではロギングAPIが使用されないため、SYS_EXT_requestLogLevelはプロセス・ジョブに適用されないことに注意してください。
ロギング・コードにより、次の見出し情報で始まるログにエントリが書き込まれます。このヘッダーは、ロギングAPIによりログに書込まれる各レコードの先頭に自動的に付けられるため、プロセス・ジョブには適用されません。
####[TIMESTAMP] [LOGLEVEL] Sample log lines: ####[2011-07-11T14:20:32.276-07:00] [INFO] This is a log record. ####[2011-07-11T14:20:32.282-07:00] [INFO] This is the first line of a multi-line log record: second line of multi-line log record.
Javaリクエスト・ロガーを使用して、Javaまたは非同期Javaジョブの実行および更新ステージ中、およびすべてのジョブ実行タイプの前処理および後処理中にログを記録できます。
ジョブ・ロジックでは、ContentFactory APIを使用して、リクエスト・ログへのメッセージの記録に使用できるRequestLoggerを取得する必要があります。Oracle Enterprise Schedulerでは、ロガーが取得されるたびに、SYS_EXT_requestLogLevelシステム・プロパティの現行値を使用して、ロギング・レベルを制限します。
Javaジョブのロジックで、oracle.as.scheduler.request.ContentFactoryクラスのgetRequestLoggerメソッド(表22-1を参照)を使用して、ログ・エントリを追加するためのRequestLoggerインスタンスを取得できます。リクエスト・ロガーでは、リソース・バンドルはサポートされていないことに注意してください。
ログの処理に使用できるJava APIは次のとおりです。
ContentFactoryクラスは、ログの作成やエントリの追加に使用できるRequestLoggerのインスタンスを取得するために使用します。表22-1を参照してください。
RequestLoggerクラスは、ログを書き込むために使用します。表22-2を参照してください。
oracle.as.scheduler.request.ContentFactoryクラスには、コードが、出力コンテンツ・フレームワークにアクセスしたり、出力自体を作成するために使用できるインスタンスにアクセスできるようにするメソッドが備えられています。
表22-1 リクエスト・ログを作成するためのContentFactoryメソッド
| メソッド | 説明 |
|---|---|
|
指定されたrequestIdに対して |
ロガー・インスタンスを取得すると、エントリを追加するために、表22-2に示されているメソッドを使用できます。
表22-2 リクエスト・ログを作成するためのRequestLoggerメソッド
| メソッド | 説明 |
|---|---|
|
これらのメソッドによって、指定されたレベルでメッセージがログに記録されます。 指定されたロギング・レベルが、 logメソッドを使用する場合、
|
例22-1に、ロギングを行う非常に単純なJavaジョブの例を示します。
例22-1 Javaのリクエスト・ロギングの例
import oracle.as.scheduler.request.ContentFactory;
import oracle.as.scheduler.request.RequestLogger;
import java.util.logging.Level;
class ExampleJavaLogger{
private boolean m_loggingEnabled = false;
private RequestLogger m_requestLogger = null;
public void execute( RequestExecutionContext ctx,
RequestParameters params )
{
try
{
m_requestLogger = ContentFactory.getRequestLogger(ctx.getRequestId());
m_loggingEnabled = true;
}
catch (Exception ex)
{
// failed to get request logger
}
log(Level.INFO, "Starting the job.");
// ...
log(Level.INFO, "Ending the job.");
}
private void log( Level level, String message )
{
if (m_loggingEnabled)
{
m_requestLogger.log(level, message);
}
}
}
PL/SQLからログを作成する場合は、ログ・エントリを書き込むために、コードでESS_JOB PL/SQLパッケージを使用できます。
Oracle Enterprise Schedulerには、PL/SQLコードからログを作成するためのファンクションおよびプロシージャを含むESS_JOBパッケージが備えられています。
表22-3 リクエスト・ロギング用のESS_JOBファンクションおよびプロシージャ
| メソッド | 説明 |
|---|---|
|
現行セッションに関連付けられているOracle Enterprise Schedulerリクエストに対して、 指定されたロギング・レベルが、 ログ・レベルの値は、
|
SQLリクエスト・ジョブ・プロシージャによるリクエスト・ロギングの例を次に示します。
create or replace procedure log_example_job
( request_handle in varchar2 )
as
v_request_id number := null;
begin
ess_job.write_log(ess_job.level_fine,
'LOG_EXAMPLE_JOB Procedure Begin');
-- Oracle Enterprise Scheduler request id being executed.
begin
v_request_id := ess_runtime.get_request_id(request_handle);
exception
when others then
ess_job.write_log(ess_job.level_severe,
'Bad request handle: '||request_handle);
raise_application_error(-20000,
'Failed to get request id for request handle '||request_handle,
true);
end;
-- Job logic
ess_job.write_log(ess_job.level_info,
'Executing job logic...');
ess_job.write_log(ess_job.level_fine,
'LOG_EXAMPLE_JOB Procedure End');
end;
/
プロセス・ジョブからジョブ・リクエスト・ログに書き込むことができます。この動作は、特定のレベルでエントリを書き込むためのAPIに実行コードからアクセスできる、JavaおよびPL/SQLジョブとは大きく異なります。プロセス・ジョブでは、かわりに、ジョブの標準出力および標準エラーが、リクエストのログ作業ディレクトリ(Oracle Enterprise Schedulerにより設定される場所)にあるファイルにリダイレクトされます。Oracle Enterprise Schedulerは、このファイルをインポートし、コンテンツ・ストア内のリクエスト・ログに付加します。
つまり、プロセス・ジョブからログを記録するために必要なのは、ジョブ・ロジック・コードから標準出力に書き込むことのみです。
ログ・ファイルの読取りに使用されるエンコーディングは、「プロセス・ジョブのロケール」の説明に従って決定されます。
プロセス・ジョブから特定のレベルでログを記録できないことに注意してください(レベルを設定するためのAPIが使用できないため)。このため、ログ・コンテンツはSYS_EXT_requestLogLevelシステム・プロパティによって制限されません。Oracle Enterprise Schedulerでは、常にログ・ファイルのコンテンツをコンテンツ・ストア内のリクエスト・ログに付加します。
EJBジョブはリモートで実行されるJavaジョブであるため、リモートEJBジョブ実装はコンテンツをログおよび出力に書込むことができます。このコンテンツを処理するには、oracle.as.scheduler.request.RemoteContentHelper APIを使用します。次の箇条書きの項目は、必要な手順の概要を示しています。例22-2に、この機能を表すEJBジョブ実装を示します。
RemoteContentHelperを設定します。パラメータRequestExecutionContextおよびRequestParametersは、ジョブ実装のexecute()メソッドから取得できます。
RemoteContentHelper rch=new RemoteContentHelper(RequestExecutionContext, RequestParameters);
コンテンツをログ・ファイルに書き込みます。
rch.log(Level.INFO, logMessage)
テキスト出力を書き込みます。
RuntimeServiceHandle rsh = null;
ContentHandle ch = null;
String contentName = "Content1";
String contentData = "Some text content";
try {
rsh = rch.getRuntimeService().open();
ch = rch.openOutputContent(rsh, contentName, ContentType.Text, EnumSet.of(ContentHandle.ContentOpenOptions.Write));
rchelper().write(ch, contentData);
} catch (Exception ex) {
throw new ExecutionErrorException(ex);
} finally {
rch.closeOutputContent(ch);
rch.getRuntimeService().close(rsh);
}
バイナリ出力を書き込みます。
RuntimeServiceHandle rsh = null;
ContentHandle ch = null;
String contentName = "Content1";
String contentData = "Some binary content"; //Binary content can differ in the variable declaration.
try {
rsh = rch.getRuntimeService().open();
ch = rch.openOutputContent(rsh, contentName, ContentType.Binary, EnumSet.of(ContentHandle.ContentOpenOptions.Write));
rchelper().write(ch, contentData.getBytes());
} catch (Exception ex) {
throw new ExecutionErrorException(ex);
} finally {
rch.closeOutputContent(ch);
rch.getRuntimeService().close(rsh);
}
例22-2に、出力およびログの処理方法を表すEJBジョブ実装を示します。
例22-2 SimpleSyncEssBean
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.EnumSet;
import javax.ejb.Stateless;
import oracle.as.scheduler.RuntimeServiceHandle;
import oracle.as.scheduler.ExecutionCancelledException;
import oracle.as.scheduler.ExecutionErrorException;
import oracle.as.scheduler.ExecutionPausedException;
import oracle.as.scheduler.ExecutionWarningException;
import oracle.as.scheduler.RemoteExecutable;
import oracle.as.scheduler.RequestExecutionContext;
import oracle.as.scheduler.RequestParameters;
import oracle.as.scheduler.request.RemoteContentHelper;
import oracle.as.scheduler.request.ContentDetail;
import oracle.as.scheduler.request.ContentHandle;
import oracle.as.scheduler.request.ContentType;
@Stateless(name = "SimpleSyncEssBean")
public class SimpleSyncEssBean implements RemoteExecutable {
private RemoteContentHelper m_rch = null;
public void execute(RequestExecutionContext requestExecutionContext,
RequestParameters requestParameters) throws ExecutionErrorException, ExecutionWarningException,
ExecutionCancelledException,
ExecutionPausedException {
long requestId = requestExecutionContext.getRequestId();
// setup helper now so it is available to println
m_rch = setupRemoteContentHelper(requestExecutionContext, requestParameters);
ContentType contentType = ContentType.Text;
String contentName = requestId + "Output.txt";
ArrayList<String> srcLines = new ArrayList<String>();
srcLines.add("SimpleSyncEssBean Output Details \n");
boolean success = false;
String exmsg = "";
try {
createOutputContent(contentName, contentType, srcLines);
success = verifyOutputContent(contentName, contentType, srcLines);
} catch (ExecutionErrorException ex) {
exmsg = ex.getMessage();
}
if (!success) {
throw new ExecutionErrorException("Output test failed: " + contentName + ", " + exmsg);
} else {
printToLog("Output test succeeded: " + contentName);
}
printToLog(" SimpleSyncEssBean job succeeded. RequestId:" + requestId);
}
/**
* Creates the remote content helper for log/output.
*/
private RemoteContentHelper setupRemoteContentHelper(RequestExecutionContext ctx, RequestParameters params) throws ExecutionErrorException {
RemoteContentHelper rch = null;
try {
rch = new RemoteContentHelper(ctx, params);
} catch (Exception ex) {
throw new ExecutionErrorException(ex);
}
return rch;
}
/**
* Gets the remote content helper that is setup.
* Throws if it is not setup.
*/
private RemoteContentHelper rchelper() throws ExecutionErrorException {
if (null == m_rch) {
throw new ExecutionErrorException("RemoteContentHelper is not setup");
}
return m_rch;
}
private void printToLog(String message) throws ExecutionErrorException {
System.out.println(message);
if (m_rch != null) {
try {
m_rch.log(Level.INFO, message);
} catch (Exception ex) {
// ignore
}
} else {
rchelper();
}
}
/**
* Writes dataList as either Text or Binary output content.
*/
private void createOutputContent(String contentName, ContentType contentType,
ArrayList<String> dataList) throws ExecutionErrorException {
RuntimeServiceHandle rsh = null;
ContentHandle ch = null;
try {
rsh = rchelper().getRuntimeService().open();
ch =
rchelper().openOutputContent(rsh, contentName, contentType,
EnumSet.of(ContentHandle.ContentOpenOptions.Write));
for (String data : dataList) {
if (ContentType.Text == contentType) {
rchelper().write(ch, data);
} else {
rchelper().write(ch, data.getBytes());
}
}
} catch (Exception ex) {
throw new ExecutionErrorException(ex);
} finally {
if (ch != null) {
try {
rchelper().closeOutputContent(ch);
} catch (Exception ex) {
printToLog("Error while closing ch: " + ex.getMessage());
//ex.printStackTrace();
throw new ExecutionErrorException(ex);
}
}
if (rsh != null) {
try {
rchelper().getRuntimeService().close(rsh);
} catch (Exception ex) {
printToLog("Error while closing rsh: " + ex.getMessage());
//ex.printStackTrace();
throw new ExecutionErrorException(ex);
}
}
}
}
/**
* Verifies Text or Binary output content.
*/
private boolean verifyOutputContent(String contentName, ContentType contentType, ArrayList<String> srcDataList) throws ExecutionErrorException {
String actualData = getOutputContent(contentName, contentType);
StringBuffer sb = new StringBuffer();
for (String str : srcDataList) {
sb.append(str);
}
String srcData = sb.toString();
boolean success = srcData.equals(actualData);
if (!success) {
printToLog("Test failed for " + contentName);
printToLog("Expected data: <\n" + srcData + ">");
printToLog("Actual data: <\n" + actualData + ">");
}
try {
if (rchelper().outputContentExists(contentName)) {
ContentDetail detail = rchelper().getOutputContentDetail(contentName);
printToLog("ContentDetail:\n" + detail);
} else {
printToLog("The output content details are not present:\n");
}
} catch (Exception ex) {
String exm = "Failed to get output content detail: " + contentName;
printToLog(exm);
throw new ExecutionErrorException(ex);
}
return success;
}
/**
* Gets either Text or Binary output content as String.
*/
private String getOutputContent(String contentName, ContentType contentType) throws ExecutionErrorException {
RuntimeServiceHandle rsh = null;
long requestId = rchelper().getRequestExecutionContext().getRequestId();
ContentHandle ch = null;
String result = null;
try {
rsh = rchelper().getRuntimeService().open();
ch =
rchelper().openOutputContent(rsh, contentName, contentType,
EnumSet.of(ContentHandle.ContentOpenOptions.Read));
if (ContentType.Text == contentType) {
char[] chars = rchelper().getTextContent(ch, Integer.MAX_VALUE);
result = new String(chars);
} else {
byte[] bytes = rchelper().getBinaryContent(ch, Integer.MAX_VALUE);
result = new String(bytes);
}
} catch (Exception ex) {
throw new ExecutionErrorException(ex);
} finally {
if (ch != null) {
try {
rchelper().closeOutputContent(ch);
} catch (Exception ex) {
printToLog("Error while closing ch: " + ex.getMessage());
//ex.printStackTrace();
throw new ExecutionErrorException(ex);
}
}
if (rsh != null) {
try {
rchelper().getRuntimeService().close(rsh);
} catch (Exception ex) {
printToLog("Error while closing rsh: " + ex.getMessage());
//ex.printStackTrace();
throw new ExecutionErrorException(ex);
}
}
}
return result;
}
}
進捗状況メッセージは、非同期ジョブにのみ提供されます。Oracle Enterprise Scheduler AsyncWebServiceJobコールバック・エンドポイントは、新しいlogAsyncWSJobProgressMessage一方向操作をサポートします。この操作では、非同期SOAコンポジット(またはその他の非同期Webサービス)により、相関のws-addressing、および同じコールバック・エンドポイントおよび関連付けされたコールバックOWSMポリシーを使用して進捗状況メッセージを記録できます。これにより、非同期SOAコンポジットからのロギング進捗状況メッセージのための簡易的で便利なオプションが提供されます。
Oracle Enterprise Schedulerの非同期Webサービス・ジョブのコールバック・エンドポイントWSDLは、この操作の使用に必要な情報を提供します。WSDLの一部分を例22-3に示します。
例22-3 非同期Webサービス・ジョブ・コールバック・エンドポイントWSDL
<xsd:complexType name="logAsyncWSJobProgressMessage">
<xsd:sequence>
<xsd:element name="level" type="tns:logLevel" form="qualified"/>
<xsd:element name="message" type="xsd:string" form="qualified"/>
</xsd:sequence>
</xsd:complexType>
<xsd:element name="logAsyncWSJobProgressMessage" type="tns:logAsyncWSJobProgressMessage"/>
<message name="logAsyncWSJobProgressMessageInput">
<part name="parameters" element="tns:logAsyncWSJobProgressMessage"/>
</message>
<portType name="RequestPort">
<operation name="logAsyncWSJobProgressMessage">
<input message="tns:logAsyncWSJobProgressMessageInput" xmlns:ns1="http://www.w3.org/2006/05/addressing/wsdl" ns1:Action="logAsyncWSJobProgressMessage"/>
</operation>
</portType>
oracle.as.scheduler.RuntimeServiceクラスのメソッドを使用して、Oracle Enterprise Schedulerコンテンツ・ストアに格納されているログを処理できます。最初に、RuntimeServiceHandleインスタンスを取得する必要があります。このインスタンスを、これらのRuntimeServiceメソッドそれぞれの引数として渡します。
RuntimeServiceHandleの詳細は、「ランタイム・サービスへのアクセスおよびランタイム・サービス・ハンドルの取得方法」を参照してください。
表22-4 リクエスト・ログを処理するためのRuntimeServiceメソッド
| メソッド | 説明 |
|---|---|
|
リクエストに対して |
|
指定されたリクエストに対して、リクエスト・ログを開いてログ・データを取得し、 |
|
リクエスト・ログから最大 |
|
ログまたは出力テキスト・コンテンツから、最大 |
|
以前開いたログまたは出力コンテンツを閉じ、ハンドルを解放します。 |
ジョブを使用して実行時に出力コンテンツを作成できます。たとえば、ユーザーへのレポートで有用なデータをジョブで収集するとします。実行時に生成した出力は、クライアント・ユーザー・インタフェースまたはFusion Middleware Controlを使用して後から取得できます。
コードによって作成される出力は、Oracle Enterprise Schedulerコンテンツ・ストア内で直接作成でき、またファイル・システム内で作成しコンテンツ・ストアにインポートすることもできます。Oracle Enterprise Schedulerにより自動的にインポートすることも、ジョブでOracle Enterprise Scheduler APIを使用して明示的にインポートすることもできます。
ファイル・システムを使用する場合は、Oracle Enterprise Schedulerのess-config.xmlファイルで構成された場所にある特定のディレクトリに書き込みます。Oracle Enterprise Schedulerにより、すべてのリクエストから書き込まれたファイルを格納するためのリクエスト・ファイル・ディレクトリが作成されます。コードでは、リクエスト用に作成されたこのディレクトリのサブディレクトリに書き込みます。Oracle Enterprise Schedulerによって、すべてのリクエストの出力が自動的にコンテンツ・ストアにインポートされ、リクエスト固有のサブディレクトリは削除されます。
Oracle Enterprise Schedulerは、コンテンツ・ストア内の出力コンテンツを管理するためのAPIを提供します。
リクエスト・ファイル・ディレクトリは、Oracle Enterprise Schedulerのess-config.xmlファイルで指定されます。Oracle Enterprise Schedulerでは、リクエストごとに、このリクエスト・ファイル・ディレクトリのリクエスト固有のサブディレクトリを作成できます。これは、一時ファイル用の作業ディレクトリおよびコンテンツ・ストアにインポートする必要がある出力ファイル用の出力ディレクトリです。
コードでは実行時に、それぞれのリクエスト固有のディレクトリに一時ファイルおよび出力ファイルを書き込むことができます。Oracle Enterprise Schedulerにより、リクエストの出力ディレクトリ内のファイルがコンテンツ・ストアにインポートされます。コンテンツのインポートのタイミングは、リクエスト・ファイル・ディレクトリが共有とローカルのどちらであるかに応じて異なります。「リクエスト・ファイル・ディレクトリの共通動作」、「共有リクエスト・ファイル・ディレクトリの動作」および「ローカル・リクエスト・ファイル・ディレクトリの動作」を参照してください。
リクエストのすべての出力がコンテンツ・ストアに自動的にインポートされた後、Oracle Enterprise Schedulerによって、リクエスト固有の出力ディレクトリとそのコンテンツが削除されます。
リクエスト・ファイル・ディレクトリはローカルにすることもでき、この場合、単一のサーバーでの作業にのみ使用することを意味します。または共有することもでき、この場合、複数のサーバーで実行される作業によって単一のディレクトリが使用されます。実行時の動作は、ディレクトリがローカルまたは共有のいずれに構成されているかによって異なります。
例22-4に示されているように、ディレクトリはess-config.xmlファイルで指定されます。Oracle Enterprise Schedulerは、RequestFileDirectoryに基づいてUSER_FILE_DIR (SYS_userFileDir)を設定し、プロパティを読取り専用にします。ジョブは、USER_FILE_DIRを設定することでこれをオーバーライドできません。
例22-4 ess-config.xmlファイルによるリクエスト・ファイル・ディレクトリの構成
<ess:EssConfig xmlns:ess="http://ess.oracle.com"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ess:EssProperties>
<ess:EssProperty key="RequestFileDirectory" value="/etc/outputfiles"
immutable="true"/>
<ess:EssProperty key="RequestFileDirectoryShared" value="false"
immutable="true"/>
</ess:EssProperties>
</ess:EssConfig>
Oracle Enterprise Schedulerにより、出力ディレクトリからすべてのリクエスト出力ファイルがコンテンツ・ストアに自動的にインポートされ、リクエスト作業ディレクトリとそこに含まれるすべてのファイルが削除されます。
既存のコンテンツが以前にインポートされたものである場合には、常に、インポートされたファイルによって同じファイル名の既存のコンテンツが上書きされます。既存のコンテンツがAPIを使用して作成された場合は、新しいファイルと異なるものとみなされ、新しいファイルで上書きされずに無視されます。つまり、APIにより作成されたコンテンツが優先されます。
Oracle Enterprise Schedulerでは、長さゼロの出力ファイルはインポートされません。
リクエストによって作成されたすべてのファイルは、リクエストが完了して終了状態になるまで、その作業ディレクトリおよび出力ディレクトリに保持されます。共有ファイル・ディレクトリにあるリクエストによって作成されたすべてのファイルは、リクエストのすべてのステージで使用できます。
Oracle Enterprise Schedulerによって、ジョブ・リクエストがRUNNING状態に遷移する前に、リクエスト作業ディレクトリが作成されます。ディレクトリの作成中にエラーが発生すると、常に、リクエストのシステム・エラーが発生します。
ジョブの処理では、ログのインポートはリクエストが終了状態に遷移した後に行われます。ログのインポート中にエラーが発生すると、エラーがログに記録され、リクエスト・ログがファイル・システム内に残されます。ログはコンテンツ・ストアに手動でインポートする必要があります。
すべてのジョブ・タイプで、出力ファイルのインポートはリクエストが終了状態に遷移した後に行われます。出力ファイルのインポート中にエラーが発生すると、エラーがログに記録され、ファイル・システム上の該当ディレクトリに出力ファイルが残されます。出力ファイルを削除する必要があります。
ステージのリクエストが実行される前には必ず、Oracle Enterprise Schedulerによって、リクエスト固有のディレクトリが作成されます。リクエスト・ファイル・ディレクトリがローカルである場合は、どのサーバーのローカルにも存在することが保証されている場所である必要があります。この場合、あるステージのリクエストによって作成されたファイルが、次のステージでも使用できるとは保証されません。これは、各ステージは独立した作業単位であり、異なるサーバーで実行される可能性があるためです。
ローカル・リクエスト・ファイル・ディレクトリには、Oracle Enterprise Schedulerによって各ステージに対するアクションが実行されることを除き、共通動作が適用されます。これは、各ステージが異なるサーバーで実行される場合があり、次のステージではファイルが存在しない可能性があることから、Oracle Enterprise Schedulerでは各ステージのファイルを取得してクリーン・アップする必要があるためです。
以前にインポートされたすべての出力ファイルにリクエストからアクセスする必要がある場合は、パラメータSYS_EXT_executeAutoExport = trueを設定できます。これが設定されている場合、実行ステージの始めに、以前にインポートされた出力ファイルがOracle Enterprise Schedulerによって自動的にリクエストの作業出力ディレクトリにエクスポートされます。これにより、実行ステージの終わりにファイルがコンテンツ・ストアに再びインポートされる前に、ファイルを更新できるようになります。(コンテンツがエクスポートされても、コンテンツ・ストアからコンテンツは削除されないことに注意してください。)さらに、Oracle Enterprise Schedulerには、以前にインポートされた出力ファイルをリクエストによって選択的にエクスポートするためのAPIが備えられています。
ローカル・リクエスト・ファイル・ディレクトリを使用する場合、ファイルのインポートは各ステージ(前処理、実行、更新、後処理)の終わりに行われます。ログまたは出力ファイルのインポート中にエラーが発生した場合、インポートに失敗したログおよび出力ファイルはrequest_file_directory/preserveにあるミラー・ディレクトリに移動されます。たとえば、リクエスト18の場合は、request_file_directory/preserve/18になります。
前処理ステージでは、ステージの始めにリクエスト・ディレクトリを作成するときか、またはステージの終わりに出力ファイルをインポートするときにエラーが発生すると、リクエストに対するシステム・エラーが発生します。
後処理ステージでは、ステージの始めにリクエスト・ディレクトリを作成するときか、またはステージの終わりに出力ファイルをインポートするときにエラーが発生すると、リクエストに対する警告が発生します。
Javaジョブ、非同期Javaジョブおよびプロセス・ジョブ・リクエストの実行ステージでは、ステージの始めにリクエスト・ディレクトリを作成するときか、以前にインポートされた出力ファイルを自動的にエクスポートするとき(SYS_EXT_executeAutoExportシステム・プロパティを使用する場合など)、またはステージの終わりに出力ファイルをインポートするときにエラーが発生すると、リクエストに対するシステム・エラーが発生します。
リクエストがプロセス・ジョブの場合、リクエスト・ログをインポートするときに発生したエラーはログに記録され、エラーとして処理されません。ログはファイル・システム内に残され、コンテンツ・ストアに手動でインポートできます。プロセス・ジョブの実行中に内部エラーが発生した場合は、ジョブの実行を続行できるため、ジョブおよび出力ファイルはインポートされません。ログおよび出力ファイルは、ジョブの終了時に自動的またはユーザーにより手動でインポートされます。ジョブがERROR_MANUAL_RECOVERYに遷移した場合は、ユーザーがリクエスト・ログおよび出力ファイルをクリーン・アップする必要があります。
更新ステージでは、リクエスト・ディレクトリを作成するときか、または出力ファイルをインポートするときに発生したエラーは、ログに記録されるのみです。
リクエスト・ファイル・ディレクトリを使用して出力ファイルを自動的にインポートする場合は、SYS_EXT_supportOutputFilesシステム・プロパティを設定する必要があります。
リクエストの出力ディレクトリを使用して出力ファイルを作成するには、ジョブでシステム・プロパティSYS_EXT_supportOutputFilesを使用してパラメータを定義する必要があります。ジョブで作成するファイルの種類に応じて、プロパティは次のいずれかの方法で設定できます。
コンテンツ・ストアにインポートするファイルをリクエストの出力ディレクトリに書き込むには、「output」に設定します。
一時ファイルなど、インポートしないファイルをリクエスト作業ディレクトリに書き込むには、「work」に設定します。
ジョブで出力ファイルや一時ファイルが作成されない場合は、「none」に設定するか、未定義のままにします。
表22-5 リクエスト出力を作成するためのシステム・プロパティ
| メソッド | 説明 |
|---|---|
|
ジョブによりファイル・システムにファイルが作成されるかどうかを示す文字列プロパティ。サポートされる値は、 |
|
以前にインポートされた出力ファイルを実行ステージの始めにエクスポートするかどうかを示すブール型プロパティ。コンテンツが自動的にエクスポートされても、コンテンツ・ストアからコンテンツは削除されません。 |
Javaからリクエスト出力を作成するには、ジョブのコードで、Oracle Enterprise Scheduler APIを使用してコンテンツ・ストアに出力コンテンツを直接作成するか、ジョブによりファイル・システム内のリクエストの出力ディレクトリにファイルを作成できます。ジョブによりリクエストの出力ディレクトリにファイルが作成される場合、これらのファイルをコンテンツ・ストアに明示的にインポートするか、Oracle Enterprise Schedulerによりファイルをコンテンツ・ストアに自動的にインポートできます。
ジョブでは、APIを使用してテキストまたはバイナリ出力コンテンツを作成できます。インポートされる出力ファイルは常にバイナリ・コンテンツとしてインポートされます。つまり、バイトは解釈されません。
リクエスト出力の処理に使用できるJava APIは次のとおりです。
ContentFactoryクラスを使用して、RequestOutputおよびOutputContentHelper出力など、出力コンテンツを作成して管理するために使用できるその他のクラスのインスタンスを取得します。表22-6を参照してください。
RequestOutputクラスを使用して、コンテンツ・ストアに出力コンテンツを直接作成します。表22-7を参照してください。
OutputContentHelperクラスを使用して、リクエスト出力ファイル・ディレクトリにファイルとして作成したコンテンツを明示的に管理し、コンテンツ・ストアと相互作用します。表22-8を参照してください。
oracle.as.scheduler.request.ContentFactoryクラスには、コードが出力コンテンツ・フレームワークにアクセスしたり、出力自体を作成するために使用可能なインスタンスにアクセスできるメソッドが備えられています。
表22-6 Javaリクエスト出力用のContentFactoryメソッド
| メソッド | 説明 |
|---|---|
|
指定されたリクエストに対して出力とともに |
|
|
|
|
oracle.as.scheduler.request.RequestOutputクラスは、コードによって作成される出力を表します。ContentFactory.getRequestOutputからこのクラスのインスタンスを取得してから、そのwriteメソッドを使用して作成中の出力コンテンツに書き込みます。
表22-7 Javaリクエスト出力用のRequestOutputメソッド
| メソッド | 説明 |
|---|---|
|
テキスト出力コンテンツに、 |
|
テキスト出力コンテンツに |
|
テキスト出力コンテンツに |
|
テキスト出力コンテンツに |
|
テキスト出力コンテンツにcharsを付加します。 |
|
バイナリ出力コンテンツにbytesを付加します。 |
|
バイナリ出力コンテンツにbytesを付加します。 |
oracle.as.scheduler.request.OutputContentHelperクラスのメソッドは、Javaジョブにおいて多くの出力ファイル処理を行います。コードでは、これらのメソッドを使用してリクエスト・ファイル・ディレクトリおよびコンテンツ・ストアそのものを操作できます。
コンテンツ・ストアにコンテンツをインポートするためのメソッドでは、インポート中にトランザクション・セマンティクスを指定するために使用できるOutputContentHelper.CommitSemantics列挙インスタンスを取得することに注意してください。詳細は、表22-9を参照してください。
表22-8 Javaリクエスト出力用のOutputContentHelperメソッド
| メソッド | 説明 |
|---|---|
|
リクエストの作業ディレクトリが存在する場合に Oracle Enterprise Schedulerによって作業ディレクトリが作成されるようにするには、ジョブで |
|
リクエストの出力ディレクトリが存在する場合に Oracle Enterprise Schedulerによって出力ディレクトリが作成されるようにするには、ジョブで |
|
リクエスト・ファイル・ディレクトリが共有されている場合に |
|
現在のサーバーに解決されるリクエスト作業ディレクトリを含む文字列を返します。ジョブでは作業ディレクトリに一時ファイルを作成でき、作業ディレクトリは、リクエストの実行終了時( |
|
現在のサーバーに解決されるリクエストの出力ディレクトリを含む文字列を返します。ジョブでは、Oracle Enterprise Schedulerコンテンツ・ストアに自動的または手動でインポートできる出力ファイルを出力ディレクトリに作成できます。 |
|
解決された出力ディレクトリから、指定されたファイルをインポートして、 |
|
解決された出力ディレクトリから、すべてのファイルをインポートして、 |
|
リクエストの出力ディレクトリ内のファイルに、指定された以前にインポート済の出力コンテンツをエクスポートして、 |
|
以前にインポートされたすべての出力コンテンツをリクエストの出力ディレクトリ内のファイルにエクスポートして、 |
|
コンテンツ・ストア内にある既存の出力コンテンツすべての詳細情報とともに |
|
コンテンツ・ストア内に出力コンテンツがある場合は、その詳細情報とともに |
|
リクエストに対して、コンテンツ・ストア内に指定された出力コンテンツが存在する場合に |
|
リクエストに対して、コンテンツ・ストアから、指定された出力コンテンツを削除します。インポートされた出力コンテンツとAPIを使用して作成された出力コンテンツを削除できます。 |
コンテンツ・ストアにコンテンツをインポートしているときにエラーが発生した場合の動作を指定するには、oracle.as.scheduler.request.OutputContentHelper.CommitSemantics列挙を使用します。
表22-9 コミット・セマンティクスを表すCommitSemantics列挙メンバー
| フィールド | 説明 |
|---|---|
|
1つのファイルにエラーがある場合に、すべてのファイルに対する操作を停止します。ハンドルが内部である場合、これはコミットされます。 |
|
エラーに関係なく、すべてのファイルに対する操作を行います。ハンドルが内部である場合、これはコミットされます。 |
|
いずれかのファイルにエラーがある場合に、すべてのファイルに対する操作を停止します。ユーザー指定のハンドルでは、これは無効です。 |
例22-5は、RequestOutput APIを使用した出力コンテンツの作成方法を示しています。出力コンテンツは、コンテンツ・ストア内に直接作成されます。
例22-6は、リクエストの出力ディレクトリに出力ファイルを作成する方法を示しています。ジョブでSYS_EXT_supportOutputFilesシステム・プロパティをoutputとして定義する必要があることに注意してください。この例は、Javaジョブ、非同期Javaジョブ、プリプロセッサまたはポストプロセッサに適用されます。
次の例では、出力ファイルを手動でエクスポートおよびインポートする方法を示します。これは、更新中にファイルからコンテンツを作成する必要がある場合に役立ちます。インポートされたファイルのみをエクスポートでき、APIを使用して作成されたファイルはエクスポートできないことに注意してください。
例では、以前に作成された可能性のあるファイルを更新してインポートする必要があるというシナリオを示します。
import oracle.as.scheduler.request.ContentFactory;
import oracle.as.scheduler.request.ImportExportResult;
import oracle.as.scheduler.request.ImportExportResult.ImportExportStatus;
import oracle.as.scheduler.request.OutputContentHelper;
import oracle.as.scheduler.request.OutputContentHelper.CommitSemantics;
class ExampleExportImport{
OutputContentHelper helper = ContentFactory.getOutputContentHelper(requestId);
if (!helper.outputDirectoryExists())
{
// error - make sure job definition defines SYS_EXT_supportOutputFiles
}
String outputDir = helper.getResolvedOutputDirectory();
String fileName = "myfile.out";
List<String> fileNamesList = new ArrayList<String>();
fileNamesList.add(fileName);
// Export the file if it exists; otherwise, create it.
if (helper.outputContentExists(fileName))
{
ImportExportResult exportResult = helper.exportOutputContent(fileNamesList);
if (exportResult.getStatus() != ImportExportStatus.Success)
{
// handle error
}
}
else
{
File f = new File(outputDir, fileName);
f.createNewFile();
}
// ... update the file as needed ...
// Import the new or updated file.
// Updated file overwrites previous contents.
ImportExportResult importResult =
helper.importOutputFile(fileNamesList, CommitSemantics.IgnoreErrors);
if (importResult.getStatus() != ImportExportStatus.Success)
{
// handle error
}
}
例22-5 RequestOutputを使用した出力コンテンツの作成
import oracle.as.scheduler.request.ContentFactory;
import oracle.as.scheduler.request.ContentType;
import oracle.as.scheduler.request.RequestOutput;
class ExampleOutputContentCreator
{
RuntimeService runtimeService = getRuntimeService();
RuntimeServiceHandle handle;
try {
handle = runtimeService.open();
RequestOutput requestOutput = ContentFactory.getRequestOutput(
handle, requestId, ContentType.Text, “SampleOutput.txt");
requestOutput.writeln(“Output data in sample output content.");
}
finally {
runtimeService.close(handle);
}
}
例22-6 自動インポート用の出力ファイルの作成
import oracle.as.scheduler.request.ContentFactory;
import oracle.as.scheduler.request.OutputContentHelper;
class ExampleOutputCreator{
OutputContentHelper helper = ContentFactory.getOutputContentHelper(requestId);
String outputDir = helper.getResolvedOutputDirectory();
File f = new File(outputDir, "myfile");
f.createNewFile();
if (f.exists())
{
// write to file
}
}
PL/SQLからリクエスト出力を作成する場合は、コンテンツ・ストアに直接出力コンテンツを作成するために、コードでESS_JOB PL/SQLパッケージを使用できます。
ジョブでは、パッケージ内のファンクションおよびプロシージャを使用して、テキストまたはバイナリ出力コンテンツを作成できます。
表22-10 リクエスト出力用のESS_JOBプロシージャおよびファンクション
| メソッド | 説明 |
|---|---|
|
現在のセッションに関連付けられているリクエストに対して、指定された出力コンテンツを開いてハンドルを返します。 適切なコンテンツ・タイプ定数により |
|
現在のセッションに関連付けられているリクエストに対して、出力コンテンツ 指定された名前の出力コンテンツ・エントリが存在しない場合、そのエントリが新規に作成されます。すでに存在する場合は、その名前に対して確立されているコンテンツ・タイプと指定されたコンテンツ・タイプが一致する必要があります。
これにより、出力コンテンツを操作する後続プロシージャに渡される不透明なハンドルが返されます。 このファンクションから正しい結果が返されると、コンテンツ・エントリはロックされます。このプロシージャが失敗した場合は、ロックされる場合とされない場合とがあります。コミットまたはロールバックによりロックが解放されます。テキスト・コンテンツのデータを書き込むには このメソッドによって返されるハンドルに関連付けられているリソースを解放するには、close_contentをコールする必要があります。クローズはトランザクションのコミットまたはロールバックの前に行う必要があります。 注意: コンテンツ出力サポートにはDMLセマンティクスが含まれます。コミットおよびロールバックは、コール元が行います。 |
|
指定されたハンドルに関連付けられている出力コンテンツにデータを
注意: コンテンツ出力サポートにはDMLセマンティクスが含まれます。コミットおよびロールバックは、コール元が行います。 |
|
指定されたハンドルに関連付けられている出力コンテンツにバイナリ・データを
注意: コンテンツ出力サポートにはDMLセマンティクスが含まれます。コミットおよびロールバックは、コール元が行います。 |
|
出力コンテンツ・ハンドルをクローズします。これにより、指定されたハンドルに関連付けられているリソースが解放され、ハンドルが無効になります。このメソッドは、トランザクションのコミットまたはロールバックより前にコールしてください。 p_content_handleは、以前の 注意: コンテンツ出力サポートにはDMLセマンティクスが含まれます。コミットおよびロールバックは、コール元が行います。このメソッドでは、コミットまたはロールバックは自動的には実行されません。 |
|
現在のセッションに関連付けられているリクエストに対して、指定された名前を持つ出力コンテンツ・エントリがすでに存在する場合はtrueを返します。
|
|
現在のセッションに関連付けられているリクエストに対して、指定された出力コンテンツを削除します。
|
例22-7では、テキスト・コンテンツを出力に書き込む方法およびログ・エントリを書き込む方法を示します。
例22-8では、出力にバイナリ・コンテンツを書き込む方法を示します。
例22-7 PL/SQL出力作成の例
create or replace procedure text_output_example_job
( request_handle in varchar2 )
as
v_request_id number := null;
v_content_name varchar2(100) := 'mycontent.txt';
v_content_handle varchar2(100);
v_ntext nvarchar2(100);
begin
ess_job.write_log(ess_job.LEVEL_FINE,
'TEXT_OUTPUT_EXAMPLE_JOB Procedure Begin');
-- Oracle Enterprise Scheduler request id being executed.
begin
v_request_id := ess_runtime.get_request_id(request_handle);
exception
when others then
ess_job.write_log(ess_job.LEVEL_SEVERE,
'Bad request handle: '||request_handle);
raise_application_error(-20000,
'Failed to get request id for request handle '||request_handle,
true);
end;
begin
-- ----------
-- Delete content entry if it already exists.
-- ----------
if (not ess_job.output_content_exists(v_content_name)) then
ess_job.write_log(ess_job.LEVEL_FINEST,
'Content does not exist: ' || v_content_name);
else
ess_job.write_log(ess_job.LEVEL_INFO,
'Deleting existing content: ' || v_content_name);
ess_job.delete_output_content(v_content_name);
commit;
end if;
-- ----------
-- Write text content. Source data has some non-ascii chars.
-- Illustrate multiple writes.
-- ----------
ess_job.write_log(ess_job.LEVEL_FINE,
'Write text content: '||v_content_name);
v_content_handle := null;
v_content_handle := ess_job.open_text_output_content(v_content_name);
ess_job.write_text_content(v_content_handle,
'Data ');
ess_job.write_ntext_content(v_content_handle,
unistr('(NTEXT data:\00c4\00c5)'));
ess_job.write_text_content(v_content_handle,
' for CONTENT ' || v_content_name);
ess_job.close_content(v_content_handle);
v_content_handle := null;
commit;
exception
when others then
ess_job.write_log(ess_job.LEVEL_WARNING,
'Error during text output operations. ' ||
'content: ' || v_content_name || chr(10) ||
'Error_Stack...' || chr(10) ||
dbms_utility.format_error_stack() || chr(10) ||
'Error_Backtace...' || chr(10) ||
dbms_utility.format_error_backtrace());
if v_content_handle is not null then
ess_job.close_content(v_content_handle);
v_content_handle := null;
end if;
rollback;
raise_application_error(-20000,
'Output content operations failed for '||v_content_name);
end;
ess_job.write_log(ess_job.level_info,
'TEXT_OUTPUT_EXAMPLE_JOB Procedure End');
end;
/
例22-8 リクエスト出力の手動エクスポートおよびインポート
create or replace procedure binary_output_example_job
( request_handle in varchar2 )
as
v_request_id number := null;
v_content_name varchar2(100) := 'mycontent.bin';
v_content_handle varchar2(100);
v_nchar_cs varchar2(100);
v_dest_cs varchar2(100);
v_ntext nvarchar2(100);
v_raw raw(500);
begin
ess_job.write_log(ess_job.LEVEL_FINE,
'BINARY_OUTPUT_EXAMPLE_JOB Procedure Begin');
-- Oracle Enterprise Scheduler request id being executed.
begin
v_request_id := ess_runtime.get_request_id(request_handle);
exception
when others then
ess_job.write_log(ess_job.LEVEL_SEVERE,
'Bad request handle: '||request_handle);
raise_application_error(-20000,
'Failed to get request id for request handle '||request_handle,
true);
end;
begin
-- ----------
-- Delete content entry if it already exists.
-- ----------
if (not ess_job.output_content_exists(v_content_name)) then
ess_job.write_log(ess_job.LEVEL_FINEST,
'Content does not exist: ' || v_content_name);
else
ess_job.write_log(ess_job.LEVEL_INFO,
'Deleting existing content: ' || v_content_name);
ess_job.delete_output_content(v_content_name);
commit;
end if;
-- ----------
-- Write binary content.
-- This is the UTF-8 representation of a string for a known byte
-- encoding rather than whatever the charset/national charset
-- happens to be for this database.
-- Source data has couple non-ascii chars.
-- ----------
-- database national character set being used
select value into v_nchar_cs
from nls_database_parameters
where parameter = 'NLS_NCHAR_CHARACTERSET';
ess_job.write_log(ess_job.LEVEL_FINEST,
'NLS_NCHAR_CHARACTERSET = '||v_nchar_cs);
ess_job.write_log(ess_job.LEVEL_FINE,
'Write binary content: '||v_content_name);
v_content_handle := null;
v_content_handle := ess_job.open_binary_output_content(v_content_name);
v_ntext := unistr('Data (NTEXT data:\00c4\00c5) for CONTENT ' ||
v_content_name);
v_dest_cs := 'AL32UTF8';
v_raw := utl_raw.cast_to_raw(convert(v_ntext, v_dest_cs, v_nchar_cs));
ess_job.write_binary_content(v_content_handle, v_raw);
ess_job.write_log(ess_job.LEVEL_FINE,
'Wrote '||utl_raw.length(v_raw)||' bytes' ||
' using ' || v_dest_cs || ' charset');
ess_job.close_content(v_content_handle);
v_content_handle := null;
commit;
exception
when others then
ess_job.write_log(ess_job.LEVEL_WARNING,
'Error during binary output operations. ' ||
'content_name=' || v_content_name || chr(10) ||
'Error_Stack...' || chr(10) ||
dbms_utility.format_error_stack());
if v_content_handle is not null then
ess_job.close_content(v_content_handle);
v_content_handle := null;
end if;
rollback;
raise_application_error(-20000,
'Output content operations failed for '||v_content_name);
end;
ess_job.write_log(ess_job.level_info,
'BINARY_OUTPUT_EXAMPLE_JOB Procedure End');
end;
/
すべてのプロセス・ジョブで使用できるESS_OUTPUT_WORK_DIR環境変数により指定された場所にコンテンツを書き込むことによって、プロセス・ジョブ・ロジックから出力を作成します。他のジョブと同様に、SYS_EXT_supportOutputFilesシステム・プロパティがoutputに設定されており、ジョブに対して環境変数が定義されるようになっていることを確認してください。
プロセス・コードによりファイルが書き込まれると、Oracle Enterprise Schedulerにより自動的に、ディレクトリ内の出力ファイルがバイナリ・コンテンツとしてコンテンツ・ストアにインポートされます。
同期および非同期のWebサービスの場合、リクエスト出力コンテンツは、次に説明するようにレスポンス・メッセージ・ペイロードから自動的に作成されます。出力コンテンツは、WebServiceJobOutput-REQUESTID.txt (REQUESTIDはリクエストのリクエストID)という名前のテキスト・データです。
同期Webサービスの場合、レスポンス・メッセージ・ペイロードはリクエスト出力として取得されます。
非同期Webサービスの場合、EssWsJobAsyncCallbackServiceで受信されるコールバック/レスポンス・メッセージ・ペイロードは、ジョブ・ステータスがSUCCESSになると取得されます。
oracle.as.scheduler.RuntimeServiceクラスのメソッドを使用して、Oracle Enterprise Schedulerコンテンツ・ストアに格納されているリクエスト出力を処理できます。最初に、RuntimeServiceHandleインスタンスを取得する必要があります。このインスタンスを、これらのRuntimeServiceメソッドそれぞれの引数として渡します。RuntimeServiceHandleの詳細は、「ランタイム・サービスへのアクセスおよびランタイム・サービス・ハンドルの取得方法」を参照してください。
表22-11 リクエスト出力を処理するためのRuntimeServiceメソッド
| メソッド | 説明 |
|---|---|
|
指定されたリクエストに対する指定された出力コンテンツの |
|
リクエストに対するすべての出力コンテンツの |
|
指定されたリクエスト出力を開いて指定されたコンテンツの出力データを取得し、 |
|
ログまたは出力テキスト・コンテンツから、最大 |
|
バイナリ・コンテンツから最大で |
|
以前開いたログまたは出力コンテンツを閉じ、ハンドルを解放します。 |