Sentinel provides a mechanism that features may use to interact with external resources and receive incoming messages as events. These incoming events are called “extension events”.
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:
|
|
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
SentinelEndpointto tell Sentinel about activities your feature has created.
The following high-level diagram shows how these three processes work together.
-
Sentinel is triggered by an event that starts a new session (such as an
INVITErequest). -
While processing the request, Sentinel triggers a feature
MyFeatureand callsstartFeature(), with theINVITEas the trigger event. -
MyFeaturesends a message to an external resource (Network Element) as a part of its business logic (request). -
The
Network Elementresponds. An event is received (response— anextension event), which triggers an event handler method inMyFeature SBBPart(onEvent()). -
MyFeature SBBPartdelegates to Sentinel (by using theSentinelEndpoint) to deliver theresponseextension event. -
Sentinel routes the
extension eventtoMyFeaturefor processing and callsstartFeature(), with theresponseas 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.
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
ActivityContextInterfacerelated to the session -
uses the
attachoperation 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.
|
|
|
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.
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
ActivityContextInterfacerelated to the session -
uses the
attachoperation 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.
|
|
The feature execution script that starts |
|
|
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.
A feature
SendHttpRequestAndWaitFeaturewill create a new outgoing http activity and issue a GET request. +It must wait to be invoked a second time with an http response (anextension 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—SendHttpRequestAndWaitFeaturecreates and sends a newGETrequest using the http provider. It uses the http activity context interface factory to get the SLEEActivityContextInterfacerelated to the new outgoing activity, and tells Sentinel toattach(httpAci). Any incoming events will be received by Sentinel (and then routed toSendHttpRequestAndWaitFeatureas an extension event). In this scenario,SendHttpRequestAndWaitFeaturewaits for a response before ending, so it issuesfeatureWaiting(). The script within whichSendHttpRequestAndWaitFeatureis triggered will complete in the SLEE transaction associated with the http response event. -
an
HttpResponse—SendHttpRequestAndWaitFeaturesimply traces properties of theHttpResponseand issuesfeatureHasfinished(). The script within whichSendHttpRequestAndWaitFeatureis triggered will now continue within this SLEE transaction -
an
ActivityEndEvent—SendHttpRequestAndWaitFeatureissuesfeatureHasfinished(). The script within whichSendHttpRequestAndWaitFeatureis triggered will now continue within this SLEE transaction.
|
|
A feature can only receive an |
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
httpResponseEventobject -
the associated
ActivityContextInterfaceandEventContextobjects.
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;
|
|
Remember that the Whilst this simple example hard-codes the name of the feature to invoke as |
