Skip Headers
Oracle® Application Server Wireless Developer's Guide
10g Release 2 (10.1.2)
B13819-02
  Go To Documentation Library
Home
Go To Product List
Solution Area
Go To Table Of Contents
Contents
Go To Index
Index

Previous
Previous
Next
Next
 

17 Billing

Each section of this document presents a different topic. These sections include:

Section 17.1, "Overview of Billing"

Section 17.2, "Using the Billing Integration Framework"

Section 17.3, "BillingLoader Utility"

Section 17.4, "Billing Collector and Service Detail Record"

Section 17.5, "Billing Driver"

Section 17.6, "Billing Integration Scenario"

Section 17.7, "Sample BillingDataCollector Implementation"

17.1 Overview of Billing

OracleAS Wireless Billing Integration Framework provides an extensible and flexible framework to model billable services, capture billable actions, and integrate with any billing engine. Here are some important Billing concepts:

Figure 17-1 Billing Framework Architecture

Description of Figure 17-1  follows
Description of "Figure 17-1 Billing Framework Architecture"

Billable Action—Customer actions which should be tracked, authorized and reported to the billing system. Typical examples are premium service access, mobile content download, alert subscription and message delivery.

Billing Context—A marker interface whose implementation object provides all the data related to a given billable action. OracleAS Wireless has the following objects predefined as Billing Context:

Service Detail Record (SDR)—A generic object that captures all the billing-specific attributes from the billing context for a given billable action. The attributes are of two types: mandatory and extended. Mandatory attributes are user information, service information and component information. Extended attributes contain the component-specific information.

Billing Collector—An extensible object that processes the BillingContext and generates the corresponding service detail record.

Billing Driver—A Java interface defined by OracleAS Wireless; it interacts with an external billing system to handle a given billable action. A billable action is usually handled in two steps:

17.2 Using the Billing Integration Framework

This section describes how to use the billing integration framework.

17.2.1 Billable Actions and Billing System Interaction

This section describes billable actions and billing system interaction.

17.2.1.1 Default Billable Actions

OracleAS Wireless defines the following billable actions:

  • Multi-Channel service request—the model service is defined with the cost attribute set to a non-zero value:

    • calling driver's preService API right after service authorization and before service invocation. If the result code of the API call indicates failure, the request is rejected.

    • calling driver's postService API after the service request has been served and before any listener notification.

  • J2ME application download:

    • calling driver's preService API right before the download request is generated by the provisioning server. If the result code of the API call indicates failure, the request is rejected.

    • calling driver's postService API after provisioning server has received notification from the installed device indicating successful installation and before any listener notification.

  • Alert Subscription:

    • calling driver's preService API right before user subscribes to a mobile alert service. If the result code of the API call indicates failure, the request is rejected.

    • calling driver's postService API after the alert subscription has been created.

  • Messaging:

    • Sending

      • calling driver's preService API before the message delivery request is accepted by the messaging framework. If the result code of the API call indicates failure, the request is rejected.

      • calling driver's postService API after the message delivery request is accepted by the messaging framework.

    • Receiving

      • calling driver's preService API before the message is routed to targeted registered application. If the result code of the API call indicates failure, the message is discarded.

      • calling driver's postService API after the message has been routed to a targeted registered application.

17.2.1.2 Custom Billable Actions

OracleAS Wireless billing integration framework allows users to introduce custom billable actions to meet their business needs. Following are the steps to introduce a new billable action:

  • Identify the place where the new billable action should take place, for example, a runtime hook or a JSP.

  • Define an object which provides access to all the data related to this new billable action. This object can be any Java class as long as it implements the marker interface BillingContext. You may also use the predefined BillingContext objects mentioned above if appropriate.

  • Customize the Billing Collector object to handle your new BillingContext object by either extending the BillingCollectorImpl or defining your own implementation of the Billing Collector. Billing Collector's implementation is presented in greater detail in the next section.

    The Billing Collector class can be extended (subclassed) from the out-of-the-box collector implementation or created new. Once it is created, the implementation class is set in: EM > Wireless Server: Site Administration > Billing Framework > Billing Collector Class name.

Use the following code segment (Example 17-1) to trigger a new billable action for a preService call.

Example 17-1 Triggering a new billable action

// Suppose your BillingContext Object is foo 
BillingController controller =  BillingController.getInstance(); 
if (controller.isBillingEnabled() ) 
 { 
       try { 
             BillingResult result = controller.preService(foo); 
            if ( result != null ){ 
               ServiceDetailRecord sdr = result.getServiceDetailRecord(); 
               if (result.getResultCode() != BillingResult.FAILED) { //Succeed 
                 // Add your logic here 
               } 
              else { // Failed 
                    // Add your logic here to handle preService failure 
                    //BillingException e = new BillingException(failure message); 
                    // e.setResult(result);
                    // throw e;
 
              } 
          } 
      } catch (BillingException be) { 
               //Handle Billing Execption here 
         } 

Use the following code segment (Example 17-2) to trigger a new billable action for postService call.

Example 17-2 Triggering a new billable action for postServcie call

// Suppose your BillingContext Object is foo 
BillingController controller =  BillingController.getInstance(); 
if (controller.isBillingEnabled() ) 
 { 
       try { 
             BillingResult result = controller.postService(foo); 
            if ( result != null ){ 
               ServiceDetailRecord sdr = result.getServiceDetailRecord(); 
               if (result.getResultCode() != BillingResult.FAILED) { //Succeed 
                 // Add your logic here 
               } 
              else { // Failed 
                    // Add your logic here to handle postService failure 
              } 
          } 
      } catch (BillingException be) { 
               //Handle Billing Execption here
         } 

17.3 BillingLoader Utility

The BillingLoader Utility is a batch utility to download, purge and upload billing transaction records. For more information on BillingLoader Utility, see OracleAS Wireless Administrator's Guide.

17.4 Billing Collector and Service Detail Record

A billable operation for every component is split into 2 parts: a pre-event and post-event. An SDR is generated for both the pre- and post- events. The billing data collector class is used to create one SDR for each pre- or post- service call.

When the pre-service SDR is passed to the billing system, the billing system is expected to set a unique Billing Reference ID and return the SDR as part of the billing result.

The returned pre-service billing reference ID is extracted by OracleAS Wireless. It is set in the post service SDR of the same billable operation so that the external billing system can maintain state between the pre- and post- event of any single billable operation based on the billing reference ID.

Only the post service billing event SDR is logged to the database, unless the driver starts-up a transaction by setting the transaction ID attribute in the SDR which it returns after the pre-service. If the transaction ID is set, then the pre-service SDRs are also logged. You can identify the pre and post service SDRs based on the LOG_TYPE column which will be either PRE_SERVICE or POST_SERVICE.

The SDR ID is an internal ID used as a primary key in our tables. You can look up a particular SDR based on the SDR ID.

There is normally only one SDR ID for every post-service event, unless the driver starts up a transaction (in which case the pre-service SDR is logged).

17.4.1 Default Billing Collector Implementation

The BillingCollector implementation object is responsible for processing the BillingContext for a given billable action. It generates an appropriate Service Detail Record for the billing driver to process. OracleAS Wireless includes a default BillingCollector implementation named BillingCollectorImpl which handles the following BillingContext objects:

  • For multi-channel service access: oracle.panama.rt.ServiceContext

    • Extended Attribute Name:

      • SERVICE_URL—the URL of the service invoked

      • SERVICE_TYPE—the type of the service, that is, Folder or Link (FOLD, LINK)

      • DEVICE_NAME—the device name

      • INVOKER—the Invoker for this runtime service. The list of values include HTTP, ASYNC, ALERT, PROVISIONING, AGENT. This attribute can be used by the driver to trace the root-invoker of this service. The Invoker attribute and the list of values are defined in the BillingDataCollector Interface.

      • ASK_IN_MSGID—this is set if the service is the INVOKER attribute value ASYNC. The value denotes the Incoming message ID for the Async application. It can use used to relate the message request with the Async action.

  • For J2ME application download: oracle.panama.model.UserDownloadStatusAPPLICATION_NAME

    • Extended Attribute Name:

      • CONTENT_NAME—the Application name

      • CONTENT_VERSION—the Content version

      • USER_DEVICE_NAME (if available)—the user device name

      • MIME_TYPE—the mime type downloaded

      • CURRENT_NUMBER_OF_DOWNLOADS—the number of previous downloads before the current download

      • CONTENT_SIZE—the size of the content

  • For mobile alert subscription: oracle.panama.mobilealert.ServiceAlertSubscription

    • Extended Attribute Name:

      • OPERATION_TYPE—indicates if it is an Alert Message SDR or Alert Subscription SDR. The value for mobile alert is ALERT_SUBSCRIPTION

      • SERVICE_URL—URL for the invoked service. Alert Engine invokes a service to generate content, and this attribute is the URL for the service.

      • ALERT_DELIVERY_ADDR—the end-user address to which alerts will be delivered. A comma-separated list of possible addresses.

  • For messaging:

    • Sending: oracle.panama.messaging.transport.impl.SendingBillingContext

    • Extended Attribute Name:

      • TYPE—indicates if the action is a sending or receiving action. It is set to S for sending.

      • FROM—the from address (can be null).

      • TO_ADDRESSES—the destination address.

      • DELIVERY_TYPE—the delivery channel type.

      • SERVICE_NAME (Optional)—the client name (such as Push Server, Async Agent).

      • DRIVER_NAME—the driver name (for the sending case only).

      • REPLYTO_ADDRESS—the reply to address.

      • CLIENT_NAME—the client that initializes the sending request.

      • MESSAGE_ID—the ID assigned to the message by the messaging server.

      • LINKED_MESSAGE_ID—the ID that links many independent transactions together. For example, an Async transaction and message sending transaction. Other transactions may assign a different name to this attribute.

    • Receiving: oracle.panama.messaging.transport.impl.ReceivingBillingContext

    • Extended Attribute Name:

      • TO_ADDRESS—the destination address of this message.

      • DELIVERY_TYPE—the delivery channel type.

      • CLIENT_NAME—the reply to address.

      • MESSAGE_ID—the ID assigned to the message by the messaging server.

17.4.2 Service Detail Record ID Versus Billing Reference ID

The Service Detail Record ID is defined by the Billing Collector. The default format is [Component Name: Random Key]. The Billing Reference ID is obtained from the billing system. In the pre-bill case, it is usually defined as the authorization ID.

17.4.3 Extend Default Billing Collector

OracleAS Wireless billing integration framework enables users to extend the default billing collector implementation for various reasons:

  • To capture more data than the default implementation for a default BillingContext, see Example 17-3.

Example 17-3 Extending default billing collector

public class MyBillingCollector extends oracle.wireless.billing.BillingDataCollectorImpl 
{ 
   ... 
    public ServiceDetailRecord createServiceDetailRecord(BillingContext context) 
   { 
       ServiceDetailRecord sdr = null; 
        if (context instanceof oracle.panama.rt.ServiceContext ){ 
            sdr = super.createServiceDetailRecord(context); 
           if ( sdr != null){ 
             // Add your additional data capture logic here 
            // For example: 
           // oracle.panama.rt.ServiceContext serviceContext = (oracle.panama.rt.ServiceContext)context; 
           // sdr.setExtendedData("SERVICE_PATHURL", context.getService().getURLPathParameter()); 
         } 
       } 
       else{ 
          sdr = super.createServiceDetailRecord(context); 
      } 
      return sdr; 
   } 
  ... 
}
  • To capture data from a custom BillingContext, see Example 17-4.

Example 17-4 Capturing data from a custom BillingContext

public class MyBillingCollector extends oracle.wireless.billing.BillingDataCollectorImpl 
{ 
   ... 
    public ServiceDetailRecord createServiceDetailRecord(BillingContext context) 
   { 
       ServiceDetailRecord sdr = null; 
        if (context instanceof MyBillingContext ){ 
             // MyBillingContext mycontext = (MyBillingContext)context; 
            // get the user name from your context 
            // Java.sql.Timestamp accessTime = null; 
            // BillingManager manager = BillingManager.getInstance(); 
            //sdr = manager.createServiceDetailRecord(<User Name>, <Your service Name>, accessTime, <your billing component name>); 
           // sdr.setExtendedData("MY_DATA", <Get data from your context object>); 
           ... 
         } 
       } 
       else{ 
          sdr = super.createServiceDetailRecord(context); 
      } 
      return sdr; 
   } 
  ... 
} 

To ignore a billable action base on the context data. Simply return a null object from the createServiceDetailRecord call based on your business logic.

Specify your extended Billing Collector using Oracle Enterprise Manager:

EM > Wireless Server: Site Administration > Billing Framework > Billing Collector Class name

17.4.4 Maintaining Transaction Context on Multipart Requests

A typical wireless request spans multiple entities (a multi-part request). For example, an Async request may originate at the Messaging Server, forwarded to the Async Listener, which invokes a Runtime service and then returns the result back to the user through the Messaging Server. The Billing Rules may demand a billing at each stage of the transaction, but the pricing may vary depending on the context of the request. To support such a scenario, it is necessary to maintain the history of the request's path (available resources to the Billing Driver [or Data Collector]), where the Billing Rules are enforced.

When the request changes, the transaction must be reset by the driver in the pre-service. The default billing collector implementation stores transaction ID information as a thread local variable, and caches it in the thread unless reset. For example, in the Async Servlet case, since subsequent requests are also processed in the context of the same thread, the Async servlet retains the previous transaction ID, unless it is reset by the collector or driver. In a typical scenario, an psych request arrives through the messaging layer. In order for the billing layer to link this messaging request with the Async request and the subsequent messaging response, the message ID is carried forward. The MESSAGE_ID extended attribute of the incoming message should match the ASK_IN_MSGID of the Async request and this should match the LINKED_MESSAGE_ID attribute of the outgoing message. This is how the incoming message ID is carried forward when the request is serviced.

17.4.4.1 Creating and Assigning Billing Transactions

The Billing Driver (or Data Collector) can assign a given Service Detail Record to be part of a transaction. For example, the pre-service call implementation of the Billing Driver can contain the following lines to add the SDR to a newly created transaction:

           BillingTransaction Trans = BillingTransactionManager.getInstance().createTransaction();
          Trans.getId(); // if its XYZ say       
           sdr.setTransaction(Trans);

This creates a new transaction, and adds the Service Detail Record to it. The subsequent service detail records can be added to the same transaction by retaining the transaction ID. The point at which a new transaction needs to be created should be decided by the driver or collector writer.

Here is the pseudo-code for subsequent Service Detail Records:

            BillingTransaction Trans = BillingTransactionManager.getInstance().lookupTransaction (XYZ);
          Trans.getId(); // if its XYZ say       
          Trans.addSdr(sdr); // OR sdr.setTransaction(Trans);

The past Service Detail Records for this transaction can be looked-up using the BillingTransaction public APIs (see BillingTransaction's getServiceDetailRecords()).

17.4.4.2 Logging Rules for Service Detail Records

A Service Detail Record, which is part of a transaction, is implicitly logged to the database as soon as the call BillingResult is returned from the BillingDriver implementation. The BillingController inspects the Service Detail Record and does this automatically.

The SDR's part of this transaction is available for lookup (see BillingTransaction's getServiceDetailRecords()). If the SDR is not part of a transaction, then its logging is deferred to the logging framework, to be accomplished in the background.

17.4.4.3 Maintaining Transaction State in a Single-Thread Multi-part Request

If all subsequent requests of a multi-part request are done in the context of the same Java Thread, the transaction information can be stored in the Thread as a Thread Local object and referenced later for a subsequent request. The Default implementation of the BillingDataCollector (oracle.wirless.billing.BillingDataCollectorImpl) provides just that. The transaction APIs for setting and getting are available through the BillingController object:

  /**
   * Returns the current billing transaction
   * @return BillingTransaction the current billing transaction
   */
public BillingTransaction getCurrentTransaction();

/** Sets the transaction for the current transaction
 * @param transaction the current transaction
 */
public void setCurrentTransaction(BillingTransaction transaction);

17.5 Billing Driver

To integrate OracleAS Wireless billing integration with an external billing system, the system integrator must provide a Java implementation class which implements the BillingDriver interface. To set your driver:

EM > Wireless Server: Site Administration > Billing Framework > Billing Driver Provider (Driver Class Name)

The desired behavior of the Billing Driver implementation is as follows:

17.6 Billing Integration Scenario

This section describes a billing integration scenario.

17.6.1 Handling Prebilling

Here is an implementation example of handling prebilling:

  • Define the billable actions using either default or custom actions.

  • Use the driver's preService call to do billing authorization and/or resource reservation, return an authorization ID generated by the billing system.

  • Use the driver's postService call to complete the billing transaction by passing the authorization obtained from the preService call.

17.6.2 Handling Postbilling

Here is an implementation example of handling postbilling:

  • Define the billable actions using either default or custom actions.

  • Use the driver's preService call to do billing authorization and/or rating/fraud detection.

  • Use the driver's postService call to submit billing-related data to the billing system.

17.7 Sample BillingDataCollector Implementation

Example 17-5 contains a code snippet is a sample billing data collector. This sample illustrates the following (see code documentation to locate the annotations).

Customers can plug in their own implementation. This class is initialized using singleton pattern. The implementation must have a method such as the public static BillingDataCollector getInstance().

Example 17-5 Sample billing data collector

public class DownloadBillingDataCollectorImpl extends BillingDataCollectorImpl { // subclassing default collector to over-ride behavior
MetaLocator m = MetaLocator.getInstance();
ModelFactory f = m.getModelFactory();
ModelServices s = m.getModelServices();
/**
* reference implementation : to store transaction id
*/
private static ThreadLocal transactionInfo = new ThreadLocal();
private static DownloadBillingDataCollectorImpl instance = new DownloadBillingDataCollectorImpl();
/**
* providing a getInstance method for runtime class instantiation 
*/
public static BillingDataCollector getInstance() {
System.out.println("Using DownloadBillingDataCollectorImpl");
return instance;
}
public ServiceDetailRecord createServiceDetailRecord(BillingContext context) {
ServiceDetailRecord sdr = null;
// changing the behavior for the provisioning (j2me) download case
// the default behavior is the one provided by the oracle.wireless.billing.BillingDataCollectorImpl class file
if (context instanceof oracle.panama.model.UserDownloadStatus) {
System.out.println("Provisioning case: ");
try {
oracle.panama.model.UserDownloadStatus uds = (oracle.panama.model.UserDownloadStatus)context;
if(UserDownloadStatus.STATUS_NOTIFIED_SUCCESS.equals(uds.getStatus())) {
return null;
// check to ignore billing if status is UserDownloadStatus.STATUS_NOTIFIED_SUCCESS
// Thus postService billing is called both after jar download completes and notify completes.
// We are handling it when download completes i.e when status is UserDownloadStatus.STATUS_COMPLETE
}
System.out.println("Provisioning case: status = "+uds.getStatus()+" mime type = "+uds.getMimeType());
java.sql.Timestamp accessTime = null;
BillingManager manager = BillingManager.getInstance();
sdr = manager.createServiceDetailRecord(uds.getUser().getName()
, uds.getService().getName()
, accessTime
, BillingContext.PROVISIONING_COMPONENT);
sdr.setExtendedData("APPLICATION_NAME", uds.getApplication().getName());
sdr.setExtendedData("CONTENT_NAME", uds.getContent().getName());
String size = null;
String mimetype = uds.getMimeType();
if (mimetype.equals(ApplicationContentLocator.MIME_TYPE_JAD)){
mimetype = ApplicationContentLocator.MIME_TYPE_JAR;
}
size = Long.toString(uds.getContent().getContentItemByMimeType(mimetype).getDataLength());
sdr.setExtendedData("CONTENT_SIZE",size);
sdr.setExtendedData("CONTENT_VERSION", uds.getContent().getVersion());
if (uds.getDevice() != null)
sdr.setExtendedData("USER_DEVICE_NAME", uds.getDevice().getName());
sdr.setExtendedData("MIME_TYPE", uds.getMimeType());
sdr.setExtendedData("CURRENT_NUMBER_OF_DOWNLOADS", (new Long(uds.getNumberOfDownloads())).toString());
} catch (BillingException be) {
L.e("Billing Exception during Provisioning SDR creation : "+be.getMessage());
}
} else {
sdr = super.createServiceDetailRecord(context);
}
// if the transaction id is set (by application integrator's logic) then set the value in the SDR
if(super.getCurrentTransaction() != null && super.getCurrentTransaction().getId() != null) {
if(sdr.getTransactionId() == null) {// don't reset transaction id in SDR if already set
sdr.setTransaction(super.getCurrentTransaction());
}
}
if(sdr != null) System.out.println("Returning SDR : component = "+sdr.getComponentName()+", Type = "+sdr.getType());
return sdr;
}
}