This subsystem provides utilities to deploy and lookup SAS Foundation Services. SAS Foundation Services deployment configuration data is specified using Open Metadata Architecture (OMA) metadata. This data defines a set of services, their interdependencies, and their configuration data.

Foundation Services Deployment

SAS Foundation Services may be configured for deployment in either a standalone or distributed environment. A general discussion of deployment models is presented followed by an example of a standalone and distributed deployment.

  1. Deployment Configuration Overview
  2. Deployment Models
    1. Standalone
    2. Distributed

Foundation Services Facade

A foundation services facade provides capabilities to specify the deployments to be instantiated locally or looked up remotely. It also implements the com.sas.services.discovery.FindServiceInterface, so it, or a solution specific subclass, can be used for service discovery. This facade provides the capability to:

If the service deployment configuration specifies lookup of remote services instantiated by another process, this facade provides the capability to re-discover remote services in the event that a service lookup fails to locate any services satisfying the lookup constraints.

Foundation services are deployed using a ServiceLoader utility which is responsible for:

  1. Querying a metadata source for one or more service deployments
  2. Instantiating and initializing foundation services
  3. Registering deployed foundation services with a local Discovery Service

Foundation services deployment configurations are specified using the SAS Open Metadata Architecture (OMA) metadata schema.

Overview

This document discusses the topic of foundation services deployment. A service deployment is a collection of foundation services that specifies the data necessary to instantiate the services as well as dependencies upon other services. Interdependencies are used to ensure that when a collection of services is being deployed that they are deployed based upon their dependencies upon other services.

There are two ways one can persist a foundation services deployment that can be used to instantiate a collection of foundation services:

  1. SAS Metadata Repository
  2. File

The preferred mechanism for persisting a service deployment is a SAS Metadata Server. The motivation for this preference is that foundation services are represented using OMA metadata and managed by a SAS Management Console (SASMC) plug-in which supports a SAS Metadata Repository back-end store. Alternatively, a service deployment may be specified in any URL accessible source such as a file exported from a repository using the Foundation Services Manager plug-in to the SAS Management Console which is used to administer foundation services deployment configurations persisted in a repository.

Deployment Configuration Overview

Services are deployed based upon a deployment configuration that is specified in either a SAS Metadata Repository or in a URL accessible input source containing a deployment configuration (queried from the repository). The deployment configuration details information describing the service, its initialization data, and how it is to be used within the context of the Discovery Service:

Deployment Models

Two deployment models are supported:

  1. Standalone
  2. Distributed

Standalone Deployment

The standalone deployment model supports local access to services deployed within a JVM. This deployment model is intended for use by standalone application using its own private set of deployed services. Services employed in a standalone deployment must implement the com.sas.services.ServiceInterface. An abstract service class com.sas.services.AbstractService may be sub-classed to implement a service which is only intended to be used within a JVM.

Distributed Deployment

A distributed deployment is characterized by services which are shared among one or more JVM processes. These services are deployed in a particular JVM process, but are available to other JVM process via stubs that act as proxies to the deployed service. Services employed in a distributed deployment must be remoteable and implement the com.sas.services.RemoteServiceInterface. An abstract remote service class com.sas.services.AbstractRemoteService may be sub-classed to implement a service which is intended to be accessed from another JVM.

A foundation services bootstrapping process is typically responsible for deploying core services which are to be shared among foundation clients. One of the core services is a remote discovery service to which other foundation services such as logging, authentication, user, session, etc. are registered. Client processes will invoke a service loader to request that it locates remoteable discovery services. Discovered remote discovery services will provide the client with the capability to access the services of previously deployed core foundation services. Note that only those service registered with the remote discovery service are accessible to a remote client operating in a different JVM from the one in which the services were deployed.

Each process will employ a local discovery service to locate other services including any remote discovery services that may exist. Services which are to be shared among processes are deployed once and registered with a remote discovery service. The remote discovery service is used to provide access to its registered services to other client processes.

When a particular service is requested, the discovery service first checks its cache of locally registered services. If a service is found that satisfies the request then it is returned. However, if a service is not available locally then the discovery service will iterate its registered discovery delegates forwarding the lookup request.

In the following example, the client's discovery service has one discovery delegate which is a reference to the remote discovery service previously deployed by a process that handles deployment of core services for use by all foundation clients.

Discovery Service Model

Foundation Services Facade

A general foundation services facade may be used to start/terminate platform services and to locate deployed services.

Service Deployment Metadata Sources

Foundation services may be obtained from the following metadata sources:

The Foundation Services Manager plug-in is used to both import and export platform service deployments into from/to a file. This file is the one that would be used if you need to deploy services and are not using a SAS Metadata Server in your runtime environment. A snapshot of the "Export Service Deployment" dialog is shown below.

  1. Select a SAS Foundation Services deployment
  2. Invoke the action to export the metadata describing the selected SAS Foundation Services deployment to an XML file

Foundation Services Manager's Export Service Deployment action snapshot

  1. Specify the XML file to which the SAS Foundation Services deployment's metadata will be exported
  2. Export the SAS Foundation Services deployment.

Foundation Services Manager's Export Service Deployment dialog snapshot

Metadata Schema

This section discusses the SAS Metadata Architecture metadata used to represent foundation services. A separate section will detail each of the major metadata elements and how they're used to represent our data.

To provide a more concrete example, one may consider an actual service deployment available in this sample service deployment. This file is representative of an export file that would be used as an input metadata source to the ServiceLoader if one was not using a SAS Metadata Server as their metadata source for the foundation services deployment.

The following metadata elements are essential to the specification of a foundation services deployment:

Foundation Services Deployment (SoftwareComponent)

A foundation services deployment is represented by an OMA SoftwareComponent metadata element. This SoftwareComponent will contain a hierarchical subtree of metadata that represents the foundation services and other ancillary data.

Foundation Services Manager's navigation tree snapshot

In this example, there is a foundation services deployment called "Sample" which contains a folder "Core Services" which in turn contains the following services:

and another folder "Stored Process Service" which contains:

The purpose of the folders is to group services in a manner which facilitates deployment of a subset of the services defined for an application. For example, if one does not wish to deploy the Stored Process Service, then one could restrict deployment of services to those that are defined in the deployment group "Core Services". In this case only the Authentication, Information, Logging, Session, and User services would be deployed. If a deployment group restriction is not specified then all services will be deployed.

<SoftwareComponent
   Name="Sample"
   ClassIdentifier="ABC1234567890" />

In our case we have a SoftwareComponent with a Name attribute with a value of "Sample". This is the name of the SoftwareComponent that one needs to specify whenever the ServiceLoader is used to load services. The ClassIdentifier attribute is a value that's used to designate a SoftwareComponent as one that is used to represent a foundation services deployment.

A SoftwareComponent is associated with Tree elements via a SoftwareTrees association. One can view these Tree elements as just folders that provide are means to organize services within a deployment hierarchy.

Foundation Services (ServiceComponent)

A foundation service is represented using the ServiceComponent metadata element. To represent a foundation service as a ServiceComponent, one needs to specify:

Attribute
NameValue
ClassIdentifierABC1212121212
FactoryClassNameThe fully qualified Java class name for an implementation of com.sas.services.ServiceFactoryInterface. The ServiceLoader will acquire an initialized instance of the service from this factory.
IsRemotelyAccessible[ 0 | 1 ]
where 0 specifies that the service is not accessible by remote clients and 1 indicates that it is. A service should specify 0 if its only intended for use within the application in which it was instantiated.

Here's an XML snippet detailing a ServiceComponent representing a Logging Service.

<ServiceComponent
   Name="Foundation Logging Service"
   Desc="The business intelligence logging service. The Logging Service is used to send runtime messages to one or more output destinations."
   ClassIdentifier="ABC1212121212"
   FactoryClassName="com.sas.services.logging.LoggingServiceFactory"
   IsRemotelyAccessible="" >

Foundation Service Interface (ServiceType)

Each service will implement one or more service interfaces. These interfaces define the services that a service provides to its consumers. When one uses the Discovery Service to locate services, one specifies the desired service interfaces. An implementation of the Logging Service satisfies the following interfaces: Therefore if one wanted to have the Discovery Service find a deployed Logging Service then one would ask it to locate an implementation of com.sas.services.logging.LoggingServiceInterface. Note that all services implement the base interface RemoteServiceInterface regardless of whether they're actually a local or distributable service.

The Foundation Services Manager plug-in will provide a property sheet tab where one can view the service types offered by a particular service.

Foundation Services Manager's Service Types snapshot

Here's a snippet from the XML file that details the service interfaces for the Logging Service.

   <ServiceTypes>
      <ServiceType InterfaceName="com.sas.services.logging.LoggingServiceInterface" />
      <ServiceType InterfaceName="com.sas.services.RemoteServiceInterface" />
   </ServiceTypes>

Service Interdependencies (UsingComponents)

If a service depends upon one or more other services being available at the time its deployed, then one must specify this relationship using the UsingComponents association. For example, if the Authentication Service uses the Logging Service then it will specify a UsingComponents association to the Logging Service.

Here's an XML snippet that details a service's dependencies upon other services.

   <UsingComponents>
      <DeployedComponent Id="A529V630.A2000005" />
      <DeployedComponent Id="A529V630.A2000006" />
      <DeployedComponent Id="A529V630.A2000007" />
   </UsingComponents>
In this example our service requires that the services referenced by the three DeployedComponent elements be deployed before this service can be deployed.

If a service does not depend upon any other services then this association can be omitted.

Service Names (ServiceNames)

If the service is remotely distributable, it may specify a NamedService which is an association class that connects a service to a naming registry.

NOTE: The ServiceNames association is not applicable to a service that is being used in a standalone (non-distributable) deployment.

The XML snippet below shows an example of the User Service's (ServiceComponent) named service binding to an RMI registry. The NamedService designates

For RMI bindings the Type attribute will have a value of "RMI_BIND" or "RMI_REBIND". Use "RMI_BIND" if you don't want to overwrite a pre-existing binding (i.e. the bind attempt will fail if a binding already exists).

   <ServiceNames SEARCH="@Type='RMI_BIND' or @Type='RMI_REBIND'">
      <NamedService Id="A529V630.AR000008" Type="RMI_BIND" ServiceName="com.sas.services.user.UserService">
         <NamingServices>
            <DeployedComponent Id="A529V630.A2000004" Name="RMI Registry" ClassIdentifier="ABC1313131313">
               <ServiceTypes>
                  <ServiceType Id="A529V630.A3000003" InterfaceName="java.rmi.registry.Registry" />
               </ServiceTypes>
               <SourceConnections SEARCH="@ApplicationProtocol='RMI'">
                  <TCPIPConnection Id="A529V630.AE000002" HostName="localhost" Port="1099" />
               </SourceConnections>
            </DeployedComponent>
         </NamingServices>
      </NamedService>
   </ServiceNames>

RMI registry (DeployedComponent)

The other side of the NamedService association is a DeployedComponent that represents a naming registry. In our case, this will be an RMI registry.

To represent an RMI registry as a DeployedComponent, one needs to specify:

The host name should be either the IP address or distinguished name of the host on which the naming service is running.

NOTE: The value "localhost" is used as a convenience to specify the machine on which the registry is running. Use of the value "localhost" will only work if all clients are running on the same machine as the naming registry which typically will not be the case in a distributed deployment.

Loading a Service Deployment Configuration into a SAS Metadata Server's Repository

Metadata describing an application's service deployment can be imported into a repository using the Foundation Services Manager SMC plug-in.The following image shows the dialog that is used to select one or more files containing importable service deployment metadata.

Foundation Services Manager's Import Service Deployment action snapshot

Foundation Services Manager's Import Service Deployment dialog snapshot

Once a file has been selected this user interface will add a tree entry representing the import file. The file's child node(s) show the names of the application service deployments that are defined in the file.

A sample Foundation service deployment configuration file is provided.

Exporting a Service Deployment from a SAS Metadata Server to a File

For those service consumers who do not have access to a SAS Metadata Server repository in their runtime environment, our ServiceLoader provides a capability to deploy services based on metadata queried from a file. One would follow the following steps:
  1. Use the Foundation Services Manager plug-in to import a service deployment from a file into a SAS Metadata Repository or just use the plug-in to create a service deployment from scratch.
  2. Use the Foundation Services Manager plug-in to export the service deployment from a repsository to a file.
This process ensures that the metadata able to be parsed by the JOMA classes which are used to instantiate the metadata objects from their XML representation.

Deploying Services

This section presents the model from the perspective of the process which is responsible for loading services based upon a service deployment configuration. A utility class com.sas.services.deployment.ServiceLoader is employed to deploy the services.

Two service deployment strategies are supported:

Application Termination

When an application terminates it should destroy the local discovery service to ensure that all locally instantiated services are are destroyed. The local discovery service will destroy the services in reverse order from which they were instantiated. Handles to any remote services which were obtained from other applications will be cleared.


import com.sas.services.discovery.DiscoveryService;
...

// destroy the local discovery service
// and all locally deployed services

final DiscoveryServiceInterface discoveryService =
   DiscoveryService.defaultInstance().destroy();

Standalone Deployment

Use a standalone deployment if you want your application to have its own exclusive set of services. These services will only be available within to classes that are common to the class loader used to obtain the Discovery Service.

The following code snippet shows the ServiceLoader method that is used to instantiate and initialize services for a particular service deployment. In this example, services are deployed and registered with local discovery service. Note that in a standalone deployment there is no need to specify a Discovery Service since you are just using a local singleton.

ServiceLoader.deployServices(
   metadataSource,
   discoveryService);

Distributed Deployment

Use a distributed deployment if you want to share a service deployment among multiple applications. For example, if you have three applications X and Y and Z that you want to share the same Information Service then you would need to use a distributed deployment.

Communication with the RMI registry, remotely accessible SAS Foundation Services, and remote objects allocated by the services may optionally be secured using SSL RMI sockets. Refer to the SAS Core Net API for information on configuring your application to secure communication with remote objects using SSL RMI sockets.

For a distributed deployment one of your applications must be responsible for deployment a set of distributable services. The metadata defining the service configurations dictate whether or not a service is distributable or not. One application would deploy the remotely accessible services for the consumption of the client applications which would lookup its services.

In our example, lets assume that application X deploys the services. X would deploy the services in the same manner as if it was deploying a standalone set of services. However the difference would be that a distributed deployment specifies a deployment configuration for a Discovery Service which can be accessed from a remote JVM. This Discovery Service is registered with the the RMI registry using a well-known name. It would also contain a distributable configuration for any service that is intended to be accessible by remote clients.

When application X deploys the distributed version of the services they are registered with a local Discovery Service, just like in a standalone deployment, but they are also registered with a remoteable Discovery Service which is the mechanism by which application Y and Z will use to access the deployed services.

In application Y one does not need to deploy any services because application X has already done so. Application Y merely need to locate the remoteable Discovery Service which in turn has knowledge of the services deployed by application X.

The following code snippet shows how application Y would initialize its local Discovery Service with the remoteable Discovery Service that was previously deployed by application X. The metadata source object will designate the same source that application X used when it deployed the services.

ServiceLoader.lookupRemoteDiscoveryServices(
   metadataSource,
   discoveryService);

If a remoteable Discovery Service was found then it will be registered with the local discovery service that was passed into the service loader. At this point when one uses the local discovery service to find a service such as an Information Service it will first look in its local cache of registered services and not finding any it will then iterate its discovery delegates asking them to find an Information Service. In our case, there is one remoteable Discovery Service that is registered as a discovery delegate and it has access to a remoteable Information Service deployed by Application X. A stub to this remoteable Information Service is then returned to the caller in Application Y and it can then use the service.

The following code snippet shows how to obtain a handle to a local discovery service. This returns a singleton local discovery service.

import com.sas.services.discovery.DiscoveryService;
...

// get the local discovery service
DiscoveryServiceInterface discoveryService = DiscoveryService.defaultInstance();

The following code snippet shows how to specify a SoftwareComponent. The SoftwareComponent is the top-level metadata element used to represent an application's collection of foundation services.

// specify the name of the service deployment,
// the metadata SoftwareComponent, that serves as the
// hierarchy root for all metadata ServiceComponent elements.
String serviceDeploymentName = "My Services";

When loading services or looking up remote discovery services one needs to specify a metadata source that defines a service deployment configuration. Two metadata sources are supported:

Using a SAS Metadata Repository metadata source

The following code snippet shows how to specify a metadata source that will obtain an OMA compliant service deployment configuration from a repository. An IOMI connection is obtained from a MetaConnection which requires an XML formatted inputs describing the connection and login.

import com.sas.services.deployment.MetadataSourceInterface;
import com.sas.services.deployment.OMRMetadataSource;
import com.sas.services.deployment.ServiceLoader;
...

//
// create a metadata source for an Open Metadata Repository
//
// NOTE: 
// The identity's password should be encoded using:
//
// import com.sas.util.SasPasswordString;
//
// String encodedPassword = SasPasswordString.encode(
//       SasPasswordString.SAS001_ENCODING,
//       String unencoded)
//
String serverHost             = "<your SAS Metadata Server's host>";
String serverPort             = "9999";
String serverIdentityId       = "DOMAIN\\userid";
String serverIdentityPassword = "{sas001}TW9saHkx";
String serverRepositoryName   = "MyRepository";

String applicationDeploymentName = "Sample";
String serviceDeploymentGroupName1 = "Core";
String serviceDeploymentGroupName2 = "Stored Process";

Set groupNames = new HashSet(2);
groupNames.add(serviceDeploymentGroupName1);
groupNames.add(serviceDeploymentGroupName2);

// Create an instance of a metadata source which will later be queried
// for the specified service deployment
final OMRMetadataSource omrMetadataSource = new OMRMetadataSource(
   serverHost,
   serverPort,
   serverIdentityId,
   serverIdentityPassword,
   serverRepositoryName,
   applicationDeploymentName,
   groupNames);

Alternatively, one can specify a properties file containing the metadata source information. Use MetadataSourceFactory.newMetadataSource(Properties) to construct a metadata source object from a properties file.

For example,

software_component=My Services

deployment_group_1=Core
deployment_group_2=Stored Process

omr_host=acme.com
omr_port=8561
omr_repository=NameOfRepository
omr_user=DOMAIN\\userid
omr_password={sas001}TW9saHkx

Using a URL accessible metadata source

The following code snippet shows how to specify a metadata source that will obtain an OMA compliant service deployment configuration from a URL accessible file.

import com.sas.services.deployment.MetadataSourceInterface;
import com.sas.services.deployment.ServiceLoader;
import com.sas.services.deployment.URLMetadataSource;
...

//
// create a metadata source for a file URL
//
String applicationDeploymentName = "My Services";
String serviceDeploymentGroupName1 = "Core";
String serviceDeploymentGroupName2 = "Stored Process";

String fileUrl  = "file:/C:/xxx/sas_foundation_services.xml";
URL metadataUrl = new URL(fileUrl);
Set groupNames = new HashSet(2);
groupNames.add(serviceDeploymentGroupName1);
groupNames.add(serviceDeploymentGroupName2);
MetadataSourceInterface metadataSource = new URLMetadataSource(
   metadataUrl,
   applicationDeploymentName,
   groupNames);

Alternatively, one can specify a properties file containing the metadata source information. Use MetadataSourceFactory.newMetadataSource(Properties) to construct a metadata source object from a properties file.

For example, given a foundation services deployment named "My Services" which contains two groups of services named "Core" and "Stored Process" which have been exported from a SAS Metadata Server to a services deployment XML file named "sas_foundation_services.xml", one would specify the following properties. Note that if all services in the deployment are to be deployed, then one may omit the deployment_group_[n] properties.

software_component=My Services
deployment_group_1=Core
deployment_group_2=Stored Process

url=file:/C:/xxx/sas_foundation_services.xml

Deploy services using the previously metadata source and register them with the local discovery service. Refer to specifying a metadata source for a code snippet that shows how to obtain a local discovery service and specify a URL accessible metadata source.

import com.sas.services.deployment.ServiceLoader;
import com.sas.services.discovery.DiscoveryService;
...

// use the ServiceLoader to deploy services available from the
// specified metadata source.
//
// Pass in a reference to a Discovery Service, so that as the
// services are deployed they can be registered with the Discovery mechanism.
try {
   ServiceLoader.deployServices(
      metadataSource,
      discoveryService);
}
finally {
   // destroy the metadata source
   metadataSource.destroy();
}

Once services have been deployed the local discovery service is initialized with services and optionally discovery delegates. Within this process the local discovery service is now ready to service requests to find services. Service access in a distributed deployment is discussed in the next section.

Accessing Services in a Distributed Deployment

This section presents the model from the perspective of a client that uses remotely deployed services. For the case of a distributed deployment, a client operating in a JVM other than the one in which the services were deployed must first obtain a handle to a remote Discovery service to which distributed services have been registered. The following figure illustrates service loading in a distributed deployment model from the perspective of the service loading process.

Discovery Service (from perspective of service loading process)

Remote client processes will need to load their local discovery service with a remote discovery service obtained from a metadata source. Refer to specifying a metadata source for a code snippet that shows how to obtain a local discovery service and specify a URL accessible metadata source.

import com.sas.services.deployment.ServiceLoader;
import com.sas.services.discovery.DiscoveryService;

...

// use the ServiceLoader to lookup any previously deployed remote discovery
// services to which other deployed services are registered.
try {
   ServiceLoader.lookupRemoteDiscoveryServices(
      metadataSource,
      discoveryService);  // discovery service to which deployed services will be registered
}
finally {
   // destroy the metadata source
   metadataSource.destroy();
}

The following figure illustrates service loading in a distributed deployment model from the perspective of a remote client process.

Discovery Service (from perspective of a remote client)