(For more resources on Axis2, see here.)
Axis2 is built upon a modular architecture that consists of core modules and non-core modules. The core engine is said to be a pure SOAP processing engine (there is not any JAX-PRC concept burnt into the core). Every message coming into the system has to be transformed into a SOAP message before it is handed over to the core engine. An incoming message can either be a SOAP message or a non-SOAP message (REST JSON or JMX). But at the transport level, it will be converted into a SOAP message.
When Axis2 was designed, the following key rules were incorporated into the architecture. These rules were mainly applied to achieve a highly flexible and extensible SOAP processing engine:
- Separation of logic and state to provide a stateless processing mechanism. (This is because Web Services are stateless.)
- A single information model in order to enable the system to suspend and resume.
- Ability to extend support to newer Web Service specifications with minimal changes made to the core architecture.
The figure below shows all the key components in Axis2 architecture (including core components as well as non-core components).
- XML Processing Model : Managing or processing the SOAP message is the most diffcult part of the execution of a message. The efficiency of message processing is the single most important factor that decides the performance of the entire system. Axis1 uses DOM as its message representation mechanism. However, Axis2 introduced a fresh XML InfoSet-based representation for SOAP messages. It is known as AXIOM (AXIs Object Model). AXIOM encapsulates the complexities of efficient XML processing within the implementation.
- SOAP Processing Model : This model involves the processing of an incoming SOAP message. The model deﬁnes the different stages (phases) that the execution will walk through. The user can then extend the processing model in speciﬁc places.
- Information Model : This keeps both static and dynamic states and has the logic to process them. The information model consists of two hierarchies to keep static and run-time information separate. Service life cycle and service session management are two objectives in the information model.
- Deployment Model : The deployment model allows the user to easily deploy the services, conﬁgure the transports, and extend the SOAP Processing Model. It also introduces newer deployment mechanisms in order to handle hot deployment, hot updates, and J2EE-style deployment.
- Client API : This provides a convenient API for users to interact with Web Services using Axis2. The API consists of two sub-APIs, for average and advanced users. Axis2 default implementation supports all the eight MEPs (Message Exchange Patterns) deﬁned in WSDL 2.0. The API also allows easy extension to support custom MEPs.
- Transports : Axis2 deﬁnes a transport framework that allows the user to use and expose the same service in multiple transports. The transports ﬁt into speciﬁc places in the SOAP processing model. The implementation, by default, provides a few common transports (HTTP, SMTP, JMX, TCP and so on). However, the user can write or plug-in custom transports, if needed.
XML Processing Model
Axis2 is built on a completely new architecture as compared to Axis 1.x. One of the key reasons for introducing Axis2 was to have a better, and an efﬁcient XML processing model. Axis 1.x used DOM as its XML representation mechanism, which required the complete object hierarchy (corresponding to incoming message) to be kept in memory. This will not be a problem for a message of small size. But when it comes to a message of large size, it becomes an issue. To overcome this problem, Axis2 has introduced a new XML representation.
AXIOM (AXIs Object Model) forms the basis of the XML representation for every SOAP-based message in Axis2. The advantage of AXIOM over other XML InfoSet representations is that it is based on the PULL parser technique, whereas most others are based on the PUSH parser technique. The main advantage of PULL over PUSH is that in the PULL technique, the invoker has full control over the parser and it can request the next event and act upon that, whereas in case of PUSH, the parser has limited control and delegates most of the functionality to handlers that respond to the events that are ﬁred during its processing of the document.
Since AXIOM is based on the PULL parser technique, it has on-demand-building capability whereby it will build an object model only if it is asked to do so. If required, one can directly access the underlying PULL parser from AXIOM, and use that rather than build an OM (Object Model).
SOAP Processing Model
Sending and receiving SOAP messages can be considered two of the key jobs of the SOAP-processing engine. The architecture in Axis2 provides two Pipes ('Flows'), in order to perform two basic actions. The AxisEngine or driver of Axis2 deﬁnes two methods, send() and receive() to implement these two Pipes. The two pipes are namedInFlow and OutFlow. The complex Message Exchange Patterns (MEPs) are constructed by combining these two types of pipes. It should be noted that in addition to these two pipes there are two other pipes as well, and those two help in handling incoming Fault messages and sending a Fault message.
Extensibility of the SOAP processing model is provided through handlers. When a SOAP message is being processed, the handlers that are registered will be executed. The handlers can be registered in global, service, or in operation scopes, and the final handler chain is calculated by combining the handlers from all the scopes.
The handlers act as interceptors, and they process parts of the SOAP message and provide the quality of service features (a good example of quality of service is security or reliability). Usually handlers work on the SOAP headers; but they may access or change the SOAP body as well.
The concept of a ﬂow is very simple and it constitutes a series of phases wherein a phase refers to a collection of handlers. Depending on the MEP for a given method invocation, the number of ﬂows associated with it may vary. In the case of an in-only MEP, the corresponding method invocation has only one pipe, that is, the message will only go through the in pipe (inﬂow). On the other hand, in the case of in-out MEP, the message will go through two pipes, that is the in pipe (inﬂow) and the out pipe (outﬂow). When a SOAP message is being sent, an OutFlow begins. The OutFlow invokes the handlers and ends with a Transport Sender that sends the SOAP message to the target endpoint. The SOAP message is received by a Transport Receiver at the target endpoint, which reads the SOAP message and starts the InFlow. The InFlow consists of handlers and ends with the Message Receiver, which handles the actual business logic invocation.
A phase is a logical collection of one or more handlers, and sometimes a phase itself acts as a handler. Axis2 introduced the phase concept as an easy way of extending core functionalities. In Axis 1.x, we need to change the global configuration ﬁles if we want to add a handler into a handler chain. But Axis2 makes it easier by using the concept of phases and phase rules. Phase rules specify how a given set of handlers, inside a particular phase, are ordered. The figure below illustrates a ﬂow and its phases.
If the message has gone through the execution chain without having any problem, then the engine will hand over the message to the message receiver in order to do the business logic invocation, After this, it is up to the message receiver to invoke the service and send the response, if necessary. The figure below shows how the Message Receiver fits into the execution chain.
The two pipes do not differentiate between the server and the client. The SOAP processing model handles the complexity and provides two abstract pipes to the user. The different areas or the stages of the pipes are named 'phases' in Axis2.
A handler always runs inside a phase, and the phase provides a mechanism to specify the ordering of handlers. Both pipes have built-in phases, and both define the areas for User Phases, which can be deﬁned by the user, as well.
As shown in the figure below, the information model consists of two hierarchies: Description hierarchy and Context hierarchy. The Description hierarchy represents the static data that may come from different deployment descriptors. If hot deployment is turned off, then the description hierarchy is not likely to change. If hot deployment is turned on, then we can deploy the service while the system is up and running. In this case, the description hierarchy is updated with the corresponding data of the service. The context hierarchy keeps run-time data. Unlike the description hierarchy, the context hierarchy keeps on changing when the server starts receiving messages.
These two hierarchies create a model that provides the ability to search for key value pairs. When the values are to be searched for at a given level, they are searched while moving up the hierarchy until a match is found. In the resulting model, the lower levels override the values present in the upper levels. For example, when a value has been searched for in the Message Context and is not found, then it would be searched in the Operation Context, and so on. The search is first done up the hierarchy, and if the starting point is a Context then it would search for in the Description hierarchy as well.
This allows the user to declare and override values, with the result being a very flexible configuration model. The flexibility could be the Achilles' heel of the system, as the search is expensive, especially for something that does not exist.
The previous versions of Axis failed to address the usability factor involved in the deployment of a Web Service. This was due to the fact that Axis 1.x was released mainly to prove the Web Service concepts. Therefore in Axis 1.x, the user has to manually invoke the admin client and update the server classpath. Then, you need to restart the server in order to apply the changes. This burdensome deployment model was a definite barrier for beginners. Axis2 is engineered to overcome this drawback, and provide a flexible, user-friendly, easily configurable deployment model.
Axis2 deployment introduced a J2EE-like deployment mechanism, wherein the developer can bundle all the class files, library ﬁles, resources ﬁles, and configuration ﬁ les together as an archive ﬁle, and drop it in a specified location in the ﬁle system.
The concept of hot deployment and hot update is not a new technical paradigm, particularly for the Web Service platform. But in the case of Apache Axis, it is a new feature. Therefore, when Axis2 was developed, hot deployment features were added to the feature list.
- Hot deployment : This refers to the capability to deploy services while the system is up and running. In a real time system or in a business environment, the availability of the system is very important. If the processing of the system is slow, even for a moment, then the loss might be substantial and it may affect the viability of the business. In the meanwhile, it is required to add new service to the system. If this can be done without needing to shut down the servers, it will be a great achievement. Axis2 addresses this issue and provides a Web Service hot deployment ability, wherein we need not shut down the system to deploy a new Web Service. All that needs to be done is to drop the required Web Service archive into the services directory in the repository. The deployment model will automatically deploy the service and make it available.
- Hot update : This refers to the ability to make changes to an existing Web Service without even shutting down the system. This is an essential feature, which is best suited to use in a testing environment. It is not advisable to use hot updates in a real-time system, because a hot update could lead a system into an unknown state. Additionally, there is the possibility of loosening the existing service data of that service. To prevent this, Axis2 comes with the hot update parameter set to FALSE by default.
Nowadays, asynchronous or non-blocking Web Service invocation is a key requirement in Web Services. There are currently two approaches to invoking a Web Service in a non-blocking manner. The first is the client programming model, where a client invokes the service in a non-blocking manner. The second way is the transport level non-blocking invocation where invocation occurs in two transports (it could either be two single-channel transports like SMTP, or two double-channel transports like HTTP). Axis2 client API supports both the non-blocking invocation scenarios.
Axis2 introduces a very convenient client API for invoking services that consists of two classes called "ServiceClient" and "OperationClient". The ServiceClient API is intended for regular usage when you just require to send and receive XML. On the other hand, the operation client is meant for advanced usage, when there is a need to work with SOAP headers and some other advanced tasks. With ServiceClient, we can only access the SOAP body or the payload. Although we can add SOAP headers, we do not have any way to retrieve the SOAP header by using the ServiceClient. We need to use an OperationClient for such a function.
ServiceClient has the following API for invoking a service:
- sendRobust : The whole idea of this is to just send an XML request to the Web Service and not care about its response. However, if something goes wrong, we require to know that too, so this API invokes a service, where it does not have a return value but would throw an exception.
- FireAndForget : This API is for just sending an XML request and not caring about either the response, or any exception. Hence, this is useful in invoking an in-only MEP.
- SendReceive : This invokes a service that has a return value. This is one of the most commonly used APIs. Hence, this is used for invoking an in-out MEP.
- SendReceiveNonBlocking : This invokes a service in a non-blocking manner. This method can be used when the service has a return value. In order to use this method, we have to pass a callback object, which is called once the invocation is complete.
As mentioned earlier, the OperationClient class is for advanced users, and working with OperationClient requires us to know Axis2 in depth. In ServiceClient, we do not have to know anything about SOAP envelope, message context, and so on. But when it comes to OperationClient, the users have to create these by themselves, before invoking a service. Creating and invoking a service using OperationClient involves the following steps:
- Create a ServiceClient.
- Then create OperationClient with the use of the ServiceClient that we have created.
- Create SOAP envelop.
- Create Message context.
- Add the SOAP envelope to message context.
- Add the messagecontext to OperationClient.
- Then invoke the OperationClient.
- If there is a response, then get the response message context from the OperationClient.
In Axis2, each and every transport consists of two parts, namely "Transport Senders" and "Transport Receivers". We can define transports along with senders and receivers in Axis2 global configuration. The Transport Receiver is the one via which the AxisEngine receives the message, whereas the transport sender is the one that sends out the message. One of the important aspects of Axis2 is that its core is completely independent of the transport sender and receiver.
Axis2 is built to support the following transport protocols:
- HTTP/HTTPS : In HTTP transport, the transport listener is a servlet or org.apache.axis2.transport.http.SimpleHTTPServer provided by Axis2. The transport sender uses a common HTTP client for connection and sends the SOAP message.
- TCP : This is the simplest transport and it needs WS-Addressing support in order to be functional.
- SMTP : This requires a single email account. The transport receiver is a thread that checks for emails at fixed time intervals.
- JMS : This provides a way to invoke a Web Service using the JMS way.
- XMPP : This provides a standard way to communicate with Jabber server, and to invoke Web Services using XMPP protocol.
- Code Generation : Axis2 provides a code generation tool that generates server-side (skeleton) and client-side (stub or proxy) code along with descriptors and a test case. The generated code simplifies the service deployment and the service invocation. This increases the usability of Axis2.
- Pluggable Data Binding: The basic client API of Axis2 lets the user process SOAP at the XML infoset level, whereas data binding extends it to make it more convenient for the users by encapsulating the infoset layer and providing a programming language-speciﬁc interface.
Although the basic objective of the code generation tools has not changed, the code generation module of Axis2 has adopted a different approach. Primarily, the change is in the use of templates, namely XSL templates, which gives flexibility to the code generator so as to generate code in multiple languages.
Databinding for Axis2 is implemented in an interesting manner. Databinding has deliberately not been included in the core, and hence the code generation allows different data binding frameworks to be plugged in. This is done through an extension mechanism where the codegen engine calls the extensions first, and then executes the core emitter. The extensions plot a map of QNames versus class names that is passed to the code generator wherein the emitter operates.
Axis2 supports the following data binding frameworks including its own data binding framework called ADB:
- ADB : ADB (Axis2 Data Binding) is a simple and lightweight framework that works off StAX and is fairly performant.
- XMLBeans : XMLBeans is preferred if we want to use full schema support as XMLBeans claims that it supports complete schema speciﬁ cation.
- JaxMe : JaxMe support has been added to XMLBeans, and it serves as another option for the user.
- JibX : This is the most recent addition to the family of data binding extensions.
Extensible Nature of Axis2
In Axis2, there are many ways to extend the functionalities. In this article, we will be discussing a few of them, which are listed below:
- Service extension of the module
- Custom deployers
- Message Receivers
Service Extension of the Module
Both Axis1 and Axis2 have the concept of handlers but when compared to Axis 1.x, there are few changes in the way Axis2 specifies and deploys handlers. In Axis 1.x, if you want to add a handler, then you need to change the global configuration file and then restart the system. In the meantime, it does not have a way to add or change handlers dynamically.
To overcome the above problem as well as to add new features, Axis2 introduced the concept of Web Service extensions or a modules, wherein the main purpose of a module is to extend the core functionality. It is similar to adding handler chains in Axis1.x. The advantage of Axis2 modules over Axis 1.x handler chains is that we can add new modules without changing any global configuration ﬁ les.
A module is a self-contained package that includes handlers, third-party libraries, module-related resources, and a module configuration ﬁle.
A module can be deployed as an archive file. Axis2 came up with a new file extension for modules, called .mar. The most important file in a module archive file is the module configuration file or module.xml. A module will not be functional unless it has a module .xml file. A module configuration file mainly specifies handlers and their phase rules. So once we engage a module, depending on the phase rule, the handlers will be placed in different flows (inflow, outflow, and so on).
The idea of modules is very simple. To implement support for WS-Addressing or WS-Security in our services, we need to download the corresponding modules and drop them into the modules directory of the Axis2 repository. We can engage the module at deployment time by adding
We can deploy a service in many ways. We could deploy a service as an archive file (Axis2 default), by creating a service using a database, or by creating a Web Service using a text file. The idea of custom deployers is to open avenues to support any kind of deployment mechanisms. Axis2 has in-built support for:
- Archive-based deployment (.aar and .mar concept)
- POJO deployment (.class or .jar)
But if someone wants to deploy a service, or a module, then he or she can achieve that goal with the use of custom deployers.
As we have discussed, the Axis2 execution chain is a collection of phases wherein each phase is a logical group of handlers. The Message Receiver, in itself, is a handler. However, it is different from other handlers because Axis2 treats the Message Receiver in a different manner. If the message has gone through the inflow with no issues, or in other words, no exceptions have occurred in the middle of the chain, then the engine hands over the message to the Message Receiver so as to invoke the associated business logic.
Message receivers interact directly with both the actual service implementation class and the AxisEngine. However, there can be some instances wherein there are no service implementation classes and all the logic is handed inside the Message Receiver. The message receiver is the last component in the inflow process. Axis2 has got nothing to do with it once the message is handled over to the Message Receiver.
Axis2 is enterprise-ready. Its Web Service engine provides a better SOAP processing model, with considerable increase in performance for both speed and memory usage with respect to Axis 1.x and other existing Web Service engines. In addition, it provides the user with a convenient API for service deployment, extending the core functionality, and thus acting as a new client programming model. In this article, we have learned about the internals and architecture of Axis2. Thus, we have learned that Axis2 architecture helps in attaining a more flexible and extensible Axis2.