Using Output Parameters


As discussed in the preceding chapter, a Web service can conveniently return multiple values using output parameters in a service call, using the concept of holders. Holders originated in the Common Object Request Broker Architecture (CORBA), where they were used for out and inout IDL parameters. A holder object acts like a box holding a Java object that needs to change in value on a service return. There is a distinct type of holder "box" for each Java type. For instance, the holder box for a String is javax.xml.rpc.holders.StringHolder (see Table 29.1 in Chapter 29 for a list of Holder classes supported by WebLogic Server 7.0). The holder "box" is passed into a service call; the service then opens the box, replaces its content with another Java object of the same type (if immutable) or a different-valued object, and returns the box to the caller.

To see a sample called ws-inout that illustrates a client and service implementation using output parameters, look at Sams Web site, www.samspublishing.com.

For details on the StockTrader service, see " InOut Parameters," p. 1089 . This section shows how its back-end provider (a stateless session bean) is implemented, how to build and run the sample, and how to develop Holder classes for your user -defined type classes.


The Holder Interface

All Holder classes implement the javax.xml.rpc.holders.Holder interface. This interface dictates the following requirements of an implementation:

  • A no-argument default constructor must be defined, initializing the contents of the holder.

  • There must be a constructor that takes one argument of the same data type that this holder embodies.

  • There must be a public instance variable named value that stores the content (data) of this holder, obviously with the same data type as the content data.

A holder object can simply be instantiated and given its initial content using the default constructor, as follows :

 
 intHolder numShares = new intHolder(250); 

Alternatively, you can change its value by using its value variable:

 
 numShares.value = 100; 

To see how a Web service client passes in holder parameters, see " InOut Parameters," p. 1089.


InOut Back-End Component

Writing a back-end component that takes output parameters is simple. The service methods just need to take holder-type arguments for any output parameter. Given that, the StockTrader.buy method has the following signature:

 
 Buy (  in   String ticker  ,  inout   int numOfShares  ,  out   float sharePrice  ) 

The back-end stateless session bean method that corresponds to this service call is shown in Listing 30.8.

Listing 30.8 Back-End Implementation of the StockTrader.buy Service
 public void buy (java.lang.String ticker, IntHolder inOutNumShares, StringHolder outBuyPrice ) { // execute the trade using ticker and numShares (code not shown) . . . // Use the input parm and update it (inout) inOutNumShares.value = inOutNumShares.value - 1; // Set the buy price (out) outBuyPrice.value = "$22.50"; } 

The public variable value is used to both access and update the holder. Note that the same Holder class is used for both out and inout parameters. It is the business logic that decides how to use the holder object. This example shows how to use a built-in type as an output parameter, but using a Holder class for a user-defined type is just as simple. The back-end component accesses the UDT object through the public value variable and modifies the UDT accordingly .

InOut in WSDL and web-services .xml

You might be surprised to learn that Holder classes are never referenced inside a WSDL or the web-services.xml file. Each of these "service description" files has other, more subtle ways of indicating out or inout parameters. This makes perfect sense considering that a service description should not be programming language specific. In the JAX-RPC prescription for Java Web services implementation, Holder classes are used to implement output parameters. So how does a WSDL file express output parameters?

Recall that the <message> element of the tModel section in a WSDL file describes the data items (or data parameters) that are sent between the caller and service provider. Each <part> subelement of a <message> represents one call parameter. There is one <message> element for the input request and another <message> element for the output return. Normally, the return <message> would indicate a return value, but in this case, you can list the same <part> subelements in both the input and return <elements> . The WSDL specification dictates that such a scenario indicates out or inout parameters. Let's quote the WSDL 1.1 specification to be precise:

  • If a part name appears in only the output message, it is an out parameter.

  • If a part name appears in both the input and output message, with the same type, it is an inout parameter.

These concepts will be clearer when you see the WSDL. Here again is the signature of the buy method:

 
 Buy (  in   String ticker  ,  inout   int numOfShares  ,  out   float sharePrice  ) 

Its corresponding input ( message name="buy" ) and output ( message name="buyResponse" ) message elements in WSDL look like Listing 30.9.

Listing 30.9 Specifying out and inout Parameters in WSDL
 <message name="buy" > <part name="string" xmlns:partns=http://www.w3.org/2001/XMLSchema type="partns:string" /> <part name="numShares" xmlns:partns=http://www.w3.org/2001/XMLSchema type="partns:int" /> </message> <message name="buyResponse" > <part name="numShares" xmlns:partns=http://www.w3.org/2001/XMLSchema type="partns:int" /> <part name="sharePrice" xmlns:partns=http://www.w3.org/2001/XMLSchema type="partns:float" /> </message> 

Part name numShares occurs in both the input and output messages, making it an inout parameter. On the other hand, part name sharePrice occurs only in the output message, making it an out parameter.

Note

If you open the generated WSDL for StockTrader , you will notice that sharePrice actually occurs in both input and output messages. That's because WebLogic Server is generating the WSDL based only on the back-end StockTraderBean.java , where it cannot distinguish between out and inout parameters because a Holder class can be used either as an out or inout parameter.


In web-services.xml , you simply specify the style attribute in the <parm> element, as shown in Listing 30.10.

Listing 30.10 Specifying out and inout Parameters in web-services.xml
 <operation method="buy"... > <params> <param location="body" class-name="java.lang.String" style="in" name="string" xmlns:xsd=http://www.w3.org/2001/XMLSchema type="xsd:string"> </param> <param location="body" class-name="javax.xml.rpc.holders.IntHolder" style="inout" name="intHolder" xmlns:xsd=http://www.w3.org/2001/XMLSchema type="xsd:int"> </param> <param location="body" class-name="javax.xml.rpc.holders.StringHolder" style="out" name="stringHolder" xmlns:xsd="http://www.w3.org/2001/XMLSchema" type="xsd:float"> </param> </params> </operation> 

Don't forget that the WebLogic ServiceGen task will generate all these files for you if you give it a back-end component (a Java class or EJB) that uses Holder classes. However, the preceding discussion should prove helpful if, for some reason, you need to manually add output parameter support for an already-established Web service.

You might think that a UDT Holder class like AddressHolder is itself a UDT that needs an XML Schema and type mapping. That is not the case. Because a Holder class is never referenced inside a service description file, it is an "under-the-covers" UDT that is automatically configured, per JAX-RPC specifications, into the Web service for output parameters.

Now that you've seen the client, back-end component, and deployment descriptor of a Web service that uses output parameters, it should be evident that these Holder classes are really nothing special. Holder classes also need serializing/deserializing, except that you don't need to define a distinct serializer/deserializer for each type of holder object. There is a built-in serializer/deserializer for the javax.xml.rpc.holders.Holder interface. While serializing/deserializing a particular holder object, it simply takes its holder.value object and calls its serializer/ deserializer. That is, your UDT classes always need serialzers/deserializers regardless of their use as in , out , or inout parameters. The only magic that WebLogic Server must perform is intelligently heed the service descriptions' cues on output arguments and presume use of the appropriate Holder classes in both the client and back-end components .

Running the InOut Sample

As mentioned previously, our Web site contains an example called ws-inout that illustrates output parameters. You can find it in \chap30\ws-inout . This example assumes you already have the WebLogic Server component of WebLogic Platform 7.0 installed or accessible, including the WebLogic examples. You need the Examples server that comes with installing the WebLogic Server Examples bundle. The following are some relevant files you will find in ws-inout :

  • StockTrader.java , StockTraderHome.java , StockTraderEJB.java These are the back-end component stateless session bean files: remote interface, home, and bean implementation, respectively. The deployment descriptors for StockTrader , ejb-jar.xml , and weblogic-ejb-jar.xml are also found here.

  • StockTraderClient.java This file calls the buy service method.

  • build.xml This Ant build file compiles and runs the EJB compiler (ejbc) on the StockTrader bean and then invokes serviceGen to create the StockTrader.ear deployable Web service file. This file can also compile the client and run it.

Follow these steps to run the example:

  1. Copy all files under ws-inout to your local drive because you will need these files in a writeable location to run the example. You can locate this example anywhere in your drive.

  2. Edit the build.xml file and follow the instructions there for modifying certain property variables such as your WebLogic Server location.

  3. Open two DOS command prompts and call them DOS1 and DOS2.

  4. In DOS1, set up your environment to build and run the examples by invoking the WebLogic Server script (where wl_home is the root directory of WebLogic Platform 7.0):

     
     <  wl_home  >\weblogic700\samples\server\config\examples\setExamplesEnv.cmd 
  5. In DOS1, use ant build to build the StockTrader EJB back-end component and the StockTrader Web service EAR file. It will automatically copy this EAR file to the WebLogic Server's Examples server applications area in

       
      <  wl_home  >\weblogic700\samples\server\config\examples\applications  
  6. In DOS2, start the WebLogic Examples server by invoking the start script:

       
      <  wl_home  >\weblogic700\samples\server\config\examples\startExamplesServer.cmd  
  7. When the Examples server is up and running, use ant run in DOS1 to run the StockTraderClient .

  8. You can also go to a browser and bring up the StockTrader home page at

       
      http://localhost:7001/StockTrader/StockTrader  

Try invoking the service to see the SOAP request and SOAP response, and note how the Holder classes are being serialized to XML. Are they? Why or why not?

InOut User-Defined Types

If you need to create a service which returns an output parameter that is not a built in type, you need to create a Holder class for your user-defined type. In most cases, WebLogic Server's ServiceGen task will generate these holders for you. In some cases, however, you must edit a generated holder or choose to write one yourself. All the points discussed in "The Holder Interface" section earlier in this chapter apply to UDT holders. In addition, you must follow a naming convention for your class that implements Holder : Type Holder , where Type is the name of your user-defined type. For example, if your UDT is named Address , its Holder class is AddressHolder , as shown in Listing 30.11.

Listing 30.11 Example of a Holder Class for the Address User-Defined Type
 package examples.webservice.holders; public final class AddressHolder implements javax.xml.rpc.holders.Holder { public Address value; public AddressHolder() { // set to default initial value } public AddressHolder(Address addr) { value = addr; } } 

Remember that you still need to define your user-defined type, with its XML Schema definition, type mapping to serializers/deserializers, as well as the serializer/ deserializer classes themselves (or have them all generated by ServiceGen ). Making a Holder class is an additional step. However, the ServiceGen task, by default, attempts to create Holder classes for your UDTs automatically and places them in the package < UDT-package > . holders , where < UDT-package > is the package of its corresponding user-defined type class. You can find these generated Holder classes in the WEB-INF\classes folder of the generated Web service WAR file, or in the client JAR file, if one is available (refer to Figure 30.6).



BEA WebLogic Platform 7
BEA WebLogic Platform 7
ISBN: 0789727129
EAN: 2147483647
Year: 2003
Pages: 360

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net