When would you use an extension event?

There are many situations where a feature may need to interact with an external resource as a part of its business logic. For example, it may need to query a network element via HTTP.

The following sections explains how you may develop features that use the extension event mechanism:

Note Extension Events are currently only available in the Sentinel SIP frontend, but the concept eventually will be extended to the other cores.

What you need to know to use extension events

To use extension events, you need to know:

  • how to write an event handler method that is triggered in receipt of events from an external resource

  • how a feature can process an extension event

  • how to use the SentinelEndpoint to tell Sentinel about activities your feature has created.

The following high-level diagram shows how these three processes work together.

extension event
Figure 1. Sentinel extension events
  1. Sentinel is triggered by an event that starts a new session (such as an INVITE request).

  2. While processing the request, Sentinel triggers a feature MyFeature and calls startFeature(), with the INVITE as the trigger event.

  3. MyFeature sends a message to an external resource (Network Element) as a part of its business logic (request).

  4. The Network Element responds. An event is received (response — an extension event), which triggers an event handler method in MyFeature SBBPart (onEvent()).

  5. MyFeature SBBPart delegates to Sentinel (by using the SentinelEndpoint) to deliver the response extension event.

  6. Sentinel routes the extension event to MyFeature for processing and calls startFeature(), with the response as the trigger event.

When are extension events processed?

Extension events may be processed when:

Feature blocks and waits for the extension event

In this scenario a feature creates an outgoing session to an external resource and waits for the response before continuing. In this case no other feature will run until a response is received, or the feature times out.

extension event blocking
Figure 2. Feature waits for the extension event before returning

Here, a feature (MyFeature) creates an outgoing session to an external resource (Network Element).
MyFeature:

  • uses a provider object related to the external resource

  • creates a new session

  • gets a SLEE ActivityContextInterface related to the session

  • uses the attach operation on the feature endpoint to tell Sentinel about the new activity; Sentinel attaches to this activity so incoming messages related to this activity can be received as events

  • sends a message to the external resource (request).

MyFeature does not return control to Sentinel, and is waiting for a response from the external resource. The current feature execution script is still active, and no more features will run in txn #1.

At some point in the future, Network Element will finish its work and generate a response. MyFeature SBBPart has an event handler method for response events that is triggered in txn #2. The event handler method will delegate to Sentinel to route the event by using the SentinelEndpoint and calling processEvent() with the response event and the name of the feature to be triggered ("MyFeature").

Sentinel routes the response event to MyFeature by calling startFeature() with response as the trigger event. MyFeature will continue its work and then return control to Sentinel by sending featureHasFinished(). The current feature execution script will continue in txn #2 and further features may run.

Note
  • The feature execution script that starts MyFeature spans two SLEE transactions (the script starts in txn #1 and ends in txn #2).

  • A feature that is waiting for a response on an activity will receive an ActivityEndEvent if the activity ends without a response event being delivered into the SLEE.

Feature does not block and is invoked later with the extension event

In this scenario, a feature creates an outgoing session to an external resource and returns control to Sentinel immediately. In this case, other features may run whilst the external resource does its work.

extension event non block
Figure 3. Feature returns immediately and is triggered in the future with the extension event

Here a feature (MyFeature) creates an outgoing session to an external resource (Network Element).
MyFeature:

  • uses a provider object related to the external resource

  • creates a new session

  • gets a SLEE ActivityContextInterface related to the session

  • uses the attach operation on the feature endpoint to tell Sentinel about the new activity; Sentinel attaches to this activity, so incoming messages related to this activity can be received as events

  • sends a message to the external resource (request)

  • returns control to Sentinel by sending featureHasFinished().

The current feature execution script will continue and other features may run in txn #1.

At some point in the future, Network Element will finish its work and generate a response. MyFeature SBBPart has an event handler method for response events that is triggered in txn #2. The event handler method will delegate to Sentinel to route the event by using the SentinelEndpoint and calling processEvent() with the response event and the name of the feature to be triggered ("MyFeature").

Sentinel routes the response event to MyFeature by calling startFeature() with response as the trigger event. MyFeature will continue its work and then return control to Sentinel by sending featureHasFinished(). In this case, MyFeature has been invoked directly, so no other feature will run as a consequence of Sentinel receiving the response event in txn #2.

Note

The feature execution script that starts MyFeature runs to completion within one SLEE transactions (the script starts and ends in txn #1).

Tip

A feature may include the name of a different feature to be invoked.

Writing a feature that uses extension events

The following example shows how to write a feature that uses extension events.

Requirements

A feature SendHttpRequestAndWaitFeature will create a new outgoing http activity and issue a GET request. +It must wait to be invoked a second time with an http response (an extension event).

There are two aspects to developing this feature:

Writing the feature

SendHttpRequestAndWaitFeature sends and receives http messages, so it needs access to an http provider. The implementation of startFeature() can then use the http provider to create an outgoing http session and receive an http response.

Injecting the http provider

In the following code sample, the raProviderJndiNames attribute of the @SentinelFeature annotation is set with values for the http provider and the http activity context interface factory. The feature implements InjectResourceAdaptorProvider and stores references to the provider and activity context interface factory objects in private attributes of the feature class:

@SentinelFeature(
    featureName = SendHttpRequestAndWaitFeature.NAME,
    // ...
    raProviderJndiNames = {
        "slee/resources/http/provider",
        "slee/resources/http/activitycontextinterfacefactory"
    }
)
// ...
public class SendHttpRequestAndWaitFeature
        extends BaseFeature<NullSentinelSessionState, SentinelSipMultiLegFeatureEndpoint>
        implements InjectResourceAdaptorProvider
{
    // ...
    @Override
    public void injectResourceAdaptorProvider(Object provider) {
        if(provider instanceof HttpProvider){
            this.httpProvider = (HttpProvider)provider;
        }
        else if(provider instanceof HttpActivityContextInterfaceFactory){
            this.httpAciFactory = (HttpActivityContextInterfaceFactory)provider;
        }
    }
    // ...
    private HttpProvider httpProvider;
    private HttpActivityContextInterfaceFactory httpAciFactory;
}

Implementing startFeature()

The startFeature() method can be invoked with three types of trigger object:

  • an INVITE — SendHttpRequestAndWaitFeature creates and sends a new GET request using the http provider. It uses the http activity context interface factory to get the SLEE ActivityContextInterface related to the new outgoing activity, and tells Sentinel to attach(httpAci). Any incoming events will be received by Sentinel (and then routed to SendHttpRequestAndWaitFeature as an extension event). In this scenario, SendHttpRequestAndWaitFeature waits for a response before ending, so it issues featureWaiting(). The script within which SendHttpRequestAndWaitFeature is triggered will complete in the SLEE transaction associated with the http response event.

  • an HttpResponse — SendHttpRequestAndWaitFeature simply traces properties of the HttpResponse and issues featureHasfinished(). The script within which SendHttpRequestAndWaitFeature is triggered will now continue within this SLEE transaction

  • an ActivityEndEvent — SendHttpRequestAndWaitFeature issues featureHasfinished(). The script within which SendHttpRequestAndWaitFeature is triggered will now continue within this SLEE transaction.

Note

A feature can only receive an ActivityEndEvent on an activity on which it has issued featureWaiting().

For example:

@Override
public void startFeature(Object trigger, Object activity, ActivityContextInterface aci) {
    final Tracer tracer = getTracer();

    if (trigger instanceof HttpResponse) {
        // I am being invoked a second time with the http response
        final HttpResponse httpResponse = (HttpResponse) trigger;
        if (tracer.isFinerEnabled()) {
            tracer.finer("Received an HttpResponse: " + httpResponse);
            tracer.finer("   StatusCode   : " + httpResponse.getStatusCode());
            tracer.finer("   StatusReason : " + httpResponse.getStatusReason());
        }
        // now I am done
        getCaller().featureHasFinished();

        if(tracer.isFineEnabled()) tracer.fine("Feature has finished");
    }
    else if (trigger instanceof ActivityEndEvent) {
        // I am being invoked with an ActivityEndEvent ... something went wrong!
        getCaller().featureFailedToExecute(
            new FeatureError(FeatureError.Cause.unclassified,
                             "Received an ActivityEndEvent instead of an HttpResponse"));
        getCaller().featureHasFinished();

        if(tracer.isFineEnabled())
            tracer.fine("Received an ActivityEndEvent ... feature has finished");
    }
    else {
        // I am being invoked the first time with an INVITE
        try {
            // create the request
            final HttpRequest request =
                httpProvider.createRequest(HttpRequest.GET, new URL(DESTINATION));

            // send the request
            final OutgoingHttpRequestActivity httpActivity =
                httpProvider.sendRequest(request);
            final ActivityContextInterface httpAci =
                httpAciFactory.getActivityContextInterface(httpActivity);

            // ... and attach to the activity
            getCaller().attach(httpAci);

            // not finished yet, I expect to be invoked a second time with an extension
            // event (the http response).
            if(tracer.isFineEnabled())
                tracer.fine("Alerting core that feature is waiting on activity: " + httpAci);
            getCaller().featureWaiting(httpAci);
        }
        catch (IOException e) {
            // I failed, record the error and finish
            getCaller().featureFailedToExecute(
                new FeatureError(FeatureError.Cause.unclassified,
                                 "Exception sending HTTP Request",
                                 e));
            getCaller().featureHasFinished();
        }
    }
}

Writing the feature SBBPart

The SendHttpRequestAndWaitFeature needs a companion SBB part that has an event handler method for HTTP response events. The event handler method uses the SentinelEndpoint to request Sentinel to route the event to a named feature.

Accessing HTTP resource adaptor classes

The SBB part needs access to HTTP resource adaptor classes such as the HttpResponse event. Adding an @RATypeBindings annotation to the SBB part class will ensure that SendAndReceiveHttpSbbPart can access all HTTP resource adaptor type classes. Like so:

@SBBPart(
    id = @ComponentId(name = "...", vendor = "...", version = "..."),
    // ...
    sbbPartClasses = @SBBPartClasses(
        sbbPartClass = @SBBPartClass(
            className="com.opencloud.sentinel.feature.eventhandler.SendHttpRequestAndWaitSbbPart"
        )
    )
)
@RATypeBindings(
    raTypeBindings = {
        @RATypeBinding(
            raType = @ComponentId(name = "HTTP", vendor = "OpenCloud", version = "2.2")
        )
    }
)
public class SendHttpRequestAndWaitSbbPart {
    // ...
}

Implementing the event handler method

The SendHttpRequestAndWaitSbbPart event handler method (onHttpResponse) has an @EventMethod annotation for the HttpResponse event. When an HttpResponse event is received by the SLEE, it will trigger the SendAndReceiveHttpSbbPart event handler method onHttpResponse. The event handler method gets a reference to the SentinelEndpoint by calling getSbbLocalObject() on the SBB part context and casting the result to SentinelEndpoint. The httpResponseEvent is delivered by calling processEvent on the SentinelEndpoint, with:

  • the name of the feature to invoke

  • the httpResponseEvent object

  • the associated ActivityContextInterface and EventContext objects.

For example:

@EventMethod(
    initialEvent = false,
    eventType = @ComponentId(name = "com.opencloud.slee.resources.http.HttpResponse",
                             vendor = "OpenCloud",
                             version = "2.2")
)
public void onHttpResponse(HttpResponse httpResponseEvent,
                           ActivityContextInterface aci,
                           EventContext eventContext)
{
    if (rootTracer.isFinerEnabled()) rootTracer.finer("Received: " + httpResponseEvent);

    final String featureToInvoke = "SendHttpRequestAndWaitFeature";
    try {
        // get the SentinelEndpoint
        final SentinelEndpoint sentinelEndpoint =
            (SentinelEndpoint)sbbPartContext.getSbbLocalObject();
        // process the http response by calling the 'featureToInvoke' feature
        sentinelEndpoint.processEvent(featureToInvoke, httpResponseEvent, false, aci, eventContext);
    }
    catch (Exception e) {
        rootTracer.fine("Caught exception in processEvent for HttpResponse", e);
    }
}

@Inject private Tracer rootTracer;
@Inject private SbbPartContext sbbPartContext;
Tip

Remember that the SendHttpRequestAndWaitFeature told Sentinel to attach to the outgoing http activity. Sentinel will therefore receive all incoming http events (such as the httpResponseEvent) on this activity.

Whilst this simple example hard-codes the name of the feature to invoke as "SendAndReceiveHttpFeature", the SBB part may include the name of any feature to invoke. For example, it might derive the name of the feature to invoke from parameters of the received event.

Previous page Next page