United States Argentina Australia Austria Belgium Canada Chile Colombia Costa Rica Dominican Republic France Germany Bangladesh/India Italy Kenya Mexico Netherlands Puerto Rico South Africa Sweden Switzerland Venezuela
BASIS International Ltd.
Home | Site Map | Contact Us | Partner Login  

 









Writing a Web Service in BBj
By David Wallwork
Table of Contents

his article focuses on developing a Web service provider for BBj® programs. See the Q1 2003 issue of the Advantage magazine for details about writing a BBj Web services consumer. A Web service must follow certain standards so that the deploying Web server knows how to serve it to the Web service consumer. There are two steps required to offer a Web service. First, write the service and second, deploy the service. This article explains how to write a Web service that allows the service consumer to execute code written in BBj, offered by the Web service. Because BBj runs in a Java runtime environment, BASIS implemented the Java Web services paradigm.

A Simple BBj Web Service
The BBj 3.0 release includes the following two classes:


  com.basis.bbj.webservice.BBjWS
  com.basis.bbj.webservice.BBjWSImpl

These classes allow BBj to offer a Web service. Offering a Web service enables other developers to write Web service consumers in other languages (VB, C++, BBj, .NET, etc.) that can run any BBj program offered by the Web service. Although this approach is certainly easy, the developer may want to do some additional work to

  • Control which BBj programs the consumer runs
  • Allow the consumer to pass information into the BBj programs
  • Allow the consumer to receive information back from the BBj programs

Controlling Which BBj Programs the Consumer May Invoke
Although the classes BBjWS.java and BBjWSImpl.java enable BBj to run as a Web service, this is not the standard method for deploying a Web service. The Web service developer should provide method signatures that are meaningful to the consumer of their service, rather than an interface that offers to run a BBj program. Additionally, developers should extend the classes BBjWS.java and BBjWSImpl.java, providing descriptive methods for the developers of the consuming applications. These methods can then invoke BBj code on behalf of the consumer. This way, the developer controls which BBj programs the consumer can run.

For example, if the consumer of BBjAuction invokes the BBjAuction.listAuctionItems() method, then the BBj program calls auction_getItems.bbj. However, BBjAuction controls which BBj programs the consumer application invokes. Now, the consumer of BBjAuction can only run a BBj program through the interface offered by BBjAuction.

Data Exchange From the BBj Program's Perspective
The BBj program receives a limited amount of data from the Web service by inspecting ARGV(). If the Web service requires more data than possible or reasonable via the command line parameters, or if the Web service needs to obtain response data from the program, then the BBj program should:

  • OPEN a bridge channel
  • READ from that channel as though it were a single keyed MKEYED file to obtain data from the Web service
  • WRITE to that channel as though it were a single keyed MKEYED file, or as though it were a STRING file in order to return data to the Web service

After the BBj program ends, the Web service may access any data written to the bridge channel.

Data Exchange From the Web Service's Perspective
The BBjWS interface exposes two methods:

  
public byte[] invokeBBjReturnBytes(String p_programName,                     
                                   String p_programParams,
                                   HashMap p_keyValues,             
                                   int p_timeoutInSeconds) throws RemoteException;
public HashMap invokeBBjReturnMap (String p_programName,                    
                                   String p_programParams, 
                                   HashMap p_keyValues,                     
                                   int p_timeoutInSeconds)throws RemoteException;

The syntax for p_programParams is the same as the syntax for the command line parameters when invoking a BBj program from the command line. If p_programParam ends with "..- argv1 argv2 argv3", then the BBj program has access to argv1, argv2, and argv3 using the ARGV() function.

If p_keyValues is not null, then the BBj program accesses each key-value pair in p_keyValues by reading the bridgeChannel. During its execution, if the BBj program writes information to the bridge channel, then the Java code of the Web service can access that information. If the BBj program writes to the bridge channel as though it were a String File, then the Java code uses the method invokeBBjReturnBytes() to retrieve the output of the BBj program. Alternatively, if the BBj program writes to the bridge channel as though it were an MKEYED file, then the Java code uses the method invokeBBjReturnMap() to retrieve the output.

Hello World Web Service
The following HelloWebService program:

  • Allows the consumer to run only one program
  • Accepts the user's name as input
  • Returns a greeting to the user

The developer needs to write two files: Hello.java and HelloImpl.java. Once deployed, these files enable the developer to offer the Web service. In addition, the developer needs to write Hello.bbj, which is the BBj program that our Web service invokes.

Hello.java

   
import java.rmi.*;
public interface Hello extends java.rmi.Remote
{        
    String sayHello(String name) throws RemoteException;
}

HelloImpl.java

   
import java.rmi*;
public class HelloImpl extends com.basis.bbj.webservice.BBjWSImpl implements Hello
{        
   String sayHello(String name)throws RemoteException
   {              
      String params = name;
      byte answer[] = invokeBBjReturnBytes("Hello.bbj", params, null, 2000);
      return new String(answer);
   }
}

Hello.bbj


Bridge = unt
REM  config file must contain a bridge alias for J0 see JavaBBjBridge docs
OPEN (bridge) "J0"

IF argc < 2    
	Answer$ = "hello world"
ELSE    
	Answer$ = "hello " + argv(1)
ENDIF

WRITE(bridge)answer$

RELEASE

With BASIS's Web service, the consumer no longer runs an arbitrary BBj program. The only option for the consumer is to invoke the method sayHello(). The Web service method HelloServiceImpl.sayHello() obtains its return value by invoking Hello.bbj. Additionally, this Web service requires only a small amount of Java code for implementation. Of course, it does not do much.

The next example is BBjAuction, which uses complex data types and multiple BBj programs to offer more meaningful methods to the consumer of the Web service. The following section returns to the BBjAuction, demonstrating how to pass more data than is practical on the command line.

Passing More Data
The BBjAuction Web service allows the consumer to logon to the system to obtain a listing of biddable items, bid on an item, and discover which item(s) the user won. Below, we examine the method BBjAuctionImpl.listActiveItems(). Listed below are the relevant portions of the code. See the complete code on the enclosed CD.

Complete code of the method BBjAuctionImpl.java


public AuctionItem[] listActiveItems(String p_loginID)throws java.rmi.RemoteException    
{        
	HashMap map = invokeBBjReturnMap("Auction_getItems.bbj", p_loginID, null, 30);
        return convertToAuctionItems(map);            
}        

Relevant portions of Auction_getItems.bbj

0050   clientChannel = unt
0090   open (clientChannel)"J0"

0110   call "auction_util.bbj::initialize"

0130   call "auction_util.bbj::makeItemTemplate", item$

0150 index = 0
0160 findRecord(dataChannel,knum=2,key="0",err=finished)item$

0170 while 1 
0210   call "auction_util.bbj::validateRecord", dataChannel, bankChannel, item$
0220   closed = item.biddingClosed

0230   if !closed
0240     call "auction_util.bbj::templateToItem", item!, item$
0250     closed = item!.getBiddingClosed()
0260     value$ = techcon03.AuctionItem.toByteString(item!)
0270     writeRecord(clientChannel, key=str(index))value$	
0280     index = index + 1
0290   endif
0300   readRecord(dataChannel, end=finished)item$
0310 wend

auction_getItems.bbj iterates through the data file, reading each record into the templated string Item$. At line 240, the program uses Item$ to create a Java Object of type techcon03.AuctionItem. At line 260, the code converts AuctionItem to bytes and places it into the string value$. At line 270, the code writes a key-value pair to the bridge channel.

auction_getItems.bbj continues until it writes all "open for bidding" items to the bridge channel. Furthermore, BBjAuction.listActiveItems() receives a HashMap as the return value of its call to invokeBBjReturnMap("auction_getItems.bbj:", p_loginID, null, 30).

Recall that the key-value pairs written by auction_getItems.bbj originated from strings. BBjAuction.listActiveItems() calls to BBjAuctionImpl.convertToAuctionItems, which converted the map of strings into an array of AuctionItems. The program then returns that list to the Web service consumer.

Passing Complex Data Types Between Web Service and BBj Program
When a BBj program reads input from its bridge channel or writes to its bridge channel, the program is only able to read or write bytes. Web service provides support for much more complex data types. If the developer can convert (serialize) those data types to bytes, the developer can pass them between the Web service and the BBj program.

The following lines from auction_getItems.bbj illustrate this example:


0240        call "auction_util.bbj::templateToItem", item!, item$
0260        value$ = techcon03.AuctionItem.toByteString(item!)
0270        writeRecord(clientChannel, key=str(index))value$

Line 240 converts the templated string Item$ to an instance of the Java class AuctionItem. Line 260 converts the AuctionItem to a string and line 270 writes the string to the bridge channel. Consequently, BBjAuctionImpl calls invokeBBjReturnMap() and does not need to understand templated strings. The map that it receives contains serialized AuctionItems, rather than serialized templated strings. BBjAuctionImpl deserializes these AuctionItems and uses them as the return value for the methods invoked by the Web service consumer.

The conversion from a templated string to an AuctionItem uses the following code:

From auction_util.bbj


0330 templateToItem:
0340   ENTER item!, A$
0350   item! = new techcon03.AuctionItem()
0360   item!.setItemID(num(A.id$))
0370   item!.setDescription(A.description$)
0380   item!.setHighBid(A.highBid)
0390   item!.setHighBidder(A.bidder$)
0400   item!.setNumberBids(A.numBids)
0410   now = int(new java.util.Date().getTime()/60000)
0420   remaining = A.endTimeMinute - now

0500   item!.setMinutesRemaining(remaining)
0510   item!.createString()
0520   techcon03.AuctionItem.setBiddingClosed(item!,A.biddingClosed)
0530 exit

One additional conversion remains. The method invokeBBjReturnMap() returns a Java HashMap. Each value in the HashMap contains bytes that are the serialization of an AuctionItem. However, we want to return an array of AuctionItems to the consumer of the Web service. Looking back at the code for BBjAuctionImpl.listItems(), notice that it calls BBjAuctionImpl.convertToAuctionItems(). See the code for this final conversion below.

From techcon03.BBjAuctionImpl.java

   

private AuctionItem[] convertToAuctionItems(HashMap p_map)
{        
	int size = p_map.size();
      AuctionItem ret[] = new AuctionItem[size]; 

      String key;
      String value;         
	Iterator next = p_map.keySet().iterator();

      while(next.hasNext())
      for(int q+0;q{ 
           key = (String)next.next();
           value = (String)p_map.get(key); 
           ret[q] = AuctionItem.fromByteString(value); 
        }
        Arrays.sort(ret,getSorter()); 
               return ret;
}

This code iterates over the Map returned by invoking BBjReturnMap() and converts each value to an AuctionItem by calling AuctionItem.fromByteString(). Furthermore, this code demonstrates how to exchange Java Objects between a BBj program and the Web service. The only requirement is knowing how to change that Java Object to bytes and back again.

Increased Security and Functionality
BBj 3.x provides the classes necessary for the immediate deployment of BBj programs as a Web service. By writing a minimal amount of Java code, a developer can write a Web service that is more secure and functional than the provided classes. Because BBj can create and manipulate Java objects, BBj programs and Web services can exchange complex data structures giving BBj programmers the ability to write very sophisticated BBj powered Web service providers. For more information about BBj and Web services, see http://www.basis.com/advantage/mag-v7n1/webservices.html .

Click HERE for the "Writing a Web Service in BBj" source code.

Table of Contents