In Axis1, when we deploy a service, we have a configuration file called service.wsdd to configure the service. In Axis2, we gave a different name for the service configuration file and called it the services.xml file. The syntax of both configuration files are completely different.
This tutorial covers all the applicable syntax in the services.xml file as well as their proper usage. In Apache Axis2/Java, we can either deploy a single service or multiple services in a single service archive file. Irrespective of the way we deploy our service, the service archive file must contain a services.xml file if it is to be a valid service. Depending on the way we deploy our service, the syntax of the services.xml will vary. There are two types of services.xml; one for a single service and one for a service group.
Writing services.xml for a Single Service
The root XML element of services.xml for a single service is service, so it looks like,
<service ..... >
When we deploy a single service in a service archive, the file name of the service will always be the name of the archive file, unless we have a name attributed to it. So if the name of the service archive file is foo.aar, then the name of the service will be foo.
If we want to add the name, we can do it as follows,
<service name="foo" >
A service description helps service authors to describe their service. When we try to list the services in the Axis2 Web administration console, we see only the services and their descriptions. If we don't add the service description into the services.xml, it will show the service name as its service description. Having a service description is very useful to the users who are going to access the service. Adding a service description is a just a matter of adding the following optional XML element. The value of the element could be either pure text or an HTML segment.
This is my first Web service.
Else it can be,
<b>This is my first Web service.</b>
Note : The description element is an option element in services.xml
Service Level Parameters
We can define parameters inside the services.xml as an immediate child element of the service element, and those can be accessed via message context (at the runtime) or via AxisService or AxisOperation. A parameter has one mandatory attribute and one optional attribute.The mandatory attribute is the name of the parameter while the optional attribute is the locked attribute.
The idea of a locked attribute is to express whether we allow the parameter value to be overridden by a child node in the hierarchy. For example, if we add a parameter in the axis2.xml file setting the locked attribute to True, then if a service tries to add a parameter with the same name, it will throw an exception
For example, let's say there is a parameter called 'Foo' in axis2.xml with a locked attribute value True, and a services.xml has the same parameter (a parameter with the name Foo), then there will be a deployment exception. We cannot override the parent parameters from child nodes if the locked attribute is set to True on them.
The value of the parameter can be anything, it can either be a simple text or it can be an XML element. We can add a service level parameter as follows,
<parameter name=location>Colombo , Sri Lanka</parameter>
In Axis2, it is not mandatory to have a service implementation class for a given Web service. The Axis2 architecture allows us to write Web services without having a service implementation class. This is simply because the message receiver allows us to do so. With Axis2, once the request is handed over to the message receiver, Axis2 thinks (the AxisEngine) that it has finished its job and it's up to the message receiver to do the rest. Therefore, there is no special XML element for specifying the service implementation class in the services.xml. If we do have a service implementation class (most of the time we do), then we can add a special parameter called ServiceClass into the services.xml. Then the value of the parameter should be the full qualified name of the service class. So if the full qualified name of the service implementation is org.apache.Foo, then we could add the following parameter into the services.xml to specify the service implementation class.
<parameter name="ServiceClass" locked="false">org.apache.Foo</parameter>
Service Level Message Receivers
Message receiver is a special handler in Axis2, and it is the last handler in the In path (Request path). Each and every operation in a service has its own message receivers, and the type of message receiver may differ from one operation to another. A Message receiver is MEP (Message Exchange Pattern) dependent, so we must have different message receivers for different MEPs.
Take the scenario where we want to use the same message receiver for all the operations in a given service. We can easily do that by adding service level message receivers. In this case, we do not need to specify a message receiver at the operation level. What we need to do is to add the operation tag along with the name and the MEP to which it belongs.
We can specify the Message Receiver along with the MEP that is implemented in the services.xml. Then, at deployment, the correct Message receivers will be set for the operations in the services.
There may be some instances where we cannot run our service without engaging the WS-Security module into the service. Engaging a module is just a matter of adding a module tag into the services.xml. If the module is available then the engaging will take place, else it will make our service a faulty service.
So if we want to engage a module called foo, then we can add the module element into the services.xml as follows,
Service Session Scope
There are four service session scopes available in Axis2 to deploy our service. If we do not specify the session scope, then the service will be deployed using the default session scope - the request session scope. To specify the scope, you must add an optional attribute to the service element, so the value of the attribute can be one of the four sessions listed below:
- application : Lifetime is equal to the lifetime of the system.
- soapsession : Session is managed using the custom reference property in the addressing headers
- transportsession : This session is managed using transport cookies, and the lifetime is equal to the lifetime of the underline transport.
- request : Lifetime is very short and it is equal to the request processing time
Service Target Namespace
The idea of a service target namespace is only applicable for WSDL generation. At runtime, if someone tries to view the WSDL for a given service using ?wsdl, then the target namespace of the generated WSDL will be the value specified by this. In the mean time, we drop a WSDL file into the META-INF directory, and we want to override its target namespace. So the solution is to add the target namespace value into the services.xml . The default value of the target namespace is http://ws.apache.org/axis2.
To specify a target namespace, you must add an optional attribute called targetNamespace. If we want to set a target namespace of the foo service to http://foo.org, then we can do that as follows,
Schema Target Namespace
If the WSDL file is not present in META-INF at the time of generating a WSDL file at runtime or generating a schema at deployment, you can use your own schema target namespace by adding a schema element into the services.xml.
At deployment, if we do not specify a schema target namespace, then the target namespace will be calculated using the package name of the service implementation class. For example, if the full qualified name of the service implementation class is org.apache.axis2.FooService then the schema namespace will be,
If you want to provide your own value for that, you can do that by adding the following element into the services.xml file.
elementFormDefault Value in WSDL
At the time of generating a WSDL using a Java class, the value of elementFormDefault in the schema is set to 'qualified' by default. Once we have qualified=true, then all the elements in the response will also be qualified. There are situations where we do not need this behavior and we want to set the value of elementFormDefault to Unqualified. To do that, we need to add the following entry into the services.xml file.
Note : We may or may not have the schemaNamespace attribute here.
Exposing a Service on a Selected Transport
Axis2 has the capability of exposing a service through multiple transports, and that is achieved using the concept called Listener Manager. For example, you can start the Axis2 system to expose its services via HTTP and TCP with the use of the Listener Manager.
When we have multiple transports, sometimes we want to expose the services on selected transports; a good example would be the system administration service. That particular service will be exposed only through SSL, and there should be a way to convey this information.
In the case of the server side with multiple transports, all the services will be exposed through those transports. If we want to expose our service only through a selected transport, then we can do that by adding the transport tag into the services.xml as shown below. If we do not add a transport element, then the service will be exposed through all the available transports.
Operations and Operation Related Elements
The previous section described how to specify service level data that are applicable for each and every operation in a given service. For example, if we engage a module at the service level, then that will affect all the operations in the service. However, there are also instances where we want to override or add new data to operations.
Note : If the service implementation class is Java, then all the public methods in the service class will be exposed whether we specify that in the services.xml or not. If we wrote our service using some other language, then we have to specify the operation that we want to publish.
As mentioned above, there may be instances where we want to override service data using operations. For example, if we have to override a service level parameter using an operation, we can do that by adding an operation tag.
<parameter name=location locked=false>Colombo , Sri Lanka </parameter>
<parameter name=location locked=false>California ,USA</parameter>
Operation Level Message Receivers
As mentioned above, we can specify service level message receivers. However, there are also instances where we want to use a different message receiver for a given operation. Then we can use a message receiver tag inside the operation.
Adding Action Mapping
Action mapping is adding an alias for an operation. This enables us to add any number of aliases for an operation. It helps us to filter requests or to perform different processing for different action mappings. In the case of a client request, he has to send the action mapping either as an SOAPAction or wsa:action. Then the Axis2 dispatchers will dispatch the incoming request to the correct operation.
Engaging a Module
Just as we engage a module to a service, we can also engage a module to an operation. For instance, if we want security only for selected operations, the best way is to engage a module to those operations. Engaging a module is just a matter of adding a module element as shown below,
Axis2 will expose all the public methods in the service implementation class (if it is implemented using Java). If we put the .wsdl file into META-INF and we do not want to publish all the operations in that, we can exclude the operations that we do not want to expose by adding the exclude operations tag as shown below,
Writing services.xml for a Service Group
A service group is a convenient way of deploying multiple services together in one service archive file. Of course there will be a logical relationship between the services at runtime. The only difference in the services.xml for a service group and single service is its root element. For a service group, the root element is serviceGroup, and we can have multiple service elements inside the serviceGroup element.
Note : In this case, the name of the service group is the name of the service archive file. The name attribute of the service element is mandatory and the name value should be unique across the whole server. There cannot be two services with the same name.
Once we know how to write a services.xml for a single service, then writing a services.xml for a service group is easy. As mentioned above, the service group is just a collection of service elements, so all the syntaxes mentioned above will be applicable.
Deepal Jayasinghe, Senior Software Engineer, WSO2. deepal AT wso2 DOT com