You have already reviewed a number of features and ways to use Axis2 in previous articles. The main focus of this article is to discuss some of the terms you encounter when you read Axis2 articles and documents. Axis2 it keeps its data and logic separately. That provides much flexibility and extensibility into Axis2. When you look at Axis2 data, it consists of two main parts, static data and dynamic data. In this article, I will discuss Axis2’s static data hierarchy. At the end of the article, you will be able to understand Axis2 static data hierarchy and different type usage of them.
Axis2 Static Hierarchy
As the name implies, static data are the data that is not going to change over the time. However, it should be noted here that some of the configuration data I will discuss here may be changed over time. In other words, you can change them at runtime. Most of the data come from various configurations that you find in Axis2. In Axis2, you easily can find three types of configuration that make the static data hierarchy:
- 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 all the bare minimum configuration data needed to start an Axis2 server. Meanwhile, you can edit your axis2.xml file to suit your requirements and start Axis2 using the edited file. A typical axis2.xml file has the following set of configuration options.
- Deployment configuration data
- Transport senders
- Transport receivers
- Execution chains
- Message formatters and Message builders
Figure 1 illustrates the relationship among various types of data (descriptions) in Axis2.
Figure 1: Relationship of Axis2 static data.
As you can see, the top component in the hierarchy is AxisConfiguration; it 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 you 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 you deploy a service in Axis2. Finally are the Transports and Other data that are read directly from axis2.xml.
AxisConfiguration is the top component of the static data hierarchy. 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. One could create an AxisConfiguration using the local file system, or using a remote repository, or even using a database. A typical axis2.xml that has the bare minimum configuration data to start an Axis2 server will look like the following:
<axisconfig name="AxisJava2.0"> <parameter name="name">value</parameter> <messageReceivers> <messageReceiver mep="MPE" class="o.a.a.r.RawXMLINOnlyMessageReceiver"/> </messageReceivers> <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> <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> <phaseOrder type="InFlow"> <phase name="Transport"> <handler name="RequestURIBasedDispatcher" class="o.a.a.d.RequestURIBasedDispatcher"> <order phase="Transport"/> </handler> </phase> <phase name="Security"/> .................................................... </phaseOrder> <phaseOrder type="OutFlow"> <phase name="OperationOutPhase"/> .................................................... </phaseOrder> <phaseOrder type="InFaultFlow"> <phase name="PreDispatch"/> .................................................... </phaseOrder> <phaseOrder type="OutFaultFlow"> <phase name="OperationOutFaultPhase"/> .................................................... </phaseOrder> </axisconfig>
As you can see from the preceding code, the axis2.xml file has parameters that can be defined in different levels as well. Here, you have parameters at the top level as well as inside transports. Parameters mainly are used to configure the system and to provide configuration data that may be needed at runtime. For example, if you need to log some request to a particular location, that location can be provided by using a parameter. Parameters are designed to store primitive data types (string, int, double, and so forth), OMelements, and the like, but NOT any type of objects. Even though storing object types inside a parameter is not invalid, it is not the correct method to follow.
Each parameter has an optional attribute called “locked”, as shown below.
<parameter name="name" locked="true/false"> value </parameter>
Note: The idea of the locked attribute is to provide a control mechanism to make sure that any child node will not override that parameter.
MessageFormatters and MessageBuilders
You know that the content-type header is used to specify the type of data in the message body, and depending on the content type, the wire format varies. Therefore, you need to have a mechanism to format the message depending on content type. In Axis2, any kind of message is represented using Axiom and, when you serialize the message, it needs to be formatted based on content type. MessageFormatters serialize the Axiom object according to the content type. You 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, but for it to go though Axis2, an Axiom element needs to be created. Therefore, MessageBuilders are employed to construct the message depending on the content type.
TransportReceiver and TransportSender
One of the interesting features that you can see in Axis2 is its transport independent nature. That allows you to talk to Axis2 using any given transport. Axis2 comes a with default set of transports (HTTP, SMTP, JMS, and the like) and one can implement a new transport and use that in Axis2. When implementing a new transport, you need to implement two things: TransportSender and TransportReceiver. Transport sender’s job is to serialize and handle the message exchanges depending on the underlying protocol, whereas the Transport Receiver’s job is to de-serialize an input stream into Axiom and respond to the client according to the protocol.
Flows and PhaseOrder
In the Axis2 Execution framework article, I talked about the use of Flows and Phase. Axis2 comes with a default configuration and most of the time you will not need to make changes. However, if it is necessary to change the configurations, please refer to the earlier article.
In simple terms, an AxisModule is a runtime representation of a module.xml. So, whatever configuration data are found in the module.xml are in AxisModule. A typical module configuration file or module.xml contains the following data.
- Module name
- Module description
- Handlers and Phase rules
- End point and Operations
At the time of deployment, an AxisModule is populated using the data from module.xml. At runtime, any of these data can be retrieved via the same AxisModule. The parent description of the AxisModule is AxisConfiguration.
Service Description Hierarchy
As you can see in Figure 1, in the middle is an object hierarchy called the service hierarchy. This particular hierarchy is created using a services.xml file or the service descriptor, and the hierarchy contains four types of descriptions. When you deploy a service into Axis2, an object hierarchy will be created and added to AxisConfiguration. Therefore, unless you have services deployed in Axis2, you do not have the service objects hierarchy in the AxisConfiguration.
<serviceGroup> <parameter name="name">value</parameter> <service name="Foo"> <parameter name="name">value</parameter> <operation name="bar"> <parameter name="name">value</parameter> <message label="in"></message> </operation> </service> <service name="XYZ"> ..... </service> </serviceGroup>
AxisServiceGroup is the top component of the service description hierarchy and is the child of AxisConfiguration. AxisServiceGroup can be considered the parent of a set of AxisServices that are defined in services.xml. Once you define a parameter in AxisServiceGroup, that parameter can be accessed from any AxisService or AxisOperation or AxisMessage lower in the hierarchy. In addition to parameters, an AxisServiceGroup may contain collections of modules engaged to this particular AxisServiceGroup.
An AxisServiceGroup should contain one or more AxisServices as children. Therefore, any configurations (such as parameters) defined in AxisServiceGroup or AxisConfiguration are accessible inside an AxisService. Axis2Service consists of the following kind of data:
- Exposed transports
- Engaged modules
- Exposed transports
- Description about the service
- Message Receivers
AxisOperation is the runtime description representation of an exposed Web service operation. As an example, say you have published an operation called “bar” in Web service “Foo”. There should be an AxisService object called “Foo” and that service will have an AxisOperation object called “bar”. The parent description of an AxisOperation is the AxisService, and any parameter defined in the parent’s descriptions can be accessed inside the child, in this case, the AxisOperation. So, any parameter in AxisConfiguration, AxisServiceGroup, and AxisService can be accessed and used inside AxisOperation. I typical AxisOperation contains:
- Engaged modules
- Operation name
- Soap actions
AxisMessage is the bottom or leaf element of the service hierarchy. Its parent is an AxisOperation. Unlike AxisService, which has a set op AxisOperations, an AxisOperation does not have a set of AxisMessages. The number of AxisMessages in an AxisOperation is based on the MEP of that particular AxisOperation. For example, if the operation is “in-out”, there will be only two AxisMessages in it, one to represent the in message configuration and other to represent the out message configuration. AxisMessage has the following set of data:
- Message Label
- Element Qname of the corresponding schema element (optional)
Having message elements inside the operation element of the services.xml is optional. You need to add that only if you need to override the default.
In this article, I discussed the Axis2 static data hierarchy, which provides more flexibility and extensibility to Axis2. Throughout the article, you learned about various types of data in the static data hierarchy and when and how they are created. More importantly, you discovered a different kind of configuration that you can see in the Axis2 global configuration file.
About the Author
Deepal Jayasinghe is a computer science graduate student at Georgia Tech and an Apache Member. Before joining Georgia Tech, he worked at WSO2 for about three years. His interest is mainly in SOA and distributed computing, especially Web services. Deepal was a key member who designed, developed, and implemented the de-facto Java Web service framework, Axis2.
In addition to Axis2, he has contributed to a number of other open source projects, such as Apache Axiom, Apache Synapse, WSO2 Registry, WSO2, and WSAS.