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
SentinelEndpoint
to 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
INVITE
request). -
While processing the request, Sentinel triggers a feature
MyFeature
and callsstartFeature()
, with theINVITE
as the trigger event. -
MyFeature
sends a message to an external resource (Network Element
) as a part of its business logic (request
). -
The
Network Element
responds. An event is received (response
— anextension event
), which triggers an event handler method inMyFeature SBBPart
(onEvent()
). -
MyFeature SBBPart
delegates to Sentinel (by using theSentinelEndpoint
) to deliver theresponse
extension event. -
Sentinel routes the
extension event
toMyFeature
for processing and callsstartFeature()
, with theresponse
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.
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.
|
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
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
.
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
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 (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
—SendHttpRequestAndWaitFeature
creates and sends a newGET
request using the http provider. It uses the http activity context interface factory to get the SLEEActivityContextInterface
related to the new outgoing activity, and tells Sentinel toattach(httpAci)
. Any incoming events will be received by Sentinel (and then routed toSendHttpRequestAndWaitFeature
as an extension event). In this scenario,SendHttpRequestAndWaitFeature
waits for a response before ending, so it issuesfeatureWaiting()
. The script within whichSendHttpRequestAndWaitFeature
is triggered will complete in the SLEE transaction associated with the http response event. -
an
HttpResponse
—SendHttpRequestAndWaitFeature
simply traces properties of theHttpResponse
and issuesfeatureHasfinished()
. The script within whichSendHttpRequestAndWaitFeature
is triggered will now continue within this SLEE transaction -
an
ActivityEndEvent
—SendHttpRequestAndWaitFeature
issuesfeatureHasfinished()
. The script within whichSendHttpRequestAndWaitFeature
is 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
httpResponseEvent
object -
the associated
ActivityContextInterface
andEventContext
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;
Remember that the Whilst this simple example hard-codes the name of the feature to invoke as |