Skip to main content

If you don't have an IBM ID and password, register here.

By clicking Submit, you agree to the developerWorks terms of use.

The first time you sign into developerWorks, a profile is created for you. This profile includes the first name, last name, and display name you identified when you registered with developerWorks. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

All information submitted is secure.

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerworks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

Developing using the ETTK, Part 2

Creating RPC and Message services

Doug Davis, ETTK Technical Lead, EMC
Doug is the Technical Lead for the Emerging Technologies Toolkit (ETTK). Previous projects include WebSphere Machine Translation, Team Connection and IBM's FORTRAN 90 Compiler. You can reach Doug at dug at us.ibm.com.

Summary:  In Part 1 of this series Doug examined the specific SOAP engine (Axis) that the Emerging Technologies Toolkit (ETTK) uses. In this article he continue the series on developing with the ETTK by focusing on how to create RPC and Message services as well as how to deploy Axis Handlers.

Date:  13 May 2003
Level:  Intermediate

Comments:  

RPC services

As a first step into the web service world let's take one of the most common web service examples used: a StockQuote service. For this purpose I will cheat and have our service just return a price of US$55.55 for all stock symbols passed in. So, let's say our web service looks like Listing 1.


Listing 1. StockQuote service
public class StockQuoteService {
  public float getQuote(String symbol) {
    return( 55.55 );
  }
}

The first thing you might notice is that the code doesn't really look like anything new or special -- where's the "web service" part of it? In simple RPC cases there isn't anything special -- that's one of the nice things about web services, you should be able to take existing Java code and turn it into a web service with little effort.

Now that you have some code, that you can claim is a web service, the next step is to make it available for someone to use -- or deploy it.


Deploying an RPC Service

Deploying a service to Axis requires two steps: first you must make sure that the Java class is available to the Axis runtime engine, and second you must make Axis aware of your service. Since Axis is a servlet, placing your class files in your webapp's WEB-INF/classes directory will make them available to the Axis servlet. Making Axis aware of your service is a little harder. Here you have two options:

  1. Modify the server side configuration file --The Axis server uses a file named server-config.wsdd to store all of its persistence information -- things like the list of services deployed. This file can be found in the webapp's WEB-INF directory. So, in this case you can manually modify this file and add the XML shown in Listing 2.

Listing 2. XML added to server-config.wsdd
<service name="StockQuoteService" provider="java:RPC">
   <parameter name="className" value="StockQuoteService"/>
   <parameter name="allowedMethods" value="*"/>
</service>

Most of what this XML is doing should be fairly obvious; you're defining a new service called "StockQuoteService" and telling Axis that it's an RPC service. The "provider" attribute tells Axis which Dispatcher to use -- in this case, the Java RPC one. There are two parameters that will be used by the provider, one tells it the Java classname of the service and the other one defines which methods are exposed as services (in this case, all of them).
Once you modify the server-config.wsdd file you'll need to restart Axis, or more specifically the application server, in order for these changes to be noticed.
This method of deploying services isn't very good for cases where you want to dynamically (at runtime) change the available services, however, if you want to predeploy services before the application server starts then this is the way to go.
  1. Dynamically (remotely) deploy your service -- In this situation you tell Axis about your new service without manually editing the server side configuration file or even restarting Axis. To do this you invoke an administrative web service running inside Axis. In short, you take any new services (or even handlers) and place them in a WSDD file and give it to the AdminService. So, for this scenario you create a WSDD file called stock.wsdd, as shown in Listing 3.

Listing 3. stock.wsdd
<deployment name="test" xmlns="http://xml.apache.org/axis/wsdd/"
       xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
   <service name="StockQuoteService" provider="java:RPC">
      <parameter name="className" value="StockQuoteService"/>
      <parameter name="allowedMethods" value="*"/>
   </service>
</deployment>

Notice that the WSDD looks just like it did for the static deployment, except it is wrapped in a <deployment> tag. Now all that's left is to invoke the AdminService, as shown in Listing 4.

Listing 4. Invoke AdminService
java org.apache.axis.client.AdminClient 
-l http://localhost:8080/wstk/services/AdminService stock.wsdd

This Java command will run the AdminClient -- basically just a simple tool that takes the wsdd file passed in on the command line (stock.wsdd in this example) and sends it to the AdminService (which by the way is an example of a Message service). The -l (el) option tells it where the AdminService is running -- in this case you have it deployed as a service in the ETTK's environment.

No matter how you choose to deploy your service you can verify that it worked by using the AdminClient's "list" feature, as shown in Listing 5.


Listing 5. AdminClient's "list" feature
java org.apache.axis.client.AdminClient 
-l http://localhost:8080/wstk/services/AdminService list 

This will return the complete list of services and handlers currently deployed in the Axis server. Now that the service is deployed you need to try to invoke it.


Using an RPC Service

There are three different ways to invoke RPC services in Axis:

  1. Dynamic Invocation Interface without WSDL -- The standard Java interface for accessing web services (also known as JAX-RPC) has a dynamic invocation interface (DII) that allows you to access RPC services with and without using the WSDL that defines the service. First you can do it without using the WSDL, as shown in Listing 6.

Listing 6. Dynamic Invocation Interface without WSDL
import java.net.*;
import org.apache.axis.client.* ;
import javax.xml.namespace.QName;

public class getQuote1 {
  public static void main(String[] args) throws Exception {
    String url = "http://localhost:8080/wstk/services/StockQuoteService";
    Service service = new Service();
    Call call = (Call) service.createCall();
    call.setTargetEndpointAddress( new URL(url) );
    call.setUseSOAPAction( true );
    call.setSOAPActionURI( "getQuote" );
    call.setEncodingStyle( "http://schemas.xmlsoap.org/soap/encoding/" );
    call.setOperationName( new QName(url, "getQuote") );
    call.addParameter( "symbol", XMLType.XSD_STRING, ParameterMode.IN );
    call.setReturnType( XMLType.XSD_FLOAT );
    Object result = call.invoke(  new Object[] {args[0]} );
    System.out.println(args[0] + ": " + result );
  }
}

Stepping through the code you can see that you create a Service and Call objects -- once you have the Call object you then have to define some basic SOAP properties: the URL of where the service is deployed, the value of the SOAPAction HTTP header, the type of encoding to use, the QName of the operation you want to invoke, the types of parameters you'll pass to this operation, and finally the result value's type. Once all of that information is defined you then invoke the service passing in the symbol that was given to you on the command line. Notice that the parameters to the operation are passed in as an array of Java objects rather than as individual parameters to the invoke() method.
So, when you run it you see the output shown in Listing 7.

Listing 7. Output from running code in Listing 6
> java getQuote1 XXX
XXX: 55.25 

This sample, while fairly short, has a lot of steps that could get very tedious over time, for example the "addParameter" method which tells Axis the name of the parameter to the method, and its type. Instead, you can have Axis determine most of that information by giving it the WSDL document for the service -- which leads to the next way of invoking RPC services.
  1. Dynamic Invocation Interface with WSDL -- This is basically the same as above except here you pass in the URL to the WSDL document, specify which specific service, port and operation you want, and Axis will figure out the other auxiliary information (see Listing 8).

Listing 8. Dynamic Invocation Interface with WSDL
import java.net.*;
import org.apache.axis.client.* ;
import javax.xml.namespace.QName;

public class getQuote2 {
  public static void main(String[] args) throws Exception {
    String url = "http://localhost:8080/wstk/services/StockQuoteService?wsdl";
    String  namespace = "http://localhost:8080/wstk/services/StockQuoteService";
    QName serviceQN = new QName( namespace, "StockQuoteServiceService" );
    QName portQN = new QName( namespace, "StockQuoteService" );
    Service service = new Service(new URL(url), serviceQN );
    Call call = (Call) service.createCall( portQN, "getQuote" );
    Object  result = call.invoke( new Object[] {args[0]} );
    System.out.println(args[0] + ": " + result );
  }
} 

Here, you see that the code is a little bit smaller, but more importantly a lot of the information that you had to manually define on the Call object is now hidden from you because Axis was able to extract it from the WSDL document. Another noteworthy thing is that the URL of the WSDL document is the URL of the service itself with a "?wsdl" at the end; here you're asking Axis to generate the WSDL for us.
  1. Proxy Classes -- The final way to invoke the service is through the use of a proxy class (also known as a Stub). Axis provides a tool that will take the WSDL document for a service and generate a client-side class that you can invoke that will hide all of the SOAPness from you. For our example if you run the code in Listing 9, it generates several Java files for you, but the most important one is called localhost/StockQuoteServiceLocator.java -- this class acts as a proxy class that does all of the SOAP work for you.

Listing 9. Generate proxy class
wsdl2java http://localhost:8080/wstk/services/StockQuoteService?wsdl

So, your code would be reduce down to that shown in Listing 10.

Listing 10. Proxy class
import localhost.* ;

public class getQuote3 {
  public static void main(String[] args) throws Exception {
    StockQuoteServiceServiceLocator loc = new StockQuoteServiceServiceLocator();
    localhost.StockQuoteService sqs = loc.getStockQuoteService();
    System.out.println( args[0] + ": " + sqs.getQuote(args[0]) );
  }
} 

Here you use the StockQuoteService class just as if the service were a local Java class.

There is no clear rule for deciding which of the three types of invocation methods to use -- it will vary depending on your situation. Obviously, if you don't have WSDL then you can only use the first. If you want your code to be portable to other JAX-RPC implementations besides Axis then, you may want to use the DII interfaces (avoiding the Axis extensions). For more information about using Axis see the Axis User's Guide (see Resources for a link).


Message services

Writing a message service

Unlike the RPC case, message services are required to match a certain method signature. In the easiest case the method should take in an array of DOM Elements (which will correspond to the SOAP Body elements) and return an array of DOM Elements (the resulting SOAP Body elements). So, for example, let's examine the BasicWS demo's Message service (see Listing 11).


Listing 11. BasicWS demo's Message service
import org.w3c.dom.* ;

public class MessageService {
  public Element[] process(Element[] xmls) {
    Element[] elems = new Element[xmls.length];
    for ( int i = 0 ; i < elems.length ; i++ )
    elems[i] = xmls[elems.length-i-1] ;
    return elems;
  }
}

So, unlike in the RPC case where Axis will convert the XML to and from Java programming language for you, in the Message case it leaves the XML untouched, and you can see you've defined a single method called "process" that takes an array of Elements and returns one as well. Just as a side note, this service will return the same array of Elements back to the client but in the reverse order.

Deploying a message service

Deploying a message service is basically the same as in the RPC case with just a couple of exceptions, let's look at the MessageService's <service> element from the WSDD file as an example (see Listing 12).


Listing 12. MessageService's <service> element
<service name="MessageService" provider="java:MSG">
  <parameter name="className" value="basicWS.MessageService" />
  <parameter name="allowedMethods" value="process" />
</service>

First, notice the "provider" attribute says "java:MSG" indicating that this is a message service instead of an RPC service. Second is the "allowedMethods" parameter. In this case, by specifying a single method name you're telling Axis that all requests should be routed though this one method regardless of what is in the XML. If you specified more than one method name, then Axis will match the local part of the first body element with the method name to determine which method to invoke.

Using a message service

Invoking a message service is basically the same as invoking an RPC service except instead of passing in an array of Java objects that will be converted into XML, you pass in an array of XML chunks. So, looking at snippets of the Message demo's client, you have the code in Listing 13.


Listing 13. Message demo's client code
  Vector xmls = new Vector();
  String str1 = "The first shall be last";
  String str2 = "The last shall be first";
  SOAPBodyElement xml1, xml2 ;

  ...

  xml1 = new SOAPBodyElement(new ByteArrayInputStream(str1.getBytes()));
  xml2 = new SOAPBodyElement(new ByteArrayInputStream(str2.getBytes()));

  ...

  xmls = (Vector) call.invoke( new Object[] {xml1, xml2} );

Stepping through the code you can see that you create two SOAPBodyElement objects by passing in an InputStream to the constructor -- the constructor also accepts a DOM Element object. Axis requires you to wrap your Elements in SOAPBodyElements so that it knows whether it should pass the XML untouched to the server or whether you want to convert the Java objects (Element in this case) into XML (not wrappering them will do an RPC call instead of a Message call).

Axis' interfaces for communicating with Message style services isn't standard -- while there are some standard interfaces out there (JAXM for example) Axis chose to take just pieces of them and integrate them into its JAX-RPC extensions. For more information about using Axis see the Axis User's Guide (see Resources for a link).


Handlers

As mentioned in the previous article, Axis supports the notion of pluggable components, Handlers, that allow you to intercept an outgoing or incoming message for the purpose of performing some additional processing. This processing can be on the message itself or can be unrelated entirely to the message -- Axis places no restriction on what a Handler can do.

Axis supports the use of Handlers in both the client and server processing models. Because of Axis' symmetry of processing (see the Axis section in Part 1 of this series), the same Handlers can be used on either side of the wire -- by that I mean the Handler interfaces are the same and the APIs you use to get data (such as the message itself) is the same. This makes it very useful when creating a Handler that wants to process an outgoing message because that means it can be placed on both the outgoing side on the client as well as the response (also outgoing) side on the server.

Really the only difference between a client-side Handler and a server-side Handler is how it is deployed into the Axis environment. Let's take a look at how this is done.

Client-side

On the client there are two ways to register or deploy Handlers: add the Handlers to your Call object or register them with the Axis engine. Listing 14 shows the first method.


Listing 14. Add handler to call object
call.setClientHandlers( requestHandler, responseHandler );

This will tell Axis to invoke requestHandler before the message is sent to the server and invoke responseHandler before control is returned back to your application.

The other way to have handlers invoked is by deploying them to the Axis engine -- the easiest way to do this is through the modification of the client-side configuration file (client-config.wsdd). Listing 15 shows a sample client-config.wsdd file.


Listing 15. Sample client-config.wsdd
<?xml version="1.0" encoding="UTF-8"?>
<deployment xmlns="http://xml.apache.org/axis/wsdd/" 
xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
  <service name="StockQuoteService">
    <requestFlow>
      <handler type="java:com.mycom.RequestHandler"/>
    </requestFlow>
    <responseFlow>
      <handler type="java:com.mycom.ResponseHandler"/>
    </responseFlow>
  </service>
  <transport name="http" 
  pivot="java:com.ibm.wstk.axis.handlers.WSTKHTTPSender"/>
</deployment>

In this example you tell Axis that for the service named StockQuoteService it should invoke the RequestHandler before sending the message to the server and invoke the ResponseHandler before returning control back to the application. Conceptually, very similar to the setClientHandlers() method call. The other entry in the xml file tells Axis what handler/dispatch to use for the http transport. That's just a default setting that needs to be there. One thing to remember is that by creating your own client-config.wsdd file you are overriding the default one Axis uses, so the best thing for you to do is to take the one from the axis.jar file and modify it (by adding your element), that way you are sure to get all of the default Axis client-side configuration files.

One last thing to note about the client-side configuration file; it needs to be available to the Axis run-time through the classpath. Most developers will simply put it in the current working directory, but it can be placed elsewhere just as long as that location is in the classpath.

Server-side

Deploying the handlers on the server-side is very similar. There's a server-config.wsdd file you can modify. For predeploying services most people will take the one from the axis.jar file, modify it, and then place a copy of it in their webapp's WEB-INF/classes directory. If you look at the ETTK's WEB-INF/classes directory you should see all of the predeployed services and handlers the Toolkit ships with.

Adding Handlers to your service on the server-side is very simple, looking at the wsdd file used to deploy the StockQuoteService back in the RPC Services section we had the code shown in Listing 16.


Listing 16. XML added to server-config.wsdd
<service name="StockQuoteService" provider="java:RPC">
   <parameter name="className" value="StockQuoteService"/>
   <parameter name="allowedMethods" value="*"/>
</service>

So, adding request or response handlers is done the same way it was done in the client-config.wsdd -- the new wsdd file is shown in Listing 17.


Listing 17. New wsdd file
<deployment name="test" xmlns="http://xml.apache.org/axis/wsdd/"
       xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
  <service name="StockQuoteService" provider="java:RPC">
    <parameter name="className" value="StockQuoteService"/>
    <parameter name="allowedMethods" value="*"/>
    <requestFlow>
      <handler type="java:com.mycom.RequestHandler"/>
    </requestFlow>
    <responseFlow>
      <handler type="java:com.mycom.ResponseHandler"/>
    </responseFlow>
  </service>
</deployment>

Now this new wsdd file can be sent to the AdminService using the AdminClient tool, or you can add this new <service> section to your predeployed server-config.wsdd.

For more information about Handlers, including how to create them and more configuration information about them, see the Axis documentation (see Resources for a link). Also, please see the ETTK for more details about the examples mentioned in this article.


Conclusion

With this quick overview of creating RPC and Message style services, along with the rest of the ETTK, you should be able to develop your own web services. The next article in this series will explore the Grid and show how you can convert your web services into Grid services.


Resources

About the author

Doug is the Technical Lead for the Emerging Technologies Toolkit (ETTK). Previous projects include WebSphere Machine Translation, Team Connection and IBM's FORTRAN 90 Compiler. You can reach Doug at dug at us.ibm.com.

Report abuse help

Report abuse

Thank you. This entry has been flagged for moderator attention.


Report abuse help

Report abuse

Report abuse submission failed. Please try again later.


developerWorks: Sign in

If you don't have an IBM ID and password, register here.


Forgot your IBM ID?


Forgot your password?
Change your password


By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. This profile includes the first name, last name, and display name you identified when you registered with developerWorks. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

Choose your display name

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

(Must be between 3 – 31 characters.)


By clicking Submit, you agree to the developerWorks terms of use.

 


Rate this article

Comments

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=SOA and web services
ArticleID=11801
ArticleTitle=Developing using the ETTK, Part 2
publish-date=05132003
author1-email=
author1-email-cc=

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

For articles in technology zones (such as Java technology, Linux, Open source, XML), Popular tags shows the top tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), Popular tags shows the top tags for just that product zone.

For articles in technology zones (such as Java technology, Linux, Open source, XML), My tags shows your tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), My tags shows your tags for just that product zone.

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).