This processing model should allow a deployment engineer to have the complete
flexibility of placing any handler at any point in the flow of messages through the server Axis engine.
In Figure 4.3, the Web service is shown as a handler at the pivot point in the Web service– specific chain. One layer of code is not shown: the dispatcher . Figure 4.4 shows a dispatcher as the pivot point handler in the Web service–specific chain. Like all handlers, this dispatcher is responsible for acting as the bridge between Axis and your business logic. It is the job of the dispatcher to locate and invoke the appropriate piece of code associated with the desired Web service. For example, Axis comes with an RPCDispatcher whose job is to convert the SOAP message from XML into Java objects, locate the appropriate Java method to invoke, invoke it, and convert any possible response data back into XML and place it in the response SOAP message. By having a dispatch handler do this work, it can be used for any Java Web service invoked. Likewise, the Web service itself does not need to be concerned with the details of how the data was delivered or how to convert XML into Java objects; it can concentrate on doing its real job.
Figure 4.4. Handlers, acting as dispatchers, are the bridges between Axis and application logic.
Although dispatchers have been presented in the context of invoking the Web service, any of the handlers in any of the chains could be dispatchers. In other words, there is no reason why any of the request/response processing handlers need to have the business logic directly inside them. Those handlers could be dispatchers that extract the necessary data from the SOAP message and pass it along to external code in the proper format.
Transports
In order to complete the overall picture of the Axis architecture, one more piece of the puzzle needs to be brought in: transports. All the figures show a single Axis engine with a single transport delivering the SOAP message; however, this need not be the case.
Figure 4.5 shows that Axis can support a variety of transports, not just HTTP. Actually, Axis itself doesn't support multiple transports. Axis is designed such that the Axis engine can be viewed simply as a chunk of code that is called with an incoming message and returns an outgoing message. Transport listeners (such as servlets that wait for a SOAP message), although key in the overall picture of how Axis is used, are themselves
not part of the Axis engine. It is assumed that the mechanism by which the Axis engine is created (a new one on each request or shared instance) will be managed by the transport listeners. Axis comes with a set of transport listeners (such as the
AxisServlet) that you can use, but if you require special processing, it is assumed that you will modify the shipped transport listener to suit your needs or write a new one.
Figure 4.5. Multiple transports.
The role of the transport listener is to deliver the SOAP message to the Axis engine. This could mean listening on port 80 for an HTTP request or waiting for a file to be FTPed to a certain directory and then handing that message to the Axis engine. Aside from invoking the Axis engine, the transport listener must also tell the Axis engine which transport was used—this allows Axis to invoke any transport-specific chain that might have been configured.
The delineation between whether certain processing should be in the transport listener or in the transport specific chain is an issue left up to the deployment engineer. For
example, in the HTTP case, the servlet waiting for SOAP requests can also perform any basic HTTP authentication checks before invoking the Axis engine. It is also perfectly acceptable for the servlet to not perform that check and leave it up to a handler on the transport specific chain to do it. The choice is left open.
Listing 4.1 shows a sample transport listener that does nothing more than look for a file called inMsg in the current directory. If the file is found, the transport listener uses it as the requesting SOAP message, calls Axis on it, and then places any response back into a file called outMsg.
Listing 4.1 FileListener.java import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileNotFoundException;
import org.apache.axis.AxisFault;
import org.apache.axis.AxisEngine;
import org.apache.axis.server.AxisServer;
import org.apache.axis.Message;
import org.apache.axis.MessageContext;
import org.apache.axis.message.SOAPEnvelope;
import org.apache.axis.message.SOAPFaultElement;
public class FileListener { public void run() { while (true) {
try {
// Look for an incoming msg, create a new Message object FileInputStream input = new FileInputStream("inMsg");
AxisEngine engine = AxisServer.getSingleton();
MessageContext msgContext = new MessageContext(engine);
Message msg = new Message(input);
try {
//Set it as the "request" message msgContext.setRequestMessage(msg);
// Set the Transport
msgContext.setTransportName("file");
// Invoke the Axis engine engine.invoke(msgContext);
}
catch(Exception e) {
// Catch any error and stick it in the response if (!(e instanceof AxisFault))
e = new AxisFault(e);
AxisFault af = (AxisFault)e;
msg = msgContext.getResponseMessage();
if (msg == null) {
msgContext.setResponseMessage(new Message(af));
} else {
SOAPEnvelope env = msg.getAsSOAPEnvelope();
env.clearBody();
env.addBodyElement(new SOAPFaultElement(af));
} }
// Close and delete the incoming message input.close();
(new File("inMsg")).delete();
// Place the response message in a file called "outMsg"
msg = msgContext.getResponseMessage();
FileOutputStream output = new FileOutputStream("outMsg");
String result = (String)msg.getAsString();
output.write(result.getBytes());
output.close();
System.out.println("Processed a request");
} catch(Exception exp) {
if (!(exp instanceof FileNotFoundException)) exp.printStackTrace();
}
// Sleep for a sec and then loop
try {
Thread.sleep( 1000 );
} catch(Exception e) { }
} }
static public void main(String[] args) { (new FileListener()).run();
} }
Let's walk through this example. The FileListener's run() method will loop forever while waiting for a new message to arrive. Once there, an InputStream is created for it.
The listener will then ask Axis for an instance of an AxisServer—the getSingleton() method will return the same instance each time. Next we create a MessageContext object. This will be discussed more in the "Building Handlers" section, but for now it is simply an object that will contain all the data (request and response messages, meta- data, and so on) about this current SOAP message flow; it is passed to each handler as it is invoked. Inside this object we place a new Message object that is created by passing in the file's InputStream. This will be the request message. There's only one more thing to do before we invoke the engine, and that's to tell Axis the name of the transport that was used to retrieve the message—in this case, file. When the engine wants to invoke the transport-specific chain, it will look for one named file and, if found, invoke it.
The rest of the code processes any result from the engine. We must, of course, handle any error conditions. The Axis engine can throw an AxisFault (see the "Fault"
section) that must be caught and used to create a response message. The catch block will also check to see if a response message already exists and clear any XML from the Body section if there is one.
In either the successful case or the faulting case, the code will then get the response message as a String, write it out to a file called outMsg, and then go look for more messages.
Completing the overall picture of what the Axis engine's architecture looks like, we have Figure 4.6.
Figure 4.6. Complete Axis architecture.
Although the final picture of the Axis engine's processing model might seem a bit complex, it really is nothing more than defining handlers and chains. Of course, we've overlooked one very important issue; up to this point, the focus has been on what an Axis engine does when it is on the receiving side of the SOAP message path (the server).
Axis can be used on the client side, as well. With just a few slight changes, all the concepts we've mentioned up to now apply on the client as shown in Figure 4.7.
Figure 4.7. Axis client architecture.
It should be clear that almost all the same components that appeared on the server are on the client as well; they are just invoked in a slightly different order: