http://www.developer.com/

Back to article

The Axis2 Transport Framework


May 16, 2006

Apache Axis2 is said to be a well-defined framework for Web services and related components developers. It has a lot of room for extending its main functionality; among them are pluggable modules, systems, even listeners and pluggable transport framework assume to be very useful. One of the most important features in Axis2 is transport independency. Axis2 does not depend on transport and Axis2 is a pure SOAP processing engine. It is the user's responsibility to select transports that match his requirements.

An asynchronous Web service is one of the main considerations in these days of Web service development, and developers are very keen on developing their Web service in an asynchrony manner. Axis2 has inbuilt capability of asynchronous Web service handling; in the meantime, none of the request-response concept has burnt into Axis2. As far as Axis2 is concerned, what it does is either process incoming messages or process outgoing messages and delivers the message to MessageReceiver or to TransportSender. In the case of an incoming message, it is the MessageReceiver; in the case of an outgoing message, it is the TransportSender. Figure 1 shows the graphical view of message processing inside Axis2 and also highlights the location of transport's fit in the flow.

Figure 1: Message processing inside Axis2

Note: The sender is the one that called AxisEngine.send(MessageContext) so it could be either MessageReceiver (if there is any response for the incoming message), or OperationClient (in the case of client side).

Transport Receiver

In the Axis2 world, Transport receiver is the one that calls AxisEngine.receive(MessageContext); in other words, the one that initializes the execution for an incoming message. In the case of a real-time system transport, the receiver is an application server or simply a listener that listens to a specific port.

There are two ways that someone can start a transport listener. The first way is to create an Axis2 system by itself and then start a listener (AxisServlet uses this technique). The second way is start listeners by using ListenerManager API (which will be discussed later in this article).

Irrespective of the way you start listener, it has to keep a reference to ConfigurationContext (which is the run-time representation of the system). When transport receiver receives a message, there are few steps that listener has to carry out:

  1. Create a new messageContext; that will be the placeholder for the incoming SOAP message as well as related properties.
  2. Set the configurationContext reference in messageContext (Transport Listener has a reference to the configuration context).
  3. Extract transport-related information into messageContext (header information, input/output stream, and so forth).
  4. Set the transport prefix into message context (the requirement of this will be discussed later).
  5. Create a SOAPMessage for the incoming message. As a result of AXIOM being the underline message representation, it will not read the entire message into memory until someone asks to do that.
  6. Add the created SOAPMessage into messageContext.
  7. Create a new AxisEngine.
  8. Call axisEngine.receive(messageContext).
Note: If the transport is a two-way transport like HTTP, there is one more step left. Once the transport receiver gets the control back (Java return back), it has to check the message context to determine whether the response is written or not. If it is written, there will be a flag in the message context to indicate that msgCtx.isResponseWritten(). If it is not, it is required to send an HTTP 202 and close the incoming stream.

Transport Sender

As its name implies, Transport sender is the one that sends the request message or simply writes the content to an output stream. To be a valid transport sender, it has to implement a "TransportSender" interface, and that interface extends the Handler interface so Transport sender is actually a handler with two more additional methods.

The simplest API that Axis2 provides to register transport senders is axis2.xml; there you can register the transport sender with the name and parameters (if it is required). As an example, the default HTTP sender in Axis2, CommonsHTTPTransportSender, has registered in axis2.xml as follows.

<transportSender name="http"
                 class="org.apache.axis2.transport.http.
                        CommonsHTTPTransportSender">
   <parameter name="PROTOCOL" locked="false">HTTP/1.1</parameter>
   <parameter name="Transfer-Encoding"
              locked="false">chunked</parameter>
</transportSender>
Note: The name attribute is the name of the transport sender; it should be a unique name. There cannot be two transport senders with the same name, but it is possible to have a transport sender and a transport receiver with the same name. The parameters are to configure the sender; the class attribute represents the implementation class of the TransportSender.

When the transport receiver is compared with the transport sender, transport sender has the lesser job. It has to get the SOAP message from the message context and serialize that into the output stream of the sender. There are no two separate transport senders for server side and client side, but in some cases, the server side transport sender has to act differently than the client side sender. (The same class can be used with slightly different logics.) As a transport sender, the following are the common steps that need to be followed when sending a message.

  1. If the message context has a To (target address) address, open up a connection. (On the client side, the TO address is needed, but on the server side it is not.)
  2. String address = msgContext.getTo().getAddress();
  3. Otherwise, try to find the Outputstream from the message context. (This happens on the server side when the request comes via two-way transport.)
  4. Write a transport-specific header if it has any (in the case of HTTP, HTTP headers such as HTTP version, content type, soapaction, and the like).
  5. Get the corresponding SOAPEnvelope from message context:
  6. SOAPEnvelope env = msgCtx. getEnvelope();
  7. Then, serialize the envelope into the output stream as follows:
  8. SOAPEnvelope envelope   = msgContext.getEnvelope();
    OMElement outputMessage = envelope;
    OMOutputFormat format   = new OMOutputFormat();
    outputMessage.serializeAndConsume(outputstream, format);
    outputstream.flush();
    

Listener Manager

Listener manager is a convenient way of managing transport receivers in a given system. It should be noted that the transport receivers discussed above may or may not be managed by using the listener manager API. The difference is that the receivers or listeners that Listener manager can handle has to implement a "TransportListener" interface, but it is not a must to implement that interface for the above-mentioned transport receivers.

Transport listeners

As discussed above, to be a listener, you must implement a TransportListener interface. It looks like the following:

public interface TransportListener {

   void init(ConfigurationContext axisConf,
             TransportInDescription transprtIn)
      throws AxisFault;

   void start() throws AxisFault;
   void stop() throws AxisFault;
   EndpointReference getEPRForService(String serviceName,
                                      String ip) throws AxisFault;
}
  • init: This method will be called when a transport listener is initialized. As discussed in the transport receiver section, a listener has to keep a reference to configuration context, so the configuration context object will be passed as an argument. TransportInDescription is the corresponding description object for the listener. The description object will contain the name of the transport and parameters specified in axis2.xml for this particular transport.
  • start: Listener manager will call this method when it is asked to start a given transport, so all the transport starting logic should be here. For example, it should contain the starting server socket and the like.
  • stop: To stop the transport, logic required to close the started socket can be written here.
  • getEPRForService :Any service available in the system has a unique address to invoke the service, and if there are multiple transports there will be multiple addresses for a given service. The well-known name for that address is End Point Reference (EPR). From any given transport listener, it should be able to get a unique EPR for a given service. When dynamic WSDL is generated and to set the wsa:ReplyTo addresses, this method will be called. At that point, it is up to the transport receiver to create an EPR for a given service. If the transport is HTTP, the EPR will look like http://myaddress.com/foo/axis2/servives/ServiceName, and in the case of SMTP it will look like ServiceName@foo.myaddress.com. The second method parameter, IP, can be null; if it is null. the transport listener has to find the IP address somehow when it generates an EPR.

There are two ways to register a transport listener into the system. The first way is to add an entry into axis2.xml. The second way is to create TransportListener by hand and add that into Listener Manager. In the case of axis2.xml, you have to add the following XML element into axis2.xml;

<transportSender name="http"
   class="org.apache.axis2.transport.http.CommonsHTTPTransportSender">
   <parameter name="PROTOCOL" locked="false">HTTP/1.1</parameter>
   <parameter name="Transfer-Encoding"
              locked="false">chunked</parameter>
</transportSender>

Here, the name of the transport is HTTP and the listener implementation class is CommonsHTTPTransportSender. The corresponding description object has two parameters.

Note: If you want to have proxy support or port a forwarding mechanism when you are using axis2 default transports, the generated EPR can be customized by adding the following parameter into the transport tag. The parameter value should be a valid URL.
<parameter name=" hostname">
   http://myaddress.com/foo/axis2/services
</parameter>

API of the Listener Manager

Listener manager provides the following APIs to mange transport listeners in a given system.

  • init: To initialize the listener manager, you must create a configuration context and pass that as the method parameter. Inside the method, it will keep a reference to the configuration context and will set the listener manger field in the configuration context as the created listener manager.
  • start: You can add any number of transport listeners in axis2.xml, but nothing will happen until you call this method. So, when you call the start method, it will take all the available transport listeners from axisConfiguration and then initialize and start that (will call the init and start methods, respectively).
  • startSystem: You can just call startSystem rather than calling the two methods above. The inside method implementation will call the init and start methods.
  • stop: This method can be used to stop all the listeners in the system.
  • addListener: You can use this method to add a new listener into the system. When you add a listener, you have to pass two method arguments, the transport description object and boolean value. The transport description object has to have a transport listener in it, and the boolean value specifies whether the listener is running or not. If the boolean value is true, it will just add the listener into the list; otherwise, it will call both the init and start methods before adding them to the list. In the case of AxisServlet, it will use true as the boolean value because AxisServlet is running when it creates the listener manager.
  • isListenerRunning: To check whether a given listener is up and running, if the listener is in the started listeners list, it will return true.
  • getEPRforService: As discussed in the transport listener section, to get an EPR for a given service, listener manager itself provides an API to get the service EPR for a given service. The method takes two parameters, the name of the service and the name of the transport. Here the name of the service cannot be null but the name of the transport can be null. If the transport name is null, it will pick a transport from the started transport list and ask for the service EPR from that transport. Otherwise, if the transport name is not null, it will get the corresponding transport and ask the service EPR from that transport.
Note: In the case of Listener manager, all the transport receivers in the system share the same configuration context. The practical usage of this listener manager and its listeners is that one can expose same service using different transports or different addresses. A good use case could be publishing same service using HTTP, TCP, and SMTP. Isn't that cool?

The important thing in Axis2 is that it can receive a message via SMTP and a response can be send using HTTP. So, Axis2 can handle different transport combinations without having any problems. Figure 2 shows how Transport Listeners, Listener Manager, and Axis2 run time link together.

Figure 2: Listener Manager and Transport Listeners

Running a client inside a server using server's runtime

What does running a client inside a server mean?

Axis2 supports full asynchronous Web service invocation. There you can send the request in one transport and you can get the response via some other transport. In Axis2 terms, this is called send/receive non blocking using two channels. In this case, you have to have a running transport listener at the client side as well; otherwise, when someone asks to invoke two channels, the Axis2 invocation will start the corresponding transport receiver at the client side if that is present in the corresponding AxisConfiguration.

On the client side, when you create a ServiceClient, you can pass the configuration context, and when invoking a service client, you can use that configuration context as its runtime. The interesting thing is all the modules, service, properties, and transports that are available in that configuration context easily can be accessible by the service client.

When someone calls the init method of the listener manager, the corresponding field in the configuration context will be set. If the configuration context that passed to the service client does not have a listener manager object,a new one will be created and added into the configuration context and init the listener manager. Therefore, the service client always has a valid listener manager object in its configuration context.

When invoking a non-blocking, two-channel invocation, it first will try to find the incoming transport by using

String tarnsportName = Options.getTransportInProtocol();

and then take the listener manger and check whether the given listener is running. If so, it will ask the EPR for the service using that transport. Otherwise, it will ask the listener manager to start the listener and then ask the EPR for the service.

So, if someone passes a configuration context with a listener manager when creating a service client, the service client has access to listeners in the system through the corresponding listener manager. As a result, if someone invokes a two-channel invocation, the service client can use the running transport listeners as its client-side listener for the response processing. To facilitate this, the listener manger has a static field to keep the configuration context. If you set that field at the time the listener manager is created, clients running inside the listener manager have the capability of using the server's configuration context. It should be noted that AxisServlet sets the static values; therefore, any client running inside Aixs2 war distribution can use AxisServlet itself as its transport receiver (no need to start a new listener for client response processing).

To access the server's configuration context, you can use the following line of code to create ServicClient:

ServiceClient serviceClient =
    new ServiceClient(ListenerManager.defaultConfigurationContext, null)

Axis2 default transport support

Axis2 comes with a set of default transports senders and receivers; most of them use standard libraries. It is obvious that more than 90% of the Web service utilization is based on HTTP transports, but there is more of a trend of using other transports as well, especially SMTP. As a result of SOAP theoretically being the underline communication mechanism, you can use any of the transport mechanisms to communicate between two SOAP nodes. Axis2 supports the following types of transports and it has senders and receivers for them as well.

  1. HTTP/HTTPS
  2. SMTP/POP
  3. TCP
  4. JMS

Summary

As mentioned earlier, Axis2 is transport independent and it does not care about the type of the senders and receivers, or all the transport-related code written using interfaces. It is very easy to implement those interfaces and extend the transport framework. Therefore, adding and removing a transport sender/receiver is not a headache; implementing a transport for a given protocol is just a matter of implementing the sender and receiver and register them in axis2.xml. At last, the Listener Manager API is very useful for applications such as BEPL, WS-Eventing, and WS-Notification, and so on.

Sitemap | Contact Us

Thanks for your registration, follow us on our social networks to keep up-to-date