3 Developing Communication Services

This chapter provides a high-level description of how to develop communication services using Oracle Communications Services Gatekeeper. It also provides an overview of other parts of the API available to extension developers.

The Javadoc for the container API is available with the Services Gatekeeper documentation. See the ”All Classes” section of the Services Gatekeeper Java API Reference for details on the individual MBeans shown in this chapter. These javadoc files are also available from the Middleware_home/ocsg_pds/doc/javadoc directory of the Platform Development studio installation, where Middleware_home is the directory in which Oracle WebLogic Server is installed.

Tips for Creating or Extending Communication Services

The following tips are useful to consider when creating or extending communication services in Services Gatekeeper:

  • Make sure to follow the naming convention for the plug-in:

    Plugin_web service interface part_network protocol

  • Make sure to implement customMatch method of the PluginInstance (or ManagedPluginInstance) interface to verify if the plug-in can be used. This is important when there are multiple plug-ins for the same communication service.

  • Create exception types that are very specific to various error scenarios. This allows fine grain control of the alarms that are generated.

  • Have a clean separation between the application-facing and the network-facing sides of the plug-in.

  • Make sure to return all application-facing interfaces (callback included) and network-facing interfaces when implementing the getNorthInterfaces and getSouthInterfaces methods of PluginInstance.

  • Make sure to implement the resolveAppInstanceGroupdId method for each PluginSouth instance (if applicable).

  • When creating the management interface, consider if the management methods and fields should be cluster-wide or local.

  • Annotate the following:

    • Each parameter in the south object methods that you need to have when aspect calls back the resolveAppInstanceGroupId or the prepareRequestContext methods.

    • All the methods you want to be woven using the @Edr annotation, when you add additional EDR fields.

    • The specific arguments you want to see in the EDR for each annotated methods. Use either @ContextKey or @ContextTranslate depending on the kind of argument.

    See "Understanding Aspects, Annotations, EDRs, Alarms, and CDRs" for more information on annotation.

  • Add all the EDRs you are triggering to the EDR descriptor.

Communicating with Container Services

The container service APIs enable communication between a communication service and the container services.

All APIs for inter-working with the container services are found in com.bea.wlcp.wlng.api.*.

For a network protocol plug-in of a communication service to interact with Services Gatekeeper, it must be deployable in the context of Services Gatekeeper. After it is deployable, it can have access to certain utility functions.

Table 3-1 lists and describes the container services API packages.

Table 3-1 Summary of the Container Services APIs

Package Description

com.bea.wlcp.wlng.api.account

Represents an application instance and the related accounts, groups, and the states of the accounts.

com.bea.wlcp.wlng.api.edr.*

Annotations, interfaces and classes used when annotating EDRs. Descriptor classes for alarms, EDRs, and CDRs.

Helper classes for EDR listeners.

See "Understanding Aspects, Annotations, EDRs, Alarms, and CDRs".

com.bea.wlcp.wlng.api.event_channel

Classes to publish and listen to events over cluster-wide event channels.

See "Broadcasting Events".

com.bea.wlcp.wlng.api.interceptor

Interfaces and classes for service interceptors.

See "Using Service Interceptors to Manipulate Requests".

com.bea.wlcp.wlng.api.management.*

MBean helper classes.

See "Making Communication Services Manageable".

com.bea.wlcp.wlng.api.plugin.*

Plug-in related classes and interfaces.

See "Using the Plug-in Packages".

com.bea.wlcp.wlng.api.servicecorrelation

Interface to implement when you extend the existing service correlation mechanism.

See "Correlating Services".

com.bea.wlcp.wlng.api.statistics

Annotation for statistics.

See "Generating Statistics with Statistics Service".

com.bea.wlcp.wlng.api.storage

Interfaces and classes for the storage service.

See "Understanding Service Gatekeeper Storage Services".

com.bea.wlcp.wlng.api.timers

Factory for using commonj.timers API.

com.bea.wlcp.wlng.api.util

Classes and interfaces for commonly used functions, for example ID generator, InstanceFactory, and clustering.

com.bea.wlcp.wlng.api.work

Factory for using commonj.work API.


For complete documentation of these APIs, see the Services Gatekeeper Java API Reference.

Retrieving Implementation Instances Using InstanceFactory

Services Gatekeeper retrieves instances of a specified interface, class, or abstract class by using InstanceFactory. You retrieve an instance of the Instance Factory using the public static method getInstance. The factory itself has a single method called getImplementation which retrieves a class that implements a given interface or extends a given class.

To use an implementation:

  1. Locate the list that maps a given interface, class, or abstract class to the preferred implementation of that functionality. This list is provided in the JAR file's instancemap, a standard java.util.Properties file. Every JAR file can have its own instancemap. See Example 3-1 for an example.

    Note:

    The interface name used in the instancemap file must be unique across all plug-ins for a given service enabler. It is not possible to use the same interface in two instancemap files belonging to two different plug-ins and still map them to two different implementations.
  2. If a mapping is provided, instantiate the public constructor or static singleton method in the target class.

  3. If there is no explicit mapping, or if there is no public constructor or static singleton method for a mapped class, instantiate an object named according to the following pattern: theClass.getClass().getName() +”Impl” if this exists and has a public constructor or static singleton method.

Example 3-1 Example instancemap file

com.bea.wlcp.wlng.MyInterface=com.bea.wlcp.wlng.MyImplementation
com.bea.wlcp.wlng.MyOtherInterface=com.bea.wlcp.wlng.MyOtherImplementation

For details, see InstanceFactory in the ”All Classes” section of the Services Gatekeeper Java API Reference.

Obtaining JNDI Context with ClusterHelper

ClusterHelper is a helper class in the com.bea.wlcp.wlng.api.util.cluster package. It is used to obtain the JNDI Context for the network and access tier.

For details see ClusterHelper in the ”All Classes” section of the Services Gatekeeper Java API Reference.

Broadcasting Events

You can use EventChannel, a utility service interface, to broadcast events by other Services Gatekeeper server instances and register listeners for events originating in other Services Gatekeeper server instances. An event has a name and a value, where the name is an identifier for the event and the value is any object implementing the java.io.Serializable interface.

Retrieve an EventChannel instance using com.bea.wlcp.wlng.api.event_channel.EventChannelFactory. Use the methods of the EventChannel interface to do the following:

  • Deactivate all registered listeners (deactivateAllListeners)

  • Publish an event to all registered listeners (publishEvent)

  • Publish an event to one Services Gatekeeper instance (publishEventToOneNode)

  • Register an EventListener (registerEventListener)

  • Unregisters an EventListener (unregisterEventListener)

Use the EventChannelListener interface to receive events published using EventChannel. It contains the processEvent(String eventType, Serializable event, String source) method which receives an event.

Generating Statistics with Statistics Service

You can generate standard statistics or exception-related statistics. In addition to this, you can generate custom statistics explicitly. Register the type of statistics by using the addStatisticType operation in the Administration Console. For extensions, the statistics ID should be in the range 1000 to 2250.

Generating Standard Statistics

Standard statistics are generated automatically when a plug-in implements PluginNorth and PluginNorthCallBack interfaces.

The @Statistics annotation generates a statistics event when the method returns. It is defined in the com.bea.wlcp.wlng.api.statistics.Statistics package. The syntax of the annotation is:

@Statistics(id=My_Statistics_Type)

To explicitly generate statistics, annotate the method where you wish to generate statistics.

Generating Statistics when Exceptions are Thrown

The @ExceptionStatistics annotation generates a statistics event if an exception is thrown. It is defined in the com.bea.wlcp.wlng.api.statistics.ExceptionStatistics package. The syntax of the annotation is:

@ExceptionStatistics(id=My_Statistics_Type)

For more information, see the discussion on ”Managing and Configuring Statistics and Transaction Licenses” in Services Gatekeeper System Administrator's Guide.

Using the Plug-in Packages

The com.bea.wlcp.wlng.api.plugin.* packages contain a range of interfaces and classes for use by extension developers.

See "Understanding Communication Service Components" for more information.

Understanding Communication Service Management

Base classes and annotations for giving the Services Gatekeeper Administration Console or other JMX tools management access to communication services. See "Making Communication Services Manageable" for more information. Also see the com.bea.wlcp.wlng.api.management.* packages in Services Gatekeeper Java API Reference.

Understanding EDRs

See "Understanding Aspects, Annotations, EDRs, Alarms, and CDRs" for details on EDRs. Also see the com.bea.wlcp.wlng.api.management.* packages in Services Gatekeeper Java API Reference.

Enforcing Service Level Agreements

Service Level Agreement (SLA) enforcement operates on methods identified by the Java representation of the interface, and the method on the application-facing interface for the communication service or the service type of the communication service. Note that:

  • The content of the <scs> element defined in the <serviceContract> element in the SLA is the plug-in type for the plug-in.

  • An operation on the application-facing interface is represented in the rules according to the following scheme: <service name> and <operation name>.

  • Parameters in the operation are represented in the rules according to the following scheme:

    argn.parameter name

    where n in argn depends on the WSDL file that defines the application-facing interface; normally this is arg0.

    If the parameter in parameter name is

    • a composed parameter, the notation is according to the Java Bean notation for that parameter.

    • an enumeration, the notation is according to the Java-representation of that parameter, parameter name.enumeration value. The enumeration value is the string representation.

  • SLA enforcement can also be done for a certain service type. The service type is defined when generating the communication service or network protocol plug-in using the Platform Developer's Studio Wizard. SLA enforcement for service types relates to quotas and request rates and are defined under the <serviceTypeContract> element.

For enforcement of custom SLAs, see "Creating Custom Runtime SLAs".

Correlating Services

Service providers often bundle separate services into a single unit for charging purposes. For example, a subscriber sends an SMS to the provider requesting the location of the coffee shop closest to her current location. In completing that request, the application provides three services. It receives the network-initiated SMS, performs a user location lookup on the customer and finally, sends the customer an MMS with a map showing the requested information. Services Gatekeeper provides the framework for a Service Correlation service that uses a service correlation ID (SCID) to combine/correlate all three Services Gatekeeper services into a single service charging unit.

About Service Correlation Identifiers

This service correlation ID is a string that is captured in all CDRs and EDRs generated by Services Gatekeeper. It is propagated in the SOAP header sent to and from the application. The CDRs and EDRs use this data to provide special treatment for a given chain of service invocations, such as applying charging to the chain as a whole rather than to the individual invocations.

Services Gatekeeper does not provide the SCID and it does not check whether the SCID is unique. The SCID is stored in the Oracle Label Security (OLS) work context, so that it can be accessed by both the access tier and the network tier.

The Service Correlation class registers itself as a RequestContextListener. The application or by an external mechanism that the communication service provides the SCID in the following way:

  • When the chain of services is initiated by an application-initiated request, the application provides and ensures a unique SCID within the chain of service invocations.

    Note:

    If a custom service correlation service supplies the SCID, it is the responsibility of the custom service to ensure the uniqueness of the SCID.

    When the application-initiated request traffic enters the plug-in, the Service Correlation service takes the SCID from the WorkContext interface instance and places it in the RequestContext class object, where it will be available to the EDR service.

  • When the chain of services is initiated by a network-triggered request, Services Gatekeeper calls an external interface to get the SCID. This interface must be implemented by an external system. No utility or integration is provided out of the box; this must be a part of a system integration project. It is the responsibility of the external system to provide a unique SCID.

    When the network-initiated request traffic leaves the plug-in, the Service Correlation service takes the SCID from the RequestContext object and places it in the WorkContext object, where it can be retrieved by the SOAP Handler and passed along to the application.

Managing Service Correlation Identifiers

A communication service needs to create a way of storing and retrieving the Service Correlator ID (SCIDs), because a RequestContext object exists only for the lifetime of a single request and SCIDs may need to be stored across several invocations.

To store and retrieve SCIDs, you use the following:

  • ExternalInvocation interface

    The ExternalInvocation interface has two methods, one to store the Service Correlation ID and the other to retrieve it. The ExternalInvocation implementation class should have an empty public constructor or a static method that returns itself. The implementor is free to modify the ID once it has been stored, or to use the ExternalInvocation object to create IDs in the first place.

    For an application-initiated request, the Service Correlation service takes the SCID (should there be one) out of the WorkContext of the request, and automatically attempts to store it in an object of this type before putting the SCID in the RequestContext.

    When a network-initiated request is leaving the plug-in, the Service Correlation service verifies the SCID before storing it in the WorkContext. The service automatically attempts to retrieve an SCID from an object of this type using the SCID (should there be one) it finds in the RequestContext object. In this way, if the ExternalInvocation object has modified the SCID in any way, the modified version is put in the WorkContext and sent on to the application.

  • ExternalInvocationFactory class

    The ExternalInvocationFactory class is used by the Service Correlation service to locate and instantiate the correct ExternalInvocation object. It does this by using an instancemap entry such as:

    com.bea.wlcp.wlng.api.servicecorrelation.ExternalInvocation=myPackageStructure.myImplClass

    where, myImplClass is the ExternalInvocation implementation.

  • ServiceCorrelation package

    This package manages the transport and storage of the Service Correlation ID across multiple service invocations.

Creating a Custom Service Correlation

To create a custom service correlation:

  1. Create a JAR file that includes your code. For example:

    Example 3-2 Sample Custom Service Correlation

    package myPackageStructure;
    import com.bea.wlcp.wlng.api.servicecorrelation.ExternalInvocation;
    import com.bea.wlcp.wlng.api.servicecorrelation.ExternalInvocationException;
    
    public class MyImplClass implements ExternalInvocation {
     public MyImplClass() {
     }
     public String pushServiceCorrelationID(String scID, String serviceName, String methodName, String spID, String appID, String appInstGrp) throws ExternalInvocationException {
      // your code here
      return scID;
     }
    
     public String getServiceCorrelationID(String scID, String serviceName, String methodName, String spID, String appID, String appInstGrp) throws ExternalInvocationException {
      // your code here
      return scID;
     }
    
    }
    
  2. Create the instancemap using ExternalInvocationFactory.

  3. Put the instancemap file in the JAR file. This makes your custom service correlation available to the service interceptor InvokeServiceCorrelation.

  4. Put the JAR file in Domain_Home/lib.

Using Parameter Tunneling

Parameter tunneling is a feature that allows an application to send additional parameters to Services Gatekeeper and lets a plug-in use these parameters. This feature makes it possible for an application to tunnel parameters that are not defined in the application-facing interface and can be seen as an extension to it.

See "Dynamically Customizing AVPs for Applications" for more information and an example SOAP header.

Understanding Service Gatekeeper Storage Services

The storage services provided in Services Gatekeeper are of two types, described below:

Storing Configuration Data with ConfigurationStore

The Services Gatekeeper container exposes a ConfigurationStore Java API that communication services can use to store simple configuration parameters instead of using JDBC and caching algorithms in each module.

Note:

This utility is intended for configuration parameters only, not traffic data.

All data stored in a ConfigurationStore are stored in a database table and cached in memory.

Below are the characteristics of a ConfigurationStore:

  • It is a named store.

  • Parameters stored in it must be initialized before they can be used.

  • Stores can be either domain wide (shared) or limited to a single Services Gatekeeper server (local). The domain wide store type replicates all data changes to all servers in the cluster, while the local store type keeps a different view of the parameters on different servers and data changes affect only the view for that particular server.

  • Parameters stored in a ConfigurationStore are persisted to the database.

  • Data in all ConfigurationStores are also cached in memory.

  • Only one instance of each named ConfigurationStore is cached in memory per server.

  • Updates to a cluster wide named ConfigurationStore is reflected in all cluster nodes.

  • The named ConfigurationStore only supports parameters of type Boolean, Integer, Long, String, and Serializable.

Interfaces

The Java interface APIs are found in the package com.bea.wlcp.wlng.api.storage.

The entry point to configuration stores is through the com.bea.wlcp.wlng.api.storage.configuration.ConfigurationStoreFactory using the following method:

public abstract ConfigurationStore getStore(String moduleName, String name, int storeType) throws ConfigurationException;

The ConfigurationStore service exposes an interface with the following features:

  • Methods to initialize the store with the following data types:

    • Boolean

    • Integer

    • Long

    • String

    • Serializable

    A ConfigurationStore is initialized using a name in key/value pair. You get and set configuration parameters using the key.

  • Methods to set and get the following data types:

    • Boolean

    • Integer

    • Long

    • String

    • Serializable

  • Methods to add and remove listeners for notifications on updates.

    When a parameter has been updated in one instance of the ConfigurationStore, a notification is broadcast to all other instances of the ConfigurationStore.

Example 3-3 is an example of using the Configuration Store.

Example 3-3 Example of a ConfigurationStoreHelper

package com.acompany.plugin.example.netex.management;
import com.bea.wlcp.wlng.api.storage.configuration.*;
/**
 * Class used for handling the configuration store.
 *
 * @author Copyright (c) 2007 by BEA Systems, Inc. All Rights Reserved.
 */
public class ConfigurationStoreHandler {
/**
   * Constants used for the values stored in the store.
   */
  public static final String KEY_NETWORK_HOST = "KEY_NETWORK_HOST";
  public static final String KEY_NETWORK_PORT = "KEY_NETWORK_PORT";
/**
   * Constant to access either the local store. Note that these are
   * just names for the store.
   */
  private static final String LOCAL_STORE = "local";
/**
   * Local configuration store instance.
   */
  private ConfigurationStore localConfigStore;
/**
   * Constructor.
   *
   * @param pluginId The plugin id
   * @throws ConfigurationException An exception thrown if the initialization failed
   */
  public ConfigurationStoreHandler(String pluginId)
    throws ConfigurationException {

    ConfigurationStoreFactory factory = ConfigurationStoreFactory.getInstance();
    localConfigStore = factory.getStore(pluginId, LOCAL_STORE,
            ConfigurationStore.STORE_TYPE_LOCAL);
    // To obtain a shared configuration store, use ConfigurationStore.STORE_TYPE_SHARED

    localConfigStore.initialize(KEY_NETWORK_HOST, "localhost");
    localConfigStore.initialize(KEY_NETWORK_PORT, 5001);
  }

  /**
   * Sets an integer value in the local store.
   *
   * @param key The key associated with the value.
   * @param value The value to store.
   * @throws ConfigurationException An exception thrown if the operation failed
   */
  public void setLocalInteger(String key, Integer value)
    throws ConfigurationException {
    localConfigStore.setInteger(key, value);
  }
/**
   * Gets an integer value from the local store.
   *
   * @param key The key associated with the value.
   * @return The value associated with the key.
   * @throws InvalidTypeException thrown if type is invalid.
   * @throws NotInitializedException thrown if key value has not been
   * initialized.
   */
  public Integer getLocalInteger(String key)
    throws InvalidTypeException, NotInitializedException {
    return localConfigStore.getInteger(key);
  }
/**
   * Sets a string value in the local store.
   *
   * @param key The key associated with the value.
   * @param value The value to store.
   * @throws ConfigurationException An exception thrown if the operation failed
   */
  public void setLocalString(String key, String value)
    throws ConfigurationException {
    localConfigStore.setString(key, value);
  }
/**
   * Gets a string value from the local store.
   *
   * @param key The key associated with the value.
   * @return The value associated with the key.
   * @throws InvalidTypeException thrown if type is invalid.
   * @throws NotInitializedException thrown if key value has not been
   * initialized.
   */
  public String getLocalString(String key)
    throws InvalidTypeException, NotInitializedException {
    return localConfigStore.getString(key);
  }
}

Storing Traffic Data with StorageService

The Storage Service is used for storing data that is not configuration-related, but related to the traffic flow through a communication service, in a cluster-wide store. See ”Managing and Configuring Storage Service” in Services Gatekeeper System Administrator's Guide for an overview.

It provides mechanisms for:

  • Store initialization

    A store is created using the StoreFactory singleton class, by specifying either a key/value class pair where the value class should be a class that is unique to the Store (recommended), or a Store name.

  • Basic Map usage

    Since the Store interface extends the java.util.Map interface, it can be used as any other Map interface, and it is extended to be a cluster-wide view of the store.

  • Named queries

    In addition to the standard java.util.Map interface, Stores have support for a StoreQuery interface. The behaviors of these named queries are configured as part of the Storage Service configuration files. There is an option to define a cache filter and/or SQL query. An index specified for the Store can be used by implementing the IndexFilter interface for the cache filter. The index is automatically used for SQL queries that can make use of these indexes.

  • Store listener

    The Store API has support for registering StoreListeners. These listeners get notified if the Storage Service decides to automatically remove Store entries (based on configuration parameters). It is not notified if the extension itself removes entries from the Store.

  • Cluster locking

    Cluster-wide locking can be done using the Store interface. If the same entry in a Store may be modified on multiple servers at the same time, use cluster locking to avoid errors from concurrent modification when a transaction commits.

A communication service extension uses the StorageService through an API. The API functionality is implemented by a storage provider.

The storage provider offers a set these store types which are described in ”Understanding the Storage Service” in Services Gatekeeper System Administrator's Guide.

  • Cluster store

  • Write-behind database store

  • Write-through database store

  • Refresh-ahead database store

  • Database log store

All stores except for the cluster store are backed by a database table that is configured in a store configuration file.

When choosing a store type, take into consideration what kind of data that will be stored, how often it is written and read, and how long the data will stay in the store.

In general, if the lifetime for data is short enough that having the data duplicated in memory on two servers in the cluster, the cluster cache type should provide sufficient persistence. In other cases, a trade-off can be made between the data integrity transaction synchronized write-through operation gives and the performance given by asynchronous write behind. For data that just needs to be added to a database table, and is never read, the database log store is recommended. This store type could be optimized to avoid keeping cache entries in memory that will never be read anyway.

Table 3-2 outlines the recommendations on how to choose a store type.

Table 3-2 Store Type Recommendations

Access Type Lifetime of Data Store Type

Read mostly

Short

Cluster store

Read mostly

Long

Write-through database store

Write mostly

Short

Cluster store

Write mostly

Long

Write-behind database store

Write only

Any

Database log store

Read and Write

Short

Cluster store

Read and Write

Long

Write-behind database store


Extensions can use the com.bea.wlcp.wlng.api.storage.Store interface. This interface extends a java.util.Map interface and adds the following methods:

  • addListener: Adds a listener for the store.

  • getQuery: Gets a named query.

  • lock: Takes a cluster-wide lock.

  • release: Releases the current store instance.

  • removeListener: Removes a registered listener.

  • unlock: Unlocks a previously obtained cluster-wide lock.

The storage service uses configuration files that define the configuration for stores and the relationship between the cluster-wide store and the database table that backs the store. In each configuration file it is possible to define named queries towards the store. There is one configuration file for each plug-in. Each configuration store configuration file together with its XSD and any complex data types should be stored, created, and packaged in a JAR file in the directory domain_Home/config/store_schema, where domain_Home is the home directory of the Services Gatekeeper domain. The configuration file must be named wlng-cachestore-config-extensions.xml and it must be present in the root of the JAR file.

For details about the store configuration file, see the corresponding xsd: com.bea.wlcp.wlng.storage_6.0.0.0.jar/wlng-cachestore-config.xsd in Middleware_home/ocsg/modules where Middleware_home is the home directory of the WebLogic Server domain.

A Store is retrieved from com.bea.wlcp.wlng.api.storage.StoreFactory, either by the name of the store or by the class names of the key/value names. How to retrieve the Store depends on how the store is configured.

The store interface needs to be released when it is no longer needed. The programming model is to retrieve the Store from the StoreFactory when the Store is used, and to release it once it has finished, using try { .. } finally { store.release(); }.

Example 3-4 shows how to retrieve a store identified by key/value classes, operate on it, and release it.

Example 3-4 Using the Store Interface

Store<String, NotificationData> store = StoreFactory.getInstance().getStore(String.class, NotificationData.class);
try {
   notificationData = store.put(address.toString(), notificationData);
} finally {
   store.release();
}

If it is a named store, it can also be retrieved by name as illustrated below.

Example 3-5 Retrieving a store by name

Store<Serializable,Serializable> store = StoreFactory.getInstance().getStore("A", this.getClass().getClassLoader());

Store configuration file

The wlng-cachestore-config-extensions.xml configuration file defines attributes of the store and relations between the store, the cache for the store, and the mapping to a database table. This part is used by extension developers.

In addition, the configuration file can contain a section with mapping information between a store, the provider it uses, and the factory for the storage provider. This section should not be used by extension developers.

The XSD for the configuration file is located in com.bea.wlcp.wlng.storage_6.0.0.0.jar/wlng-cachestore-config.xsd in Middleware_home/ocsg/modules.

There is one configuration file for each plug-in. The file must be embedded in a JAR file that contains the file itself and any complex data types used. The JAR file must be stored in domain_Home/config/store_schema.

Below is an example of a store configuration file for extensions.

Example 3-6 Example of a store configuration file for extensions

<store-config>
  <db_table name="example_store_notification">

    <key_column name="address" data_type="VARCHAR(255)"/>
    <!-- bucket_column using default BLOB type -->
    <bucket_column name="notification_data_value"/>

    <value_column name="correlator" data_type="VARCHAR(255)">
      <methods>
        <get_method name="getCorrelator"/>
        <set_method name="setCorrelator"/>
      </methods>
    </value_column>

  </db_table>

  <store type_id="wlng.db.wt.example_store_notification"
         db_table_name="example_store_notification">
    <identifier>
      <classes key-class="java.lang.String"
               value-class="com.acompany.plugin.example.netex.notification.NotificationData"/>
    </identifier>
    <index>
      <get_method name="getCorrelator"/>
    </index>
  </store>

  <query name="com.bea.wlcp.wlng.plugin.example.netex.Query">
    <sql>
      <![CDATA[
    SELECT * FROM example_store_notification WHERE correlator = ?
   ]]>
    </sql>
    <filter-class>com.acompany.plugin.example.netex.store.FilterImpl</filter-class>
  </query>
</store-config>

A store is defined between the <store-config> and </store-config> tags.

Each Store consists of the following elements:

  • <store>: Defines the store.

  • <db_table>: Defines the database table used to persist data in the store.

  • <query>: Defines queries on the store. This is optional, only required if non-key queries are used with the store.

<store>

The <store> element defines the store itself. The type_id attribute defines the type of cache to use and a store type identifier. The ID must be mapped to a provider store mapping defined in wlng-cachestore-config.xml.

Which cache type to use depends on the use case. A store is identified by a class name. The type is given by adding the store type ID prefix followed by an identifier for the store. For example, the store wlng.db.wt.example_store_notification uses the cache type wlng.db.wt. Table 3-3 describes the correlation between a store type and a store type ID prefix.

Table 3-3 Store Types and Store Type ID

Store Type Store type ID prefix

Write behind database store

wlng.db.wb.

Write through database store

wlng.db.wt.

Cluster store

wlng.cache.

Database log store

wlng.db.log.


The db_table_name attribute identifies the database definition to use.

The <store> element contains the following elements:

  • <identifier>: Holds one <classes> element. This element defines the classes for the key and the value that defines the store. The class for the key is defined in the key-class attribute and the class for the value part is defined in the value-class attribute. If a named store is used, the name is given in the <name> element.

  • <index>: Defines an index on the cache and one or more get methods. The methods maps to an index on the corresponding columns in the table and potentially a cache index if supported by the provider in use.

<db_table>

The <db_table> element defines the database table used to persist data in store. The name attribute defines the table name to use. This name must be the same as the db_table_name specified in the <store> element. It contains the following elements:

  • <key_column>: Has the name and data_type attributes. The name attribute specifies the column name for the key and data_type specifies the SQL data type for the key.

  • <multi_key_column>: Has the name and data_type attributes. The name attribute specifies the column name for one part of a multi-key column and data_type specifies the SQL data type for the part of the key. The difference between <multi_key_column> and <key_column> is that <multi_key_column> supports two or more columns to be parts of the key, so <multi_key_column> can occur two or more times in the configuration file.

  • <bucket_column>: Has the name attribute. This attribute specifies the name of the column for the value part of the store. By default, this is a BLOB. There is an optional attribute data_type, that can be used if other data types are used. This must be a Java to SQL supported data type mapping and corresponds to the data type in the value part of the store.

  • <value_column>: Used if attributes in the value part of the store should be stored in a separate column. The name attribute defines the name of the column and the data_type specifies the SQL data type for the column. The <value_column> element contains the <methods> element, which encloses the <get_method> and <set_method> elements. The <methods> element defines the names of the set and get methods for the data stored in <value_column> and the set and get methods for the attribute of the object in the store.

Example 3-7 Example of single key column configuration

...
<db_table name="single_key_store">
  <key_column name="sample_key_1" data_type="VARCHAR(30)">
    <methods>
      <get_method name="getSampleKey1"/>
      <set_method name="setSampleKey1"/>
    </methods>
  </key_column>
  <value_column name="sample_value" data_type="VARCHAR(30)">
    <methods>
      <get_method name="getSampleValue"/>
      <set_method name="setSampleValue"/>
    </methods>
  </value_column>
</db_table>

...

Example 3-8 Example of Multi-key Column Configuration

...
<db_table name="combined_key_store">
  <multi_key_column name="sample_key_1" data_type="VARCHAR(30)">
    <methods>
      <get_method name="getSampleKey1"/>
      <set_method name="setSampleKey1"/>
    </methods>
  </multi_key_column>
  <multi_key_column name="sample_key_2" data_type="INT">
    <methods>
      <get_method name="getSampleKey2"/>
      <set_method name="setSampleKey2"/>
    </methods>
  </multi_key_column>
  <value_column name="sample_value" data_type="VARCHAR(30)">
    <methods>
      <get_method name="getSampleValue"/>
      <set_method name="setSampleValue"/>
    </methods>
  </value_column>
</db_table>

...

<query>

In addition to the standard java.util.Map interface, Stores support a StoreQuery interface.

The <query> element specifies a named query and a filter associated with the named query. The attribute name defines the name of the query. The behavior of these named queries are configured as part of the Storage Service configuration files. When using the storage service, the query is fetched using this name. The SQL query towards the database is defined in the element sql. The actual query is defined in the element <![CDATA[.....]]>.

The filter is a class that implements com.bea.wlcp.wlng.api.storage.filter.Filter, and the name of the class is defined in the <filter-class> element. The filter implements the setParameters method and a matches(...) method.

The setParameters method maps the parameters to the filter class or a PreparedStatement setObject call ordered as the parameter array given. The filter class must implement the matches method in such a way that it will yield the same result as the SQL query specified.

Example 3-9 Example of a named query

<query name="com.bea.wlcp.wlng.plugin.example.netex.Query">
    <sql>
      <![CDATA[
    SELECT * FROM example_store_notification WHERE correlator = ?
   ]]>
    </sql>
    <filter-class>com.acompany.plugin.example.netex.store.FilterImpl</filter-class>
  </query>

Example 3-10 Example of using the named query using a filter

StoreQuery<String, NotificationData> storeQuery = store.getQuery("com.bea.wlcp.wlng.plugin.example.netex.Query");
storeQuery.setParameters(correlator);
set = storeQuery.entrySet();

Example 3-11 Example of a filter implementation

public class FilterImpl implements Filter {

  /**
   * The query parameters.
   */
  private Serializable[] parameters;

  /**
   * Default constructor.
   */
  public FilterImpl() {

  }

  /**
   * Evaluate if a store entry matches the filter.
   *
   * @param value The store entry value to evaluate.
   */
  public boolean matches(Object value) {

     if (parameters == null || value == null || parameters.length == 0) {

       return false;
    }

    if (value instanceof NotificationData) {
      String compareValue = ((NotificationData) value).getCorrelator();

      if (compareValue != null) {
        return compareValue.equals(parameters[0]);
      }
      return compareValue == parameters[0];
    }

    return false;
  }

  /**
   * Set query parameters. The parameters will be ordered as provided to the
   * StoreQuery and it it the responsibility of the implementation to handle
   * them in this order.
   *
   * @param parameters The query parameters to use.
   */
  public void setParameters(Serializable ... parameters)
    throws StorageException {

    this.parameters = parameters;
  }


}

<provider-mapping>

The <provider-mapping> element contains definitions of which storage provider a given type-id is mapped to. This element should not be used unless a custom storage provider is used.

In the type_id attribute for store_mapping type, the same ID shall be used as when the store was defined. A best match (longest matching entry) is performed. A wildcard (*) can be used at the end of type_id to match the prefix.

The <provider-name> entry references the type of store being used, see "<providers>".

The type_id for the storage provider mapping in use is wlng.db.wt.*. which references the write-through provider.

There is another set of type_id attributes defined for store_mapping:

  • wlng.db.log.*, which is used for internal purposes only.

  • wlng.db.wb.*, which is used if the storage provider supports write-behind operations. The invalidating storage provider does not support write-behind operations, write-through will be used.

  • wlng.db.wt.*, which is used if the storage provider supports write-through operations.

  • wlng.cache.*, which is used if the storage provider supports cache-only operations. The invalidating storage provider does not support cache-only operations, write-through will be used.

  • wlng.local.*, which is used for internal purposes only.

These store mapping types are present for internal and future use. All store mapping types (except for the internal wlng.db.log.*) are by default mapped to the keyword invalidating which represents the invalidating storage provider. This should not be changed unless a custom storage provider is used.

<providers>

The <providers> element contains mappings between the provider-name defined in the <provider-mapping> element and the factory class for the storage provider. This element should not be changed used unless a custom storage provider is used.

Sharing Common Libraries

It is possible for multiple plug-ins to share common libraries, for example a third party library or custom code that can be shared.

If there are such parts, these should preferably not be packaged into the plug-in JAR but instead be copied into the APP-INF/lib directory of the communication service network tier EAR file. All classes in this directory are available for all of the plug-ins in the EAR file.