# Platform Development Studio - Developer’s Guide

# Annotations, EDRs, Alarms, and CDRs

The following section describe aspects and generation of EDRs, alarms, CDRs, and statistics:

- About aspects and annotations
- How aspects are applied
- Context Aspect
- EDR Generation

- Exception scenarios
- Adding data to the RequestContext
- Trigger an EDR programmatically
- EDR Content
- RequestContext and EDR

- Categorizing EDRs

- The EDR descriptor

- Check-list for EDR generation
- Alarm generation

- Trigger an alarm programmatically
- Alarm content

- CDR generation

- Triggering a CDR
- Trigger a CDR programmatically
- CDR content
- Out-of-the box (OOTB) CDR support

## About aspects and annotations

Aspects allow developers to manage cross-cutting concerns in their code in a straight forward and coherent way. Aspects in Oracle Communications 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.

## How aspects are applied

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 Oracle Communications 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.

## Context Aspect

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 Plugin 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:

1. 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.
2. The plug-in puts the application instance ID and the ID for the request into a store.
3. At a later stage, when a response to the original requests arrives at the plug-in, the method `resolveAppInstanceGroupId()` is called by aspects.
4. 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.
5. The aspect authenticates the application instance with the container and puts the application instance ID in the RequestContext.
6. 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.

Listing 9-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.

Listing 9-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.

## EDR Generation

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 9-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)

### Exception scenarios

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.

The diagram illustrates typical scenarios when a library (or core service) throws an exception in the plug-in.

Figure 9-1 Exception scenarios

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.

### Adding data to the RequestContext

In addition to the default values, an EDR also contains all the values put into the RequestContext using the`putEdr()` method.

Listing 9-3 Example to add values to and EDR using RequestContex

    ...

    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.

#### Using translators

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
Listing 9-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.

Listing 9-5 Example of a 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.

Listing 9-6 Example of registering a context translator

    ContextTranslatorManager.register(ACContextTranslator.class.getName(), new ACContextTranslator());

Below is a summary of annotations to use.

Table 9-2 Annotations
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.

### Trigger an EDR programmatically

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:

1. Create an EdrData object
2. Trigger the EDR using the EdrService instance

Below is an example of triggering an EDR from inside a plug-in.

Listing 9-7 Trigger 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);

          ...

       }

    }

### EDR Content

The following table describes the content of an EDR. It describes 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 element <attribute> to specify a custom filter.

Note: | EDRs triggered by aspects will have all the mandatory fields provided by the aspect.

Table 9-3 EDR content
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>
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
AppInstanceGroupId | Application instance ID. Fields in EdrConstants: FIELD_APP_INSTANCE_GROUP_ID 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

#### Using send lists

If more than one address needs to be stored in the DestAddress field, use the following pattern. Both patterns described below can be used.

Listing 9-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.

Listing 9-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));

### RequestContext and EDR

The following diagram 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.

Figure 9-2 RequestContext and EDR

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.

## Categorizing EDRs

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.

### The EDR descriptor

Each descriptor contains a list of EDR descriptors that define an EDR as a pure-EDR, as an alarm or as a CDR.

Table 9-4 EDR descriptors.
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 9-5 describes the elements allowed in the <filter> part:

Table 9-5 Elements allowed in <filter> part of an EDR descriptor.
Source | Filter | Min occurs | Max occurs | Description
--- | --- | --- | --- | ---
<method> |  | 0 | unbounded | Filter EDR triggered by a method
| <name> | 0 | unbounded | Name of the method that triggered the EDR
| <class> | 0 | unbounded | Name of the class that triggered the EDR
| <direction> | 0 | 2 | Direction of the request
| <interface> | 0 | 3 | Interface where the EDR has been triggered
| <position> | 0 | 2 | Position relative to the method that triggered the EDR
<exception> |  | 0 | unbounded | Filter EDR triggered by an exception
| <name> | 0 | unbounded | Name of the exception that triggered the EDR
| <class> | 0 | unbounded | Name of the class where the exception was thrown
| <method> | 0 | unbounded | Name of the method where the exception was thrown
| <direction> | 0 | 2 | Direction of the request
| <interface> | 0 | 3 | Interface where the EDR has been triggered
| <position> | 0 | 2 | Position relative to the method that triggered the EDR
<attribute> |  | 0 | unbounded | Filter EDR by looking at custom attribute
| <key> | 1 | 1 | Name of the key
| <value> | 1 | 1 | Value

Table 9-6 describes the values allowed for each element of the <filter> part:

Table 9-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.
| <class> | “fullnameofclass” | Fully qualified class name. See Special characters below.
| <direction> | “south”, “north” |
| <interface> | “north”, “south”, “other” |
| <position> | “before”, “after” |
<exception> | <name> | “fullnameofexceptionclass” | Fully qualified exception class name. See Special characters below.
| <class> | “fullnameofclass” | Fully qualified class name where the exception was triggered. See Special characters below.
| <method> | “returntype nameofmethod([args])” | Method name. The arguments can be omitted with the parenthesis See Special characters below.
| <direction> | “south”, “north” |
| <interface> | “north”, “south”, “other” |
| <position> | “before”, “after” |
<attribute> | <key> | “astring” |
| <value> | “astring” |

#### Special characters

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 usage 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.

Table 9-7 Example filters
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>

#### Values provided

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

#### Boolean semantic of the filters

The following diagram 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), they are combined with OR.
Figure 9-3 Filter mechanism

#### Example filters

##### Example 1: filter

Listing 9-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)
Listing 9-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

Listing 9-11categorizes 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.*. 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.

Listing 9-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

Listing 9-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
Listing 9-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

Listing 9-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 plugin 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
Listing 9-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

Listing 9-14 shows a manually triggered EDR with its corresponding filter. The EDR is triggered using these lines.

Listing 9-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 Listing 9-15 (note the various ways of identifying this EDR):

Listing 9-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>

## Check-list for EDR generation

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 file `edrjmslistener.jar` 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 resides in the directory `edr` in `edrjmslistener.jar`.

## Frequently Asked Questions about EDRs and EDR filters

Question: Is it possible to specify both exception and method name in the filter section?

Listing 9-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?

Listing 9-17 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?

Listing 9-18 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> tag 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>

## Alarm generation

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 shall be in the range 500 000 to 999 999.

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 alarm programmatically

Trigger an EDR as described in EDR Content. Then specify in the alarm descriptor the corresponding alarms.

Listing 9-19 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.

Listing 9-20 Alarm descriptor

      <alarm id="2006"

             severity="major"

             description="Sample alarm">

        <filter>

          <method>

            <name>com.bea.wlcp.wlng.myMethod</name>

            <class>com.bea.wlcp.wlng.myClass</class>

          </method>

        </filter>

      </alarm>

### Alarm content

Below is a list of the information provided in alarms.

Table 9-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): FIELD_TIMESTAMP FIELD_SERVICE_NAME FIELD_CLASS_NAME FIELD_METHOD_NAME FIELD_SOURCE FIELD_DIRECTION FIELD_POSITION FIELD_INTERFACE FIELD_EXCEPTION_NAME FIELD_ORIGINATING_ADDRESS FIELD_DESTINATION_ADDRESS FIELD_CONTAINER_TRANSACTION_ID FIELD_CORRELATOR FIELD_SESSION_ID FIELD_SERVER_NAME ExternalInvocatorFactory.SERVICE_CORRELATION_ID FIELD_BC_EDR_ID FIELD_BC_EDR_ID_3 FIELD_BC_ALARM_IDENTIFIER FIELD_BC_ALARM_INFO

## CDR generation

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.

### Triggering a CDR

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.

### Trigger a CDR programmatically

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, Trigger 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.

Listing 9-21 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 Listing 9-22.

Listing 9-22 Filter to match the EDR

    <cdr>

        <filter>

          <method>

            <name>com.bea.wlcp.wlng.myEndOfRequestMethod</name>

            <class>com.bea.wlcp.wlng.myClass</class>

          </method>

        </filter>

    </cdr>

### CDR content

In addition to the EDR fields, there are specific fields used only for CDRs. They are listed in Table 9-9.

Table 9-9 Fields in EdrConstants specific for CDRs.
Field in EdrConstants | Comment
--- | ---
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 | Same pattern applies as for send lists, see Using send lists.
FIELD_CDR_CHARGING_INFO |

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 9-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

#### Additional_info column

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_GROUP_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_EXCEPTION_NAME
- FIELD_ORIGINATING_ADDRESS
- FIELD_DESTINATION_ADDRESS
- FIELD_CORRELATOR
- FIELD_APP_ACCOUNT_ID
- FIELD_SESSION_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 9-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.

### Out-of-the box (OOTB) CDR support

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.