Oracle® Communications Services Gatekeeper Platform Development Studio Developer's Guide Release 5.1 E37535-01 |
|
|
PDF · Mobi · ePub |
This chapter describes aspects and generation of EDRs, alarms, CDRs, and statistics in Oracle Communications Services Gatekeeper (Services Gatekeeper).
Aspects allow developers to manage cross-cutting concerns in their code in a straightforward and coherent way. Aspects in Services Gatekeeper (pointcuts, advice, etc.) are written in the AspectJ 1.5.3 annotation style. There is already support for editing annotations in many modern IDEs, and aspects are simply set up as annotated classes.
All aspects are applied at build time by weaving the byte code of previously complied Java packages. Minimal reflection is used at runtime to make aspect-based decisions.
Different aspect types are applicable to different Services Gatekeeper modules. In general there are two categories of aspects:
Those restricted to the code for the traffic flow
Those that can be applied to other packages.
Note:
In this case, traffic flow is defined to include only plug-in implementations.Traffic aspects are subdivided into two categories:
Those that are always applied
Those that are controlled using annotations.
Only statistics aspects are always applied because they are used to calculate usage costs. Traffic aspects are applied to north and south boundaries of a plug-in as well as to the internal processing of the plug-in.
Annotations are used to control the aspects that are not always applied for each plug-in. These annotations are defined as part of the functional areas that a given set of aspect implements. They allow the plug-in to communicate with the aspects as well as to customize their behavior.
The Context aspect is woven at compile time, using PluginSouth as a marker.
While requests coming from the north interface have a valid context (with attributes like Service provider account ID, application Account ID, and so on) any events triggered by the network and entering a plug-in's south interface do not have a valid context.
The Context aspect solves this problem by rebuilding the context as soon as a south interface method is invoked: after this aspect is executed, a valid context will be available for any subsequent usages, such as the EDR aspect. All methods inside a class implementing the interface PluginSouth are woven by the Context aspect.
The Context aspect requires the following in order to correctly weave the south interface methods and be able to rebuild the context:
Each Plug-in must explicitly register its north and south interfaces.
Each south interface must implement the resolveAppInstanceGroupdId() and prepareRequestContext() methods of the PluginSouth interface.
North interfaces must implement PluginNorth and south interfaces must implement PluginSouth.
The following rules apply for methods in classes that implement PluginNorth:
The default behavior is that EDRs are triggered only for exceptions and callbacks to EJBs in the access tier (Service Callback EJB)
If a method is annotated with @NoEdr, no EDRs will be generated. It overrides the default behavior.
If a method is annotated with @EDR, 2 EDRs will be generated:
When entering the method
When exiting the method.
The following rule applies for methods in classes that implement PluginSouth:
Methods that perform requests to the network may have a parameter annotated with @MapperInfo in order to be able to rebuild the RequestContext when the response to the request arrives from the network. The annotated parameter must be used as a key to resolve the application instance ID using some plug-in specific lookup.
Methods must implement resolveAppInstanceGroupdId(ContextMapperInfo info) in PluginSouth and return the application instance ID that corresponds to the original request to the network.
The ways of doing this are plug-in-specific, but normally a network triggered request is tied to an application instance in a store that is managed by the plug-in. The store used for context mapping may be a local cache or a cluster wide store, depending on whether responses are known to always arrive on the same plug-in instance, or if they can arrive at a plug-in on another server in the cluster.
Example:
An application sends a request to the network and an ID for this request is either supplied by the network or generated by the plug-in. At this point the originator of the requests, the application instance, is known since the request originated from an application.
The plug-in puts the application instance ID and the ID for the request into a store.
At a later stage, when a response to the original requests arrives at the plug-in, the method resolveAppInstanceGroupId() is called by aspects.
In this method, the plug-in must perform a lookup in the store of the application instance related to that request and return the application instance ID to the aspect.
The aspect authenticates the application instance with the container and puts the application instance ID in the RequestContext.
The method in the plug-in receives the request from the network and the RequestContext contains the application instance ID.
In the example below the method deliver(...) is a request from the underlying network. The destinationAddress is annotated to be available to the aspect that handles network-triggered requests associated with this request, represented by constant C.
NotificationHandler handles the store for notifications and supplies all necessary parameters to the store.
Example 11-1 Application initiated request
protected static final String C = "destinationAddress"; @Edr public void deliver(String data, @ContextKey(EdrConstants.FIELD_DESTINATION_ADDRESS) @MapperInfo(C) String destinationAddress, @ContextKey(EdrConstants.FIELD_ORIGINATING_ADDRESS) String originatingAddress, String nwTransactionId) throws Exception { notificationHandler.deliver(data, destinationAddress, originatingAddress, nwTransactionId); }
When a network triggered event occurs, the aspect calls resolveApplicationInstanceGroup(...) in PluginSouth and the plug-in looks up the application instance using any argument available in ContextMapperInfo that can help the plug-in to resolve this ID from ContextMapperInfo, using info.getArgument(C). The application instance ID is returned to the aspect and the execution flow continues in the plug-in, with a RequestContext that contains the application instance ID, session ID and so on.
Example 11-2 Rebuilding RequestContext
protected static final String C = "destinationAddress"; public String resolveAppInstanceGroupdId(ContextMapperInfo info) { String destinationAddress = (String) info.getArgument(C); NotificationData notificationData = null; try { notificationData = StoreHelper.getInstance().getNotificationData(destinationAddress); } catch (StorageException e) { return null; } if (notificationData == null) { return null; } return notificationData.getAppInstanceGroupId(); }
Below are the steps you have to take to make your plug-in compliant with the Context aspect:
Make sure to register all your PluginSouth objects before registering your plug-in in the Plug-in Manager.
Make sure to implement the resolveAppInstanceGroupdId() method for each PluginSouth instance.
Annotate each parameter in south object methods that you need to have when aspects call back the resolveAppInstanceGroupId() or the prepareRequestContext() methods. All the annotated parameters will be available in the ContextMapperInfo parameter. The aspects need to have them annotated to be able to store them into the ContextMapperInfo object.
EDRs are generated in the two following ways:
automatically using aspects at given points in the traffic execution flow in a plug-in.
manually anywhere in the code using the EdrService.
EDRs should be generated at the plug-in boundaries (north and south), using the @Edr annotation to ensure that the boundaries are covered. Additional EDRs can be added elsewhere in the plug-in if needed: for example for CDRs.
For extensions, the EDR ID should be in the range 500 000 to 999 999.
EDRs are generated automatically by an aspect in the following locations in the plug-in:
Before and after any method annotated with @Edr
Before and after any callback to an EJB
After any exception is thrown
Note:
Note that aspects are not applied outside the plug-in.Table 11-1 Manual annotation for EDRs
Trigger | When | Modifiers restrictions | What is woven |
---|---|---|---|
method |
before executing |
public method only |
only in methods annotated with @Edr |
method |
after executing |
public method only |
only in methods annotated with @Edr |
method-call |
before calling |
any method |
only for method call to a class implementing the PluginNorthCallback interface (EJB callback) |
method-call |
after calling |
any method |
only for method call to a class implementing the PluginNorthCallback interface (EJB callback) |
exception |
after throwing |
any method |
any exception thrown except in methods annotated with @NoEdr |
The following values are always available in an EDR when it is generated from an aspect:
class name
method name
direction the request is going toward (south, north)
position (before, after)
interface (north, south, other, null)
source (method, exception)
Exceptions are automatically woven by the aspect.
Some limitations apply:
The aspect will catch only exceptions that are thrown by a plug-in method.
The aspect will not catch an exception that is thrown by a library and caught by the plug-in.
If the same exception is re-thrown several times, the aspect will only trigger an EDR once, for the first instance of the exception.
Figure 11-1 illustrates typical scenarios when a library (or core service) throws an exception in the plug-in.
Scenario 1:
The plug-in method in Stage 2 simply catches the exception but does not re-throw it or throw another exception. Since it just consume the exception, the aspect will not trigger an EDR.
Scenario 2:
The plug-in method in Stage 2 lets the exception A propagate (or re-throws exception A).
In this case, the aspect triggers an EDR after the method in stage 2. Since the same exception A (the same exception instance object) is propagated (or re-thrown), only the first method triggers an EDR.
Scenario 3:
This scenario is almost identical to scenario 2 except that the method in stage 1 is not throwing the exception A but another exception, named B. In this case, because B is not the same instance as A, the aspect will trigger another EDR after the method in stage 1.
In addition to the default values, an EDR also contains all the values put into the RequestContext using the putEdr() method.
Example 11-3 Adding values using RequestContext
... RequestContext ctx = RequestContextManager.getCurrent(); // this value will be part of any EDRs generated in the current request ctx.putEdr("address", "tel:1234"); // this value will NOT be part of any EDRs since ctx.put(...) is used ctx.put("foo", "bar"); ...
Note:
Common key names are defined in the class com.bea.wlcp.wlng.api.edr.EdrConstants.When a parameter is a more complex object, it is possible to specify a translator that will take care of extracting the relevant information from this parameter.
The annotation is @ContextTranslate.
For example, the following method declares:
The first (and only) parameter should be translated using the specified translator ACContextTranslator
The returned object should also be translated using the specified translator ACContextTranslator
Example 11-4 Using a translator
... @Edr public @ContextTranslate(ACContextTranslator.class) PlayTextMessageResponse playTextMessage(@ContextTranslate(ACContextTranslator.class) PlayTextMessage parameters) { ... return response; } ...
The Translator is a class implementing the ContextTranslator interface.
Example 11-5 Example Translator
public class ACContextTranslator implements ContextTranslator { public void translate(Object param, ContextInfo info) { if(param instanceof PlayTextMessage) { PlayTextMessage msg = (PlayTextMessage) param; info.put("address", msg.getAddress().toString()); } else if(param instanceof PlayTextMessageResponse) { PlayTextMessageResponse response = (PlayTextMessageResponse) param; info.put("correlator", response.getResult()); } ... } }
The ContextTranslator class specified in the @ContextTranslate annotation is automatically instantiated by the aspect when needed. It is however possible to explicitly register it using the ContextTranslatorManager.
Example 11-6 Registering a Context Translator
ContextTranslatorManager.register(ACContextTranslator.class.getName(), new ACContextTranslator());
Table 11-2 is a summary of annotations to use.
Name | Type | Description |
---|---|---|
@ContextKey |
Annotation |
Specifies that an argument must be put into the current RequestContext under the name provided in this annotation |
@ContextTranslate |
Annotation |
Same as @ContextKey but for complex argument that need to be translated using a translator (implementing the ContextTranslator interface). |
ContextTranslator |
Interface |
Interface used by static translators to translate complex object. |
Oracle Communications Services Gatekeeper triggers EDRs automatically in all plug-ins where aspects have been applied. It is also possible to trigger EDRs explicitly. In this case, you will have to manually create and trigger the EDR by following these steps:
Create an EdrData object
Trigger the EDR using the EdrService instance
Below is an example of triggering an EDR from inside a plug-in.
Example 11-7 Triggering an EDR Programmatically
public class SamplePlugin { // Get the EdrDataHelper like a logger private static final EdrDataHelper helper = EdrDataHelper.getHelper(SamplePlugin.class); public void doSomething() { ... // Create a new EdrData using the EdrDataHelper class to allow // Services Gatekeeper to automatically populate some fields EdrData data = helper.createData(); // Since we are creating the EdrData manually, // we have to provide the mandatory fields. // Note that the EdrDataHelper will provide most of them data.setValue(EdrConstants.FIELD_SOURCE, EdrConstants.VALUE_SOURCE_METHOD); data.setValue(EdrConstants.FIELD_METHOD_NAME, "doSomething"); // Log the EDR EdrServiceFactory.getService().logEdr(data); ... } }
Table 11-3 describes the content of an EDR. It shows which values are mandatory, who is responsible for providing these values, and other information.
Legends:
A: Automatically provided by Oracle Communications Services Gatekeeper
H: Provided if the EdrDataHelper createData API is used to create the EdrData (which is the recommended way)
M: Provided manually in the EdrData
X: Provided in the EDR descriptor.
C: Custom filter. Use the <attribute>
element to specify a custom filter.
Note:
EDRs triggered by aspects will have all the mandatory fields provided by the aspect.Name | Description | Filter tag name |
---|---|---|
EdrId |
To get the ID, use getIdentifier() in EdrConfigDescriptor. This value is provided in the EDR descriptor. Provider INSIDE plug-in: X Provider OUTSIDE plug-in: X Mandatory: Yes |
C |
ServiceName |
The name (or type) of the service. Fields in EdrConstants: FIELD_SERVICE_NAME Provider INSIDE plug-in: H Provider OUTSIDE plug-in: M Mandatory: Yes |
C |
ServerName |
The name of the Oracle Communications Services Gatekeeper server. Fields in EdrConstants: FIELD_SERVER_NAME Provider INSIDE plug-in: H Provider OUTSIDE plug-in: H Mandatory: Yes |
C |
Timestamp |
The time at which the EDR was triggered (in ms since midnight, January 1, 1970 UTC) Fields in EdrConstants: FIELD_TIMESTAMP Provider INSIDE plug-in: A Provider OUTSIDE plug-in: A Mandatory: Yes |
C |
ContainerTransactionId |
The WebLogic Server transaction ID, if available. Fields in EdrConstants: FIELD_CONTAINER_TRANSACTION_ID Provider INSIDE plug-in: H Provider OUTSIDE plug-in: H Mandatory: No |
C |
Class |
Name of the class that triggered the EDR. Fields in EdrConstants: FIELD_CLASS_NAME Provider INSIDE plug-in: H Provider OUTSIDE plug-in: H Mandatory: Yes |
<class> |
Method |
Name of the method that triggered the EDR. Provider INSIDE plug-in: M Provider OUTSIDE plug-in: M Mandatory: Yes |
<name> inside <method> or <method> inside <exception> |
Source |
Indicates the type of source that triggered the EDR. Fields in EdrConstants: FIELD_SOURCE Values in EdrConstants: VALUE_SOURCE_METHOD, VALUE_SOURCE_EXCEPTION Provider INSIDE plug-in: M Provider OUTSIDE plug-in: M Mandatory: Yes |
<method> or <exception> |
Direction |
Direction of the request. Fields in EdrConstants: FIELD_DIRECTION Values in EdrConstants:VALUE_DIRECTION_SOUTH, VALUE_DIRECTION_NORTH Provider INSIDE plug-in: M Provider OUTSIDE plug-in: M Mandatory: No |
<direction> |
Position |
Position of the EDR relative to the method that triggered the EDR. Fields in EdrConstants: FIELD_POSITION Values in EdrConstants: VALUE_POSITION_BEFORE, VALUE_POSITION_AFTER Provider INSIDE plug-in: M Provider OUTSIDE plug-in: M Mandatory: No |
<position> |
Interface |
Interface where the EDR is triggered. Fields in EdrConstants: FIELD_INTERFACE Values in EdrConstants: VALUE_INTERFACE_NORTH, VALUE_INTERFACE_SOUTH, VALUE_INTERFACE_OTHER Provider INSIDE plug-in: M Provider OUTSIDE plug-in: M Mandatory: No |
<interface> |
State |
Where the EDR was dispatched. Fields in EdrConstants: FIELD_STATE Values in EdrConstants: ENTER_AT, ENTER_NT, ENTER_NET, EXIT_AT, EXIT_NT, EXIT_NET Provider INSIDE plug-in: M Provider OUTSIDE plug-in: M Mandatory: No |
<state> |
Exception |
Name of the exception that triggered the EDR. Fields in EdrConstants: FIELD_EXCEPTION_NAME Provider INSIDE plug-in: M Provider OUTSIDE plug-in: M Mandatory: No |
<name> inside <exception> |
SessionId |
Session ID. Fields in EdrConstants: FIELD_SESSION_ID Provider INSIDE plug-in: H Provider OUTSIDE plug-in: M Mandatory: No |
C |
ServiceProviderId |
Service provider account ID. Fields in EdrConstants: FIELD_SP_ACCOUNT_ID Provider INSIDE plug-in: H Provider OUTSIDE plug-in: M Mandatory: No |
C |
ApplicationId |
Application account ID. Fields in EdrConstants: FIELD_APP_ACCOUNT_ID Provider INSIDE plug-in: H Provider OUTSIDE plug-in: M Mandatory: No |
C |
AppInstanceId |
Application instance ID. Fields in EdrConstants: FIELD_APP_INSTANCE_ID Provider INSIDE plug-in: H Provider OUTSIDE plug-in: M Mandatory: No. |
C |
TransactionId |
Transaction ID. Fields in EdrConstants: FIELD_TRANSACTION_ID Provider INSIDE plug-in: H Provider OUTSIDE plug-in: M Mandatory: No. |
C |
Facade |
Facade. Fields in EdrConstants: FIELD_FACADE Values in EdrConstants: VALUE_FACADE_REST, VALUE_FACADE_SOAP Provider INSIDE plug-in: H Provider OUTSIDE plug-in: M Mandatory: No. |
C |
OrigAddress |
The originating address with scheme included (for example “tel:1234”). Fields in EdrConstants: FIELD_ORIGINATING_ADDRESS Provider INSIDE plug-in: M Provider OUTSIDE plug-in: M Mandatory: No |
C |
DestAddress |
The destination address(es) with scheme included (For example “tel:1234”). See "Using send lists". Fields in EdrConstants: FIELD_DESTINATION_ADDRESS Provider INSIDE plug-in: M Provider OUTSIDE plug-in: M Mandatory: No |
C |
<custom> |
Any additional information put into the current RequestContext using the putEdr() API will end up in the EDR. Fields in EdrConstants: - Provider INSIDE plug-in: - Provider OUTSIDE plug-in: - Mandatory: No |
C |
URL |
URL. Fields in EdrConstants: FIELD_URL Provider INSIDE plug-in: M Provider OUTSIDE plug-in: M Mandatory: No |
|
WebAppName |
Name of the current web application. Fields in EdrConstants: FIELD_WEB_APP_NAME Provider INSIDE plug-in: M Provider OUTSIDE plug-in: M Mandatory: No |
|
HttpMethod |
HTTP request method. For example "POST", or "GET". Fields in EdrConstants: FIELD_HTTP_METHOD Provider INSIDE plug-in: M Provider OUTSIDE plug-in: M Mandatory: No |
|
RequestContext |
Attributes in the request context map. Fields in EdrConstants: FIELD_REQUEST_CONTEXT Provider INSIDE plug-in: M Provider OUTSIDE plug-in: M Mandatory: No |
|
InterceptorChain |
List of all the interceptors that are triggered. Fields in EdrConstants: FIELD_INTERCEPTOR_CHAIN Provider INSIDE plug-in: M Provider OUTSIDE plug-in: M Mandatory: No |
|
SubscriberId |
Subscriber identifier (using route address) Fields in EdrConstants: FIELD_SUBSCRIBER_ID Provider INSIDE plug-in: M Provider OUTSIDE plug-in: M Mandatory: No |
If more than one address needs to be stored in the DestAddress field, use the following pattern. Both patterns described below can be used.
Example 11-8 Pattern to store one single or multiple addresses in field destination directly on EdrData.
EdrData data = ...; // If there is only one address data.setValue(EdrConstants.FIELD_DESTINATION_ADDRESS, address); // If there are multiple addresses data.setValues(EdrConstants.FIELD_DESTINATION_ADDRESS, addresses);
If you are using the current RequestContext object, simply store a List of addresses. The EdrDataHelper will automatically take care of converting this to a List of Strings in the EdrData.
Example 11-9 Pattern to store one single or multiple addresses in field destination using RequestContext.
RequestContext ctx = RequestContextManager.getCurrent(); // If there is only one address ctx.putEdr(EdrConstants.FIELD_DESTINATION_ADDRESS, address); // If there are multiple addresses URI[] addresses = ...; ctx.putEdr(EdrConstants.FIELD_DESTINATION_ADDRESS, Arrays.asList(addresses));
Figure 11-2 shows how and where information for the EDR is added to the RequestContext and how it finally ends up in the additional info column of the alarm and CDR databases.
There are 3 ways of putting information in the RequestContext that will end up in the EDR (more precisely in the EdrData object):
Using the putEdr() API of the RequestContext
Using the @ContextKey or @ContextTranslate annotation. In the case of the @ContextTranslate annotation, the information that will end up in the RequestContext will be what is put into the ContextInfo object.
Any information put in the RequestContext parameter of the PluginSouth.prepareRequestContext() method.
When an EDR is created, the EdrDataHelper (which is the recommended way to create the EDR) will populate the EdrData with all the key/value pairs found in the RequestContext.
When the EdrService writes the alarm or CDR additional information content into the database, it will use all the EdrData key/value pairs EXCEPT a set of well-known keys that are either not relevant or already included in other columns of the database, see "Alarm content" and "CDR content".
Only one type of EDR exists: alarms and CDRs are subsets of this EDR type. In order to categorize the flow of EDRs as either pure EDRS, alarms or CDRs, the EDR service uses 3 descriptors:
The EDR descriptor contains descriptors that describe pure EDRs.
The alarm descriptor contains descriptors that describe EDRs that should be considered alarms.
The CDR descriptor contains descriptors that describe EDRs that should be considered CDRs.
These XML descriptors can be manipulated using the EDR Configuration Pane as described in Managing and Configuring EDRs, CDRs and Alarms in the System Administrator's Guide. File representations of these must be included in edrjmslistener.jar if you are using external EDR listeners.
Each descriptor contains a list of EDR descriptors that define an EDR as a pure-EDR, as an alarm or as a CDR.
Descriptor | Descriptor | Description |
---|---|---|
EDR |
<edr...> |
Defines which EDRs are pure EDRs |
Alarm |
<alarm...> |
Defines which EDRs are alarms |
CDR |
<cdr...> |
Defines which EDRs are CDRs |
The descriptor is composed of two parts:
The <filter>
element: this is the filter
The <data>
element: this part is used to attach additional data with the EDR if it is matched by the <filter>
part
Table 11-5 describes the elements allowed in the <filter>
part:
Table 11-5 Elements allowed in <filter> part of an EDR descriptor.
Source | Filter | Min occurs | Max occurs | Description |
---|---|---|---|---|
<method> |
N/A |
0 |
unbounded |
Filter EDR triggered by a method |
<method> |
<name> |
0 |
unbounded |
Name of the method that triggered the EDR |
<method> |
<class> |
0 |
unbounded |
Name of the class that triggered the EDR |
<method> |
<direction> |
0 |
2 |
Direction of the request |
<method> |
<interface> |
0 |
3 |
Interface where the EDR has been triggered |
<method> |
<position> |
0 |
2 |
Position relative to the method that triggered the EDR |
<exception> |
N/A |
0 |
unbounded |
Filter EDR triggered by an exception |
<exception> |
<name> |
0 |
unbounded |
Name of the exception that triggered the EDR |
<exception> |
<class> |
0 |
unbounded |
Name of the class where the exception was thrown |
<exception> |
<method> |
0 |
unbounded |
Name of the method where the exception was thrown |
<exception> |
<direction> |
0 |
2 |
Direction of the request |
<exception> |
<interface> |
0 |
3 |
Interface where the EDR has been triggered |
<exception> |
<position> |
0 |
2 |
Position relative to the method that triggered the EDR |
<attribute> |
N/A |
0 |
unbounded |
Filter EDR by looking at custom attribute |
<attribute> |
<key> |
1 |
1 |
Name of the key |
<attribute> |
<value> |
1 |
1 |
Value |
Table 11-5 describes the values allowed for each element of the <filter> part:
Table 11-6 Values allowed in each element of the <filter> part.
Source | Filter | Allowed values | Comment |
---|---|---|---|
<method> |
<name> |
“returntype nameofmethod([args])” |
Method name. The arguments can be omitted with the parenthesis. See "Special characters" below. |
<method> |
<class> |
“fullnameofclass” |
Fully qualified class name. See "Special characters" below. |
<method> |
<direction> |
“south”, “north” |
N/A |
<method> |
<interface> |
“north”, “south”, “other” |
N/A |
<method> |
<position> |
“before”, “after” |
N/A |
<exception> |
<name> |
“fullnameofexceptionclass” |
Fully qualified exception class name. See "Special characters" below. |
<exception> |
<class> |
“fullnameofclass” |
Fully qualified class name where the exception was triggered. See "Special characters" below. |
<exception> |
<method> |
“returntype nameofmethod([args])” |
Method name. The arguments can be omitted with the parenthesis See "Special characters" below. |
<exception> |
<direction> |
“south”, “north” |
N/A |
<exception> |
<interface> |
“north”, “south”, “other” |
N/A |
<exception> |
<position> |
“before”, “after” |
N/A |
<attribute> |
<key> |
“astring” |
N/A |
<attribute> |
<value> |
“astring” |
N/A |
The filter uses special characters to indicate more precisely how to match certain values.
Using * at the end of a method, class or exception name matches all names that match the string specified prior to the * (that is, what the string starts with).
Note:
The use of any of these characters disables the caching of the filter containing them. To avoid a performance hit, using the other way of matching is strongly encouraged.To match on | Use the filter |
---|---|
All sendInfoRes methods with one argument of type int. |
<method> <name>void sendInfoRes(int)</name> ... </method> |
All methods starting with sendInfoRes regardless of the arguments. |
<method> <name>void sendInfoRes</name> ... </method> |
All methods starting with void sendInfo. |
<method> <name>void sendInfo*</name> ... </method> |
All class names beginning with com.bea.wlcp.wlng.plugin |
<method> <class>com.bea.wlcp.wlng.plugin*</class> ... </method> |
The exact value in these fields depends on who triggered the EDR. If the aspect triggered the EDR, then the name of the method (with return type and parameters) or the fully qualified name of the class/exception is indicated. If the EDR is manually triggered from the code, it is up to the implementer to decide what name to use. Here are some examples of fully qualified method/class names as specified by the aspect:
Example methods:
SendSmsResponse sendSms(SendSms) void receivedMobileOriginatedSMS(NotificationInfo, boolean, SmsMessageState, String, SmsNotificationRemote) TpAppMultiPartyCallBack reportNotification(TpMultiPartyCallIdentifier, TpCallLegIdentifier[], TpCallNotificationInfo, int)
Example Class:
com.bea.wlcp.wlng.plugin.sms.smpp.SMPPManagedPluginImpl
Figure 11-3 shows briefly how the filter works:
The EdrConfigSource elements are the following: <method>
, <exception>
or <attribute>
. They are combined using OR.
The filter elements of each EdrConfigSource are combined using AND. However, if the same filter is available more than once (e.g. multiple class names), it is combined with OR.
Example 1: filter
Example 11-10 categorizes EDRs as pure EDRs with an id of 1000 when the following conditions are met:
The class where the method triggered the EDR is com.bea.wlcp.wlng.plugin.AudioCallPlugin or any subclass of it.
AND the request is southbound (direction = south)
AND the interface where the EDR was trigger is north
AND the EDR has been triggered after the method has been executed (position = after)
Example 11-10 Example 1: filter
<edr id="1000" description="..."> <filter> <method> <class>com.bea.wlcp.wlng.plugin.AudioCallPlugin</class> <direction>south</direction> <interface>north</interface> <position>after</position> </method> </filter> </edr>
Example 2: Alarm filter
Example 11-11 categorizes EDRs as alarms when the following conditions are met:
The exception is the com.bea.wlcp.wlng.plugin.PluginException class or a subclass of it.
OR the name of the exception starts with org.csapi.*. Since “'*” is used, the matching will not be performed using the class hierarchy but only using a pure string matching.
The alarms descriptor has a <alarm-group>
element that is used to group alarms by service/source: this group id and each individual alarm id is used to generate the OID of SNMP traps.
Example 11-11 Example 2: filter
<alarm-group id="104" name="parlayX" description="Parlay X alarms">> <alarm id="1000" severity="minor" description="Parlay X exception"> <filter> <exception> <name>com.bea.wlcp.wlng.plugin.PluginException</name> <name>org.csapi*</name> </exception> </filter> </alarm> </alarm-group>
Example 3: Alarm filter
Example 11-12 categorizes EDRs as alarms when the following conditions are met:
The exception is the class com.bea.wlcp.wlng.plugin.PluginException or a subclass of it
OR the name of the exception starts with “org.csapi”. String matching in used.
AND the exception was triggered in a class whose name starts with com.bea.wlcp.wlng.plugin
AND the request is northbound (direction = north) when the exception was triggered
If the filter determines that the EDR is an alarm, the following attributes are available to the alarm listener. They are defined in the <data>
part.
identifier = 123
source = wlng_nt1
Example 11-12 Example 3: filter
<alarm id="1000" severity="minor" description="Parlay X exception"> <filter> <exception> <name>com.bea.wlcp.wlng.plugin.PluginException</name> <name>org.csapi*</name> <class>com.bea.wlcp.wlng.plugin*</class> <direction>north</direction> </exception> </filter> <data> <attribute key="identifier" value="123"/> <attribute key="source" value="wlng_nt1"/> </data> </alarm>
Example 4: filter
Example 11-13 (for example purposes only) categorizes EDRs as pure EDRs with the id 1002 when the following conditions are met:
The name of the method that triggered the EDR starts with “void play” AND the class is com.bea.wlcp.wlng.plugin.AudioCallPluginNorth or a subclass of it AND the EDR was triggered after executing this method.
OR the name of the method that triggered the EDR is “String getMessageStatus” AND the class is 'com.bea.wlcp.wlng.plugin.AudioCallPluginNorth' or a subclass of it AND the EDR was triggered before executing this method.
OR the name of the exception that triggered the EDR starts with com.bea.wlcp.wlng.bar AND the exception was triggered in a plug-in north interface
OR the name of the exception that triggered the EDR starts with com.bea.wlcp.wlng.plugin.exceptionA AND the exception was triggered in a class whose name starts with com.bea.wlcp.wlng.plugin.classD AND the exception was triggered in a method whose name starts with void com.bea.wlcp.wlng.plugin.methodA AND the exception was triggered in a plug-in north interface
OR the EDR contains an attribute with key attribute_a and value value_a
OR the EDR contains an attribute with key attribute_b and value value_b
Example 11-13 Example 4: filter
<edr id="1002"> <filter> <method> <name>void play*</name> <class>com.bea.wlcp.wlng.plugin.AudioCallPluginNorth</class> <position>after</position> </method> <method> <name>String getMessageStatus</name> <class>com.bea.wlcp.wlng.plugin.AudioCallPluginNorth</class> <position>before</position> </method> <exception> <name>com.bea.wlcp.wlng.bar*</name> <interface>north</interface> </exception> <exception> <name>com.bea.wlcp.wlng.plugin.exceptionA</name> <class>com.bea.wlcp.wlng.plugin.classD</class> <method>void com.bea.wlcp.wlng.plugin.methodA</method> <interface>north</interface> </exception> <attribute key="attribute_a" value="value_a"/> <attribute key="attribute_b" value="value_b"/> </filter> </edr>
Example 5: filter with corresponding code for manually triggering a matching EDR
Example 11-14 shows a manually triggered EDR with its corresponding filter. The EDR is triggered using these lines.
Example 11-14 Example 5: Trigger the EDR
// Declare the EdrDataHelper for each class private static final EdrDataHelper helper = EdrDataHelper.getHelper(MyClass.class); public void myMethodName() { ... // Create a new EdrData. Use the EdrDataHelper class to allow Services Gatekeeper to automatically populate some fields EdrData data = helper.createData(); // Because we are creating the EdrData manually, we have to provide the mandatory fields data.setValue(EdrConstants.FIELD_SOURCE, EdrConstants.VALUE_SOURCE_METHOD); data.setValue(EdrConstants.FIELD_METHOD_NAME, "myMethodName"); data.setValue("myKey", "myValue"); // Log the EDR EdrServiceFactory.getService().logEdr(data); ... }
This EDR can be filtered using Example 11-15 (note the various ways of identifying this EDR):
Example 11-15 Example: Filter 5
<edr id="1003"> <filter> <!-- Match both method name and class name --> <method> <name>myMethodName</name> <class>com.bea.wlcp.wlng.myClassName</class> </method> <!-- OR match only the method name (looser than matching also the class name) --> <method> <name>myMethodName</name> </method> <!-- OR match only the classname (looser than matching also the method name) --> <method> <class>com.bea.wlcp.wlng.myClassName</class> </method> <!-- OR match only the custom attribute --> <attribute key="myKey" value="myValue"/> </filter> </edr>
Below is a list of steps to take to make your plug-in able to use aspect EDRs:
Make sure to register all your PluginNorth (and south) objects within the ManagedPlugin before registering in the PluginManager.
Annotate all the methods you want to be woven using the @Edr annotation.
Annotate 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.
Add to the EDR descriptor all the EDRs you are triggering, either manually or with the @Edr annotation. This is the only way to customize alarms and CDRs.
If external EDR listeners, CDR, and alarms are used, the edrjmslistener.jar file needs to be updated on all the listeners. Add the contents of the EDR descriptors to edr.xml, CDR descriptor to cdr.xml, and alarm descriptor to alarm.xml. The xml files reside in the edr directory in edrjmslistener.jar.
Question (Q): Is it possible to specify both exception and method name in the filter section?
Example 11-16 Example: method name and exception in a filter.
<filter> <method> <name>internalSendSms</name> </method> <exception> <name>com.bea.wlcp.wlng.plugin.sms.smpp.TooManyAddressesException</name> </exception> </filter>
Answer
Yes, make sure that the <method>
element is before the <exception>
element. Otherwise the XSD will complain.
Q: Is it possible to specify multiple method names?
Answer
Yes.
Q: In some places I have methods re-throwing an exception. Is it possible to have only one of the methods generate the EDR and map that EDR to an alarm?
Re-throwing an exception
myMethodA()throws MyException{ myMethodB(); } myMethodB()throws MyException{ myMethodC(); } myMethodC()throws MyException{ ... //on error throw new MyException(“Exception text..”); }
Answer
In this case, only the first exception will be caught by aspects. Or more precisely, they will all be caught by aspects but will only trigger an EDR for the first one, but not for the re-thrown ones (if they are the same, of course). So you don't need to use the @NoEdr annotation for myMethodA and myMethodB.
Q: Will aspects detect the following exception?
Example exception
try{ throw new ReceiverConnectionFailureException(message); }catch(ReceiverConnectionFailureException connfail){ //EDR-ALARM-MAPPING }
Answer
This exception will not be detected by aspects. If you need to generate an EDR you will have to either manually create an EDR or call a method throwing an exception.
Q: Will EDRs for exceptions also work for private methods?
Answer
Yes, EDRs can work for any method.
Q: Will exceptions be disabled with the @NoEdr annotation?
Answer
Yes, with the @NoEdr annotation you will not get any EDRs, not even for exceptions.
Q: How can data from the current context be included in an alarm?
For example, can an alarm be generated in a request with more than 12 destination addresses? How can information about how many addresses were included in the request be added to the alarm
It is possible to specify some info in the alarm descriptor with something like
<data> <attribute key="source" value="thesource"/> </data>
Can something be put in the RequestContext using the putEdr method and then get it into the alarm in some way?
Answer
Yes, add custom information by putting this information into the current RequestContext, as show below.
RequestContext ctx = RequestContextManager.getCurrent(); ctx.putEdr("address", "tel:1234");
This value is part of any EDRs generated in the current request.
The information will be available in the database in the additional_info column. Make sure you are putting in only relevant information.
Q: Is it possible to specify classname in the filtering section?
Answer
Yes, use the <class>
element inside <method>
or <exception>
in the filter.
<filter> <exception> <class>com.y.y.z.MyClass</class> <name>com.x.y.z.MyException</name> </exception> </filter>
An alarm is a subset of an EDR. To generate an alarm, generate an EDR, either using one generated in aspects or programmatically, and define the ID and the descriptor of the alarm in the alarm descriptor.
The alarm ID, severity, description and other kind of attributes are defined in the alarm descriptor, see "The EDR descriptor". For extensions, the alarm ID should be in the 500 000 to 999 999 range.
Note:
The alarm filter that provides the first match in the alarm descriptor is used for triggering the alarm.There are two ways to trigger an alarm:
Use an existing EDR that is generated in the plug-in and add its descriptor to the alarm descriptor.
Programmatically trigger an EDR and add its descriptor in both the alarm descriptor file and the EDR descriptor. Make sure the ID of the alarm is unique and that the description is the same as in the EDR descriptor.T
Trigger an EDR as described in "EDR Content". Then specify in the alarm descriptor the corresponding alarms.
Example 11-17 Example code to trigger an alarm
private static final EdrDataHelper helper = EdrDataHelper.getHelper(MyClass.class); ... EdrData data = helper.createData(); data.setValue(EdrConstants.FIELD_SOURCE, EdrConstants.VALUE_SOURCE_METHOD); data.setValue(EdrConstants.FIELD_METHOD_NAME, "com.bea.wlcp.wlng.myMethod"); data.setValue("myAdditionalInformation", ...); EdrServiceFactory.getService().logEdr(data); ...
The corresponding entry in the alarm descriptor that matches this EDR is shown below.
Table 11-8 shows a list of the information provided in alarms.
Table 11-8 Alarm information for alarm listeners, also stored in DB
Field | Comment |
---|---|
alarm_id |
Unique ID for the alarm. Automatically provided by the EdrService. |
source |
Service name emitting the alarm. Automatically provided by the EdrService. |
timestamp |
Timestamp in milliseconds since midnight, January 1, 1970 UTC. Automatically provided by the EdrService. |
severity |
Severity level. Defined in the alarm. descriptor. |
identifier |
The alarm identifier. Defined in the alarm descriptor. The column in the database will always contain the identifier defined in the alarm descriptor. |
alarm_info |
The alarm information or description. Defined in the alarm descriptor. |
additional_info |
Automatically provided by the EdrService. Not valid for backwards compatible alarm listeners. Each entry is formatted as: key=value\n Similar to the Java properties file. All the custom key/value pairs found in the EdrData except these are present (EdrConstants if not specified):
|
A CDR is a subset of an EDR. To generate a CDR, generate an EDR and define the ID of the EDR in the CDR descriptor.
There are two ways to trigger a CDR:
Use an existing EDR that is generated in the plug-in and add its description to the CDR descriptor.
Programmatically trigger an EDR and add its description to the CDR descriptor.
If none of the existing EDRs is appropriate for a CDR, you can programmatically trigger an EDR that will become a CDR. See the section, "Triggering an EDR Programmatically" for information on how to create and trigger an EDR. Specify in the CDR descriptor the description necessary for this EDR to be considered a CDR.
Example 11-19 Example, triggering a CDR
private static final EdrDataHelper helper = EdrDataHelper.getHelper(MyClass.class); ... EdrData data = helper .createData(); data.setValue(EdrConstants.FIELD_SOURCE, EdrConstants.VALUE_SOURCE_METHOD); data.setValue(EdrConstants.FIELD_METHOD_NAME, "com.bea.wlcp.wlng.myEndOfRequestMethod"); // Fill the required fields for a CDR data.setValue(EdrConstants.FIELD_CDR_START_OF_USAGE, ...); ... EdrServiceFactory.getService().logEdr(data); ...
The description, in the CDR descriptor, that matches this EDR is shown in Example 11-20.
In addition to the EDR fields, there are specific fields used only for CDRs. They are listed in Table 11-5.
Table 11-9 Fields in EdrConstants specific for CDRs.
Field in EdrConstants | Comment |
---|---|
FIELD_CDR_SESSION_ID |
Session ID |
FIELD_CDR_START_OF_USAGE |
Start Time |
FIELD_CDR_CONNECT_TIME |
Connect Time |
FIELD_CDR_END_OF_USAGE |
End Time |
FIELD_CDR_DURATION_OF_USAGE |
Duration |
FIELD_CDR_AMOUNT_OF_USAGE |
Amount |
FIELD_CDR_ORIGINATING_PARTY |
Originating Party |
FIELD_CDR_DESTINATION_PARTY |
Same pattern applies as for send lists, see "Using send lists". |
FIELD_CDR_CHARGING_INFO |
Charging Information |
The structure of the CDR content is aligned toward the 3GPP Charging Applications specifications. As a result the database schema has been changed to accommodate these ends and to facilitate future extensions.
Legends:
NU: Not used
NC: New column in DB
RC: Renamed column in DB
Table 11-10 Content in database
Field | Comment | DB |
---|---|---|
transaction_id |
Unique id for the CDR. Provided automatically by the EDR service. |
x |
service_name |
name of the service Provided automatically by the EDR service. |
x |
service_provider |
the service provider account ID Provided automatically by the EDR service. |
x |
application_id |
the application account ID (was user_id in 2.2) |
RC |
application_instance_grp_id |
the application instance ID. |
NC |
container_transaction_id |
id of the current user transaction Provided automatically by the EDR service. |
NC |
server_name |
name of the server that generated the CDR. Provided automatically by the EDR service. |
NC |
timestamp |
in ms since midnight, January 1, 1970 UTC |
NC |
service_correlation_id |
Service Correlation ID. Provided automatically by the EDR service. |
NC |
charging_session_id |
Id that correlates requests that belong to one charging session as defined by the plug-in. Was 'session_id' in 2.2. Plug-in specific. Plug-in needs to put the value into the RequestContext of the request that will trigger the CDR. |
x |
start_of_usage |
The date and time the service capability module started to use services in the network (in ms since midnight, January 1, 1970 UTC) Plug-in specific. Plug-in needs to put the value into the RequestContext of the request that will trigger the CDR. |
x |
connect_time |
The date and time the destination party responded (in ms since midnight, January 1, 1970 UTC). Used for call control only. Plug-in specific. Plug-in needs to put the value into the RequestContext of the request that will trigger the CDR. |
x |
end_of_usage |
The date and time the service capability module stopped using services in the network (in ms since midnight, January 1, 1970 UTC). Plug-in specific. Plug-in needs to put the value into the RequestContext of the request that will trigger the CDR |
x |
duration_of_usage |
The total time the service capability module used the network services (in ms) Plug-in specific. Plug-in needs to put the value into the RequestContext of the request that will trigger the CDR |
x |
amount_of_usage |
Plug-in specific. Plug-in needs to put the value into the RequestContext of the request that will trigger the CDR. |
x |
originating_party |
The originating party address with scheme included (e.g. “tel:1234”) Plug-in specific. Plug-in needs to put the value into the RequestContext of the request that will trigger the CDR. |
x |
destination_party |
the originating party address with scheme included (e.g. “tel:1234”). Additional addresses are stored in the additional_info field. |
x |
charging_info |
The charging service code from the application. Plug-in specific. Plug-in needs to put the value into the RequestContext of the request that will trigger the CDR. |
x |
additional_info |
Additional information provided by the plug-in |
x |
revenue_share_percentage |
Not used. |
NU |
party_to_charge |
Not used. |
NU |
slee_instance |
Not used. |
NU |
network_transaction_id |
Not used. |
NU |
network_plugin_id |
Not used. |
NU |
transaction_part_number |
Not used. |
NU |
completion_status |
Not used. |
NU |
The EDR populates the additional_info column of the DB with all the custom key/value pairs found in the EdrData except the ones listed below.
Excluded keys (EdrConstants if not specified):
FIELD_SERVICE_NAME
FIELD_APP_INSTANCE_ID
FIELD_SP_ACCOUNT_ID
FIELD_CONTAINER_TRANSACTION_ID
FIELD_SERVER_NAME
FIELD_TIMESTAMP
ExternalInvocatorFactory.SERVICE_CORRELATION_ID
FIELD_CDR_SESSION_ID
FIELD_CDR_START_OF_USAGE
FIELD_CDR_CONNECT_TIME
FIELD_CDR_END_OF_USAGE
FIELD_CDR_DURATION_OF_USAGE
FIELD_CDR_AMOUNT_OF_USAGE
FIELD_CDR_ORIGINATING_PARTY
FIELD_CDR_DESTINATION_PARTY
FIELD_CDR_CHARGING_INFO
FIELD_CLASS_NAME
FIELD_METHOD_NAME
FIELD_SOURCE
FIELD_DIRECTION
FIELD_POSITION
FIELD_INTERFACE
FIELD_STATE
FIELD_EXCEPTION_NAME
FIELD_ORIGINATING_ADDRESS
FIELD_DESTINATION_ADDRESS
FIELD_CORRELATOR
FIELD_APP_ACCOUNT_ID
FIELD_SESSION_ID
FIELD_TRANSACTION_ID
FIELD_FACADE
FIELD_URL
FIELD_WEB_APP_NAME
FIELD_REQUEST_CONTEXT
FIELD_INTERCEPTOR_CHAIN
FIELD_SUBSCRIBER_ID
FIELD_BC_EDR_ID
FIELD_BC_EDR_ID_3
FIELD_BC_ALARM_IDENTIFIER
FIELD_BC_ALARM_INFO
Two keys not present in the EdrData are added to additional_info.
Table 11-11 Keys not present in EdrData, but added in additional_info
Key | Description |
---|---|
destinationParty |
If a send list is specified as the destination party, the first address will be written in the destination_party field of the DB and the remainder of the list will be written under this key name |
oldInfo |
Any backwards compatible additional info is available |
The format of the additional_info field is formatted as:
key=value\n
similar to the Java properties file.
It is difficult to come up with a CDR generation scheme that fulfills the requirements of all customers. Oracle Communications Services Gatekeeper generates a default set of CDRs which can be customized by re-configuring the CDR descriptor.
The guiding principle for deciding when to generate CDRs is:
Generate a CDR when you are 100% sure that you have completely handled the service request
In other words, after the last method, in a potential sequence of method calls, returns.
For network-triggered requests this means that you should a trigger a CDR at the south interface after the method has returned back to the network. For application-triggered requests generate a CDR at the north interface after the method has returned to the Network Tier SLSB.