Skip Headers
Oracle® Communication and Mobility Server Developer Guide
Release 10.1.3

Part Number B31511-01
Go to Documentation Home
Home
Go to Book List
Book List
Go to Table of Contents
Contents
Go to Index
Index
Go to Feedback page
Contact Us

Go to previous page
Previous
Go to next page
Next
View PDF

B Programming Oracle Diameter Applications

This appendix describes programming Oracle Diameter applications in the following sections:

IP and Routes Configuration

Before a Java Diameter application is able to process messages exchanged with a distant peer, the IP configuration and Diameter protocol-specific configuration have to be done by the application as follows:

  1. Create a DiameterStack instance.

  2. Register the Diameter application to the Diameter stack.

  3. Create listening points to bind to local transport addresses.

  4. Configure routes and connect to Diameter peers.

Creating a Diameter Stack

An instance of the Diameter stack can be created as follows:

import oracle.sdp.diameter.*;
DiameterFactory myFactory;
DiameterStack myStack;
myFactory = DiameterFactory.getInstance();
myStack =  myFactory.createDiameterStack("realm.domain.com",
        "server.realm.domain.com",
        null);

This code creates a Diameter stack for use by the local Diameter node in which Fully Qualified Domain Name (FQDN) is server.realm.domain.com and Origin Realm is realm.domain.net.

Binding to Local Transport Addresses

When a Diameter application needs to listen for incoming connections on one or several transport addresses, it has to create one or several instances of the DiameterListeningPoint interface:

String localURI = "aaa://server.realm.domain.com:41001";
myStack.createDiameterListeningPoint(localURI);

As soon as the listening point has been created, the Diameter stack is ready to accept incoming connection from remote peers. If the Diameter stack receives a connection request from a peer that as not been declared in the routing table, then the isUnknownPeerAuthorized() of the DiameterListener interface is called. The connection is accepted only if this method returns true.

Note:

There is no need for the user application to keep the references on the listening points since they can be retrieved later by calling DiameterStack.getDiameterListeningPoints().

Configuring Routes and Binding to Diameter Peers

A Diameter client application can declare remote peers by using the createDiameterRoute()method.

The code fragment illustrated in Example B-1 configures two Diameter realms, realm1.domain.com and realm2.domain.com. The first realm is served by two peers: peer1.realm1.domain.com and peer2.realm1.domain.com, whereas the second realm is served by only one peer, peer.realm2.domain.com. The metric values (1 and 2) are such that peer1 and peer2 are set up in master/backup mode. Example B-1 illustrates this source code for setting up this peer configuration.

Example B-1 Configuring Peers

myStack.createDiameterRoute("ExampleApp", "realm1.domain.com",
                            "aaa://peer1.realm1.domain.com", 1);
myStack.createDiameterRoute("ExampleApp", "realm1.domain.com",
                            "aaa://peer2.realm1.domain.com", 2);
myStack.createDiameterRoute("ExampleApp", "realm2.domain.com",
                            "aaa://peer.realm2.domain.com:41002", 1);

Note:

If a peer name (FQDN) is used in createDiameterRoute() and if that peer is not yet known to the local stack, a transport connection is initiated with the peer using the specified peer URI (taking into account any URI optional information such as port number and transport protocol). On the contrary, if the peer specified by the FQDN part of the URI is already known, the URI is ignored, and the existing peer entry is added to the routing table for the specified realm and application ID.

Realm State Availability

The DiameterRealmStateChangeEvent class is used to notify the application of the reachability or unreachability of a remote realm as a result of peers coming up or down. This is important because the Diameter stack will not accept an outgoing message for which the remote realm is not available. Therefore, the application should wait until the realm is available before sending requests.

A RealmStateChange event is passed to DiameterListener.processEvent() whenever the availability of a pair (Remote-Realm, Application-ID) changes. The availability of a remote realm for a given application ID depends on the availability of active connections to at least one remote peer that is able to serve the specific realm and application ID. Since the route is not available, the application is not able to exchange messages with the remote realm peers.

Example B-2 illustrates a typical implementation of the DiameterListener.processEvent() method.

Example B-2 Implementing the DiameterListener.processEvent() Method

public void processEvent(DiameterEvent event)
{
  if (event instanceof DiameterRealmStateChangeEvent) {
      // A remote realm has become available or unavailable
      DiameterRealmStateChangeEvent event =
 (DiameterRealmStateChangeEvent)event;
      if (event.isRealmAvailable()) {
        System.out.println("Realm " + event.getRealm() + " is available");
      } else {
        System.out.println("Realm " + event.getRealm() + " is unavailable");
      }
      // ...
  }

Counters Management

Upon Diameter stack initialization, a set of defined counters is initialized and associated to each DiameterStack and DiameterProvider instance created by the application. These counters are defined in the DiameterStackImplMBean and DiameterProviderImplMBean management interfaces.

There are two ways to access to these counters:

  1. Directly, by calling one of the different methods defined in both management interface.

  2. Remotely, by registering the Diameter MBeans to a JMX agent using javax.management package. Only the JDK 1.5 provides this package.

MBeans Management Interface

There are two management interfaces defined in the oracle.sdp.diameterimpl package:

  1. DiameterStackImplMBean: This interface represents the management API for an instance of the DiameterStack interface.

  2. DiameterProviderImplMBean: This interface represents the management API for an instance of the DiameterProvider interface

Example B-3 illustrates how to directly get the value of one of these defined counters:

Example B-3 Getting the Value of a Counter

//--> Example Stack: getting the NbTransactions counter
MyStack->getNbTransactions();
//--> Example Provider: getting the NbSessionsCreated counter
MyProvider->getNbSessionsCreated();

Managing a Diameter Application with MBeans

A Diameter Application can be managed remotely by registering the Diameter MBeans to a JMX agent and can be monitored by using the Java JConsole program.

Registering the Diameter MBeans

A Java application using the Diameter API can publish management information by registering instances of the DiameterStackImplMBean and DiameterProviderImplMBean interfaced to a JMX agent. This can be done as follows:

import javax.management.MBeanServerFactory;
import javax.management.MBeanServer;
import javax.management.ObjectName;
 
import oracle.sdp.diameter.*;
 
// Create DiameterStack and DiameterProvider instances.
// DiameterStack myStack = ...
// DiameterProvider myProvider = ...
List srvList = MBeanServerFactory.findMBeanServer(null);
 
if (srvList.isEmpty() == false) {
 MBeanServer server = (MBeanServer)srvList.iterator().next();
 try {
   ObjectName name;
 
   name = new ObjectName( "oracle.sdp.diameterimpl:name=DiameterProvider");
   server.registerMBean(myProvider, name);
 
   name = new ObjectName("oracle.sdp.diameterimpl:name=DiameterStack");
   server.registerMBean(myStack, name);
 }
 catch (Exception e) {
   // Handle register exception
   // ...
 }
}

Note:

This code requires the JDK 1.5 or later. Previous versions do not have the required javax.management package.

If you intend to allow remote access to the MBeans, you must define the Java property com.sun.management.jmxremote when running your application, as follows:

java -Dcom.sun.management.jmxremote -classpath mdiameter.jar MyApplication

Using jconsole to Monitor Diameter Applications

When you have a Diameter application running -- and provided you have registered the MBeans as described above -- you can use the JDK's jconsole application to browse the management characteristics of the stack and application.

Start jconsole as follows:

jconsole

And then select the application's JVM from the local list. The Diameter MBeans should be visible under the MBeans tab.

Dictionary

This section includes the following topics:

Dictionary Composition

When a user's application requires using commands or AVPs that are not defined in the default loaded application dictionary, the user can extend the dictionary to define new commands and/or AVPs syntaxes to be used by the Diameter stack.

dictionary Element

The root or top-level element of a Diameter dictionary extension is the <dictionary> element:

<dictionary>
.... (other elements)
</dictionary>

The <dictionary> element contains zero or more <vendor> elements and zero or more <application> elements.

vendor Element

The <vendor> element defines a vendor by a name and associated IANA.

The <vendor> attributes are:

  1. The vendor id attribute must be unique across all <vendor> element definitions of the dictionary. The value 0 is dedicated to the base protocol which corresponds to the syntaxes defined in [RFC-3588] and [RFC-4006].

  2. The vendor name attribute is some text describing the vendor.

In Example B-4, the <vendor> element defines the vendor named "3GPP" whose enterprise code is 10415:

Example B-4 Defining a Vendor

<dictionary>
      <vendor id="10415" name="3GPP">
      ....(other elements)
      </vendor>
</dictionary>

The <vendor> element contains zero or more <returnCode> elements and zero or more <avp> elements.

application Element

One of the ways in which the Diameter protocol can be extended is through the addition of new applications.

The <application> element defines the new commands needed to support a new vendor Diameter application.

The <application> attributes are:

  1. The application id attribute is the IANA-assigned Application Identifier for this application. The value 0 is dedicated to the base protocol which corresponds to the commands defined in RFC-3588 and RFC-4006.

  2. The application name attribute is the human-readable name of this application.

  3. The application vendor attribute is the name of the application vendor as previously defined in the <vendor> element.

  4. The application service-type attribute defined the type of service delivered by the application. Possible values are "Acct" for accounting and "Auth" for authorization.

In Example B-5, the <application> element contains information for the 3GPP accounting "Rf" application identified by the value "3":

Example B-5 Defining an <application> Element

<dictionary>
      <application id="3" name="Rf" vendor="3GPP" service-type="Acct">
      ....(other elements)
      </application>
</dictionary>

The <application> element contains zero or more <command> elements.

command Element

A <command> element defines the attributes for a command.

The <command> attributes are:

  1. The command name attribute defines the name of the command. Because only one command is defined for both "Request" and "Answer" portions, the "Accounting" command defines both "Accounting-Request" and "Accounting-Answer" messages.

  2. The command code attribute defines the command code used to transmit this command.

In Example B-6, the Rf application contains the command "Accounting" whose code is 271:

Example B-6 Defining the <command> Element

<dictionary>
      <application id="3" name="Rf" vendor="3GPP" service-type="Acct">
         <command name="Accounting" code="271" />
         ....
      </application>
</dictionary>

returnCode Element

The <returnCode> element defines a possible value of the Result-Code AVP. In Example B-7, the 3GPP vendor defines the returnCode 5030 named DIAMETER_USER_UNKNOWN.

Example B-7 Defining the <returnCode> Element

<dictionary>
      <vendor id="10415" name="3GPP">
         <returnCode name="DIAMETER_USER_UNKNOWN" code="5030" />
         ....
      </vendor>
</dictionary>

avp Element

The <avp> element defines an AVP as described in RFC-3588.

The <avp> attributes are:

  1. The avp name attribute is the human-readable name of this AVP.

  2. The avp code attribute defines the integer value used to encode the AVP for transmission on the network.

  3. The avp mandatory attribute defines whether the mandatory bit of this AVP should or should not be set. Possible values are "must" or "mustnot".

  4. The avp protected attribute defines whether the protected bit of this AVP should or should not be set. Possible values are "may" or "maynot".

  5. The avp may-encrypt attribute defines whether the AVP has to be encrypted in case of CMS security usage. Possible values are "yes" or "no".

  6. The avp vendor-specific attribute specifies if this is a vendor specific AVP or not. Possible values are "yes" or "no".

In Example B-8, the 3GPP vendor extends the dictionary with the AVP "Application-provided-called-party-address".

Example B-8 Defining the <avp> Element

<dictionary>
      <vendor id="10415" name="3GPP">
         <avp name="Application-provided-called-party-address"
            code="837"
            mandatory="mustnot"
            protected="may"
            may-encrypt="no"
            vendor-specific="yes">
            ....
         </avp>
      </vendor>
</dictionary>

The <avp> element regroups either a <type> element or a <grouped> element.

type Element

The <type> element defines the data type of the AVP in which it appears. This element must appear in all non-grouped AVP definitions.

The type-name attribute of the <type> element contains the data type name as defined in RFC-3588: Possible values are:

  • "OCTETSTRING"

  • "INTEGER32"

  • "INTEGER64"

  • "UNSIGNED32"

  • "UNSIGNED64"

  • "FLOAT32"

  • "FLOAT64"

  • "ADDRESS"

  • "IPADDRESS"

  • "TIME"

  • "UTF8STRING"

  • "DIAMETERIDENTITY"

  • "DIAMETERURI"

  • "IPFILTERRULE"

  • "QOSFILTERRULE"

  • "ENUMERATED"

  • "GROUPED"

Note:

These values are case-sensitive.

In Example B-9, the AVP "Application-provided-called-party-address" is an UTF8String.

Example B-9 Defining the <type> Element

<dictionary>
   <vendor id="10415" name="3GPP">
      <avp name="Application-provided-called-party-address"
         code="837"
         mandatory="mustnot"
         protected="may"
         may-encrypt="no"
         vendor-specific="yes">
            <type type-name="UTF8String"/>
      </avp>
   </vendor>
</dictionary>

enum Element

The <enum> element defines a name which is mapped to an Unsigned32 value used in encoding and decoding AVPs of type Unsigned32. Enumerated elements should only be used with Unsigned32 typed AVPs.

The <enum> element's attributes are:

  1. The enum name attribute is the text corresponding to a particular value for the attribute.

  2. The enum code attribute is the Unsigned32 value corresponding to this enumerated value

In Example B-10, the Accounting-Record-Type AVP has four values: EVENT_RECORD, START_RECORD, INTERIM_RECORD and STOP_RECORD.

Example B-10 Defining the <enum> Element

<dictionary>
      <vendor id="10415" name="3GPP">
         <avp name="Accounting-Record-Type"
            code="480"
            mandatory="must"
            protected="may"
            may-encrypt="yes">
               <type type-name="Unsigned32"/>
               <enum name="EVENT_RECORD" code="1"/>
               <enum name="START_RECORD" code="2"/>
               <enum name="INTERIM_RECORD" code="3"/>
               <enum name="STOP_RECORD" code="4"/>
         </avp>
      </vendor>
</dictionary>

grouped Element

The <grouped> element defines an AVP which encapsulates a sequence of AVPs together as a single payload. It consists in grouping one or more <gavp> elements. This way, a single "grouped" element can contain references to multiple AVPs. Each <gavp> element holds an AVP name and a vendor-id attribute.

The <gavp> attributes are:

  1. The gavp name attribute must correspond to some existing AVP's name attribute.

  2. The gavp vendor-id attribute refers to an existing vendor's id attribute.

    In Example B-11, the 3GPP vendor defines an AVP named "CC-Money" which is a set of previously defined AVPs named "Unit-Value" and "Currency-Code".

Example B-11 Defining the <grouped> and <gavp> Elements

<dictionary>
      <vendor id="10415" name="3GPP">
         <avp name="CC-Money"
            code="413"
            mandatory="must"
            protected="may"
            may-encrypt="yes">
               <grouped>
                  <gavp name="Unit-Value" />
                  <gavp name="Currency-Code" />
                  ....
               </grouped>
         </avp>
      </vendor>
</dictionary

Dictionary Extension

Once the Diameter dictionary extension has been defined, use the extendGrammar() method to apply the extension to the default dictionary as follows:.

//--> Define dictionary extension string
String myDictionary =
   "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"             +
   "<!DOCTYPE dictionary SYSTEM \"dictionary.dtd\">\n"        +
   "<dictionary>\n"                                           +
   " <vendor id=\"10415\" name=\"3GPP\">\n"                   +
   " </vendor>\n"                                             +
   " <application id=\"3\" name=\"Rf\" vendor=\"3GPP\" \n"    +
   " service-type=\"Acct\">\n"                                +
   " <command name=\"Accounting\" code=\"271\" />\n"          +
   " </application>\n"                                        +
   "</dictionary>\n";
 
//--> Apply new extension to current dictionary
try {
  myStack . extendGrammar(myDictionary);
} catch (DiameterException e) {
  // Handle dictionary syntax errors ...
}

For increased flexibility in a real application, you may want to read the XML syntax description from a file rather than having it embedded in the Java source code. This way, it becomes possible to change the mapping between names and codes without recompiling the application.

The 3GPP Rf Interface dictionary is returned by getRfDictionary() and the 3GPP Ro Interface dictionary is returned by getRoDictionary() and can be extended by the Diameter stack.

Tracing and Logging Mechanism

The DiameterTraceLoggerListener class is an interface to the Diameter tracing and logging mechanism. This interface represents the communication channel implemented by an application to receive debug traces and logs from the Diameter stack implementation. Logs are messages targeted to the user of DiameterStack. Traces are for internal use and are meaningful only to people with a good knowledge of the DiameterStack implementation.

All the messages that may be sent through the DiameterTraceLoggerListener.log() logging interface are defined in LogMessages.def. There is no definition file for trace messages.

By default, logs are sent to stdout and traces are not sent. This behavior may be modified by users either by registering a user-defined subclass of DiameterTraceLoggerListener or by defining specific environment variables. An example of a DiameterTraceLoggerListener implementation is as follows:

Class MyTraceLoggerListener implements DiameterTraceLoggerListener
{
      // true or false.
      public boolean isTracingEnabled()
      {
         return true;
}

public void log (String file, int line, int severity, String message)
{
         String severity;
         switch (severity) {
            case LOG_INFO_SEVERITY: severity="INFO"; break;
            case LOG_WARNING_SEVERITY: severity="WARNING"; break;
            case LOG_ERROR_SEVERITY: severity="ERROR"; break;
            case LOG_DISASTER_SEVERITY: severity="DISASTER"; break;
            default: severity="?"; break;
         }
         // ...
      }

      public void trace (String file, int line, int mask, String message)
      {
         System.err.println(...);
}
}