Note:

Extension of the classes in this package is prohibited unless otherwise documented. Similarly, extension or implementation of the interfaces in this package is prohibited except as documented.

Package com.sas.services.storedprocess


@CodeSet("sas.platform") @SASScope("ALL") package com.sas.services.storedprocess
Execute stored processes.

Stored Process Service

Overview

The Stored Process Service enables a client to execute stored processes. A stored process is a SAS language program that is stored on a SAS server or in metadata. Input parameters (name/value pairs) and input data (via a streaming interface, client-side file or client-side data-set) can be passed to the stored process. Output can be returned to the client in a package, via a streaming interface or to a client side file or client-side data-set. Stored processes can also access any SAS data source or external file and create new data sets, files, or other data targets supported by SAS.

Note: The Stored Process Service cannot be used to execute a SAS language program stored on a client.

Model

The Information Service is used to search for and identify stored processes that meet specified criteria. A stored process is then selected for exploitation. Alternatively, the Information Service can be used to access a stored process at a known location in metadata. Input parameters, if present, can be assigned values. For package-capable stored processes, the package location can be specified via input parameters. The locations of input and output tables and filerefs can also be be specified. The stored process can then be executed either synchronously or asynchronously. A package might be generated. If executed asynchronously, streaming input might be provided to the stored process and streaming results might be available during execution. An alert might be created in the Personal Repository to capture the execution of the stored process.

Stored Processes can also be manually created for exploitation though this is not the normal usage pattern: methods are provided to completely specify certain types of stored processes. For more information about manually creating a stored process, see the sample code provided.

The following sections apply to the exploitation of stored processes defined in a SAS Metadata Repository, though some sections are also applicable to manually created stored processes.

Starting the Service

The Stored Process Service is one of the SAS Foundation Services, though not one of the core services. To use it within the Discovery Service framework, the Stored Process Service must be specified in the service deployment being used. No specific configuration information is needed for the Stored Process Service.

At initialization, the Stored Process Service determines whether the Logging Service is available and, if it is, various items related to the use of the Stored Process Service can be logged. Service deployments are typically created using the Foundation Services Manager Plug-in in the SAS Management Console and that plug-in automatically adds a dependency on the Logging Service.

Metadata format changed in 9.2 and 9.3

To provide enhanced capabilities, the format of the metadata describing stored processes was changed in version 9.2 and again in 9.3. As a result there have been various changes to the API, including the creation of new interfaces in 9.2 and the enhancement of those interfaces in 9.3. The version of the stored processes metadata format introduced in 9.2 was version 1 and the version introduced in 9.3 was version 2. Hence 9.2 stored processes are also known as version 1 stored processes and 9.3 stored processes may be called version 2 stored processes. Both version 1 and version 2 stored processes can be present in a 9.3 metadata repository. Summaries of the changes for 9.2 and the changes for 9.3 are available.

Defining a Stored Process

Stored process definitions can be created in a SAS Metadata Repository using the Folder View of the SAS Management Console or by any SAS component that has the ability to create stored process metadata. A design time Java api based on the stored process smart object is provided to programmatically create and modify stored processes.

The Stored Process Service is used to execute stored processes that exist in a SAS Metadata Repository. The typical pattern is to obtain a smart object corresponding to the stored process of interest and then create a service object (in other words, an object that implements StoredProcess2Interface) from the smart object. A StoredProcess2Interface contains all of the information needed to execute a stored process. This includes the location of the stored process program, the server to be used to execute the stored process, any input parameters, and the desired output. Detailed information about that stored process, if needed, can be obtained from the smart object.

A StoredProcess2Interface can also be manually initialized by obtaining an empty object which implements StoredProcess2Interface from the Stored Process Service and then calling various setter methods with appropriate values to create a version 1 stored process, though this is not the anticipated use of the service.

Input Parameters

Stored processes accept input parameters. Input parameters at the stored process (SAS code) level have string names and string values. Input parameters are optionally defined in stored process metadata and might include default values and / or lists of valid values which may be statically specified or dynamically obtained. Values for input parameters can be set programmatically using the setParameterValue() method call.

If defined at the metadata level, input parameters metadata is compatible with that used by the Prompting Framework. The SMC support for defining and modifying stored processes uses a design time component provided by the Prompting Framework and the term input parameters is used interchangably with "prompts". And, since StoredProcess2Interface surfaces a com.sas.prompts.PromptValuesInterface, parameter values can be initialized and modified by components that support the Prompting Framework. An example of such components would be com.sas.prompts.components.webapp.visuals.PromptPropertiesPanel and com.sas.prompts.visuals.swing.PromptPropertiesPanel, which can be used to display a visual so that parameter values can be entered in the servlet and Swing environments respectively.

Parameter Name Case-sensitivity

SAS is not case-sensitive in its treatment of macro variable names. However, the Prompting Framework is case-sensitive. The approach taken by the SMC Folder View is to store macro (prompt) names as is. This means if a name is entered in mixed-case, the name is saved in mixed-case. No normalization is done. However, for the purposes of checking for duplicates, name comparisons are done in a case-insensitive way.

Therefore, at execution time, when a stored process object is instantiated from metadata, parameter names are in the case used to enter them in the SMC Folder View. However, the various flavors of the setParameterValue method function in a case-insensitive way. e.g. if StoredProcess2Interface's setParameterValue() method is invoked, case insensitive comparisons are performed to determine if a parameter of that name exists in the deserialized stored process. If you directly manipulate Prompting Framework objects you need to keep this case-sensitivity issue in mind.

Parameter Value Escaping

Parameter value validation is done by the Service for Version 1 stored processes run on a SAS Workspace Server. The following algorithm is used:

The value is examined to see if there are any unsafe characters such as a percent sign (%), ampersand (&), single quotation mark ('), double quotation marks ("), or semicolon (;). If an unsafe character is present, the character is enclosed by the %NRSTR() macro. If the unsafe character is a percent sign, single quotation mark or double quotation marks then the unsafe character is escaped using a percent sign before being enclosed by a %NRSTR() macro.

Processing similar to that described above is done on the server for all other stored processes.

Dynamic Data Source Parameter Validation

If a parameter is to be constrained to the set of values specified by a dynamic data source, run-time parameter value validation against this data source will be performed provided a data provider is available to the StoredProcess2Interface. The controlling application can make such a data provider available by binding an object which implements com.sas.prompts.DataProviderInterface to the session context using the name com.sas.prompts.DataProviderInterface.DATA_PROVIDER_KEY. When the validatePromptValues() method of StoredProcess2Interface is called, the session context is examined to see if a DataProviderInterface is bound to DataProviderInterface.DATA_PROVIDER_KEY. If a DataProviderInterface is bound, a DynamicPromptValueValidator is constructed using the data provider for value validation; if one is not bound, a DynamicPromptValueValidator is constructed without a data provider and validation against dynamic data sources will not be done.

Supported Servers

A version 2 stored process is associated with a specific Application Server; a version 1 Stored Process is associated with a specific Stored Process Server or a specific Workspace Server. Also, the Workspace Server was enhanced in 9.3 to provide functionality similar to that provided by the Stored Process Server including output parameters and streaming input and output. However, there are two areas where the functionality provided by the two types of servers is different:
  • On a Workspace Server the stored process executes under the client identity. On a Stored Process Server the identity corresponds to the login defined in metadata for the Stored Process Server. This is unchanged from 9.2
  • The Workspace Server does not support stored process server sessions (and consequently replay stored processes)

Given these differences between the servers and the performance characteristics of each type of server, the writer of the stored process may choose to restrict the execution of the stored process to a certain type of server. If the stored process is not restricted, default behavior of the service for a version 2 stored process is to attempt to first obtain a connection to a Stored Process Server and if that fails (either because no such server is defined in metadata or a connection to the server could not be obtained), an attempt is made to obtain a connection to a Workspace Server.

Version 1 stored processes are directly associated with either a Workspace Server or a Stored Process Server and an attempt is only made to obtain a connection to the server associated with the stored process.

A version 2 stored process can also be designated to run on other Application Servers (in addition to the one specified in metadata). For such stored processes, the setServerContext() method allows the run time specification of the Application Server to be used for execution.

If a client supplies a connection to a pooled Workspace servers, the available feature set is similar to that available on a Workspace server.

Result Capabilities, generated Input Parameters and Result Selection

The Stored Process service provides methods to access certain types of results (packages and streams) if the stored process is defined in metadata to possess those capabilities and if any needed parameters have appropriate values at execution time. StoredProcess2Interface surfaces two methods (isPackageCapable() and isStreamCapable()) which can be used to determine the result capabilities of the stored process. Stored processes defined in metadata possess the capabilities specified in their definition; manually created stored processes are version 1 and are created with package only capability on a Workspace server and with both capabilities (stream and package) on a Stored Process server.

The following section describes the input parameters generated by the service when the execute() method or executeAsynch() method of StoredProcess2Interface is called. It also lists which of these input parameters the client is allowed to set. The combination of client set and service generated values is a set of name-value pairs that are passed, along with other input parameters, to the stored process to be used by the STPBEGIN / STPEND macros and can be ignored if these macros are not used. And, for certain types of packages, additional parameters recognized by the STPBEGIN and STPEND macros can be set by the client (consumer of this API).

  • If the stored process is neither stream or package capable, the client may not set _RESULT to a value which begins with "STREAM" or "PACKAGE_TO_". All other values are acceptable. If _RESULT is not set, the service will set _RESULT to "STATUS".
  • If the stored process is only stream capable, the client may only set _RESULT to a value which begins with "STREAM". If _RESULT is not set, the service will set _RESULT to "STREAM". The special "output" stream _WEBOUT (so named to better support legacy SAS/IntrNet stored processes) will be available as a Stream name.

    Because output is streamed while the stored process executes, streaming stored processes should normally be executed asynchronously.

  • If the stored process is only package capable, the client may only set _RESULT to a value which begins with "PACKAGE_TO_".

    • If _RESULT is absent or not set, then a transient package is assumed and the parameters generated depend on the version of the stored process and the type of server the stored process executes on. For a version 1 stored process based on a Workspace server _RESULT is set to "PACKAGE_TO_REQUESTER"; for all other stored processes _RESULT is set to "PACKAGE_TO_ARCHIVE" and _ARCHIVE_PATH set to "TEMPFILE".
    • A value of "PACKAGE_TO_REQUESTER" may only be specified for _RESULT for a version 1 stored process based on a Workspace server to generate a permanent file package; for all other stored processes a value of "PACKAGE_TO_ARCHIVE" should be specified for _RESULT to generate a permanent file package. In addition, it is required that the _ARCHIVE_PATH input parameter be present and have a value. The _ARCHIVE_NAME input parameter is optional and if absent a new instance of the permanent file package will be generated. The _CREATE_NEW_PACKAGE_INSTANCE input parameter, if present, is ignored.
    • If _RESULT is set to PACKAGE_TO_WEBDAV, the _PUBLISH_TO_PR input parameter is examined. If _PUBLISH_TO_PR is present and set to True, the value of the input parameter _PR_COLLECTION_PATH is treated as a path relative to the MyResults folder of the Personal Repository. Input parameter _COLLECTION_URL is set to the absolute path based on _PR_COLLECTION_PATH. If _PUBLISH_TO_PR is absent or set to False, _COLLECTION_URL contains the location under a WebDAV server and the protocol and hostname are extracted from the URL to obtain credentials from the metadata server. If mulitple authentication domains are associated with the WebDAV server the first one is used and a warning sent to the log. Input parameter _HTTP_PROXY_URL is generated if a proxy url is available for the WebDAV server (from metadata).

      For both WebDAV cases: if the stored process writes the package to a unique service created instance name (as determined by _CREATE_NEW_PACKAGE_INSTANCE), _COLLECTION_URL reflects the unique name value.

      If credentials are available, input parameters _HTTP_USER and _HTTP_PASSWORD are generated based on the credentials. Credentials are obtained from the User Context and depend on how the WebDAV server is defined in metadata. If the WebDAV sever's authentication type is "metadata", a one time password is generated; otherwise, the domain is used to try to get credentials using the UserContext's getIdentityByDomain() method and, if successful, bound to _HTTP_USER and _HTTP_PASSWORD. An exception is if _PUBLISH_TO_PR is absent or set to False and if the client supplies _HTTP_USER and optionally _HTTP_PASSWORD - in that case client supplied values are used and no attempt is made to obtain credentials.

  • If a stored process has both capabilities, the client can select the capability desired by appropriately setting _RESULT. Behavior is as described in the previous discussions for stream capable and package capable stored processes, depending on the value set for _RESULT. If no value is set for _RESULT, then behavior is as described in the package only case.

The only output parameter relevant to result capabilities is _ARCHIVE_FULLPATH which must be set by the stored process to the path of the archive (the STPBEGIN / STPEND macros, if used, automatically do this) in the case of "PACKAGE_TO_ARCHIVE" on a Stored Process server. On completion of execution, the service uses the value of _ARCHIVE_FULLPATH to bind to the result package.

Redirecting the Output of the Stored Process

As discussed in the previous section, the type of any result (package or stream) and destination (if package) is determined by a combination of the capabilities of the stored process and the presence and values of various parameters. Provided the capabilities permit it the type and destination (if applicable) can be changed by suitable changes to the parameter values. StoredProcess2Interface's setParameterValue() can be used to add a parameter or modify the value of an existing parameter. Alternatively, the parameter hierarchy can be directly manipulated by obtaining a handle to it via StoredProcess2Interface's getPromptValues()

Generated Input Parameters

In addition to the result capability based input parameters described above, the following input parameters are generated by the service:

  • _METAPERSON and _METAUSER. _METAPERSON is set to the Person name as specified by the getName() method of the User Context and _METAUSER, also obtained from the User Context, is set to the username used to login to the SAS Metadata Server. If the User Context is not available or a value is not obtainable for either of these macros, the value for that macro is set to "UNKNOWN".
  • _CLIENT is set to a value obtained using the following template:

    ClientName; JVM java.version; os.name (os.arch) os.version

    The first substitution ClientName is obtained via the getClientName() method of StoredProcess2Interface. If not present, a value of "StoredProcessService 9.3" is used for ClientName. java.version, os.name, os.arch and os.version are the properties returned by Java's System.getProperty() method. If the value of any of these properties is not available a blank is substituted.
  • _PROGRAM and _METAFOLDER. _PROGRAM is set to the path to the stored process (e.g. /Users/Russell/stp/tests/My Stored Process) and _METAFOLDER is set to the path to the folder containing the stored process. (e.g. /Users/Russell/stp/tests/). If a value cannot be obtained it is set to an empty string. For manual stored processes, _PROGRAM is set to the file name as set by the call to setSourceFromFile() and _METAFOLDER is set to an empty string.

If the client does set a value on an input parameter which the service would typically set and if the value set by the service is different, the client value will be overridden unless explicitly described otherwise. If overridden, a warning is logged in all cases except _PROGRAM and _METAFOLDER.

Data Sources and Data Targets.

Multiple data sources and data targets are supported and can be defined in metadata. Data sources and data targets are used to model SAS files and SAS datasets.

SAS files:

A file is defined in metadata either as a data source or a data target depending on whether it provides input to or gets output from the stored process. Each such metadata entry has a fileref and the fileref is bound to data at run time in one of two ways. In both ways, the stored process program is written to read from or write to the fileref.
  1. Various flavors of setInputFileref() and setOutputFileref() exist on StoredProcess2Interface to associate the fileref with either a server side location or a client side file. If the file is on the client side the association is done via a client-supplied Reader or InputStream for a data source and a client-supplied Writer or OutputStream for a data target. For input from the client, the content is obtained from the client-supplied Reader or InputStream and copied to a temporary location on the server and the fileref programmatically associated with that temporary file. For output to the client, the fileref is programmatically associated with a temporary location and after the stored process has completed execution, output is copied from that temporary location to the client-supplied OutputStream or Writer.
  2. If none of the setInputFileref() or setOutputFileref() methods is called on a fileref, then the service assumes that the fileref will be handled in streaming fashion by the client using the CACHE access method. The client application is coded to write to OutputStreams (this is input to the SAS stored process) and read from InputStreams (output from the SAS stored process). Execution2Interface provides methods for the client to obtain the InputStream or OutputStream corresponding to the fileref as well as interfaces to access the stream headers, if needed. Data is either a byte stream or in xml format (typically handled by the XML Libname engine). Because input and output can be streamed while the stored process executes, streaming stored processes are normally executed asynchronously.

    Streaming input and output is not supported for version 1 stored processes that run on a Workspace Server but is supported for all other stored processes. This streaming feature is independent of the result capability of the stored process and the stored process should only be marked stream capable if it coded to use that capability. That capability is equivalent to the stored process streaming output to a fileref of name _WEBOUT.

    For data sources, the expected content type specified in metadata is set in the stream headers at the time the stream is constructed using the header property name "HTTP:Content-type". If no expected content type is specified in metadata, the service sets a default value of "text/xml" for XMLStreams and "application/unknown" for GenericStreams. The client can override the value set by the service by invoking the setHeader() method on the corresponding OutputStreamHeaderInterface.

SAS datasets:

A dataset, modeled in metadata as a data table entry, is either a data source or a data target depending on whether it provides input to or gets output from the stored process. Each data table entry has a table parameter name, which should be thought of as a logical name. At run-time, the service associates a two level dataset name for each logical name and generates a macro name-value pair corresponding to the modified table parameter name and the two level dataset name. The table parameter name is modified by prefixing it with "_SOURCE_" or "_TARGET_", depending on whether it is a data source or data target. This results in separate name spaces for source and target table parameter names. As an example, for a table name CARTAB which is a data source and which the client wishes to associate with Sashelp.Cars, the the name-value pair generated by the service at run time would be ("_SOURCE_CARTAB","Sashelp.Cars"). The SAS code would consume this via a statement such as "SET &_SOURCE_CARTAB;".

At run time the actual name of the dataset is associated with the prefix added table parameter name in one of the following ways:

  • If the table is on the client side, the client provides an InputStream or OutputStream to setInputDataTable() for client tables or setOutputDataTable() for client tables and uses the XML library engine. The service performs all the setup including generating a LIBNAME statement, a FILENAME statement and the macro name-value pair. Complete details can be found in the Javadoc for those setter methods.
  • If the table is on the server, a pre-assigned (assigned outside the Stored Process Service) libref is needed and the two level dataset name is specified by the client to setInputDataTable() for server tables or setOutputDataTable() for server tables and results in the generation of the macro name-value pair. Complete details can be found in the Javadoc for those setter methods.
  • If a prompt (with a value) is present with the same name as one of the prefixed names, then there's no need for one of the above setters to be called. However, if a setter is called, the prompt value is overridden and a warning logged. If there is no prompt with a value and one of the above setters is not called for a table, a macro value identical to the parameter name (without the prefix) is generated.

Detailed metadata about the data sources and data targets defined in a stored process can be obtained from the getDataSourcesAndTargets() method of the smart object for those consumers which need this information.

Executing the Stored Process

Executing a stored process creates an Execution2Interface object. This object is a placeholder for the stored process that is executing or has completed execution and contains the execution status and results of the stored process. A single stored process can be executed multiple times; each execution returns a new Execution2Interface.

For stored processes defined by metadata, a connection to the server is obtained by the Stored Process service via the Connection service. However, the client can override this behavior by supplying a connection. A connection based on stored process metadata can be obtained by calling the getConnection() method.

Stored process execution can be synchronous or asynchronous. If synchronous, the execute() method blocks until execution is completed. If asynchronous, the method returns immediately. An execution listener interface is provided to notify the caller when execution starts and completes. Alternatively, the caller can poll the Execution2Interface associated with the execution for a completion status or call one of the waitForCompletion() methods.

After the stored process has completed execution, the consumer can obtain the values of output parameters, test the completion status (the SAS return code), or fetch the SAS log or SAS listing.

Stored processes that run on Workspace Servers can be run synchronously or asynchronously. Stored processes that run on Stored Process Servers that deal with streams (for the reasons noted in Data Sources and Data Targets) are typically executed asynchronously. If the stored process that generates a package is run asynchronously, the package is not available until the stored process has completed execution.

Aborting execution

The execution of a stored process can be interrupted. The execute() method when run synchronously blocks until execution is complete. To be able to abort an executing stored process, the execute() method has to be run asynchronously. The abort() method can then be called on the Execution2Interface returned from the call to execute() when the stored has to be aborted.

Alert Creation

The execution of the stored process can be captured in the MyInbox folder of the Personal Repository by a StoredProcessAlertItemInterface object.

Alerts are described in complete detail later in this document.

Lifecycle Issues

The Execution2Interface is closed with an explicit call to its destroy() method after the client application has completed processing results.

The StoredProcess2Interface is closed with an explicit call to its destroy() method when there is no further need for it. Unless the client intends to re-execute the stored process, there is no further use for this object after the execute method has returned.

Note: The Stored Process service locks the Session Context associated with the stored process for the duration of the execution of the stored process. After execution is complete, it unlocks the Session Context and then attempts to destroy the Session Context. "Best practices" associated with the Session Service for Context sharing require applications which use the Session Context to lock it for the duration of their use, therefore the Stored Process Service's attempt to destroy the Session Context should not affect the controlling application's use of it. If the controlling application does not lock the Session Context, the Stored Process Service will destroy the Session Context and any attempt to retrieve artifacts (e.g. a package which depends on the Session Context) after the execute method has returned may result in errors.

If desired, notification of completion of execution can be provided by installing a listener.

Package Lifecycle

Packages generated by certain package capable stored processes are surfaced by Execution2Interface's getResultPackage() method. The package can be either SAS server based or WebDAV based depending on various prompt settings. Package surfaced by getResultPackage() are automatically closed by Execution2Interface's destroy method.

If there is a need for the package to have a life-span independent of the Execution2Interface, Execution2Interface's setResultPackageLifeCycleBound() method can be used. If this method is used to unbind the life cycle of the package from the Execution2Interface, the Stored Process service copies the package to the mid-tier for SAS server based packages since access to the package is lost once the connection to the server is closed; for WebDAV based packages no such copy is needed and setLifecycleBound() is a directive to the Stored Process service to not close the package when Execution2Interface's destroy method is called. The Usage section contains a code example.

Alerts provide a more permanent mechanism to access a package beyond the life-span of Execution2Interface and the SessionContext session. If the application requires the creation of an alert, "best practices" recommend accessing the package via the alert if access is needed beyond the life-span of Execution2Interface, and not via Execution2Interface's setResultPackageLifeCycleBound() method as described above.

Permissions Issues

The Stored Process Service uses one or more of the following services depending on the usage pattern:

Routines which require specific permissions to run if a security manager is installed that the service calls are:

  • System.getProperty to get the value of "line.separator" - if the SAS log is requested by invoking the readSASLog() method.
  • UserContext.getIdentityByDomain(domain) to get the user identity - if results are published to a WebDAV server.
  • UserContext.getIdentities() to get the username used to login to the SAS Metadata Server - this is set as the value of _METAUSER.

These methods are called from within "privileged code" in the service. Refer to the documentation for those methods to determine the permissions which need to be given to the CodeSource associated with the Stored Process Service.

Logging and Monitoring

The Stored Process Service uses the Logging Service to log usage under a logging context of "com.sas.services.storedprocess".

The context used for output directed to the SAS Management Console Application Monitor plug-in is "ApplicationMonitor.StoredProcessService".

Locale

The Stored Process follows Foundation services best practices in its locale usage. If a locale needs to be supplied (e.g. when interacting with the prompting framework) one is obtained from the User Service via the UserContext's getLocale() method. When establishing a connection to a Workspace or Stored Process server there is no explicit locale passing to the Connection service as the Connection service also follows Foundation services best practices in its locale handling.

Usage

Code fragments to perform various operations are as follows:

Obtaining a Stored Process for exploitation via the Information Service

  • The Information Service is used to search for stored processes in a metadata repository that meet certain filter criteria and the client is returned a list of stored processes. The Information Service documentation can provide additional information about other ways of finding stored processes.
        // Find all stored processes that contain the search string specified in the "Name" field
        import com.sas.services.storedprocess.metadata.StoredProcessFilter;
        import com.sas.services.information.InformationServiceInterface;
        import com.sas.services.user.UserContextInterface;
        ...
        InformationServiceInterface informationService;
        UserContextInterface userContext;
        ...
        // At this point in the code it is assumed that the Foundation Services
        // have been deployed and the variable "informationService"
        // is a handle to a discovered Information Service and "userContext" is
        // the UserContextInterface (obtained from the User Service)
        // representing the user.
        ...
        StoredProcessFilter filter =
           new StoredProcessFilter("Name", com.sas.services.information.FilterComponent.CONTAINS, search);
        java.util.List list = informationService.search(userContext, filter);
     
    "list" contains a list of Information Service stored process smart objects. The client can then present this list of stored processes to the user, who can select one for execution.
        import com.sas.services.storedprocess.metadata.StoredProcessInterface;
        ...
        // assuming the user selects the ith object
        StoredProcessInterface smartObject = (StoredProcessInterface)list.get(i);
     

    Alternatively, if the path in metadata to the stored process is known, the smart object can be directly obtained as follows:
        // Get the stored processes given its location in metadata.
        import com.sas.services.information.InformationServiceInterface;
        import com.sas.services.user.UserContextInterface;
        import com.sas.services.information.metadata.PathUrl;
        import com.sas.services.storedprocess.metadata.StoredProcessInterface;
        ...
        InformationServiceInterface informationService;
        UserContextInterface userContext;
        ...
        // At this point in the code it is assumed that the Foundation Services
        // have been deployed and the variable "informationService"
        // is a handle to a discovered Information Service and "userContext" is
        // the UserContextInterface (obtained from the User Service)
        // representing the user.
        ...
        String path = set to a path like "SBIP://METASERVER/Shared Data/Test_Stored_Process(StoredProcess)"
        StoredProcessInterface smartObject = (StoredProcessInterface)informationService.getObjectByPath(userContext, new PathUrl(path));
     
    The client then obtains a StoredProcess object for exploitation by calling the newServiceObject() method on the stored process smart object:
        import com.sas.services.storedprocess.metadata.StoredProcessInterface;
        import com.sas.services.storedprocess.StoredProcess2Interface;
        ...
        StoredProcessInterface smartObject = ... // set as shown previously
        StoredProcess2Interface storedProcess = (StoredProcess2Interface)smartObject.newServiceObject();
     
    The object returned is a Stored Process Service StoredProcess2Interface.

Manually Defining a Stored Process

  • Get a reference to the Stored Process Service:

    • If the Stored Process Service has been deployed, the Discovery Service can be used to find the Stored Process Service:
          import com.sas.services.storedprocess.StoredProcessServiceInterface;
          ...
          Class[] desiredServiceTypes = new Class[] {StoredProcessServiceInterface.class};
          ServiceTemplate serviceTemplate = new ServiceTemplate(desiredServiceTypes);
          StoredProcessServiceInterface storedProcessService =
             (StoredProcessServiceInterface)DiscoveryService.defaultInstance().findService(serviceTemplate);
       

    • If this is a standalone program and the Stored Process Service has not been instantiated:
          StoredProcessServiceFactory spsf = new StoredProcessServiceFactory();
          StoredProcessServiceInterface storedProcessService = (StoredProcessServiceInterface)spsf.getStoredProcessService();
       

  • Obtain a version 1 stored process object from the service, specifying the server type that the stored process runs on:
        StoredProcessOptions options = new StoredProcessOptions();
        StoredProcess2Interface storedProcess = (StoredProcess2Interface)
           storedProcessService.newStoredProcess(StoredProcessInterface.SERVERTYPE_WORKSPACE, options);
     

    or

        StoredProcessOptions options = new StoredProcessOptions();
        StoredProcess2Interface storedProcess = (StoredProcess2Interface)
           storedProcessService.newStoredProcess(StoredProcessInterface.SERVERTYPE_STOREDPROCESS, options);
     
    As described in the javadoc for the method, the former will create a stored process to run on a Workspace server with package capability only and the latter will create a stored processs to run on a Stored Process server with both stream and package capabilities. See the section on result capabilities to learn how _RESULT dictates the type of result.

    By default, a transient result package will created if _RESULT is not specified. To obtain streaming results:
                  storedProcess.setParameterValue("_RESULT", "STREAM");
               

  • Describe the location in the file system of the file that contains the stored process by specifying the directory and the filename:
        storedProcess.setSourceFromFile("/sas/pub/sprocess", "prdsale.sas");
     
The Stored Process Service is intended to be used to run stored processes described in metadata. Certain circumstances (running a replay stored process with stored process server sessions) warrant the use of manual stored processes and for such usage version 1 stored processes are adequate. There is no need for and hence no way to create a version 2 stored process manually.

Parameter Manipulation

  • A stored process created from metadata has the parameter definitions present in the metadata for the stored process objects. If additional parameters need to be defined StoredProcess2Interface's setParameterValue() method can be invoked.

  • Parameter values can be set programmatically:
        storedProcess.setParameterValue("pCountry", "US");
        storedProcess.setParameterValue("pYear", "1993");
     

  • Visual components can be used to prompt the user for parameter values. StoredProcess2Interface surfaces a com.sas.prompts.PromptValuesInterface and parameter values can be initialized and modified by components that support the Prompting Framework. The components handle default values and various constraints that might have been specified in the metadata or set programmatically. Parameter values entered in the visuals are automatically set on the StoredProcess2Interface.

    Two code fragments follow to illustrate how the Prompting Framework can be used to set prompt values on the stored process. The first one is Swing based.

     com.sas.prompts.PromptValuesInterface promptValues = storedProcess.getPromptValues();
     if (com.sas.prompts.PromptUtil.isPromptPresentAndVisible(promptValues)) {
         com.sas.prompts.DataProviderInterface dataProvider = new com.sas.prompts.valueprovider.dynamic.DataProvider(userContextInterface);
         com.sas.prompts.swing.visuals.PromptDialog pd = new com.sas.prompts.swing.visuals.PromptDialog(promptValues, dataProvider, parentFrameOrDialog, "Prompts", true, locale);
         pd.pack();
         pd.setVisible(true);
     }
     

    The second one is servlet based.

     com.sas.prompts.PromptValuesInterface promptValues = storedProcess.getPromptValues();
     if (com.sas.prompts.PromptUtil.isPromptPresentAndVisible(promptValues)) {
         com.sas.prompts.DataProviderInterface dataProvider = new com.sas.prompts.valueprovider.dynamic.DataProvider(userContextInterface);
         com.sas.prompts.components.webapp.visuals.model.PromptPropertiesPanelModelInterface model = new com.sas.prompts.components.webapp.visuals.model.DefaultPromptPropertiesPanelModel(promptValues, dataProvider , request.getLocale());
         com.sas.prompts.components.webapp.visuals.PromptPropertiesPanel propertyPanel = new com.sas.prompts.components.webapp.visuals.PromptPropertiesPanel(model);
         propertyPanel.setId("myPrompt");
         propertyPanel.setRequest(request);
         propertyPanel.setResponse(response);
         propertyPanel.write(out);
     }
     

    For further details, see the Javadoc on the com.sas.prompts.* packages.

Executing a Stored Process

  • After parameters have been assigned values, the stored process can be executed. Execution can be synchronous or asynchronous. An Execution2Interface is created to represent each execution instance of a stored process.
        // The first parameter to execute determines whether execution is synchronous
        Execution2Interface spExecution =
           storedProcess.execute(true,null,false,null); // synchronous
     

  • An alert can be created as follows:
        // The third parameter to execute determines whether an alert is created
        Execution2Interface spExecution =
           storedProcess.execute(false,null,true,null); // create alert
     
    The alert can be accessed either via the Execution2Interface or at a later time by examining the Personal Repository. From an Execution2Interface the alert is obtained as follows:
        StoredProcessAlertItemInterface alert = spExecution.getStoredProcessAlert();
     
    See the section on accessing alerts for an example of obtaining the alert from the Personal Repository.

    Note: In order to create an alert, the user must have access to the Personal Repository. For further instructions, see documentation describing Personal Repository setup.

  • A listener can be installed in both the synchronous and asynchronous cases. The client creates a class that implements ExecutionStatusListener2Interface, and when execution is complete, the executionStatusChanged() method in this class gets control and results can be examined as before using the Execution2Interface that is passed to the method. In the following code fragment, it is assumed that the client's class, ClientsExecutionStatusListener, implements ExecutionStatusListener2Interface.
        ExecutionStatusListenerInterface listener = new ClientsExecutionStatusListener();
        Execution2Interface spExecution =
           storedProcess.execute(false,listener,false,null); // asynchronous with a listener
     

  • The executionStatusChanged() method implemented by the client's ClientsExecutionStatusListener class gets control twice - at the start of execution and at the completion of execution. In this example, the stored process was run on a Workspace Server and the results are in a package.
        public void executionStatusChanged(Execution2Interface spExecution)
        {
           int status = spExecution.getStatus();
           if (status == spExecution.STATUS_EXECUTING) {
              // execution commencing ...
           }
           else if (status == spExecution.STATUS_COMPLETED_WITHOUT_EXCEPTION) {
              ResultPackageInterface pkg = spExecution.getResultPackage();
              // Display the results.
           }
           else {
              // An exception occurred.
           }
        }
     

Package stored process example

The following code sample executes a stored process that produces a package. The stored process accepts two input parameters.

    // The stored process is named "ResultPackageDemo".  Locate this stored process.
    import com.sas.services.storedprocess.metadata.StoredProcessFilter;
    ...
    StoredProcessFilter filter =
       new StoredProcessFilter("Name",
       com.sas.services.information.FilterComponent.EQUALS,
       "ResultPackageDemo");
    java.util.List list = informationService.search(userContext, filter);
    // Assume we have one object returned from the search.
    // Get a Stored Process Service object from the smart object.
    com.sas.services.storedprocess.metadata.StoredProcessInterface
       spSmartObject = (com.sas.services.storedprocess.metadata.StoredProcessInterface)list.get(0);
    com.sas.services.storedprocess.StoredProcess2Interface spi =
       spSmartObject.newServiceObject();
    // Set the values of the two parameters.
    spi.setParameterValue("pyear", "1993");
    spi.setParameterValue("pcountry", "US");
    // We are now ready to execute.
    // The first parameter (true) determines whether the execution is synchronous.
    // The call to execute blocks until the stored process completes.
    com.sas.services.storedprocess.Execution2Interface ei =
       spi.execute(true, null, false, null);
    // In a real case, you would test the status code using
    // ei.getStatus() before proceeding to get the package.
    // You can use the status code to determine whether any
    // additional processing is needed.
    // For example, an application might choose to dump out
    // exceptions / get the SAS log if errors are encountered.
    com.sas.services.publish.ResultPackageInterface rpi = ei.getResultPackage();
    // You can now process the results.
    ...
    rpi.close();
    // Destroy the Stored Process Service objects that are created.
    ei.destroy();
    spi.destroy();
 

Package Lifecycle control:

Package lifetime is discussed here. The following code fragment shown how one can obtain a Package which outlives the Execution2Interface object. The example assumes "storedProcess" contains a reference to a com.sas.services.storedprocess.StoredProcess2Interface service object that has been constructed from metadata.
    ...
    Execution2Interface ei = storedProcess.execute(...);
    // the following call to setResultPackageLifeCycleBound() should be made before a reference 
    // to the result package is obtainted via the getResultPackage() call on Execution2Interface
    ei.setResultPackageLifeCycleBound(false);
    // now the result package can be obtained for processing
    com.sas.services.publish.ResultPackageInterface rpi = ei.getResultPackage();
    ...
 
The package obtained will now have a life-time under consumer control and is no longer automatically closed when Execution2Interface.destroy() is called. The code to process the result package is no different.

Streaming Stored Process Example

The following code sample executes a stored process that streams results back. The stored process accepts three fixed input parameters.

    // The stored process is named "StreamingDemo".  Locate this stored process.
    import com.sas.services.storedprocess.metadata.StoredProcessFilter;
    ...
    StoredProcessFilter filter = new StoredProcessFilter("Name",
       com.sas.services.information.FilterComponent.EQUALS, "StreamingDemo");
    java.util.List list = informationService.search(userContext, filter);
    // Assume we have one object returned from the search.
    // Next, get a Stored Process Service object from the smart object.
    com.sas.services.storedprocess.metadata.StoredProcessInterface spSmartObject =
       (com.sas.services.storedprocess.metadata.StoredProcessInterface)list.get(0);
    com.sas.services.storedprocess.StoredProcess2Interface spi =
       spSmartObject.newServiceObject();
    // Set the values of the three parameters.
    spi.setParameterValue("ODSSTYLE", "boring");
    spi.setParameterValue("CHARTTYPE", "vbar");
    spi.setParameterValue("TIMEUNIT", "weeks");
    // We are now ready to execute.
    // The first parameter (false) determines whether the execution is synchronous.
    // The call to execute does not block but returns with an Execution2Interface from which
    // input and output streams can be accessed to supply data to the stored process and
    // read data from the stored process.
    com.sas.services.storedprocess.Execution2Interface ei =
       spi.execute(false, listener, false, null);
    // Get the InputStream associated with "_WEBOUT."
    InputStream is = ei.getInputStream("_WEBOUT");
    // If a Reader is desired it may be obtained as shown in the next three
    // statements (which are commented out):
    // InputStreamHeaderInterface ishi = ei.getInputStreamHeader("_WEBOUT");
    // String encoding = ishi.getCharacterEncoding();
    // InputStreamReader r = new InputStreamReader(is, encoding);
    // You can now can process the input stream - read until end-of-file
    // [code to process the input stream is not shown]
    // Wait for completion of the stored process.
    // The stream closing does not necessarily mean that the stored process has completed.
    int status = ei.waitForCompletion();
    // You can use the status code to determine whether any additional processing is needed.
    // For example, an application might choose to dump out
    // exceptions / get the SAS log if errors are encountered.
    // Destroy the Stored Process Service objects that are created.
    ei.destroy();
    spi.destroy();
 

Streaming Input

Version 1 stored processes that run on a Stored Process Server and all version 2 stored processes can accept one or more streams of input. The following code fragment is based on one input stream, "_webin", being defined in the metadata. The input stream would be defined in the Data tab of the stored process object in the SMC. The execute() is called to specify asynchronous execution so that control returns to the code following the call to execute() after which input may be streamed to the stored process.

    // ... find the stored process and specify parameter values if needed
    // We are now ready to execute.
    // The first parameter (false) specifies asynchronous execution
    com.sas.services.storedprocess.Execution2Interface ei =  spi.execute(false, null, false, null);
    // Get the OutputStream associated with "_WEBIN".
    OutputStream os = ei.getOutputStream("_WEBIN");
    OutputStreamWriter osw = new OutputStreamWriter(os);
    osw.write("line1: some text for line 1\n");
    osw.write("line2: and this is line 2\n");
    osw.write("line3: and here's the third and last line\n");
    osw.close();
    // ... process results as before
 

Alert Details

The execution of the stored process can be captured by an alert in the MyInbox folder of the Personal Repository by a StoredProcessAlertItemInterface object. You can view a code example which describes how the creation of an alert is requested. The event contained in the StoredProcessAlertItemInterface provides information about various aspects of the stored process (e.g., its name, description, Information Service entity key, etc.), the particular execution (e.g., parameters values, package (if present)) that it describes and execution status. Do note that generated parameters are not captured by the alert.

The Alert is created as soon as the stored process begins execution and seeded with those elements of the event that are known. After the stored process has completed execution, the alert is updated and contains all of the elements appropriate to that stored process. If the listener mechanism provided by ExecutionStatusListener2Interface is used, the alert is created before executionStatusChanged() is called for the first time and is updated before executionStatusChanged() is called for the subsequent call(s). If the stored process is executed using the execute() method the alert is updated once after creation; if the executeAsynch() method is used the alert is updated twice after creation. A typical use case would be for the stored process to be executed asynchronously and for a separate application to examine and display the execution status of stored processes of interest to the user. If the stored process creates a package, this separate application can use StoredProcessAlertItemInterface's getResults() to materialize the package.

Alerts are persisted in the MyInbox folder of the Personal Repository. See the section about accessing alerts for more details about accessing the alert.

Alerts are described in XML with an "Event" structure defined by the Event Service. Version 2 stored processes create alerts using the same format as that used in alerts created by version 1 stored processes. The specification for an alert follows:

    <sas-event:Event xmlns:sas-event=
       "http://www.sas.com/xml/namespace/services.events-1.1"
       sas-event:name="com.sas.services.storedprocess.ExecutionStatusEvent">
       <sas-event:Header>
          <sas-event:Version>1.0</sas-event:Version>
          <sas-event:SentAt>timestamp</sas-event:SentAt>
          <sas-event:Response sas-event:type="none"/>
          <sas-event:Properties>
             <Version xmlns="http://www.sas.com/xml/namespace/services.alerts.sp-1.1">
                           2.0</Version>
             <ResultType xmlns="http://www.sas.com/xml/namespace/services.alerts.sp-1.1">
                           resultType</ResultType>
             <Status xmlns="http://www.sas.com/xml/namespace/services.alerts.sp-1.1">
                           status</Status>
             <StoredProcessName
                xmlns="http://www.sas.com/xml/namespace/services.alerts.sp-1.1">
                           storedProcessName</StoredProcessName>
             </sas-event:Properties>
       </sas-event:Header>
       <sas-event:Body>
          <sas-alerts-sp:StoredProcessAlert
             xmlns:sas-alerts-sp=
                           "http://www.sas.com/xml/namespace/services.alerts.sp-1.1"
             sas-alerts-sp:version="2.0"
             sas-alerts-sp:name=name
             sas-alerts-sp:startTime=startTime
             sas-alerts-sp:endTime=endTime>
             <sas-alerts-sp:AlertEntityKey>entityKey
                           </sas-alerts-sp:AlertEntityKey>
             <sas-alerts-sp:Description>description
                           </sas-alerts-sp:Description>
             <sas-alerts-sp:StoredProcessName>storedProcessName
                           </sas-alerts-sp:StoredProcessName>
             <sas-alerts-sp:StoredProcessDescription>
                           storedProcessDescription
                       </sas-alerts-sp:StoredProcessDescription>
             <sas-alerts-sp:Status>status</sas-alerts-sp:Status>
             <sas-alerts-sp:ResultType>resultType
                           </sas-alerts-sp:ResultType>
             <sas-alerts-sp:StoredProcessEntityKey>storedProcessEntityKey
                           </sas-alerts-sp:StoredProcessEntityKey>
             <sas-alerts-sp:StoredProcessPath>storedProcessPath
                           </sas-alerts-sp:StoredProcessPath>
             <sas-alerts-sp:StoredProcessParameters>
                <sas-alerts-sp:StoredProcessParameter>
                   <sas-alerts-sp:ParmName>parmName
                                     </sas-alerts-sp:ParmName>
                   <sas-alerts-sp:ParmValue>parmValue
                                     </sas-alerts-sp:ParmValue>
                </sas-alerts-sp:StoredProcessParameter>
                ...
             </sas-alerts-sp:StoredProcessParameters>
             <sas-alerts-sp:Package>
                <sas-alerts-sp:PackageEntityKey>packageEntityKey
                              </sas-alerts-sp:PackageEntityKey>
                <sas-publish:Package>
                ...
                </sas-publish:Package>
             </sas-alerts-sp:Package>
             <sas-alerts-sp:ExecutionExceptions>
                <sas-alerts-sp:Exception>exception message,
                              cause and stack trace</sas-alerts-sp:Exception>
                ...
             </sas-alerts-sp:ExecutionExceptions>
          </sas-alerts-sp:StoredProcessAlert>
       </sas-event:Body>
       </sas-event:Event>
  

The header elements are standard event elements as defined by the Event Services. The name of the event is "com.sas.services.storedprocess.ExecutionStatusEvent". The following table offers an explanation of those header elements, which vary by event. Descriptions of elements that are an intrinsic part of the Event structure are described in the Event Service.

Element/Attribute: Description:
sas-event:SentAt A time stamp indicating when the event was created.
sas-event:Properties Properties set by the stored process are
  • sas-alerts-sp:Version - the version of this stored process alert. Same as the value of the version attribute in the body (see below for details).
  • sas-alerts-sp:ResultType - the result type. Same as the value of the ResultType element in the body (see below for details).
  • sas-alerts-sp:Status - the execution status. Same as the value of the Status element in the body (see below for details).
  • sas-alerts-sp:StoredProcessName - the name of the stored process. Same as the value of the StoredProcessName element in the body.

Explanations of the body elements are in the following table. If an element does not have a value when the alert is created, or if its value changes when the stored process completes, the behavior is documented in the Description column.

Element/Attribute: Description:
sas-alerts-sp:name The name of the alert.
sas-alerts-sp:version The version number of the alert. Currently 2.0.
sas-alerts-sp:startTime The approx time at which the stored process began execution. The timezone is GMT and the format used is yyyy-MM-dd'T'HH:mm:ss'Z'.
sas-alerts-sp:endTime The approx time at which the stored process completed execution in the same format as startTime. Is blank if the stored process is still executing.
sas-alerts-sp:AlertEntityKey The Information Service entity key of the alert.
sas-alerts-sp:Description The description of the alert. It contains the name of the stored process. After execution completes, the text also has the completion time.
sas-alerts-sp:StoredProcessName The name of the stored process.
sas-alerts-sp:StoredProcessDescription The description of the stored process.
sas-alerts-sp:Status The status of this execution. When the alert is created, it is set to ExecutionBaseInterface.STATUS_EXECUTING. When execution is completed, it is set to ExecutionBaseInterface.STATUS_SAS_EXCEPTION_OCCURRED, ExecutionBaseInterface.STATUS_COMPLETED_WITHOUT_EXCEPTION, ExecutionBaseInterface.STATUS_EXCEPTION_OCCURRED, or Execution2Interface.STATUS_ABORTED.
sas-alerts-sp:ResultType The type of result generated by the stored process. One of the values from StoredProcessInterface2.RESULT_TYPE_*.
sas-alerts-sp:StoredProcessEntityKey The Information Service Entity Key of the stored process.
sas-alerts-sp:StoredProcessPath The SBIP URL of the stored process.
sas-alerts-sp:StoredProcessParameters Describes the parameters of the stored process. Contains zero or more StoredProcessParameter entries.
sas-alerts-sp:StoredProcessParameter Describes each parameter of the stored process.

If the parameter is a scalar it's described as follows:

  • sas-alerts-sp:ParmName - the name of the parameter
  • sas-alerts-sp:ParmValue - the value of the parameter

If the parameter is an array it's described as follows:

  • sas-alerts-sp:ParmName - the name of the parameter
  • sas-alerts-sp:ParmValues - the values of the parameter - this element contains one or more sas-alerts-sp:ParmValue elements.
sas-alerts-sp:Package Describes the package. This element is present only if the result type is a transient package, a SAS server based file package, or a WebDAV server based package.

When the stored process starts executing an empty Package element is created. After execution is complete, the following two elements are added:

  • sas-alerts-sp:PackageEntityKey - the Information Service entity key of the package
  • sas-publish:Package - an event as described in the Publish Service, which describes the package
sas-alerts-sp:ExecutionExceptions Describes any exceptions encountered in the execution of the stored process. Contains zero or more Exception entries. When the stored process starts executing an empty ExecutionExceptions element is created. After execution is complete, Exception elements are added if exceptions occurred.
sas-alerts-sp:Exception Describes the exception: the message, the cause, and a stack trace of the root exception.

A sample alert is shown:

    <?xml version="1.0" encoding="UTF-8"?>
    <sas-event:Event xmlns:sas-event=
       "http://www.sas.com/xml/namespace/services.events-1.1"
       sas-event:name="com.sas.services.storedprocess.ExecutionStatusEvent">
       <sas-event:Header>
          <sas-event:Version>1.0</sas-event:Version>
          <sas-event:SentAt>2008-04-02T20:16:48Z</sas-event:SentAt>
          <sas-event:Response sas-event:type="none"/>
          <sas-event:Properties>
             <ResultType xmlns=
                "http://www.sas.com/xml/namespace/services.alerts.sp-1.1">512
                </ResultType>
             <Status xmlns=
                "http://www.sas.com/xml/namespace/services.alerts.sp-1.1">3
                </Status>
             <Version xmlns=
                "http://www.sas.com/xml/namespace/services.alerts.sp-1.1">2.0
                </Version>              
             <StoredProcessName xmlns=
                "http://www.sas.com/xml/namespace/services.alerts.sp-1.1">SP2_PSR (PR Existing Instance - Workspace)
                </StoredProcessName>
          </sas-event:Properties>
       </sas-event:Header>
       <sas-event:Body>
          <sas-alerts-sp:StoredProcessAlert xmlns:sas-alerts-sp=
             "http://www.sas.com/xml/namespace/services.alerts.sp-1.1"
             sas-alerts-sp:version="2.0"
             sas-alerts-sp:name="Sd7458859"
             sas-alerts-sp:startTime="2008-04-02T20:15:39.638Z"
             sas-alerts-sp:endTime="2008-04-02T20:16:17.211Z">
             <sas-alerts-sp:AlertEntityKey>
                storedprocessalert+dav:RGWebDav/noname/PR/MyInbox/Sd7458859/storedprocessalert
                </sas-alerts-sp:AlertEntityKey>
             <sas-alerts-sp:Description>This alert describes the execution
                of stored process "SP2_PSR (PR Existing Instance - Workspace)" which completed at
                2008-04-02T20:16:17.211Z.</sas-alerts-sp:Description>
             <sas-alerts-sp:StoredProcessName>SP2_PSR (PR Existing Instance - Workspace)
                </sas-alerts-sp:StoredProcessName>
             <sas-alerts-sp:StoredProcessDescription>
                Sample Product Sales Report (PSR) Stored Process - to the Personal Repository reusing an exisiting instance.
                </sas-alerts-sp:StoredProcessDescription>
             <sas-alerts-sp:Status>3</sas-alerts-sp:Status>
             <sas-alerts-sp:ResultType>512</sas-alerts-sp:ResultType>
             <sas-alerts-sp:StoredProcessEntityKey>
                StoredProcess+omi://Primary/reposname=primary/ClassifierMap;id=A5Z6U1YS.AK0016D1
                </sas-alerts-sp:StoredProcessEntityKey>
             <sas-alerts-sp:StoredProcessPath>
                SBIP://METASERVER/WSP2/SP2_PSR (PR Existing Instance - Workspace)(StoredProcess)
                </sas-alerts-sp:StoredProcessPath>
             <sas-alerts-sp:StoredProcessParameters>
                <sas-alerts-sp:Parameter>
                   <sas-alerts-sp:ParmName>pCountry
                      </sas-alerts-sp:ParmName>
                   <sas-alerts-sp:ParmValue>Canada
                      </sas-alerts-sp:ParmValue>
                </sas-alerts-sp:Parameter>
                <sas-alerts-sp:Parameter>
                   <sas-alerts-sp:ParmName>pYear
                      </sas-alerts-sp:ParmName>
                   <sas-alerts-sp:ParmValue>1993
                      </sas-alerts-sp:ParmValue>
                </sas-alerts-sp:Parameter>
                <sas-alerts-sp:Parameter>
                   <sas-alerts-sp:ParmName>_result
                      </sas-alerts-sp:ParmName>
                   <sas-alerts-sp:ParmValue>PACKAGE_TO_WEBDAV
                      </sas-alerts-sp:ParmValue>
                </sas-alerts-sp:Parameter>
                <sas-alerts-sp:Parameter>
                   <sas-alerts-sp:ParmName>_publish_to_pr
                      </sas-alerts-sp:ParmName>
                   <sas-alerts-sp:ParmValue>true
                      </sas-alerts-sp:ParmValue>
                </sas-alerts-sp:Parameter>
                <sas-alerts-sp:Parameter>
                   <sas-alerts-sp:ParmName>_pr_collection_path
                      </sas-alerts-sp:ParmName>
                   <sas-alerts-sp:ParmValue>SPResults/collection1
                      </sas-alerts-sp:ParmValue>
                </sas-alerts-sp:Parameter>
             </sas-alerts-sp:StoredProcessParameters>
             <sas-alerts-sp:Package>
                <sas-alerts-sp:PackageEntityKey>
                   package+dav://RGWebDav/noname/PR/MyResults/SPResults/collection1/package
                   </sas-alerts-sp:PackageEntityKey>
                <sas-publish:Package xmlns:sas-publish=
                   "http://www.sas.com/xml/namespace/services.publish-1.1"
                   sas-publish:version="1.0" sas-publish:description=
                   "1993 Sales Report for Canada"
                   sas-publish:packageUrl=
                   "http://d14844.na.sas.com:80/DAVStuff/noname/PR/MyResults/SPResults/collection1"
                   sas-publish:transport="webdav" category="sales"
                   context="product">
                   <sas-publish:Entries>
                   <sas-publish:Entry 
                     sas-publish:description="Sales Report: Tabular" sas-publish:type="html">
                     <sas-publish:Html sas-publish:name="body.htm" sas-publish:type="body"
                     sas-publish:url="body.htm"/>
                   </sas-publish:Entry>
                   </sas-publish:Entries>
                </sas-publish:Package>
             </sas-alerts-sp:Package>
             <sas-alerts-sp:ExecutionExceptions/>
          </sas-alerts-sp:StoredProcessAlert>
       </sas-event:Body>
    </sas-event:Event>
 

Accessing Alerts

Alerts describing the execution of a stored process are placed in the MyInbox folder of the Personal Repository. The first step is to access the Personal Repository. Personal Repository documentation provides code fragments that show how to obtain a reference to MyInbox.

    FolderInterface myInbox = ... get a reference to "MyInbox".
    // A list of all alerts can be obtained.
    List list = myInbox.getItemsByClass(StoredProcessAlertItem.class);
    // These alerts might be presented to the user.
    // Alternatively, a specific alert can be obtained by name.
    StoredProcessAlertItem alert =
       (StoredProcessAlertItem)myInbox.getItemByClass(alertName, StoredProcessAlertItem.class);
    // Various elements of the alert can be obtained as follows from the getProperty() method:
    // Note: Constants.NS_STOREDPROCESS_ALERT_PREFIX_COLON maps to "sas-alerts-sp:"
    String prefix = "//" + com.sas.services.util.Constants.NS_STOREDPROCESS_ALERT_PREFIX_COLON;
    String statusStr = alert.getProperty( prefix + "Status" );
    String resultTypeStr = alert.getProperty( prefix + "ResultType" );
    int status = Integer.parseInt(statusStr);
    int resultType = Integer.parseInt(resultTypeStr);
    if (status ==  ExecutionBaseInterface.STATUS_COMPLETED_WITHOUT_EXCEPTION) {
       if (resultType == StoredProcess2Interface.RESULT_TYPE_PACKAGE) {
          PackageInterface pkg = alert.getResults();
          ResultPackageInterface rpkg = (ResultPackageInterface)pkg.newServiceObject();
          ... process the package ...
       }
    }
 

Changes for 9.3:

  • New metadata modeling of stored processes (version 2) was introduced. However, 9.2 (version 1) stored processes are also supported and a metadata repository is allowed to have a mix of version 1 and version 2 stored processes. The SAS Management Console permits the conversion of an individual stored process from one version to another. More information about conversion between versions including how the value of _result may change can be found here.
  • Version 2 Stored processes are Application Server based; version 1 are Logical Server based.
  • Version 2 Stored processes may be marked to allow execution on Application Servers other than the one configured in metadata. For such stored processes, the setServerContext() method can be used to specify the Application Server to execute on at run time.
  • Version 2 Stored processes support streaming and output parameters on Workspace servers. However, Stored Process server sessions (and consequently Replay stored processes) are not supported on Workspace servers.
  • Version 2 stored processes support SAS files and SAS datasets which can be bound by API methods to client side or server side files and datasets.

Changes for 9.2:

  • Pre-9.2, a stored process service object was represented by a StoredProcessInterface object; in 9.2, due to the metadata format changed a service object is captured by a StoredProcess2Interface. Calling the execute method on the service object returned an ExecutionInterface pre-9.2; in 9.2 it returns an Execution2Interface. The optional listener parameter to execute implemented an ExecutionStatusListenerInterface pre-9.2; in 9.2 it implements an ExecutionStatusListener2Interface.
  • The Results model has changed to one of describing the capabilities of the stored process.
  • In 9.2, input parameters use the Prompting Framework.
  • Pre-9.2, an input parameter of a stored process which ran on a Workspace server was not allowed to have more than one value; in 9.2 certain input parameters generate multiple name-value pairs.
  • The execution of a stored process can be aborted by calling the abort() method on Execution2Interface.
  • New input parameters _PROGRAM, _METAFOLDER and _CLIENT are generated by the service.
  • Stored process alerts are at version 2.0 and the version number has been added to the properties in the alert header. The values contained by sas-alerts-sp:ResultType, sas-alerts-sp:startTime and sas-alerts-sp:endTime are not backward compatible.

Using StoredProcessInterface to execute 9.2 stored process:

Stored processes created pre-9.2 were created using a pre-9.2 SMC and a StoredProcessInterface was used to execute them. Stored processes created by a 9.2 SMC have an improved model, are modeled differently in metadata and are executed by StoredProcess2Interface objects. The migration process converts stored processes from the pre-9.2 format to the 9.2 format. The implementation backing the original StoredProcessInterface object has been enhanced so that a stored processes migrated to the new format can be processed by it. This section describes how 9.2 stored processes are interpreted by StoredProcessInterface.

9.2 style prompts are converted to the pre-9.2 Entity based model using the convertPromptGroupToEntityconvertPromptGroupToEntity method of PromptToEntityConverter.

Data Sources and Data Targets are added to the list of output streams and input streams supported by the Stored Process.

Pre-9.2 stored processes had different result types. 9.2 stored processes have result capabilities with the type of result being driven by the capabilities allowed and prompt values. The following describes how different combinations of capability and prompts (converted to the Entity model) in a migrated stored process map to the pre-9.2 result type of StoredProcessInterface when a StoredProcessInterface is constructed.

If the "_result" parameter is missing or present with no value:

  • No package or stream capability specified. This results in the result type being set to RESULT_TYPE_NONE
  • Package capability specified. Stream capability may or may not be specified. This results in the result type being set to RESULT_TYPE_TRANSIENT_PACKAGE
  • Package capability not specified. Stream capability specified. This results in the result type being set to RESULT_TYPE_STREAM

If the "_result" parameter has a non-empty value:

  • The value of "_result" is set to (a case-insensitive compare is done) "PACKAGE_TO_REQUESTER". If package capability is not specified or the server selected is not a Workspace server an exception is thrown. Parameter "_archive_path" should be non-empty and point to the location where the package will be created. The presence of a non-empty "_archive_path" parameter determines the name of the package; if missing, a new instance is created. A PermanentPackageResultHints is appropriately constructed and the result type is set to RESULT_TYPE_PERMANENT_FILE_PACKAGE
  • The value of "_result" is set to (a case-insensitive compare is done) "PACKAGE_TO_ARCHIVE". If package capability is not specified or the server selected is not a Stored Process server an exception is thrown. Parameter "_archive_path" should be non-empty and point to the location where the package will be created. The presence of a non-empty "_archive_path" parameter determines the name of the package; if missing, a new instance is created. A PermanentPackageResultHints is appropriately constructed and the result type is set to RESULT_TYPE_PERMANENT_FILE_PACKAGE
  • The value of "_result" is set to (a case-insensitive compare is done) "PACKAGE_TO_WEBDAV". If package capability is not specified an exception is thrown. Parameter "_publish_to_pr" determines which of the following cases applies:
    • "_publish_to_pr" is present and set to (a case-insensitive compare is done) "true". "_create_new_package_instance" (a case-insensitive compare to "true" is done) determines whether a new package instance is created and the value of "_pr_collection_path" determines where in the Personal Repository the package is published. A WebDAVPackagePRResultHints is appropriately constructed and the result type is set to RESULT_TYPE_PERMANENT_WEBDAV_PACKAGE
    • "_publish_to_pr" is absent or present and not set to (a case-insensitive compare is done) "true". "_create_new_package_instance" (a case-insensitive compare to "true" is done) determines whether a new package instance is created and the value of "_collection_url" (an exception is thrown if absent) determines the location where in WebDAV the package is published. This location is used to find the appropriate WebDAV server in metadata - for a match to occur, the file portion of the URL should match a base-path of the WebDAV server. A WebDAVPackagePRResultHints is appropriately constructed and the result type is set to RESULT_TYPE_PERMANENT_WEBDAV_PACKAGE. If a proxy URL is needed, the WebDAV server needs to be configured to contain the proxy URL.
If the value of "_result" is not one of the values described above, an exception is thrown.

Do note the above functionality is provided for compatibility purposes, so that old code can run newly migrated stored processes. The functionality is not intended for newly created stored processes to be run using old code. And, StoredProcessInterface cannot be used to execute Version 2 stored processes introduced in 9.3.