C H A P T E R  3

Billing API

The Sun Java System Content Delivery Server Billing API provides an interface between Content Delivery Server and your billing system. Use the Billing API to create a customized billing adapter that supports prepaid billing or synchronous billing.

The Billing API consists of the following classes and interfaces:

The classes and interfaces for the Billing API are in the com.sun.content.server.billing package. For additional information on these classes and interfaces, see the HTML output of the Javadoctrademark tool at $CDS_HOME/javadoc/cdsapi/index.html.


3.1 General Process Flow

The Billing API handles the communication between Content Delivery Server and the external billing system. The details of the billing transaction are maintained in a BillingInfo object. The billing adapter, which is your implementation of the BillingManager interface, determines how the transaction is processed.

This section describes the following flows of information between Content Delivery Server and the external billing system:

For details on the BillingManager methods mentioned in this section, see Section 3.2, BillingManager Interface.

3.1.1 Content Listing

The list process is initiated when a subscriber requests a list of available content or a Vending Manager administrator requests a list of stocked content. FIGURE 3-1 shows this process.

FIGURE 3-1 Process Flow for Content Listing


Overview of getting a list of content. This figure is described in the text.

The following items provide additional details on the process for listing content:

1. When a subscriber or Vending Manager administrator requests a list of content, Content Delivery Server creates an initial BillingInfo object for each object in the list and calls the billing adapter’s getBillingInfos method.

2. Your implementation of getBillingInfos can modify the purchase price or other details of each transaction, if needed. You can also specify if authorization is needed at the time of purchase and if you want a confirmation message when the content is successfully downloaded. These details are set in the BillingInfo objects returned to Content Delivery Server. See Section 3.2.6, getBillingInfos Method for additional information.

3. Content Delivery Server uses each returned BillingInfo object to show the pricing information in the list displayed.

3.1.2 Transaction Initiation

A billing transaction is initiated when a subscriber clicks View Details for an item of content. FIGURE 3-2 shows this process.

FIGURE 3-2 Process Flow for Transaction Initiation


Overview of the initiation of a transaction. This figure is described in the text.

The following items provide additional detail on the process for initiating transactions:

1. When a subscriber requests the details for an item, Content Delivery Server creates the initial BillingInfo object for the subscriber’s selection based on information in Content Delivery Server database.

2. Content Delivery Server then calls the billing adapter’s getBillingInfo method and passes the BillingInfo object to the method.

3. Your implementation of the getBillingInfo method can modify the purchase price or other details of the transaction, if needed. You can also specify if authorization is needed at the time of purchase and if you want a confirmation message when the content is successfully downloaded. These details are set in the BillingInfo object returned to Content Delivery Server. See Section 3.2.5, getBillingInfo Method for additional information.

4. Content Delivery Server uses the returned BillingInfo object to show the content details and pricing information for the selected item to the subscriber.

3.1.3 Subscriber Purchase

The purchase process is initiated when the subscriber selects an item and clicks Purchase. The BillingInfo object that was created when the transaction was initiated is used for the purchase. FIGURE 3-3 shows this process.

FIGURE 3-3 Process Flow for Subscriber Purchase


Overview of a subscriber purchase. This figure is described in the text.

The following items provide additional detail on the process for a subscriber purchase:

1. When the subscriber chooses to purchase the content, Content Delivery Server checks the BillingInfo object returned by the getBillingInfo method to see if authorization is required.

2. If authorization is required, Content Delivery Server calls the billing adapter’s authorize method and passes the BillingInfo object. This method is expected to determine if the subscriber is allowed to purchase the content and set the OK flag in the BillingInfo object. That object is then returned to Content Delivery Server. See Section 3.2.1, authorize Method for additional information.

3. If the subscriber is authorized to purchase the content, or no authorization is needed, the purchase page is presented. If the subscriber is not authorized to purchase the content, an error message is issued.

When a subscriber purchases content, the BillingInfo object associated with the transaction is stored in the Content Delivery Server database. For any further actions that require the billing information, Content Delivery Server retrieves the object from the database using the subscriber ID and content ID as the key.

3.1.4 Download Confirmation

The confirmation process is initiated when the device completes the download and notifies Content Delivery Server. FIGURE 3-4 shows this process. If the download is successful and the billing system does not require notification, no action is taken.

FIGURE 3-4 Process Flow for Download Confirmation


Overview of handling a download confirmation. This figure is described in the text.

The following items provide additional detail on the process for confirming a download:

1. When Content Delivery Server receives confirmation from the device that a download was successful, Content Delivery Server checks the billing information to see if the billing system wants to be notified of the confirmation.

2. If confirmation is required, Content Delivery Server calls the billing adapter’s confirm method. See Section 3.2.3, confirm Method for additional information.

3. If the device returns an error instead of a successful confirmation, Content Delivery Server calls the billing adapter’s reverse method and passes the BillingInfo object for this transaction. Code your implementation of reverse() to ensure that the subscriber is not charged for the content that was not downloaded. See Section 3.2.8, reverse Method for additional information.

3.1.5 Subscription Verification

The subscription verification process is initiated when a subscriber accesses content after the subscription period has ended. FIGURE 3-5 shows this process.

FIGURE 3-5 Process Flow for Subscription Verification


Overview of verification of a subscription. This figure is described in the text.

The following items provide additional detail on the process for verifying a subscription:

1. When a subscriber accesses content after the subscription period has ended, Content Delivery Server calls the checkSubscription method to see if the subscription was canceled outside of Content Delivery Server.

2. Code your implementation of the checkSubscription method to set the Subscription Terminated flag in the BillingInfo object that is returned to Content Delivery Server. See Section 3.2.2, checkSubscription Method for additional information.

3. If the Subscription Terminated flag in the BillingInfo object is true, or if the Content Delivery Server subscription status is canceled, the subscriber is prompted to renew the subscription. If the flag is false and the status is not canceled, the subscription is automatically renewed and the content is run.

3.1.6 Error Handling

When the billing system detects an error, a generic error message is displayed to the subscriber. You can customize this message to display additional information by setting the reply message in the BillingInfo object returned by your implementation of the BillingManager interface. Whenever an error is detected by your billing adapter, call the setOK method to set the OK flag in the BillingInfo object to false, and call the setReplyMessage method to set the message displayed to the subscriber.

3.1.7 Custom Field Access

Information about content is stored in the data fields provided by Content Delivery Server, such as name, description, and content type. Additional information needed by your implementation can be stored in custom fields that you define. The BillingInfo object provides access to the information about content, including information in custom fields.

When Content Delivery Server creates a BillingInfo object, the setReplyOthers method is called to add custom fields to the hash table that contains information specific to your implementation. The key for each field added to the table is the same as the key used to define the custom field. To access the fields from your billing manager, call the getReplyOthers method and extract the item from the hash table using the custom field key.

For information on setting up custom fields, see Section 1.8 in the Sun Java System Content Delivery Server Integration and Configuration Guide.


3.2 BillingManager Interface

The BillingManager interface processes the billing transaction based on the details of the transaction contained in the BillingInfo object. Implement BillingManager to create a billing adapter for your system. This billing adapter is the interface between Content Delivery Server and your billing system.

3.2.1 authorize Method

abstract BillingInfo authorize(BillingInfo inBillingInfo, boolean[] inNeedToAuthorizeBillingModel)

If the external billing system requires that transactions be authorized, the authorize method is called by Content Delivery Server when the subscriber clicks the Purchase button for an item. To indicate that authorization is required, the Authorize Needed flag in the BillingInfo object must be set by the getBillingInfo method.

Use this method to determine if the subscriber is authorized to purchase the content requested. If your billing system supports the prepaid billing model, use this method to verify that there are enough funds in the subscriber’s account to purchase the content.

The parameter inNeedToAuthorizeBillingModel provides an array of flags that are indexed by the following pricing model constants, which are defined in the BillingConstants class:

Each flag indicates if that pricing model is considered when the transaction is authorized. For example, assume you are given the following parameters:

The flag indexed by DOWNLOAD is set to false, indicating that this transaction has no download charge. Therefore, the download charge does not need to be considered when authorizing the transaction. Use or ignore these flags based on the needs of your system.

If the subscriber is authorized to purchase the content, set the OK flag in the BillingInfo object to true by calling the setIsOK method before returning the BillingInfo object to Content Delivery Server. If the subscriber is not authorized to purchase the content, set the OK flag to false.

If the Confirm Needed flag in the BillingInfo object was not set by the getBillingInfo method, set the flag by calling the setConfirmNeeded method. To notify the billing system when the content is successfully downloaded to the device, set the flag to true. If you do not want the billing system notified, set the flag to false.

3.2.2 checkSubscription Method

abstract BillingInfo checkSubscription(BillingInfo inBillingInfo) throws BillingException

The checkSubscription method is called by Content Delivery Server when a subscriber attempts to use content after the subscription period ends. Use this method to notify Content Delivery Server that a subscription was terminated outside of Content Delivery Server.

Code your implementation to set the Subscription Terminated flag by calling the setSubscriptionTerminated method for the BillingInfo object. To indicate that the subscription was terminated, set the flag to true. The subscriber is then prompted to renew the subscription. To indicate that the subscription is still valid, set the flag to false. The subscription is then automatically renewed for another period.

3.2.3 confirm Method

abstract BillingInfo confirm(BillingInfo inBillingInfo)

If the external billing system requires notification of successful downloads, the confirm method is called by Content Delivery Server when confirmation of the download is received from the subscriber’s device. To indicate that confirmation is required, the Confirm Needed flag in the BillingInfo object must be set by either the getBillingInfo method or the authorize method.

Use this method to perform the actions needed when the download of content is confirmed. For example, you might want to deduct funds from a subscriber’s account only after confirmation of a successful download is received.

3.2.4 contentDelete Method

public abstract void contentDelete(BillingInfo inBillingInfo) throws BillingException

The contentDelete method is called by Content Delivery Server after content is removed from a device. Implement this method to notify the billing system that the subscriber is no longer using the content.

3.2.5 getBillingInfo Method

abstract BillingInfo getBillingInfo(BillingInfo inBillingInfo)

The getBillingInfo method is called by Content Delivery Server when a subscriber requests the details for an item or purchases an item. Content Delivery Server creates a BillingInfo object that contains the billing information and passes it to this method.

Use this method to modify the billing information as needed and return the modified BillingInfo object to Content Delivery Server. For example, to provide a discount to selected subscribers, change the price specified by Content Delivery Server.

Code your implementation to set the Authorize Needed flag by calling the setAuthorizeNeeded method for the BillingInfo object. To have the billing system verify that a subscriber is authorized to purchase the selected content, set the flag to true. If you do not want to preauthorize the subscriber, set the flag to false.

If you set the Authorize Needed flag to false, set the Confirm Needed flag and the OK flag in this method. To notify the billing system when the content is successfully downloaded to the device, set the Confirm Needed flag to true by calling the setConfirmNeeded method. If you do not want the billing system notified, set the flag to false.

To enable the subscriber to purchase content when the Authorize Needed flag is false, set the OK flag to true by calling the setOK method. If you set the OK flag to false and the Authorize Needed flag is also false, the subscriber is not allowed to download the selected content. If the Authorize Needed flag is set to true, set the OK flag in the authorize method.

3.2.6 getBillingInfos Method

abstract BillingInfo[] getBillingInfos(BillingInfo[] inBillingInfos)

The getBillingInfos method is called by Content Delivery Server when a subscriber requests the list of content available, or the Vending Manager administrator requests the list of stocked content. Content Delivery Server creates a list of BillingInfo objects that contains the billing information and passes it to this method.

Use this method to modify the billing information as needed and return the modified list of BillingInfo objects to Content Delivery Server. For example, to provide a discount, change the price specified by Content Delivery Server.

Code your implementation to set the Authorize Needed flag by calling the setAuthorizeNeeded method for each BillingInfo object in the list. To have the billing system verify that a subscriber is authorized to purchase the selected content, set the flag to true. If you do not want to preauthorize the subscriber, set the flag to false.

If you set the Authorize Needed flag to false, set the Confirm Needed flag and the OK flag in this method. To have the billing system notified when the content is successfully downloaded to the device, set the Confirm Needed flag to true by calling the setConfirmNeeded method. If you do not want the billing system notified, set the flag to false.

To enable the subscriber to purchase content when the Authorize Needed flag is false, set the OK flag to true by calling the setOK method. If you set the OK flag to false and the Authorize Needed flag is also false, the subscriber is not allowed to download the selected content. If the Authorize Needed flag is set to true, set the OK flag in the authorize method.

3.2.7 refund Method

abstract void refund(BillingInfo inBillingInfo)

The refund method is called by Content Delivery Server when a customer care agent uses the Vending Manager administration console to refund a subscriber’s purchase. Content Delivery Server creates a BillingInfo object from the billing information stored in the database for the original billing transaction and passes the object to this method.

Use this method to perform the actions needed to credit a subscriber’s account.

3.2.8 reverse Method

abstract void reverse(BillingInfo inBillingInfo)

The reverse method is called by Content Delivery Server when the download of content to a subscriber’s device fails. Content Delivery Server creates a BillingInfo object from the billing information stored in the database for the original billing transaction and passes the object to this method.

Use this method to cancel the billing transaction so the subscriber is not charged for the content.

3.2.9 subscribe Method

abstract void subscribe(BillingInfo inBillingInfo)

The subscribe method is called by Content Delivery Server when a subscriber starts a subscription for content. Content Delivery Server creates a BillingInfo object from the billing information stored in the database for the original billing transaction and passes the object to this method.

Use this method to initiate a subscription for a subscriber. If the subscription is recurring, this method is called only once when the subscription starts. The billing system must remember to charge the subscriber each time the subscription period ends. If the subscription is non-recurring, this method is called each time the subscriber renews the subscription.

3.2.10 unsubscribe Method

abstract void unsubscribe(BillingInfo inBillingInfo)

The unsubscribe method is called by Content Delivery Server when a subscriber cancels a recurring subscription. Content Delivery Server creates a BillingInfo object from the billing information stored in the database for the original billing transaction and passes the object to this method.

Use this method to stop the automatic charge when the subscription period ends.


3.3 Using the Billing API

The classes for the Billing API are available in the cdsapi.jar file. This file must be in your classpath when you compile your adapter. For convenience, a copy of all Content Delivery Server JAR files are available in the $CDS_HOME/dist/cds/staging/jar directory. Use this staging area in your classpath when compiling the adapter that you create.

Making your adapter available to Content Delivery Server depends on the application server you are using and whether you have already deployed. To make your adapter available, follow these steps:

1. Create a JAR file for your adapter.

2. For all application servers, place the JAR file in the $CDS_HOME/dist/cds/lib/external directory.

The adapter is now included in all future deployments.

3. If you have existing deployments that need to use the adapter, place the JAR file in the $CDS_HOME/deployment/deployment-name/lib/external directory for each deployment.

If you are using WebLogic Server, the classpath is handled for you.

If you are using Sun Java System Application Server, update the classpath for each deployment:

a. Back up the $CDS_HOME/deployment/deployment-name/sun/domains/cdsdomain/config/domain.xml file before editing it so you can recover from any errors that might be introduced during editing.

b. Edit domain.xml and modify the java-config element to add the absolute path for your JAR file to the classpath-suffix attribute.

c. Save your changes.

4. Edit the security.config file in the $CDS_HOME/deployment/deployment-name/conf directory:

a. Set the module.security.billingmanager property to the class name of your implementation of the BillingManager class, for example:

module.security.billingmanager=com.sun.content.server.billing.external.MyBillingManager

b. Save your changes.

5. Restart any existing deployment to make it aware of the new JAR file.


3.4 Sample Billing Adapter

CODE EXAMPLE 3-1 shows the default implementation of the BillingManager.


CODE EXAMPLE 3-1 Sample BillingManager Implementation
package com.sun.content.server.billing.external;
 
import com.sun.content.server.billing.BillingException;
import com.sun.content.server.billing.BillingInfo;
import com.sun.content.server.billing.BillingManager;
 
/**
 * This is a sample implementation of the Billing API.
 */
public class CDSBillingManager implements BillingManager
{
  // These flags can be used to simulate responses from the billing
  //integration.
  public static final int SUCCESS = 0;
  public static final int EXCEPTION = 1;
  public static final int BILLING_EXCEPTION = 2;
  public static final int UNAUTHORIZED = 3;
  public static final int NULL = 4;
 
  // by default everything will pass through fine
  // but you can change these at runtime.
  public static int AUTHORIZE_RESPONSE = SUCCESS;
  public static int GET_BILLING_INFO_RESPONSE = SUCCESS;
  public static int GET_BILLING_INFOS_RESPONSE = SUCCESS;
  public static int CONFIRM_RESPONSE = SUCCESS;
  public static int DELETE_RESPONSE = SUCCESS;
  public static int REFUND_RESPONSE = SUCCESS;
  public static int REVERSE_RESPONSE = SUCCESS;
  public static int SUBSCRIBE_RESPONSE = SUCCESS;
  public static int UNSUBSCRIBE_RESPONSE = SUCCESS;
  public static int CHECK_SUBSCRIPTION_RESPONSE = SUCCESS;
 
  /**
   * see BillingManager#getBillingInfo(BillingInfo)
   */
  public BillingInfo getBillingInfo(BillingInfo inBillingInfo)
         throws BillingException
  {
    if (GET_BILLING_INFO_RESPONSE == NULL)
      return null;
 
    if (GET_BILLING_INFO_RESPONSE == EXCEPTION)
      throw new NullPointerException("Developer Null Pointer");
 
    if (GET_BILLING_INFO_RESPONSE == BILLING_EXCEPTION)
      throw new BillingException("Developer Billing Exception");
 
    // Set IsAuthorizeNeeded flag
    inBillingInfo.setAuthorizeNeeded(true);
    return inBillingInfo;
  }
 
  /**
   * see BillingManager#getBillingInfos(BillingInfo[])
   */
  public BillingInfo[] 
    getBillingInfos(BillingInfo[] inBillingInfos) 
    throws BillingException
  {
      for (int index = 0; index < inBillingInfos.length; index++)
    {
      // Set IsAuthorizeNeeded flag
      inBillingInfos[index].setAuthorizeNeeded(true);
    }
 
    if (GET_BILLING_INFOS_RESPONSE == NULL)
      return null;
 
    if (GET_BILLING_INFOS_RESPONSE == EXCEPTION)
      throw new NullPointerException("Testing Null Pointer");
 
    if (GET_BILLING_INFOS_RESPONSE == BILLING_EXCEPTION)
      throw new BillingException("Testing Billing Exception");
 
    return inBillingInfos;
  }
 
  /**
   * see.BillingManager#authorize(BillingInfo, boolean[])
   */
  public BillingInfo authorize(BillingInfo inBillingInfo, 
         boolean[] inNeedToAuthorizeBillingModel)
         throws BillingException
  {
    if (AUTHORIZE_RESPONSE == NULL)
      return null;
 
    if (AUTHORIZE_RESPONSE == EXCEPTION)
      throw new NullPointerException("Testing Null Pointer");
 
    if (AUTHORIZE_RESPONSE == BILLING_EXCEPTION)
     throw new BillingException("Testing Billing Exception");
 
    if (AUTHORIZE_RESPONSE == UNAUTHORIZED)
    {
      inBillingInfo.setOk(false);
      inBillingInfo.setReplyMessage("You are not authorized");
      return inBillingInfo;
    }
 
// Set IsOk and IsConfirmNeeded flags
    inBillingInfo.setConfirmNeeded(true);
    inBillingInfo.setOk(true);
 
    return inBillingInfo;
  }
 
  /**
   * seeBillingManager#confirm(BillingInfo)
   */
  public BillingInfo confirm(BillingInfo inBillingInfo)
      throws BillingException
  {
    if (CONFIRM_RESPONSE == EXCEPTION)
      throw new NullPointerException("Developer Null Pointer");
 
    if (CONFIRM_RESPONSE == BILLING_EXCEPTION)
      throw new BillingException("Developer Billing Exception");
    return inBillingInfo;
  }
 
  /**
   * see BillingManager#reverse(BillingInfo)
   */
  public void reverse(BillingInfo inBillingInfo)
      throws BillingException
  {
    if (REVERSE_RESPONSE == EXCEPTION)
      throw new NullPointerException("Developer Null Pointer");
 
    if (REVERSE_RESPONSE == BILLING_EXCEPTION)
      throw new BillingException("Developer Billing Exception");
  }
 
  /**
   * see BillingManager#refund(BillingInfo)
   */
  public void refund(BillingInfo inBillingInfo)
      throws BillingException
  {
    if (REFUND_RESPONSE == EXCEPTION)
      throw new NullPointerException("Developer Null Pointer");
 
    if (REFUND_RESPONSE == BILLING_EXCEPTION)
      throw new BillingException("Developer Billing Exception");
  }
 
  /**
   * seeBillingManager#subscribe(BillingInfo)
   */
  public void subscribe(BillingInfo inBillingInfo)
      throws BillingException
  {
    if (SUBSCRIBE_RESPONSE == EXCEPTION)
      throw new NullPointerException("Developer Null Pointer");
 
    if (SUBSCRIBE_RESPONSE == BILLING_EXCEPTION)
       throw new BillingException("Developer Billing Exception");
  }
 
  /**
   * see BillingManager#unsubscribe(BillingInfo)
   */
  public void unsubscribe(BillingInfo inBillingInfo)
      throws BillingException
  {
    if (UNSUBSCRIBE_RESPONSE == EXCEPTION)
      throw new NullPointerException("Developer Null Pointer");
 
    if (UNSUBSCRIBE_RESPONSE == BILLING_EXCEPTION)
      throw new BillingException("Developer Billing Exception");
  }
 
  /**
   * see BillingManager#checkSubscription(BillingInfo)
   */
  public BillingInfo checkSubscription(BillingInfo inBillingInfo)
      throws BillingException
  {
    if (CHECK_SUBSCRIPTION_RESPONSE == NULL)
      return null;
 
    if (CHECK_SUBSCRIPTION_RESPONSE == EXCEPTION)
      throw new NullPointerException("Developer Null Pointer");
 
    if (CHECK_SUBSCRIPTION_RESPONSE == BILLING_EXCEPTION)
      throw new BillingException("Developer Billing Exception");
 
    inBillingInfo.setSubscriptionTerminated(false);
 
    return inBillingInfo;
  }
 
  /**
   * see BillingManager#contentDelete(BillingInfo)
   */
  public void contentDelete(BillingInfo inBillingInfo)
      throws BillingException
  {
    if (DELETE_RESPONSE == EXCEPTION)
     throw new NullPointerException("Developer Null Pointer");
 
    if (DELETE_RESPONSE == BILLING_EXCEPTION)
     throw new BillingException("Developer Billing Exception");
  }
}