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.
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:
Foundation services deployment configurations are specified using the SAS Open Metadata Architecture (OMA) metadata schema.
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:
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.
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:
com.sas.services.ServiceFactoryInterface. This factory will be
used by the ServiceLoader to obtain an initialized service.
com.sas.services.RemoteServiceInterface,
the base interface implemented by all services, is always one of the
service types. Additional service type(s) are specified to further
describe one's service capabilities.Two deployment models are supported:
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.
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.
A general foundation services facade may be used to start/terminate platform services and to locate deployed services.
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.
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:
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.
![]() |
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.
ServiceComponent)
A foundation service is represented using the ServiceComponent metadata element.
To represent a foundation service as a ServiceComponent, one needs to
specify:
| Attribute | |
|---|---|
| Name | Value |
| ClassIdentifier | ABC1212121212 |
| FactoryClassName | The 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="" >
ServiceType)com.sas.services.logging.LoggingServiceInterfacecom.sas.services.RemoteServiceInterfacecom.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.
![]() |
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>
UsingComponents)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.
ServiceNames)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
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>
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:
ClassIdentifier
attribute of "ABC1313131313"
ServiceType association with an InterfaceName of "java.rmi.registry.Registry"TCPIPConnection association to designate where the naming registry is running.
The TCPIPConnection specifies:
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.
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.
ServiceLoader provides a capability to deploy
services based on metadata queried from a file. One would follow the following
steps:
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:
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(); |
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); |
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:
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
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.
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.
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.