Skip to main content

Notice: This Wiki is now read only and edits are no longer possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

Difference between revisions of "Aperi Data Server R2 Extensibility"

m (How do you create and register a new service provider?)
m (How do you create and register a new service provider?)
Line 39: Line 39:
 
* [http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.aperi/org.eclipse.aperi.server.data/src/org/eclipse/aperi/server/svp/ServerSvp.java?root=Technology_Project&view=markup&pathrev=v20070111 ServerSvp]. The request handlers associated with the Server service provider handle generic management tasks (e.g., service provider startup / shutdown, agent registration, etc.).
 
* [http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.aperi/org.eclipse.aperi.server.data/src/org/eclipse/aperi/server/svp/ServerSvp.java?root=Technology_Project&view=markup&pathrev=v20070111 ServerSvp]. The request handlers associated with the Server service provider handle generic management tasks (e.g., service provider startup / shutdown, agent registration, etc.).
  
The service providers mentioned above are defined in the org.eclipse.aperi.server.svp package of the org.eclipse.aperi.server.data plugin. Their availability largely eliminates the need to put together new service providers. Service providers and request handlers are loosely coupled. A new request handler can be associated with any existing service provider.
+
The availability of the service providers listed above largely eliminates the need to implement new service providers. Service providers and request handlers are loosely coupled. A given request handler can be associated with any existing service provider.
  
All the above said, there may be certain situations that require the creation and registration of a new service provider. For example, there may be a desire to logically isolate some set of request handlers from all of the other request handlers in the Data Server. Or, there may be a requirement that the message log output produced by some set of request handlers appear in a specific file. Whatever the case may be, creating and registering a new service provider can be accomplished by carrying out the following steps:
+
All of the above said, there may be certain situations that require the creation and registration of a new service provider. For example, there may be a desire to logically isolate some set of request handlers from all of the other request handlers in the Data Server. Or, there may be a requirement that the message log output produced by some set of request handlers appear in a specific file (all of the message log output produced by the request handlers associated with a given service provider is written to a single file). Whatever the case may be, creating and registering a new service provider can be accomplished by carrying out the following steps:
  
* <b>[1]</b> Define a request type constant for the service provider. It must be a string value unique to, at least within the JVM, the service provider. In support of uniqueness, the use of a Java-based naming scheme is recommended. For example, the request type constant associated with the Agent service provider is org.eclipse.aperi.agent.svp.AgentSvp, the name of the Agent service provider implementation class. The request type constant should be placed in a class defined in a package that is exported by the plugin in which it resides. Request type constants are used to set the typeCode instance variable of request objects (instances of the Request (org.eclipse.aperi.request) class), which is involved in routing requests, within the Data Server, to the appropriate service provider. Here is a sample request type constant definition:
+
* <b>[1]</b> Define a request type constant for the service provider. It must be a string value unique to, at least within the JVM, the service provider. In support of uniqueness, the use of a Java-based naming scheme is recommended. For example, the request type constant associated with the Agent service provider is <i>org.eclipse.aperi.agent.svp.AgentSvp</i>, the fully qualified name of the Agent service provider implementation class. The request type constant should be placed in a class defined in a package that is exported by the plugin in which it resides. Request type constants are used to set the <code>typeCode</code> instance variable of [http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.aperi/org.eclipse.aperi.common/src/org/eclipse/aperi/request/Request.java?revision=1.2&root=Technology_Project&view=markup Request] objects. It is involved in routing requests, within the Data Server, to the appropriate service provider. Here is a sample request type constant definition:
  
 
<pre>
 
<pre>
Line 49: Line 49:
 
</pre>
 
</pre>
  
* <b>[2]</b> Define a request type metadata source for the service provider. There are three key pieces of metadata associated with request type constants. First there is the internal name, used to identify the service provider in trace output and error messages produced by the Data Server. Next, there is the external name, used to identify the service provider in the list of Data Server services presented in the GUI. And finally, there is the log prefix, used to name the message log files associated with the service provider. The metadata source should implement the IMetadataSource (org.eclipse.aperi.constants.metadata) interface and look like the RequestTypeSource (org.eclipse.aperi.constants.core.metadata) class. The plugin containing the metadata source must import the appropriate packages from org.eclipse.aperi.common. A request type metadata source might look something like this:
+
* <b>[2]</b> Define a request type metadata source for the service provider. There are three key pieces of metadata associated with request type constants. First there is the internal name, used to identify the service provider in trace output and error messages produced by the Data Server. Next, there is the external name, used to identify the service provider in the list of Data Server services presented in the GUI. And finally, there is the log prefix, used to name the message log files associated with the service provider. The metadata source should implement [http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.aperi/org.eclipse.aperi.common/src/org/eclipse/aperi/constants/metadata/IMetadataSource.java?revision=1.1&root=Technology_Project&view=markup  IMetadataSource] and look like the [http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.aperi/org.eclipse.aperi.common/src/org/eclipse/aperi/core/constants/metadata/RequestTypeSource.java?revision=1.1&root=Technology_Project&view=markup RequestTypeSource]. The plugin containing the metadata source must import the appropriate packages from the <code>org.eclipse.aperi.common</code> plugin. A request type metadata source might look something like this:
  
 
<pre>
 
<pre>

Revision as of 16:57, 23 January 2007

Introduction

NOTE: This page is still very much a work in progress!

The purpose of this page is to present information on how to extend the functionality provided by the Aperi Data Server. More than anything, this page should be viewed as a series of HOWTOs. It assumes knowledge of key Equinox / OSGi concepts (e.g., plugins, extension points, etc.), as well as a basic understanding of Aperi’s architecture. Below is a brief, high-level, outline of the topics this page addresses:

  • General Infrastructure
    • Deployment
    • Serviceability
  • Service Infrastructure
  • Resource Attribute Infrastructure
  • Job / Schedule Infrastructure
  • Alert Infrastructure

As with all software projects, Aperi will evolve over time. However, the content of this page is specific to its 0.2 release. This page should be viewed as a living document. It will evolve in response to the needs of developers looking to build on top of the Aperi platform. Please feel free to share any questions, comments, and / or concerns on either the Aperi Development mailing list or the Aperi newsgroup. Any and all feedback is welcome.

General Infrastructure

Deployment

Serviceability

Service Infrastructure

The key service infrastructure building blocks are service providers, request handlers, request objects, and response objects. Service providers handle thread management for, and coordinate message log output across, a set of request handlers. Request handlers are responsible for processing incoming request objects and producing corresponding response objects. This section focuses on answering the following questions related to the service infrastructure:

  • How do you create and register a new service provider?
  • How do you create and register a new request handler?
  • How do you create a custom request / response object?

How do you create and register a new service provider?

Before getting into a discussion of how to create and register a new service provider, it is important to note that the Data Server ships with the following service providers:

  • AgentSvp. The request handlers associated with the Agent service provider processes non-GUI originated requests. They take care of requests submitted by agents and handle several internal server-side jobs.
  • CimomSvp. The request handlers associated with CIMOM service provider are responsible for requests and internal server-side jobs that require communication with a CIMOM. The CIMOM service provider is intended to be used to process long running requests, isolating them from others that can be processed more quickly.
  • GuiSvp. The request handlers associated with the GUI service provider are designed to handle requests submitted by the GUI.
  • SchedulerSvp. The request handlers associated with the Scheduler service provider handle requests related to the Data Server scheduler (e.g., requests to obtain information about long running jobs, etc.).
  • ServerSvp. The request handlers associated with the Server service provider handle generic management tasks (e.g., service provider startup / shutdown, agent registration, etc.).

The availability of the service providers listed above largely eliminates the need to implement new service providers. Service providers and request handlers are loosely coupled. A given request handler can be associated with any existing service provider.

All of the above said, there may be certain situations that require the creation and registration of a new service provider. For example, there may be a desire to logically isolate some set of request handlers from all of the other request handlers in the Data Server. Or, there may be a requirement that the message log output produced by some set of request handlers appear in a specific file (all of the message log output produced by the request handlers associated with a given service provider is written to a single file). Whatever the case may be, creating and registering a new service provider can be accomplished by carrying out the following steps:

  • [1] Define a request type constant for the service provider. It must be a string value unique to, at least within the JVM, the service provider. In support of uniqueness, the use of a Java-based naming scheme is recommended. For example, the request type constant associated with the Agent service provider is org.eclipse.aperi.agent.svp.AgentSvp, the fully qualified name of the Agent service provider implementation class. The request type constant should be placed in a class defined in a package that is exported by the plugin in which it resides. Request type constants are used to set the typeCode instance variable of Request objects. It is involved in routing requests, within the Data Server, to the appropriate service provider. Here is a sample request type constant definition:
Insert sample code...
  • [2] Define a request type metadata source for the service provider. There are three key pieces of metadata associated with request type constants. First there is the internal name, used to identify the service provider in trace output and error messages produced by the Data Server. Next, there is the external name, used to identify the service provider in the list of Data Server services presented in the GUI. And finally, there is the log prefix, used to name the message log files associated with the service provider. The metadata source should implement IMetadataSource and look like the RequestTypeSource. The plugin containing the metadata source must import the appropriate packages from the org.eclipse.aperi.common plugin. A request type metadata source might look something like this:
Insert sample code...
Present GUI screenshot (list of Data Server services)...
  • [3] Register the request type metadata source associated with the service provider. The org.eclipse.aperi.common plugin defines the requestTypeSource extension point for registering request type metdata sources. The following XML snippet would be added to the plugin.xml of the plugin containing the metadata source presented above:
Insert sample XML content...

Request type metadata is used not only in the Data Server, but also in the Agent and the GUI. That means that the request type metadata source must be registered in multiple JVMs. Given that requirement, it makes sense to place the request type constant, and its associated metadata source, in a plugin separate from the one containing the actual service provider implementation. For example, the request type constants and metadata sources associated with the service providers that ship with the Data Server are defined in the org.eclipes.aperi.common plugin (see RequestType (org.eclipse.aperi.constants) and RequestTypeSource), while their implementations are in the org.eclipse.aperi.server.data plugin (e.g., AgentSvp).

  • [4] Create a request handler extension point for the service provider. The extension point is used to register request handlers with the service provider. Its definition should leverage the request handler extension point schema available in the org.eclipse.aperi.server.data plugin (requestHandler.exsd), and look something like this:
Insert screenshot of extension point wizard...
Insert sample code (stripped-down schema) (highlight schema inclusion)...

For the sake of reference, the request handler extension point schemas associated with the service providers that ship with the Data Server are available in the schema folder of the org.eclipse.aperi.server.data plugin.

  • [5] Extend the abstract ServiceProvider (org.eclipse.aperi.server) class:
/**
 * This abstract class must be extended by all service providers.
 * The methods declared in this class are used by the service
 * controller to initiate and terminate a service provider.
 */
public abstract class ServiceProvider
{
    /**
     * Must return the service ID that can be used to look up this
     * provider's name and major request code. The major request code
     * describes the category of requests that this provider is capable 
     * of processing.
     */
    public abstract String getTypeCode();

    /**
     * Should spawn 1 or more threads to handle the requests placed on
     * the passed ServiceQueue. Threading & routing of requests to your
     * service's request handlers can be managed by the RequestManager
     * class. Should return to caller after kicking off your threads.
     */
    public abstract void startup(ServiceQueue queue) throws Exception;

    /**
     * Should terminate all threads of execution, release all held 
     * resources and return to caller. The shutdownOption will be one of
     * Constants.SHUTDOWN_NORMAL or Constants.SHUTDOWN_IMMEDIATE.
     */
    public abstract void shutdown(byte shutdownOption);
}

The getTypeCode() method must return the request type constant associated with the service provider. The startup() method should instantiate and initialize a new RequestManager (org.eclipse.aperi.server). The RequestManager class manages the request handlers registered against the service provider. It takes care of thread management and is responsible for routing incoming requests to the correct handlers. The RequestManager must be constructed using the ID of the extension point setup to accommodate request handler registration for the service provider. The shutdown() method simply needs to dispose of the RequestManager created in startup(). A full service provider implementation might look something like this:

Insert sample code (see ServerSvp)
(use pseudocode comment to refer to loading service provider configuration) 
(comment parameters passed to RequestManager constructor)
  • [6] Register the service provider implementation. The org.eclipse.aperi.server.data plugin defines the serviceProvider extension point for service provider registration. The following XML snippet would be added to the plugin.xml containing the service provider implementation presented above:
Insert sample XML content...

How do you create and register a new request handler?

Request handlers are responsible for processing the requests sent to the Data Server. To do any work, they must be registered against an existing service provider. The Data Server ships with several built-in request handlers, available in the org.eclipse.aperi.server.handler.* packages of the org.eclipse.aperi.server.data plugin. How does one create and register a new request handler? By doing the following:

  • [1] Define a request handler constant for the request handler. It must be a string value unique to the request handler within the scope of such values associated with the service provider against which it will be registered. In support of uniqueness, the use of a Java-based naming scheme is recommended. For example, the request handler constant associated with the server status request handler registered against the Server service provider is org.eclipse.aperi.server.handler.server.ServerStatusHndlr, its fully-qualified class name. The request handler constant should be placed in a class defined in a package that is exported by the plugin in which it resides. Request handler constants are used to set the subType instance variable of request objects, which is involved in routing requests, within a service provider, to the appropriate request handler. Here is a sample request handler constant definition:
Insert sample code...
  • [2] Implement the RequestHandler (org.eclipse.aperi.server) interface:
/**
 * Describes an object capable of processing a work request. Optionally, an
 * implementation of this class can implement either the ThreadSafe interface
 * or the ThrowAway interface. Doing so affects caching in the request manager.
 * By default, request handler instances are cached in request manager threads.
 * If the ThreadSafe interface is implemented, an instance of the request
 * handler class will be cached by the request manager and shared across
 * all of its active threads. If the ThrowAway interface is implemented, no
 * instance of the request handler class will be cached. The ThrowAway
 * interface must take priority over the ThreadSafe interface.
 */
public interface RequestHandler {
    Response handle(Request request, Transceiver transceiver);
}

The RequestHandler interface is fairly straightforward, requiring implementation of just a single method, handle(). The Request argument contains the information put together by the party that submitted the request to the Data Server. The request handler returns the results of its work with Response (org.eclipse.aperi.request) object returned from handle(). The Transceiver (org.eclipse.aperi.request) argument is present to support two-way communication between the caller and the request handler during request processing, which is required in certain scenarios. Additional information about the Transceiver class is available in Communication Infrastructure section of this page.

The Javadoc on the RequestHandler interface presented above reference two additional interfaces, ThreadSafe (org.eclipse.aperi.server) and ThrowAway (org.eclipse.aperi.server). Both interfaces are reproduced below:

/**
 * Marker interface used to flag an object that can be driven by multiple
 * threads simultaneously. If a request handler class implements this
 * interface, its instances will be cached by the request manager and
 * shared across all of its active threads. The ThrowAway interface must
 * take priority over this interface.
 */
public interface ThreadSafe
{
}
/**
 * Marker interface used to flag an object that should be discarded when it
 * is no longer needed. If a request handler class implements this interface,
 * its instances will not be cached in either a request manager or any of its
 * threads. This interface must take priority of the ThreadSafe interface.
 */
public interface ThrowAway
{
}

The ThreadSafe and ThrowAway interfaces can be used to control the behavior of the request handler in the context of the thread management performed by a request manager, on behalf of a service provider. By default, a single instance of the request handler is allocated for, and cached within, every request manager thread. If the request handler is marked as thread safe, then a single instance is allocated and shared across all request manager threads. If the request handler is marked as throw away, then a new instance is allocated for every request. No caching is performed. It does not make sense for a request handler to implement both the ThreadSafe and ThrowAway interfaces. However, if such is done, the request manager errs on the side of safety, giving priority to the ThrowAway interface. As an aside, it should be noted that the request manager does all request handler allocation in a lazy fashion (i.e., only when necessary).

The request handler can be either single-phase or multi-phase. With a single-phase request handler, the caller is expected to send all of the data required to process its request in a single transmission. In turn, the request handler responds with a single transmission, via the Response object returned from its implementation of handle(). With a multi-phase request handler, the caller and request handler use the a Transceiver to communicate and exchange data while a given request is being processed. The Sample1PhaseHandler class, in the org.eclipse.aperi.server.handler package of the org.eclipse.aperi.server.data plugin, is an example of a single-phase request handler. The Sample2PhaseHandler class, defined in the same package, is an example of a multi-phase request handler.

It may be the case that the request handler must communicate with the Device Server to successfully process a request. If such is the case, rather than implementing the RequestHandler interface, the request handler should extend the DeviceRequestHndlr (org.eclipse.aperi.server.handler) class and implement the abstract deviceAPI() method:

/**
 * An implementation of this method should invoke Device Server API, place
 * the returned data in the response object and return. Any error condition
 * should cause Response.status to be set to Response.ERROR and an
 * appropriate message to be placed in Response.errorMessage.
 */
public abstract int deviceAPI(DeviceRequest request, Response response);

DeviceRequestHndlr handles the common task of initializing communication with the Device Server.

  • [3] Register the request handler implementation with an existing service provider. Every service provider should have an associated extension point for request handler registration. For example, the following XML snippet is used to register the server status handler with the Server service provider in the org.eclipse.aperi.server.data plugin:
<extension
    id="org.eclipse.aperi.server.handler.server.ServerStatusHndlr"
    name="org.eclipse.aperi.server.handler.server.ServerStatusHndlr"
    point="org.eclipse.aperi.server.data.serverHandler">
    <requestHandler impl=
        "org.eclipse.aperi.server.handler.server.ServerStatusHndlr"/>
</extension>

The request handler extension point associated with the Server service provider is org.eclipse.aperi.server.data.serverHandler. The id attribute of the extension tag is set to the request handler constant string value. The impl attribute of the requestHandler tag (defined in the request handler extension point schema, requestHandler.exsd in the org.eclipse.aperi.server.data plugin), is set to the name of the class that implements the RequestHandler interface. In line with the naming convention discussed above, it matches the request handler constant string value. The value assigned to the name attribute of the extension tag is not important.

It is important to note that request handlers and service providers are loosely coupled. In order to do anything useful, the request handler must be registered against at least one service provider. However, there is nothing that prevents it from being registered against multiple service providers. In fact, a request handler can even be registered against the same service provider multiple times, provided that each registration is performed under a different request handler constant (e.g., the built-in configuration settings handler of the Data Server, ConfigSettingsHndlr (org.eclipse.aperi.server.handler.server)).

How do you create a custom request / response object?

A requestData instance variable is defined in the Request class. It can be used to pass to custom request data objects to a request handler. If a request handler requires specification of a custom request data object, it should check the validity of an incoming request using the isDesiredType() method of RequestChecker (org.eclipse.aperi.backend). For example, the GUI login validation request handler, SignonHndlr (org.eclipse.aperi.server.handler.server), expects that requesData be an instance of SignonReq (org.eclipse.aperi.server.req). As such, it begins with the following block of code (comments added for explanation):

// Create response object assuming request will result in success
Response response = Response.getResponse(Response.SUCCESS, null);

// Check whether or not request.requestData is an instance of SignonReq
// The status of the response is set to error if such is not the case
if (!RequestChecker.isDesiredType(SignonReq.class, request, response)) {
    // The type of request.requestData is invalid
    // Return the error response to the caller
    // The response contains a message indicating what went wrong
    Response traceResult = response;
    if (TraceLogger.enableTrace) {
        TraceLogger.exit(
            SignonHndlr.class.getName(),
            "handle",
            traceResult);
    }

    return traceResult;
}

// The type of request.requestData is valid
// Obtain the custom request data object and move on ...
SignonReq sr = (SignonReq) request.requestData;

Custom request data objects must implement the Serializable interface and appropriately set the serialVersionUID class variable. Such is required because communication with the Data Server involves the use of object serialization.

The responseData instance variable defined in the Response class is similar to the requestData instance variable defined in the Request class. However, there is nothing equivalent to the isDesiredType() method of RequestChecker for custom response objects. The responseData instance variable can be used to pass custom response data objects from a request handler to a caller. It is important to note that custom request / response data objects must be available to both the code that submits requests / handles responses and their corresponding request handlers. Several request / response data objects are available in the org.eclipse.aperi.common plugin (e.g., see the org.eclipse.aperi.server.req package).

In addition to the creation of custom request / response data objects, as discussed above, it also possible to extend the Request and Response classes. For example, that it what was done to create the DeviceRequest (org.eclipse.aperi.TStorm.server.guireq) class, used for requests sent to the Data Server to be routed to the Device Server.

Resource Attribute Infrastructure

Job / Scheduler Infrastructure

Alert Infrastructure

Back to the top