What exactly are web services? Probably the easiest way to think of web services are as pieces of code on a remote host that you can access. The Internet/Web has opened the door on data sharing -- from your PC you can access data from all over the world. This concept has now been extended to include business logic. So, instead of accessing static data on someone else's machine, you can now ask them to perform some function on your behalf. For example, given the stock symbol IBM, what is its current stock price? This very simple example might not seem like a good one because you can get this information already just by going to your favorite portal and typing in IBM. However, what if you wanted to get that information from inside of a program? Still possible; you can do the equivalent of getting that Web page from inside of a program and scan it for the result, but the layout of that page will change over time and not everyone has the programming skills to do all of that. Imagine, if instead you could write something as simple as the code in Listing 1, and it would do everything for you under the covers using the getQuote method. You can do this with web services.
Listing 1. Simple line of program code
value = StockQuoteService.getQuote("IBM");
|
As you probably already know, at the core of web services is SOAP. SOAP defines what the layout of the message (in XML) between your client and the remote service should look like. One of the really nice things about SOAP is that it is platform and language independent. So, while on your client you might have Java code calling the getQuote method, on the server you could have C++, Perl, or any other language doing the actual work for you. It doesn't matter to SOAP which language is on the server -- which leads directly into the reason for the industry's rapid adoption of web services: platform neutrality and interoperability. Now product vendors will be able to talk to one another without concern for the platform or language being used. Several companies have joined together to form an organization called WS-I (see Resources) to help ensure that the interoperability claim of web services continues to become a reality. Even though there are agreed-upon specifications being developed, ambiguities in those specs might lead to interoperability problems. Organizations, such as WS-I, are working to develop resolutions to those issues.
For the most part, you can group web services into two categories: RPC (Remote Procedure Call) and Message (or Doc-Literal). RPC services are the simpler of the two categories to learn. They allow both the client and the server developer to write code as if they were making a simple procedure call. The parameters passed into the procedures and any results returned are automatically converted for you between Java objects and SOAP/XML. Message services are not really that different from RPC services except the contents (the XML) of the SOAP Body are not converted to/from Java objects for you - instead you give the SOAP processor a chunk (or chunks) of XML to send.
So, how do you decide which one to use? In a lot of cases it is really a matter of personal preference. Some people will argue that Message style is preferable while others will argue in favor of RPC. Really, it all depends on how much effort you want to devote into generating the XML. If the scenario you are working with doesn't require anything special, just simple data types that are easily mapped into Java objects, then RPC is probably the right choice. If however, you are sending a lot of data that is best represented as an XML document, then Message style would make more sense.
As you might imagine, using web services requires some infrastructure to manage your requests. All SOAP toolkits offer the same basic functionality; on the client side they give you the ability to easily construct a web service request and to get back a response. On the server side they take an incoming request, determine which web service to invoke, invoke it with the data from the SOAP message, and then send back the results. The differences among SOAP engines are in what languages you can work in, which tools are available for building services, how services are managed and deployed, and the ease of use and performance. The Emerging Technologies Toolkit (ETTK) uses Axis as the SOAP processor/engine for its demos.
Axis is probably the most widely used Java based SOAP processor currently available. It has helped shape the way people use web services, ranging from what features people expect a SOAP processor to offer to helping define the standard Java APIs people will use when invoking web services. One of Axis' key features is the incredible pluggabilty it offers its users. Almost everything in the Axis engine can be replaced with a customized component, and the single most important component is a Handler. More information about Handlers will be covered in the following sections but for now let's look, at a high level, at what happens on the client.
Figure 1. Axis client
Ignoring the contents of the dashed box in Figure 1 for a moment, the concept here is pretty simple; the client code will invoke the Axis client, which will construct an outgoing message and send it to a SOAP server (in this example using HTTP). Then a response (or incoming) message is received back, processed by the Axis client and any results are returned back to the client code as Java objects. In the following sections you'll see how the client code will invoke the Axis engine. But to start, let's look at what's inside the Axis Client box. You'll notice that there are three types of Pre-Processing Handlers, and three type of Post-Processing Handlers invoked. Think of Handlers as pluggable components through which the message will pass, allowing each Handler a chance to perform some action based on the message or even to modify the message. Axis allows you to place a Handler into three different stages of a message's processing flow:
- Service-Specific -- The Handler will be called just when a specific service is invoked.
- Global -- The Handler will be invoked for all services invoked.
- Transport-Specific -- The Handler will be invoked only when a certain transport (such as HTTP) is used.
Because you can place a Handler in any of these three layers, you should be able to perform very specific processing in almost any scenario. The last box, the Transport Sender, is also a Handler but it has a very special task -- to take the message and send it out to the requested SOAP server.
So, what are these Handlers used for? Well, common uses include things like adding SOAP Headers to the message and encrypting parts (or all) of the message. Axis doesn't mandate or restrict what a Handler can do which is one of the reasons it is so popular. There's a lot more involved with the Axis client. Some of that will be discussed in a later section, but understanding the various levels of Handlers on the client is enough for now. The next section takes you on to the server side.
Figure 2. Axis server
The first thing that you might notice in Figure 2 is that the Axis Server box looks a lot like the Axis client box - and that's done on purpose. At the core of the Axis there really isn't much but a looping mechanism that will iterate through the list of desired Handlers. So, if you think about what an Axis server would need to do, it should do the same thing as the client but in reverse order -- so you'll notice that it runs through the same types of Handlers and, instead of a Transport Sender (Handler), there's a Dispatch Handler. A Dispatch Handler will take the SOAP message, convert the SOAP/XML into Java objects, invoke the desired web service, and finally convert any response back into XML. Nothing too magical -- it should be what you'd expect a SOAP engine to do. Again, what makes Axis so special is the pluggability of the Handlers, letting you pretty much make Axis do whatever you want or need it to do.
Before moving on let's examine the Dispatch Handler a little more. In the RPC case it will convert the SOAP/XML into Java objects and then invoke the web service. For simple data types, such as String and Integer, Axis will know how to convert those to (and from) XML for you. For more complex types, such as user-defined classes, you'll have to tell Axis how to convert those, but Axis provides some utilities to make that easier. But, what if you're service is a Message service (one which wants to process chunks of XML)? In this case the Dispatch Handler will take the XML and read it into a DOM structure and invoke the web service with the DOM/Java objects for that XML structure. It's really not that different from the RPC case.
As discussed in the previous section, one of Axis' key value-adds is its notion of Handlers. While it is true that anything you could do in a Handler you could also do in your client-side code or in your service, componentizing the logic into Handlers gives you several benefits. For one, it allows you to cleanly separate the business logic from your SOAP processing logic. A good example of this is adding security to your SOAP requests. With the definition of new security specifications, such as WS-Security, you'll want to be able to add these new features to your services (or your SOAP environment) with minimal impact on your code and configuration. By keeping a clean separation between your service and these add-on features, you can add and remove them as needed. Also, as third-party vendors develop Handlers, you will be able to plug them into your configuration without any changes to your service. And in fact your service will be totally unaware of their existence.
The previous section explained how Axis lets you to categorize your Handlers into three different groups (service-specific, global, and transport-specific). With this you have the freedom to decide when certain Handlers should be used and under what circumstances. For example, you can decide that all Web Service invocations should go through some Logging Handler (that is placed in the Global grouping), but only services that are invoked over HTTP should be required to go through a Handler that checks an HTTP Basic Authentication header (in the HTTP Transport grouping). Basically, you can drop a Handler into one of these three categories and each one will be invoked at the appropriate time and can do anything you want - even completely rewrite the message, as is the case in some of the new WS-Security Handlers. They will let you to do things like Encrypt part or all of the SOAP message to ensure it isn't read by someone else.
In order to not limit the use-cases supported by Axis, Handlers are given access to all available data. Handlers will obviously have access to the SOAP message itself, but they also have access to all Axis-specific data, such as configuration and administrative data. Additionally, there is no restriction on what a Handler can do. As you can see in the Utility Services demo (see Resources), Handlers can even invoke other web services on remote systems. While you will need to be careful when doing things like this because it could dramatically influence the performance of your services, the choice is yours.
While this article won't go into the specifics of how to write a Handler, there are a couple of key concepts that are important enough to discuss here. First is the MessageContext class. As Axis traverses the list of Handlers it needs to invoke, it passes to each Handler a single object called a MessageContext. This MessageContext object is the Handler's portal to all of Axis' data as well as the SOAP message being processed. Any data that is related to this current SOAP message will be placed into the MessageContext. The MessageContext can be viewed as nothing more than a simple HashTable of Java objects. Any Handler (or even Axis itself) is free to place anything it wants into this HashTable, and in fact is required to do so since this is the recommended way of sharing data between Handlers. What this means is that the SOAP message itself is placed into the MessageContext and is treated just like any other piece of data in there. So, taking this one step further, it also means that any Handler can use any piece of data in there for any purpose and even change it in any way. This notion is crucial for Handlers such as Encryption Handlers that will want to completely replace the entire SOAP message after its processing.
The other key concept is that Axis distinguishes between a Request and a Response message. If you look at the figures in the previous section on the flow of the Handlers within the Axis engines, you'll notice that at the mid-point of its traversal there's a point at which the SOAP message being processed will switch from a Request to a Response message. For example, on the client-side, all of the Handlers before the Transport Sender will be processing a Request message, while the Handlers after the Transport Sender will be processing a Response message. The same is true for the server-side; all Handlers before the Dispatcher will want to process the Request message while those after it will process the Response message. This seems obvious, but what if you want to have a Handler on the server-side that will be executed before the service that looks for a specific SOAP header, and based on that Header will send back another SOAP header to the requestor? There are two options here: one is to have a Handler before the service that will look for the Header, process it, place some data in the MessageContext and then place another Handler on the Post-Processing side of the service which grabs that data from the MessageContext and adds a SOAP header to the Response SOAP message. That will work, but there's another option: just allow the Handler that was on the Pre-Processing side of the service to add the Header to the Response SOAP message during its normal processing. Axis will allow this by keeping two SOAP messages in the MessageContext, a Request and a Response message. Any Handler is free to modify either one at any time. And, to make things easier, Handlers can ask for the currentMessage and Axis will know whether that means the Request or Response message based on whether you have passed the Transport Sender or Dispatcher.
You can consult the Axis Developer's Guide (see Resources) if you're interested in writing one of your own Handlers. Some of the ETTK demos use Handlers for their processing. The most notable ones are the Utility Services demo and the WS-Security demos (see Resources). Feel free to use these demos.
One of the first things to think about when writing a web service is how much work you want it to do. The obvious answer is "I want it to do what it's supposed to" -- well, sure, but when it comes to writing web services, a good practice is to keep a clear separation between the web service and your business logic. If you are familiar with writing Servlets/JSP pages, then you know that it is a good idea to separate your presentation logic from your data calculations, and working with web services is similar. Think of your web service as simply the thin layer of code that will connect your back-end/business logic with the SOAP server (or more importantly, the rest of the world). If you keep the interface and logic in the web service itself to a minimum, then as the world of web services changes, your migration path should be fairly small.
So, what does all of this really mean? What it means is that you should give some thought to the exact interfaces that you want to expose. Taking your current set of Java classes and turning all of them into web services probably isn't a good idea. Instead think about the exact list of APIs you want to expose and what parameters you really need. Keeping this set to a minimum should help you in the long run.
With this introduction into web services technology and Axis you can now move onto actually writing and deploying real running code. In the next article in this series you will learn how to create RPC as well as Message services. You'll also see what's involved in actually using Axis Handlers on the client and the server.
- Download the ETTK from alphaWorks.
- See a live running install of the ETTK on developerWorks.
- You can find the ETTK's Utility Services demo's documentation on developerWorks.
- Take the tutorial, "Implementing web services with the ETTK" by James Snell. (developerWorks, April 2003)
- Learn more information about Axis at apache.org.
- You can find the SOAP Spec at w3.org.
- Check out more information about WS-I at ws-i.org.
- Details about JAX-RPC are available at Sun's web site.




