22 Job Request Logs and Output

This chapter describes how to use Oracle Enterprise Scheduler to generate job request logs and output that should be saved for later use by administrators and users.

Logs generated by job requests help administrators diagnose problems and see job-specific status. Logs are accessible through the Fusion Middleware Control. In addition, some jobs generate output as part of their work, such as a report about job-specific data that a user can review after the job has completed. Your code can create and store request log information as well as request output.

This chapter includes the following sections:

22.1 Request Logs

Oracle Enterprise Scheduler provides APIs your job can use to request logging. All job types, except for process jobs, use the logging APIs. Oracle Enterprise Scheduler also provides APIs to handle request logs in the content store.

Oracle Enterprise Scheduler supports a single log per request. The log has a name of the form REQUESTID.log. The logging APIs log directly to the content store, and log content may not be rolled back.

For more about viewing job request logs with Fusion Middleware Control, see Viewing Job Request Logs in Oracle Fusion Middleware Administering Oracle Enterprise Scheduler.

22.1.1 System Properties

The system property SYS_EXT_requestLogLevel constrains which messages logged using the API are stored in the request log.

The property's value defaults to INFO. The complete set of valid values are SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST. Use Java and PL/SQL APIs to discover the request log level.

Note that SYS_EXT_requestLogLevel does not apply to process jobs because they do not use the logging API.

22.1.2 Log Header

Your logging code writes entries to a log that begins with the following heading information. This header is automatically prefixed to each record written to the log using the logging APIs, therefore it does not apply to process jobs.

####[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.

22.1.3 Request Logging from a Java Job

You can use the Java request logger to log during the execute and update stages of a Java or asynchronous Java job, as well as during pre-processing and post-processing for all job execution types.

The job logic must use the ContentFactory API to get the RequestLogger that can be used to log messages to the request log. Oracle Enterprise Scheduler uses the current value of the SYS_EXT_requestLogLevel system property to constrain logging level each time the logger is retrieved.

22.1.3.1 APIs for Java Job Logging

In your Java job's logic, you can use the oracle.as.scheduler.request.ContentFactory class getRequestLogger method (see Table 22-1) to get a RequestLogger instance for adding log entries. Note that the request logger does not support a resource bundle.

The Java APIs available for handling logs include the following:

  • Use the ContentFactory class to get instances of a RequestLogger you can use to create the log and add entries. See Table 22-1.

  • Use the RequestLogger class to write the log. See Table 22-2.

The oracle.as.scheduler.request.ContentFactory class provides methods to get your code access to the output content framework, as well as to an instance you can use to create the output itself.


Table 22-1 ContentFactory Methods for Creating Request Logs

Method Description

getRequestLogger( long requestId )

Returns a RequestLogger instance for the specified requestId and creates log content named requestId.log in Oracle Enterprise Scheduler content store.


After you have a logger instance, you can use the methods in Table 22-2 to add entries.


Table 22-2 RequestLogger Methods for Creating Request Logs

Method Description

log( Level level, String msg )

fine( String msg )

finer( String msg )

finest( String msg )

These methods log messages at the specified levels.

The message is logged only if the specified logging level is equal or greater than the log level specified by the SYS_EXT_requestLogLevel system property. If the property isn't set, the default log level is INFO.

When using the log method, the java.util.logging.Level supports the following values, in descending order.

  • SEVERE

  • WARNING

  • INFO

  • CONFIG

  • FINE

  • FINER

  • FINEST


22.1.3.2 Java Request Logging Example

Example 22-1 shows a very simple Java job example that does logging.

Example 22-1 Java Request Logging Example

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);
    }
  }
}

22.1.4 Request Logging from a PL/SQL Job

To create logs from PL/SQL, your code can use the ESS_JOB PL/SQL package to write log entries.

22.1.4.1 ESS_JOB Package Support for Creating Logs

Oracle Enterprise Scheduler provides the ESS_JOB package with functions and procedures for logging from PL/SQL code.


Table 22-3 ESS_JOB Functions and Procedures for Request Logging

Method Description

procedure write_log( p_level in integer, p_text in varchar2 );

Writes p_text as a message to request log content for the Oracle Enterprise Scheduler request associated with the current session.

The message is logged only if the specified logging level is equal or greater than the log level specified by the SYS_EXT_requestLogLevel system property. If the property isn't set, the default log level is LEVEL_INFO.

Log level values correspond to those defined in java.util.logging.Level.

Use the following values for the p_level parameter (shown in descending order):

  • LEVEL_SEVERE

  • LEVEL_WARNING

  • LEVEL_INFO

  • LEVEL_CONFIG

  • LEVEL_FINE

  • LEVEL_FINER

  • LEVEL_FINEST


22.1.4.2 PL/SQL Request Logging Example

An example of request logging by a SQL request job procedure is shown below.

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;
/

22.1.5 Request Logging from a Process Job

You can write to the job request log from process job. The way this works is quite different from Java and PL/SQL jobs, where the executing code has access to an API for writing entries at a particular level. Instead, for a process job, the job's standard output and standard error are redirected to a file in the request's log work directory (a location set by Oracle Enterprise Scheduler). Oracle Enterprise Scheduler imports this file and append it to the request log in the content store.

In other words, to log from a process job, you need only write to standard output from job logic code.

The encoding used to read the log file is determined as described in Process Job Locale.

Note that you cannot log at particular levels from a process job (where the API for setting the level isn't available). So the SYS_EXT_requestLogLevel system property does not constrain log contents. Oracle Enterprise Scheduler always appends the contents of the log file to the request log in the content store.

22.1.6 Request Logging and Output From an EJB Job

Because an EJB Job is a Java job that gets executed remotely, the remote EJB job implementation can write content to logs and output. Use the oracle.as.scheduler.request.RemoteContentHelper API to handle this content. The following bullet items describe the high-level steps involved. Example 22-2 shows an EJB job implementation that illustrates this functionality.

  • Set up the RemoteContentHelper. The parameters RequestExecutionContext and RequestParameters can be obtained from the execute() method of the job implementation.

    RemoteContentHelper rch=new RemoteContentHelper(RequestExecutionContext, RequestParameters);
    
  • Write content to the log file.

    rch.log(Level.INFO, logMessage)
    
  • Write text output.

    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);
     }
    
  • Write binary output.

    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);
     }
    

Example 22-2 shows an EJB job implementation that demonstrates how to handle output and logs.

Example 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;
    }
 
}

22.1.7 Request Logging from a Web Service Job

Progress messages are only available to asynchronous jobs. The Oracle Enterprise Scheduler AsyncWebServiceJob callback endpoint supports a new logAsyncWSJobProgressMessage one-way operation. This operation allows an asynchronous SOA composite (or other asynchronous web service) to log progress messages using ws-addressing for correlation and the same callback endpoint and associated callback OWSM policy. This provides a simple, convenient option for logging progress messages from asynchronous SOA composites.

The Oracle Enterprise Scheduler asynchronous web service job callback endpoint WSDL provides the necessary information for using this operation. A portion of the WSDL is shown in Example 22-3.

Example 22-3 Asynchronous Web Service Job Callback Endpoint 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>

22.1.8 APIs for Handling Request Logs

You can use methods of the oracle.as.scheduler.RuntimeService class to handle logs stored in the Oracle Enterprise Scheduler content store. You'll need to first get a RuntimeServiceHandle instance. You'll pass this instance as an argument for each of these RuntimeService methods.

For more on the RuntimeServiceHandle, see How to Access the Runtime Service and Obtain a Runtime Service Handle.


Table 22-4 RuntimeService Methods for Handling Request Logs

Method Description

getLogContentDetail(RuntimeServiceHandle handle, long requestId)

Returns a ContentDetail instance with the log content detail for the request, or null if the log does not exist.

openLogContent( RuntimeServiceHandle handle, long requestId )

Returns a ContentHandle instance from opening the request log to retrieve log data for the specified request. You can use the handle to retrieve output data. The content must be closed to release the handle.

getLogLines( RuntimeServiceHandle handle, ContentHandle contentHandle, int maxLines )

Returns a String array with at most maxLines lines from the request log, continuing from the last call to this method. The content handle is from the previous call to openLogContent. This returns a String array of lines from the log without line terminators; if no more lines, array is empty.

getTextContent( RuntimeServiceHandle handle, ContentHandle contentHandle, int maxChars )

Returns a char array with at most maxChars characters from the log or output text content.

closeContent( RuntimeServiceHandle handle, ContentHandle contentHandle )

Closes the previously opened log or output content and releases the handle.


22.2 Request Output

You can have your job create output content at runtime. For example, your job might collect data that would be useful in a report for users. When you generate output at runtime, it's available to be retrieved later through a client user interface or the Fusion Middleware Control.

The output your code creates can be created directly in the Oracle Enterprise Scheduler content store, or it can be created in the file system and imported to the content store. Oracle Enterprise Scheduler can import it automatically or your job can use Oracle Enterprise Scheduler APIs to import it explicitly.

When you use the file system, you write to a particular directory whose location has been configured in the Oracle Enterprise Scheduler ess-config.xml file. Oracle Enterprise Scheduler creates a request file directory to contain files written from all requests. Your code writes to a subdirectory of this created specifically for the request. Oracle Enterprise Scheduler automatically imports all of the request's output to the content store, and then deletes request-specific subdirectories.

Oracle Enterprise Scheduler provides APIs for managing output content in the content store.

22.2.1 Using the Request File Directory

The request file directory is specified in the Oracle Enterprise Scheduler ess-config.xml file. For each request, Oracle Enterprise Scheduler can create request-specific subdirectories of this request file directory: a working directory for temporary files and an output directory for output files that should be imported into the content store.

Your code can write temporary and output files to their respective request-specific directories at runtime. Oracle Enterprise Scheduler imports to the content store files in the request's output directory. When the content is imported depends on whether the request file directory is shared or local, as described in Common Request File Directory Behavior, Shared Request File Directory Behavior, and Local Request File Directory Behavior.

After automatically importing all of the request's output to the content store, Oracle Enterprise Scheduler deletes the request-specific output directory and its contents.

The request file directory can be local, meaning that it is used only for work done on a single server. It can also instead be shared, in which a single directory is used for work done on multiple servers. Runtime behavior differs depending on whether the directory is configured to be local or shared.

The directory is specified in the ess-config.xml file, as shown in Example 22-4. Oracle Enterprise Scheduler sets USER_FILE_DIR (SYS_userFileDir) based on RequestFileDirectory and then makes the property read-only. The job cannot override this by setting USER_FILE_DIR.

Example 22-4 Request File Directory Configuration with ess-config.xml file

<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>

22.2.1.1 Common Request File Directory Behavior

Oracle Enterprise Scheduler automatically imports all request output files from the output directory to the content store, and deletes the request working directory and all files in it.

Imported files always overwrite existing content of the same file name as long as the existing content was previously imported. If the existing content was created using the API, then it is considered to be distinct from the new file, and the new file does not overwrite and is ignored. In other words, content created with the API has precedence.

Oracle Enterprise Scheduler does not import output files of zero length.

22.2.1.2 Shared Request File Directory Behavior

Any files created by the request remains in its working and output directories until the request completes and goes to a terminal state. Any files created by a request in a shared file directory are available to all stages of the request.

22.2.1.2.1 Error Handling When a Shared Request File Directory is Used

Oracle Enterprise Scheduler creates the request work directory before the job request transitions to the RUNNING state. Any error while creating the directory results in a system error for the request.

For process a job, importing the log occurs after the request transitions to a terminal state. If an error occurs while importing the log, the error is logged and the request log is left in the file system. You must manually import the log to the content store.

Importing output files for any job type occurs after the request transitions to a terminal state. If there is an error while importing output files, the error is logged and the output files are left in their directories on the file system. You must remove the output files.

22.2.1.3 Local Request File Directory Behavior

Oracle Enterprise Scheduler creates request-specific directories before any stage of the request runs. If the request file directory is local, it must be a location that is guaranteed to exist locally on every server. In this case, files created by one stage of the request are not guaranteed to be available in the next stage because stages are independent units of work and may run on different servers.

For a local request file directory, the common behavior holds except that Oracle Enterprise Scheduler performs the actions for each stage. The reason is that each stage may execute on a different server, and it is necessary for Oracle Enterprise Scheduler to capture and clean up the files for each stage because they may not be there for the next stage.

In case a request requires access to all previously imported output files, it can set the parameter SYS_EXT_executeAutoExport = true. If this is set, at the beginning of the execute stage, Oracle Enterprise Scheduler automatically exports previously imported output files to the request's working output directory. This gives you an opportunity to update the file before it is imported back to the content store at the end of the execute stage. (Note that the content isn't removed from the content store when the content is exported.) Furthermore, Oracle Enterprise Scheduler provides an API for a request to selectively export previously imported output files.

22.2.1.3.1 Error Handling When a Local Request File Directory is Used

When a local request file directory is used, file imports happen at the end of each stage (pre-processing, execution, update, post-processing). If an error occurs while importing logs or output files, the log and output files that failed to import are moved to a mirror directory at request_file_directory/preserve. For example, for request 18 this would be request_file_directory/preserve/18.

For the pre-processing stage, an error creating the request directory at the beginning of the stage or importing output files at the end of the stage results in a system error for the request.

For the post-processing stage, an error creating the request directory at the beginning of the stage or importing output files at the end of the stage results in a warning for the request.

For the execution stage of a Java job, asynchronous Java job, and process job request, an error creating the request directory or automatically exporting previously imported output files (such as when the SYS_EXT_executeAutoExport system property is used) at the beginning of the stage or importing output files at the end of the stage results in a system error for the request.

If the request is a process job, an error importing the request log is logged and not treated as an error. The log is left in the file system, and you may manually import it to the content store. If there is an internal error during execution of a process job, log and output files are not imported because the job could still be running. The log and output files are imported when the job is terminated, either automatically or manually by the user. If the job goes to ERROR_MANUAL_RECOVERY, it is the user's responsibility to clean up the request log and output files.

For the update stage, an error creating the request directory or importing output files is logged only.

22.2.2 System Properties

Setting the SYS_EXT_supportOutputFiles system property is essential to using the request file directory and automatic importing of output files.

To use the request output directory to create output files, the job must define a parameter using the system property SYS_EXT_supportOutputFiles. Depending on what sort of files the job wants to create, the property can be set in one of the following ways:

  • Set it to "output" in order to have files written to the request output directory imported to the content store.

  • Set it to "work" in order to write files to the request working directory that are not intended for import, such as temporary files.

  • Set it to "none", or leave it undefined, if the job does not create any output or temporary files.


Table 22-5 System Properties for Creating Request Output

Method Description

SYS_EXT_supportOutputFiles

String property indicating whether a job creates files in the file system. Supported values are work, output, and none. An invalid value is treated as none.

SYS_EXT_executeAutoExport

Boolean property indicating whether previously imported output files shall be exported at the start of the execute stage. The content isn't removed from the content store when it is automatically exported.


22.2.3 Creating Request Output from a Java Job

To create request output from Java, your job's code can use the Oracle Enterprise Scheduler API to create output content directly in the content store, or your job can create files in the request's output directory in the file system. If your job creates files in the request's output directory, you can either explicitly import those files to the content store or allow Oracle Enterprise Scheduler to automatically import the files to the content store.

Using the API, the job can create text or binary output content. Imported output files are always imported as binary content, meaning the bytes are uninterpreted.

22.2.3.1 APIs for Handling Request Output from a Java Job

The Java APIs available for handling request output include the following:

  • Use the ContentFactory class to get instances of other classes you can use to create and manage output content, including RequestOutput and OutputContentHelper output. See Table 22-6.

  • Use the RequestOutput class to create output content directly in the content store. See Table 22-7.

  • Use the OutputContentHelper class to explicitly manage content you create as files in the request output file directory, and to interact with the content store. See Table 22-8.

The oracle.as.scheduler.request.ContentFactory class provides methods to get your code access to the output content framework, as well as to an instance you can use to create the output itself.


Table 22-6 ContentFactory Methods for Java Request Output

Method Description

getRequestOutput( RuntimeServiceHandle rsh, long requestId, ContentType contentType, String contentName )

Returns a RequestOutput instance with output for the specified request and creates the output content for the request. Each write uses the specified request service handle; your calling code is responsible for committing or rolling back the transaction.

getOutputContentHelper( long requestId )

Returns a OutputContentHelper instance for creating output content for requests with Standard or Extended request mode. Each operation is performed in a separate transaction.

getOutputContentHelper( long requestId, RuntimeServiceHandle rsh )

Returns a OutputContentHelper instance for creating output content for requests with Standard or Extended request mode. Each operation uses the provided handle, and it is the caller's responsibility to commit or rollback the transaction.


The oracle.as.scheduler.request.RequestOutput class represents the output your code is creating. You get an instance of this class from ContentFactory.getRequestOutput, then use its write methods to write to the output content you are creating.


Table 22-7 RequestOutput Methods for Java Request Output

Method Description

writeln( String str )

Appends str to the text output content, followed by a line feed character.

write( String str )

Appends str to the text output content.

write( String str, int offset, int length )

Appends str to the text output content.

write( char[] chars )

Appends chars to the text output content.

write( char[] chars, int offset, int length )

Appends chars to the text output content.

write( byte[] bytes )

Appends bytes to the binary output content.

write( byte[] bytes, int offset, int length )

Appends bytes to the binary output content.


Methods of the oracle.as.scheduler.request.OutputContentHelper class do the heavy lifting for output file handling in Java jobs. Using these methods, your code can work with the request file directory and the content store itself.

Note that methods for importing content to the content store take a OutputContentHelper.CommitSemantics enum instance that you can use to specify transaction semantics during import. For more information, see Table 22-9.


Table 22-8 OutputContentHelper Methods for Java Request Output

Method Description

workDirectoryExists( )

Returns true if the request's work directory exists. Allows the job at any stage to determine if the work directory exists before it attempts to create temporary files.

The job must define the SYS_EXT_supportOutputFiles system property with a value of work or output to cause Oracle Enterprise Scheduler to create the work directory.

outputDirectoryExists( );

Returns true if the request's output directory exists. Allows the job at any stage, such as update, to determine if the output directory exists before it attempts to create output files.

The job must define the SYS_EXT_supportOutputFiles system property with a value of output to cause Oracle Enterprise Scheduler to create the output directory.

isRequestWorkDirectoryShared( );

Returns true if the request file directory is shared. If it is, then any files created in the request work dir or output dir in any stage is available to all subsequent stages of the request.

getResolvedWorkDirectory( );

Returns a String with the request work directory as resolved to the current server. The job may create temporary files in the work directory, and Oracle Enterprise Scheduler automatically deletes the work directory at the end of request execution if the RequestFileDirectory is shared, or at the end of each stage (pre-processing, execution, update, post-processing) if the RequestFileDirectory is local.

getResolvedOutputDirectory( );

Returns a String with the request output directory, resolved to the current server. The job may create output files in the output directory that can be automatically or manually imported to the Oracle Enterprise Scheduler content store.

importOutputFiles( List<String> fileNames, CommitSemantics semantics );

Returns an ImportExportResult instance from importing the specified files from the resolved output directory. Imported content overwrites existing content of the same name, unless the existing content was created using the API. In that case, the file is not imported.

importOutputFiles( CommitSemantics semantics );

Returns an ImportExportResult instance from importing all files from the resolved output directory. Imported content overwrites existing content of the same name, unless the existing content was created using the API. In that case, the file is not imported.

exportOutputContent( List<String> contentNames );

Returns an ImportExportResult from exporting the specified previously imported output content to files in the request output directory. The exported files overwrite any existing files of the same names. Note that output content created using the API can not be exported.

exportOutputContent( );

Returns an ImportExportResult instance from exporting all previously imported output content to files in the request output directory. The exported files overwrite any existing files of the same names. Note that output content created using the API can not be exported.

queryOutputContent( )

Returns a list of ContentDetail instances with detailed information for all existing output content in the content store. This returns information on both output content that was imported and output content created using the API.

queryOutputContent( String contentName )

Returns a ContentDetail instance with detailed information for the output content in the content store, if it exists (null if it does not). This returns information on both output content that was imported and output content created using the API.

outputContentExists( String contentName )

Returns true if the specified output content exists in the content store for the request. This returns information on output content that was imported and output content created using the API.

deleteOutputContent( List<String> contentNames )

Deletes the specified output content from the content store for the request. Can delete output content that was imported and output content created using the API.


Use the oracle.as.scheduler.request.OutputContentHelper.CommitSemantics enum to specify what should happen if errors occur while importing content to the content store.


Table 22-9 CommitSemantics Enum Members to Express Commit Semantics

Field Description

StopOnFirstError

Stop the operation for all files when there is an error on a file. If the handle is internal, it is committed.

IgnoreErrors

Attempt the operation on all files regardless of errors. If the handle is internal, it is committed.

Transactional

Stop the operation for all files when any file has an error. This is not valid with a user-provided handle.


22.2.3.2 Java Request Output Examples

Example 22-5 illustrates how to create output content using the RequestOutput API. The output content is created directly in the content store.

Example 22-6 illustrates how to create an output file in the request output directory. Remember that the job must define the SYS_EXT_supportOutputFiles system property as output. This example is appropriate for a Java job, an asynchronous Java job, a pre-processor, or a post-processor.

The following example shows how to manually export and import output files. This would be useful if you need to create content from files during update. Be aware that you can export only files that have been imported and not files that were created using the API.

The example illustrates the scenario that a file that may have been created previously must be updated and imported.

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
    }
}

Example 22-5 Creating Output Content using 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);
    }
}

Example 22-6 Creating an Output File for Automatic Import

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
    }
}

22.2.4 Creating Request Output from a PL/SQL Job

To create request output from PL/SQL, your code can use the ESS_JOB PL/SQL package to create output content directly in the content store.

Using functions and procedures in the package, the job can create text or binary output content.

22.2.4.1 PL/SQL Package Support for Creating Output


Table 22-10 ESS_JOB Procedures and Functions for Request Output

Method Description

open_text_output_content( p_content_name in varchar2 ) return varchar2

open_binary_output_content( p_content_name in varchar2 ) return varchar2

Returns a handle from opening the specified output content for the request associated with the current session.

These are convenience functions that call open_output_content with the appropriate content type constant. See open_output_content for additional details.

open_output_content( p_content_name in varchar2, p_content_type in integer ) return varchar2;

Returns an opaque handle from opening the output content p_content_name for the request associated with the current session.

This creates a new output content entry if one does not already exist for the given name. If one already exists, then the specified content type must match that already established for that name.

p_content_type represents content type with one of the content type constants:

CONTENT_TYPE_TEXT (value: 1) for text content.

CONTENT_TYPE_BINARY (value: 2) for binary content.

This returns an opaque handle that is passed to subsequent procedures that operate on that output content.

The content entry is locked on successful return from this function. It may or may not be locked if this procedure fails. A commit or rollback releases the lock. The write_text_content or write_ntext_content procedures must be used to write data for text content, while the write_binary_content procedure must be used to write data for binary content.

You should call close_content to free any resources associated with the handle returned by this method. The close should be done prior to transaction commit or rollback.

NOTE: The content output support has DML semantics. The caller is responsible for the commit/rollback.

write_ntext_content( p_content_handle in varchar2, p_data in nvarchar2 )

write_text_content( p_content_handle in varchar2, p_data in varchar2 );

Writes data as p_data to the output content associated with the given handle. These operations are supported only for CONTENT_TYPE_TEXT content type.

p_content_handle is the output handle from a prior open_output_content call.

NOTE: The content output support has DML semantics. The caller is responsible for the commit/rollback.

write_binary_content( p_content_handle in varchar2, p_data in raw );

Writes binary data as p_data to the output content associated with the given handle. This operation is supported only for CONTENT_TYPE_BINARY content type.

p_content_handle is the output handle from a prior open_output_content call.

NOTE: The content output support has DML semantics. The caller is responsible for the commit/rollback.

close_content( p_content_handle in varchar2 );

Closes the output content handle. This releases resources associated with the given handle and it is no longer valid. Call this method before transaction commit or rollback.

p_content_handle is the output handle from a prior open_output_content call.

NOTE: The content output support has DML semantics. The caller is responsible for the commit/rollback. This method does not automatically perform a commit or rollback

output_content_exists( p_content_name in varchar2 ) return boolean;

Returns true if an output content entry having the specified name already exists for the request associated with the current session.

p_content_name is the name of the output content entity.

delete_output_content( p_content_name in varchar2 );

Deletes the specified output content entry for the request associated with the current session.

p_content_name is the name of the output content entity.


22.2.4.2 PL/SQL Output Creation Examples

Example 22-7 illustrates how to write text content into output, as well as how to write log entries along the way.

Example 22-8 illustrates how to write binary content for output.

Example 22-7 PL/SQL Output Creation Examples

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;
/

Example 22-8 Manual Export and Import of Request Output

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;
/

22.2.5 Creating Request Output from a Process Job

You create output from process job logic by writing the content to the location specified by the ESS_OUTPUT_WORK_DIR environment variable that is available for all process jobs. As with other jobs, ensure that the SYS_EXT_supportOutputFiles system property is set to output so that the environment variable is defined for the job.

After your process code writes the file, Oracle Enterprise Scheduler automatically imports output files in the directory into the content store as binary content.

22.2.6 Creating Request Output from an EJB Job

See Request Logging and Output From an EJB Job for a description and examples about how to create output from an EJB job.

22.2.7 Creating Request Output from a Web Service Job

For synchronous and asynchronous web services, request output content is automatically created from the response message payload as described below. The output content is text data with the name WebServiceJobOutput-REQUESTID.txt, where REQUESTID is the request ID of the request.

For a synchronous web service, the response message payload is captured as the request output.

For an asynchronous web service, the callback/response message payload received at EssWsJobAsyncCallbackService is captured as the request output when the job status is SUCCESS.

22.2.8 APIs for Handling Request Output

You can use methods of the oracle.as.scheduler.RuntimeService class to handle request output stored in the Oracle Enterprise Scheduler content store. You'll need to first get a RuntimeServiceHandle instance. You'll pass this instance as an argument for each of these RuntimeService methods. For more on the RuntimeServiceHandle, see How to Access the Runtime Service and Obtain a Runtime Service Handle.


Table 22-11 RuntimeService Methods for Handling Request Output

Method Description

getOutputContentDetail( RuntimeServiceHandle handle, long requestId, String contentName )

Returns a ContentDetail instance for the specified output content for the specified request, or null if the content does not exist.

getOutputContentDetail( RuntimeServiceHandle handle, long requestId )

Returns a ContentDetail List instance for all output content for the request. The list is empty if there is no output content.

openOutputContent( RuntimeServiceHandle handle, long requestId, String contentName )

Opens the specified request output to retrieve output data for the specified content, returning ContentHandle instance. You can use the handle to retrieve output data. The content must be closed to release the handle.

getTextContent( RuntimeServiceHandle handle, ContentHandle contentHandle, int maxChars )

Returns a char array with at most maxChars characters from the log or output text content.

getBinaryContent( RuntimeServiceHandle handle, ContentHandle contentHandle, int maxBytes )

Returns a byte array with at most maxBytes bytes from the binary content.

closeContent( RuntimeServiceHandle handle, ContentHandle contentHandle )

Closes the previously opened log or output content and releases the handle.