Access Keys:
Skip to content (Access Key - 0)









How Do I Use the New SLEE 1.1 CMP Types

Print this page

Introduction

The SLEE architecture defines how a service can be composed of a series of SBB components. Each SBB component apart from defining e.g. the event types received and fired by the component or the relations to child components also can specify Container Managed Persistent (CMP) attribute fields that can maintain persistent state that should persist across failures. As the get and set-operations on this per-instance state are managed by the SLEE container there are certain limitations to the types of objects that can be stored in CMP fields.

CMP types in SLEE 1.0

The SLEE 1.0 specification allows Java primitive types, Java serializable types (this obviously includes in particular the primitive types' object wrapper classes and java.lang.String) and SBB local interfaces (i.e. SbbLocalObject and the types derived from SbbLocalObject).

New CMP types in SLEE 1.1

In addition to the above mentioned types the SLEE 1.1 specification permits the following:

  • Activity Context Interface interfaces (i.e. javax.slee.ActivityContextInterface and the types derived from javax.slee.ActivityContextInterface)
  • Event Context interfaces (i.e. javax.slee.EventContext)
  • Profile Local interfaces (i.e. javax.slee.profile.ProfileLocalObject and the types derived from javax.slee.profile.ProfileLocalObject)

Example usage of ProfileLocal interface CMP fields

The following example demonstrates how the newly provided ability to store a ProfileLocalObject in a CMP field can be used to improve the performance of an application.

Static query in Profile Specification Deployment Descriptor:

<profile-spec-jar>
	...
        <query name="somequery">
            <description>Testdesription</description>
            <query-parameter name="param" type="java.lang.String"/>
            <compare attribute-name="stringValue" op="equals" parameter="param"/>
        </query>
	...
</profile-spec-jar>

Code in an example SBB

public void onEvent1(ExampleEvent event, ActivityContextInterface aci) {
	Collection col;

	//run a static query on a profile table to retrieve the wanted profile
	col = profileTable.querySomequery("42");

	//assuming there is at least one match, store the profile reference in a CMP field
	ProfileLocalObject profileLocal = (ProfileLocalObject)col.iterator().next();
	setProfile(profileLocal);

	//operations on the profile, setting attributes etc.
	...
}

public void ()(ExampleEvent event, ActivityContextInterface aci) {
	//instead of running the potentially time-consuming query a second time
	//rather retrieve the profile reference from the CMP field
	ProfileLocalObject profileLocal = getProfile();

	//operations on the profile, setting attributes etc.
	...
}
...
public abstract ProfileLocalObject getProfile();
public abstract void setProfile(ProfileLocalObject value);

When receiving the first event the SBB's event handler method looks up the profile via static query on the ProfileTable interface. It then stores the reference to the found profile in the SBB's 'profile' CMP field. In a second event handler method and thus in a completely different transaction context, rather than running the potentially time-consuming query a second time, the SBB just looks up the previously stored reference from the CMP field.

Note that in the example the potential modifications to the profile found via query are done AFTER the call to setProfile(). However, the order of modifying and storing the profile does not matter as the CMP field only stores a reference to the profile. Thus it is guaranteed that when retrieving the profile in onEvent2() the profile handed back is up-to-date with the most recent state.

Example usage of EventContext CMP fields

The EventContext interface is new in SLEE 1.1. One possible use is demonstrated in the following example:

public void onCallStartEvent(CallEvent event,  ActivityContextInterface aci, EventContext context) {
	//store the context in a CMP field
	setEventContext(context);

	//suspend event delivery
	context.suspendDelivery();

	//lookup some billing RA and send event to do some account processing there
	...
}

public void onBillingSystemCallsBack(BillingCallbackEvent event, ActivityContextInterface aci) {
	//retrieve original event context of onCallStartEvent() event handler
	EventContext context = getEventContext();

	//resume delivery of call event now that the billing subsystem has done its work
	context.resumeDelivery();
}
...
public abstract EventContext getEventContext();
public abstract void setEventContext(EventContext value);

In the above scenario an SBBs onCallStartEvent() event handler is triggered when a new call is started. The CallEvent's event context is stored in a CMP field for later use. Afterwards the SBB looks up the Resource Adaptor SBB Interface of some Billing RA (e.g. Diameter) and triggers some account processing (asynchronous operations). When the Billing RA fires an event back to the SBB that call processing can proceed, the original event context is retrieved from the CMP field and the delivery of the original CallEvent is resumed.

Example usage of Activity Context Interface CMP fields

To use an Activity Context over the boundaries of two or more SBB event handlers in SLEE 1.0 you had to work via Activity Context Naming Facility lookup. First a name had to be bound to the Activity Context Interface in the first event handler, then in the second event handler the Activity Context Interface could be retrieved via lookup for the previously bound name. In SLEE 1.1 however you can achieve this by simply storing a reference to the Activity Context Interface as an SBB's CMP field. This obviously does not only shorten the application code and makes it more readable but also improves the performance of the application as the rather expensive Activity Context Naming Facility lookup can be dropped.

An example how to use Activity Context Interface objects via CMP fields can be found in appendix section D.11.3 of the JAIN SLEE 1.1 specification document.

public abstract class SimpleB2BUASbb implements Sbb{
    // Initial request
    public void onInitialInvite(RequestEvent event, ActivityContextInterface aci) {
        // ACI is the server transaction activity
        ServerTransaction st = event.getServerTransaction();
        try {
            // Create the dialogs representing the incoming and outgoing call legs.
            DialogActivity incomingDialog = (DialogActivity) getSipProvider().getNewDialog(st);
            DialogActivity outgoingDialog = getSipProvider().getNewDialog(incomingDialog, true);

            // Obtain the dialog activity contexts and attach to them
            ActivityContextInterface outgoingDialogACI = 
                        getSipACIFactory().getActivityContextInterface(outgoingDialog);
            ActivityContextInterface incomingDialogACI = 
                        getSipACIFactory().getActivityContextInterface(incomingDialog);
            incomingDialogACI.attach(myLocalObject);
            outgoingDialogACI.attach(myLocalObject);

            // Record which dialog is which, so we can find the peer dialog
            // when forwarding messages between dialogs.
            setIncomingDialog(incomingDialogACI);
            setOutgoingDialog(outgoingDialogACI);

            forwardRequest(st, outgoingDialog);
        } catch (SipException e) {
            sendErrorResponse(st, Response.SERVICE_UNAVAILABLE);
        }
    }
...
    public void onAck(RequestEvent event, ActivityContextInterface aci) {
        processMidDialogRequest(event, aci);
    }
...
    private void processMidDialogRequest(RequestEvent event, ActivityContextInterface dialogACI) {
        try {
            // Find the dialog to forward the request on
            ActivityContextInterface peerACI = getPeerDialog(dialogACI);
            forwardRequest(event.getServerTransaction(),
            (DialogActivity)peerACI.getActivity());
        } catch (SipException e) {
            sendErrorResponse(event.getServerTransaction(),Response.SERVICE_UNAVAILABLE);
        }
    }
...
    private ActivityContextInterface getPeerDialog(ActivityContextInterface aci) throws SipException {
        if (aci.equals(getIncomingDialog())) return getOutgoingDialog();
        if (aci.equals(getOutgoingDialog())) return getIncomingDialog();
        throw new SipException("could not find peer dialog");
    }
...
    // CMP field accessors for each Dialogs ACI
    public abstract void setIncomingDialog(ActivityContextInterface aci);
    public abstract ActivityContextInterface getIncomingDialog();
    public abstract void setOutgoingDialog(ActivityContextInterface aci);
    public abstract ActivityContextInterface getOutgoingDialog();
}
Adaptavist Theme Builder Powered by Atlassian Confluence