Skip to main content

Using the Payment API for Microcredit and Other Applications

August 2, 2009

{cs.r.title}




The Payment API (JSR 229) is an optional package that defines the architecture of a specification for creating Java ME applications to handle payment transactions. This API is designed to work with both MIDP and IMP (Information Module Profile). Although primarily meant for providing access to application features against payment, the methodology of making a payment defined in this API can be used for other kinds of applications, too. In this article, we shall restrict ourselves to the MIDP environment and shall examine an application that uses JSR 229 to extend a loan in a micro-credit environment.

I have used the LG SDK 1.2 for the Java ME Platform (referred to as the LGSDK from now on) to develop this example. While there are a number of SDKs available, I found the LGSDK very convenient to use because of its simple application signing mechanism and its range of valid certificates. The LGSDK is a free download and can be easily installed.

The LGSDK will need a JDK (version 1.6 or later) that provides the overall Java environment. If you don't already have one on your computer, you can get the latest version at the Java SE Downloads page of the Sun Developer Network.

The final specification document of JSR 229 has very detailed information on this API and is a very useful reference document. It would be a good idea to download this document too.

The Payment API

The package javax.microedition.payment contains the class, the interfaces, and the exceptions of the payment API. The two interfaces are:

  • TransactionRecord
  • TransactionListener

The only class in the package is:

  • TransactionModule

In addition to the interfaces and the class listed above, the package contains the following exceptions:

  • TransactionModuleException
  • TransactionListenerException
  • TransactionFeatureException
  • TransactionPayloadException
The TransactionRecord Interface

The TransactionRecord interface defines the structure of an object to represent a payment transaction. The fields of this interface represent the possible results of a transaction: SUCCESSFUL, FAILED, and REJECTED. Information about the transaction can be retrieved by using the various methods of this interface, as we shall see when we analyze the example code.

The TransactionListener Interface

This interface defines a listener that receives the result of processing a transaction. The only method of this interface is processed(TransactionRecord record). Once a payment transaction is completed, the processed method is called and the transaction record that was generated is passed to it. It is mandatory for a developer to set a transaction listener. If such a listener is not set, a TransactionListenerException is thrown whenever an action is taken that would necessitate a callback to the processed method.

The TransactionModule Class

The TransactionModule class provides the interface between the user (that is, the application) and the module (the payment module) that actually carries out the transaction. The constructor for this class is responsible for checking that all information required to handle payment transactions is available. In case any relevant information is found to be missing, a TransactionModuleException is thrown.

The methods of this class are listed below:

  • setListener: Sets a listener for receiving the result of a transaction. If the TransactionListener object passed as a parameter for this method is null, the current listener will be removed.
  • process: Initiates a payment transaction. There are two versions of this method. One of the versions takes an optional payload that can be transmitted as a part of the payment transaction. The maximum size of the payload is 132 bytes. If the payload size exceeds the 132-byte limit, a TransactionPayloadException is thrown. The process method does not wait for the transaction to be completed and returns immediately after passing the parameters to the payment module.
  • getPastTransactions: Returns an array of TransactionRecord objects covering past transactions. The parameter for this method specifies the maximum number of records to be returned.
  • deliverMissedTransactions: Requests that the payment module generate transaction records for all missed transactions for passing on to the application through the processed method of the registered listener. A transaction is missed if payment action is initiated but the result is not conveyed to the application. This might happen if the application shuts down or the device crashes after a transaction has been initiated but before the result was returned to the listener.
The Exceptions

The payment API does not have a general exception of the form TransactionException. This is a deliberate design decision to ensure that a developer handles each type of exception individually.

The following list shows the situations that cause the exceptions to be thrown:

  • TransactionModuleException: Thrown if any error related to the payment module occurs.
  • TransactionListenerException: Thrown if any action is taken that requires a callback to the processed method of TransactionListener but there is no registered listener.
  • TransactionFeatureException: Thrown if a feature not specified in an application's resource file is used by an application.
  • TransactionPayloadException: Thrown if the payload size exceeds the 132-byte limit.

The Microcredit Environment

Wikipedia defines "microcredit" as "the extension of very small loans (microloans) to those in poverty designed to spur entrepreneurship." In the current context, microcredit has been made internationally known primarily through the efforts of Grameen Bank in Bangladesh. Microloans essentially target people who are extremely poor, are not able to furnish collateral, and cannot meet the required criteria for accessing normal financing channels. Microcredit enables individuals with such handicaps to build an asset base and emerge from extreme poverty. Microcredit has now moved out of Bangladesh and is available in many other countries. Recently, Grameen Bank has opened a branch in New York and has started offering small loans.

A Look at the Example

Today microcredit is widely patronized even by individuals who want to help alleviate poverty. The example in this article shows how a JSR 229-based application can be used by individual lenders. In a live application, information about various projects would be downloaded from a server and the loan selection page would list all eligible projects and possible loan amounts. This is where our demo takes off. In Figure 1, we can see the screen for selecting the project and the loan amount.

Selecting Project and<br />
Loan Amount

Figure 1. Selecting project and loan amount

Once a project and the loan amount are selected, and the Next command is selected from the menu, the application asks the user to confirm the selection. This is the screen we see in Figure 2 below.

Confirming the<br />
Selections

Figure 2. Confirming the selections

This screen offers an opportunity to correct any errors in selection. A confirmation here will show another screen to select the mode of payment and finally initiate or reject the payment transaction. This screen is displayed by the API and its contents cannot be altered by the application. As we have already noted, JSR 229 was designed to meet the requirements of applications with payment-enabled features. Accordingly, the API asks whether the user would like to buy a specific feature. This can be seen in Figure 3.

Initiating Payment

Figure 3. Initiating payment

In order to maintain compatibility with the terminology used by the API, the transaction in our application is used for purchasing a loan voucher. This is why the UI shown in Figure 2 asks the user to confirm the purchase of a loan voucher. The result of the transaction, however, would be a payment for a loan to the specified project.

Executing the Yes command will initiate the payment transaction. The screenshot of Figure 4 shows the Alert that is displayed when the transaction is successful.

A Successful<br />
Transaction

Figure 4. A successful transaction

The menu for the first screen shown here (Figure 1) has two commands. We have already seen the result of executing the Next command. If the History command is executed, the record for the last transaction is printed to the console. This is shown in Figure 5.

 Details of Last<br />
Transaction

Figure 5. Details of last transaction

Project Settings

Project settings play a very important role in building applications using the payment API. This is because much of the information required for a payment transaction gets packaged into the provisioning files -- that is, the JAD file and the JAR manifest. The required information can be passed into these files by selecting Settings -> Payment on the LGSDK console and filling in the relevant fields.

Figure 6 shows the general entries that are mandatory. In the Version field, enter 1.0 or 1.1. Values for other fields can be filled in as shown. The significance of these values will be discussed when we talk about updates.

The General<br />
Settings

Figure 6. The General Settings

The next set of values to be entered link the features defined in the application with those predefined in the API. This will be explained in section on code analysis. Figure 7 shows the entries for our example. Features can be added or removed by clicking on the corresponding buttons.

Setting<br />
Features

Figure 7. Setting features

Finally, we need to provide information about the payment service providers. A payment service provider (PSP) is responsible for making the actual payment to the designated receiver of the payment. The preferred mode of payment defined in the payment API is Premium Priced SMS (PPSMS). In this payment mode, a payment is made by sending an SMS to the provider and the value of the payment is determined by the content of the SMS or by the number to which the SMS is sent. In our example we have two providers, as shown in Figure 8.

The List of<br />
Payment Service Providers

Figure 8. The list of payment service providers

Names can be added to or removed from the list by using the Add or Remove button. The Edit button is used to enter the details for a provider. Figure 9 shows the dialog that opens for entering provider information.

Provider Information

Figure 9. Provider information

The Payment Specific Info shown here are the applicable Mobile Country Code (MCC) and the Mobile Network Code (MNC) for the provider. The Price Info shown here contains the payment amount for each tag, along with other optional information. The number of tags here is equal to the number of features in Figure 7. The final specification document for the API includes detailed information on all the fields for the settings described above.

The MIDlet Code

It's time now to look at the code that does the payment-specific work. The declaration of the features comes first. The number of features is the same as the possible values that the loan amount can take. In this example the loan amount is a multiple of $10.00, with the minimum value being $10.00 and the maximum being $50.00. In the listing below, FEATURE_LOAN1 has the value 0, which links the feature to Pay-Feature-0 (Figure 7) and then to Pay--Tag-0 (Figure 9). So FEATURE_LOAN1 now corresponds to an amount of $10.00.

         //definition of feature to pay for         private static final int FEATURE_LOAN1 = 0;         private static final int FEATURE_LOAN2 = 1;         private static final int FEATURE_LOAN3 = 2;         private static final int FEATURE_LOAN4 = 3;         private static final int FEATURE_LOAN5 = 4; 

The activities related to making the payment are all performed within the commandAction method of the MIDlet. When we confirm our selections (Figure 2), the PAY_COMMAND is executed and the corresponding code is listed below. Note that the payload (payloadString converted to byte[]) is used to specify the selected project.

                  if (cmd == PAY_COMMAND)                 {                         String payloadString;                         int featureID;                          //set payloadString depending on                         //index of selected project                         switch (projIndex)                         {                                 case 1:                                         payloadString = "Project A";                                         break;                                  case 2:                                         payloadString = "Project B";                                         break;                                  case 3:                                         payloadString = "Project C";                                         break;                                  default:                                         payloadString = "Project A";                         }                          //set featureID depending on                         //index of selected amount                         switch (amtIndex)                         {                                 case 1:                                         featureID = FEATURE_LOAN1;                                         break;                                  case 2:                                         featureID = FEATURE_LOAN2;                                         break;                                  case 3:                                         featureID = FEATURE_LOAN3;                                         break;                                  case 4:                                         featureID = FEATURE_LOAN4;                                         break;                                  case 5:                                         featureID = FEATURE_LOAN5;                                         break;                                  default:                                         featureID = FEATURE_LOAN1;                         }                          try                         {                                 //ask TransactionModule instance                                 //to process the payment                                 txnModule.process(featureID,  "Loan Approval", "You can buy a Loan Voucher for " +  payloadString, payloadString.getBytes());                         }                         catch(Exception e)                         {                                 System.out.println(e.toString());                         }                 } 

When we call the process method, the API shows its own confirmation screen (Figure 3). If we choose to go ahead with the transaction, the payment is committed and the processed method is called back into by the payment module. Here we check what the result was and accordingly show an alert. The listing for the processed method is given below. Note that selForm is the form for Figure 1.

         public void processed(TransactionRecord tRecord)         {                 //get the result (state) of the transaction                 //and show alert accordingly                 switch (tRecord.getState())                 {                         case  TransactionRecord.TRANSACTION_SUCCESSFUL:                                 //Show success alert with feature info                                 final Alert successAlert =  new Alert("PayMIDlet", "Payment successful\r\nThank you",  null, AlertType.INFO);                                 successAlert.setTimeout(2000);                                 display.setCurrent(successAlert, selForm);                                 break;                          case  TransactionRecord.TRANSACTION_REJECTED:                                 //show reject alert with feature info                                 final Alert rejectAlert =  new Alert("PayMIDlet", "Payment rejected",  null, AlertType.INFO);                                 rejectAlert.setTimeout(2000);                                 display.setCurrent(rejectAlert, selForm);                                 break;                          case  TransactionRecord.TRANSACTION_FAILED:                                 //show fail alert with feature info                                 final Alert failAlert =  new Alert("PayMIDlet", "Transaction failed",  null, AlertType.INFO);                                 failAlert.setTimeout(2000);                                 display.setCurrent(failAlert, selForm);                 }         } 

After a transaction is completed, the corresponding record is saved by the API. Such past records can be accessed by the application to get a history of transactions. Selecting the History command on the screen corresponding to Figure 1 results in the following code being executed to display the last transaction, as shown in Figure 5.

 if (cmd == HISTORY_COMMAND)                 {                         //get record for last transaction                         //this is the first and only element                         //of the returned array                         TransactionRecord hRecord =  txnModule.getPastTransactions(1)[0];                          if(hRecord != null)                         {                                 String result = "";                                 String start = "a loan of ";                                 String end = "on";                                 String time = "";                                 Date hDate = new Date();                                  //get the result and                                  //set the beginning                                 //of the string to be shown                                  //accordingly                                 switch (hRecord.getState())                                 {                                         case  TransactionRecord.TRANSACTION_SUCCESSFUL:                                                 result = "Suceeded -- ";                                                 break;                                          case  TransactionRecord.TRANSACTION_FAILED:                                                 result = "Failed -- ";                                                 break;                                          case  TransactionRecord.TRANSACTION_REJECTED:                                                 result = "Rejected -- ";                                 }                                  //get the feature and form the middle                                 //part of the string accordingly                                 switch (hRecord.getFeatureID())                                 {                                         case FEATURE_LOAN1:                                                 result += start + "USD 10.00 "  + end + " ";                                                 break;                                          case FEATURE_LOAN2:                                                 result += start + "USD 20.00 "  + end + " ";                                                 break;                                          case FEATURE_LOAN3:                                                 result += start + "USD 30.00 "  + end + " ";                                                 break;                                          case FEATURE_LOAN4:                                                 result += start + "USD 40.00 "  + end + " ";                                                 break;                                          case FEATURE_LOAN5:                                                 result += start + "USD 50.00 "  + end + " ";                                 }                                  //get the time stamp for the transaction                                 hDate.setTime(hRecord.getFinishedTimestamp());                                 time = hDate.toString();                                  //form and display the entire string                                 System.out.println(result +  time.substring(0, time.lastIndexOf(':')));                         }                 } 

The getPastTransactions method of TransactionModule has been used to get the history. Only the latest record is returned, as the parameter used with the method is 1. The transaction record does not include the payload and, therefore, we cannot obtain the name of the project for a past transaction. One way of solving this problem would be to have the processed method create a separate record store to save the payload. The unique ID of a transaction could be used as a key to link a transaction record to the corresponding payload.

Running the MIDlet

In addition to the settings shown earlier, you need to select JSR 229 in the API Selection dialog, as shown in Figure 10.

API Selection

Figure 10. API selection

We are now ready to build the project. Load the source file for the MIDlet -- PayMIDlet -- into the src folder of the project and click the Package icon. You should now have the JAD and JAR files for the project in the bin folder.

Before running the MIDlet, some more work needs to be done. So far we have entered settings for the project. We now have to enter some settings for the platform (the emulator) on which the MIDlet will run. The first of these sets the MCC and the MNC so that they match the entries for the providers. Select Edit -> Preferences -> Payment on the LGSDK menu and you will get a dialog as shown in Figure 11. Enter the values shown.

Payment<br />
Preferences

Figure 11. Payment preferences

The second platform preference to be set will define the security policy. Select Edit -> Preferences -> Security to get the dialog and enter the values shown in Figure 12.

Security<br />
Preferences

Figure 12. Security preferences

The payment API can run only if the MIDlet is trusted. To confer that status on PayMIDlet, it has to be signed in accordance with the platform security preference that has been set. Click on the Sign icon and the dialog shown in Figure 13 will open. Click on Sign Application and you are done.

Signing the<br />
MIDlet

Figure 13. Signing the MIDlet

To run the MIDlet, click "Run via OTA" (OTA is "over-the-air provisioning") and follow the prompts.

Getting Updates

JSR 229 allows the price and provisioning information to be updated from a specified URL and the corresponding settings must be entered even if, as in this case, we don't need to use this facility. Referring to Figure 6, the entry for Update Stamp specifies the date from which the payment data becomes effective. The Update URL also has to be specified, although it can be a dummy URL as shown here. The final specification document contains elaborate information on the update feature.

Conclusion

We have seen here how to use the Payment API (JSR 229) for applications that use payment-enabled features and also to address general-purpose payment requirements. We used as a specific example an application that enables lenders to provide microcredit for specific projects. The final specification document for the API contains very detailed explanations, examples, and information on all aspects of JSR 229. Please refer to this document for a more comprehensive understanding of the API.

Resources

  • src.zip: source code for the demo application.

References

Biswajit Sarkar is an electrical engineer with specialization in Programmable Industrial Automation. Biswajit is the author of "LWUIT 1.1 for Java ME Developers" published by PACKT Publishing.
Related Topics >> GUI   |   Mobility   |   Programming   |   Featured Article   |