• Parameters and their hierarchy
• Formatting and building messages through MessageFormatters and MessageBuilders
• Transport senders and transport receivers
• Static data hierarchy focusing on AxisOperating, AxisService, AxisServiceGroup, and AxisModule
• Dynamic data hierarchy, including ConfigurationContext, MessageContext, OperationContext, and ServiceContxt
Axis2 static data
As mentioned earlier, for any given application, it is common to have two types of data called static and dynamic. A classic example of this is a banking application.
It needs to keep the data such as user information (for example, name, address, date of birth, phone number, and other such information) static (changes that are infrequent). Now, let's consider an application that provides XML-based configuration (for example, Apache Tomcat, Apache Axis2, and so on). At the time of system initialization, it is required to load these configurations and store them in some structure (or use them to configure the application). Once the application stores all the configuration information in a static structure, it can use that information whenever it's required with minimum or zero cost. In contrast, if the application is written in such a way that, whenever it needs to read some information, it reads the XML file and retrieve data, it leads to higher performance issues.
Performance is a major consideration when it comes to web services, loading configuration data at runtime from a secondary storage (when required) is not an option. So it may be better to keep such data in memory, ready for use whenever required. On the other hand, if we have to contain all the configuration data in one large object, it can also add to the performance overhead (Hot pots). To address this problem in a more efficient manner, Axis2 has an object hierarchy to store configuration data more organized manner. Some of the objects in the hierarchy will be created at deployment time and some at runtime, depending on the deployment options employed. Now let us discuss the different types of objects in this hierarchy and try to understand how and when they are created.
Axis2 has three types of configuration files (deployment descriptors) that populate and configure the object hierarchy. Those types are as follows:
• Global level configuration file – axis2.xml
• Service level configuration file – services.xml
• Module or service extension configuration file – module.xml
The global configuration file is called axis2.xml and contains the bare minimum configuration data that is needed to start an Axis2 Web Service framework, either as a server or as a client. As we will discuss in this chapter, a user can modify axis2.xml to suit the user requirements and start Axis2 with the modified file. This is the whole point of providing a configuration file. In the web service domain, there are a large number of parameters that users wish to configure such as the default SOAP version to be used, default HTTP version, namespaces, platform-specific configurations, other user data, data binding information, and so on. Being a very configurable web service framework, this holds true for Axis2. A typical axis2.xml that we can use to run Axis2 has the following set of configuration options:
• Deployment configuration data
• Transport senders
• Transport receivers
• Execution chains
• Phases
• Parameters
• Message formatters and message builders
We have already encountered some of the mentioned terms and the rest will be discussed soon in this chapter as well as throughout this book.
The following figure shows the relationship among various types of descriptions or metadata in Axis2:
As we can see, the top-most component in the hierarchy is AxisConfiguration that keeps track of all the configuration data, either directly or indirectly. There are three major types of objects shown in the figure. Firstly, AxisModule originates from a descriptor file called module.xml, so that when we deploy a module in Axis2, there will be a new AxisModule object to keep track of that particular module's configuration data. Secondly, the middle object hierarchy is created when we deploy a service in Axis2. Finally, there are the transports and other data that are read directly from axis2.xml.
AxisConfiguration
AxisConfiguration is the top-most component of the static data hierarchy.
Nevertheless, it should be noted that although we call AxisConfiguration as a static hierarchy, it does not mean that it is immutable. There are a number of instances where it changes the content, but these changes are very infrequent. The whole AxisConfiguration object is effectively a collection of data coming from axis2.
xml, a set of module.xml files, and a set of services.xml files. There are many ways to create AxisConfiguration as well. One could create an AxisConfiguration using the local filesystem, using a remote repository, or even by using a database.
We will discuss these options in Chapter 15, Building a Secure Reliable Web Service. In this chapter, the focus will be on creating an AxisConfiguration using the default axis2.xml file from the local filesystem. A typical axis2.xml, which has the bare minimum configuration data to start an Axis2 server, is shown in the following figure (a detailed explanation of the element structure is given after the figure):
Parameters
As you can see in the previous figure, the axis2.xml file has parameters, and these can be defined at different levels in the document as well. As illustrated, we have parameters at the top level as well as inside the transports. The main use of parameters is to configure the system and to provide configuration data that is needed at runtime. For example, if we need to log some request to a particular location, that location can be provided using a parameter. Parameters are designed to store primitive data types (for example, string, int, double, and so on) and OMelements, but not any type of objects. The following code snippet shows how to define a parameter in any of the configuration files in Axis2.
Each parameter has an optional attribute called locked, as shown here:
<parameter name="name" locked="true/false"> value </parameter>
The idea of the locked attribute is to provide a control mechanism to make sure that none of the child nodes override that parameter. For example, let's say we have a parameter, as mentioned here, as an immediate child of axis2.xml:
<axisconfig name="AxisJava2.0">
<parameter name="port" locked="true">6060</parameter>
...
</axisconfig>
This will ensure that any other description in Axis2 cannot have a parameter with the same name, here port. This phenomenon is illustrated in the following section.
Here, axis2.xml becomes invalid, as it tries to override a locked parameter.
Furthermore, we cannot have the parameter with the name port in any of the other two descriptors, which are services.xml and module.xml. If they exist, they become invalid.
<axisconfig name="AxisJava2.0">
<parameter name="port" locked="true">6060</parameter>
<transportReceiver name="http"
class="o.a.a.t.h.SimpleHTTPServer">
<parameter name="port">6060</parameter>
</transportReceiver>
</axisconfig>
There is a scope associated with a parameter. A parameter defined in axis2.
xml as an immediate child can be accessed by any of the descriptors in the system.
If a parameter is defined inside a first level child of axis2.xml (for example, transportSender), then that parameter can only be accessed inside that particular child, in this case that specific transportSender.
When accessing a parameter, Axis2 first checks whether the parameter is defined in the current description where we are. If not, it checks the immediate parent to see whether the parameter exists there. If found, the parameter will be returned;
otherwise, the parent's parent will be checked, and so on. In this manner, it will search the hierarchy when a request for a parameter is made.
MessageReceiver
In Chapter 4, Execution Chain, we discussed more about MessageReceiver and its usage. All the message receivers we are going to use for our services should be specified in axis2.xml. You can have as many message receivers as you want and use the right one at the services.xml. The way to specify the message receiver in axis2.xml is shown next:
<messageReceivers>
<messageReceiver mep="MPE"
class="o.a.a.r.RawXMLINOnlyMessageReceiver"/>
</messageReceivers>
Note: In the preceding XML element, MEP stands for the Message Exchange Patterns that the MessageReceiver can handle. Class attribute is to specify the actual implementation class of the MR. You can register any number of message receivers alone with a unique MEP. For example, WSDL 2.0 allows 8 types of MEPs.
MessageFormatters and MessageBuilders
In HTTP, we use a content-type header to specify the type of data in the message body. Moreover, depending on the content type, the wire format of the message varies, for example, XML, JSON, base64, and so on. Axis2 also supports a number of different message types, thus it requires serializing and deserializing a message into the correct format. To facilitate, Axis2 has introduced MessageFormatters and MessageBuilders; the first one is to serialize the message into the wire format and the second one is to build the SOAP message from the incoming message stream. We already know that any kind of message is represented in Axis2 using Axiom, and when we serialize the message, it needs to be formatted, based on the content type.
MessageFormatters exist to do that job for us. We can specify MessageFormatters along with the content type in axis2.xml. On the other hand, a message coming into Axis2 may or may not be XML. However, for it to go through Axis2, an Axiom element needs to be created. Therefore, MessageBuilders are employed to construct the message, depending on the content type.
These two types of descriptions can be considered complex, and as users are not likely to change them, users can happily live with the default axis2.xml, as it will have configured all the commonly used content types along with their corresponding builders and formatters. The structure of XML elements in axis2.xml is shown next:
<messageFormatters>
<messageFormatter contentType="application/x-www-form- urlencoded"
class="o.a.a.t.h.XFormURLEncodedFormatter"/>
</messageFormatters>
<messageBuilders>
<messageBuilder contentType="application/xml"
class="o.a.a.b.ApplicationXMLBuilder"/>
</messageBuilders>
As shown here, you can specify message builders and formatters with content type and the implementation class. At runtime, Axis2 picks the right one to serialize and de-serialize the message.
TransportReceiver and TransportSender
Axis2 is transport independent, and hence one can communicate with Axis2 using a number of transports. For example, Axis2 has inbuilt support for HTTP, TCP, SMTP, and JMS. All of these are configurable through axis2.xml.
The job of a transport sender is to serialize and handle the message exchanges, depending on the underlying protocol. On the other hand, the transport receiver's job is to deserialize an input stream into Axiom and respond to the client according to the protocol. Axis2 comes with a better configuration for all the transport.
However, transport such as SMTP requires some user involvement to provide correct server names, for example, POP and SMTP. Other than that, a user does not need to change the original transport definition. The structure of XML elements in axis2.
xml is shown next:
<transportReceiver name="http"
class="o.a.a.t.h.SimpleHTTPServer">
<parameter name="port">6060</parameter>
</transportReceiver>
<transportSender name="http"
class="o.a.a.t.h.CommonsHTTPTransportSender">
<parameter name="PROTOCOL">HTTP/1.1</parameter>
<parameter name="Transfer-Encoding">chunked</parameter>
</transportSender>
As shown here, you can add new transport senders and receivers by specifying name (a.k.a protocol) and the implementation class. In addition, you can also add transport specific parameters.