Axis2 provides extended support for modules (See the Architecture Guide for more details about modules in Axis2). Let's create a custom module and deploy it to MyService, which we created earlier.
Send your feedback or questions to: axis-dev@ws.apache.org. ( Subscription details are available on the Axis2 site.) Kindly prefix subject with [Axis2].
public void init(ConfigurationContext configContext, AxisModule module) throws AxisFault;//Initialize the module public void shutdown(ConfigurationContext configurationContext) throws AxisFault;//End of module processing public void engageNotify(AxisDescription axisDescription) throws AxisFault; public String[] getPolicyNamespaces() throws AxisFault; public void applyPolicy(Policy policy, AxisDescription axisDescription) throws AxisFault ; public boolean canSupportAssertion(Assertion assertion) ;The first three methods can be used to control the module initialization and the termination, and the next three methods are used to perform policy related operations. With the input parameter AxisConfiguration, the user is provided with the complete configuration hierarchy. This can be used to fine-tune the module behavior by the module writers. For a simple logging service, we can keep these methods blank in our implementation class.
public class LogHandler extends AbstractHandler implements Handler { private static final Log log = LogFactory.getLog(LogHandler.class); private String name; public String getName() { return name; } public InvocationResponse invoke(MessageContext msgContext) throws AxisFault { log.info(msgContext.getEnvelope().toString()); return InvocationResponse.CONTINUE; } public void revoke(MessageContext msgContext) { log.info(msgContext.getEnvelope().toString()); } public void setName(String name) { this.name = name; } }
<module name="logging" class="userguide.loggingmodule.LoggingModule"> <InFlow> <handler name="InFlowLogHandler" class="userguide.loggingmodule.LogHandler"> <order phase="loggingPhase" /> </handler> </InFlow> <OutFlow> <handler name="OutFlowLogHandler" class="userguide.loggingmodule.LogHandler"> <order phase="loggingPhase"/> </handler> </OutFlow> <OutFaultFlow> <handler name="FaultOutFlowLogHandler" class="userguide.loggingmodule.LogHandler"> <order phase="loggingPhase"/> </handler> </OutFaultFlow> <InFaultFlow> <handler name="FaultInFlowLogHandler" class="userguide.loggingmodule.LogHandler"> <order phase="loggingPhase"/> </handler> </InFaultFlow> </module>
As you can see, there are four flows defined in the "module.xml"
<handler name="InFlowLogHandler" class="userguide.loggingmodule.LogHandler"> <order phase="loggingPhase" /> </handler>
To learn more about Phase rules, check out the article Axis2 Execution Framework
In this handler, the "loggingPhase", is defined by the module writer. It is not a pre-defined handler phase, hence the module writer should introduce it to the "axis2.xml" (NOT the services.xml) so that the Axis2 engine knows where to place the handler in different "flows" (inFlow, outFlow, etc.). The following XML lines show the respective changes made to the "axis2.xml" in order to deploy the logging module in the Axis2 engine. This is an extract of the phase section of "axis2.xml".
<!-- ================================================= --> <!-- Phases --> <!-- ================================================= --> <phaseOrder type="inflow"> <!-- System pre defined phases --> <phase name="TransportIn"/> <phase name="PreDispatch"/> <phase name="Dispatch" class="org.apache.axis2.engine.DispatchPhase"> <handler name="AddressingBasedDispatcher" class="org.apache.axis2.dispatchers.AddressingBasedDispatcher"> <order phase="Dispatch"/> </handler> <handler name="RequestURIBasedDispatcher" class="org.apache.axis2.dispatchers.RequestURIBasedDispatcher"> <order phase="Dispatch"/> </handler> <handler name="SOAPActionBasedDispatcher" class="org.apache.axis2.dispatchers.SOAPActionBasedDispatcher"> <order phase="Dispatch"/> </handler> <handler name="SOAPMessageBodyBasedDispatcher" class="org.apache.axis2.dispatchers.SOAPMessageBodyBasedDispatcher"> <order phase="Dispatch"/> </handler> <handler name="InstanceDispatcher" class="org.apache.axis2.engine.InstanceDispatcher"> <order phase="PostDispatch"/> </handler> </phase> <!-- System pre defined phases --> <!-- After Postdispatch phase module author or service author can add any phase he wants --> <phase name="OperationInPhase"/> <phase name="loggingPhase"/> </phaseOrder> <phaseOrder type="outflow"> <!-- user can add his own phases to this area --> <phase name="OperationOutPhase"/> <phase name="loggingPhase"/> <!--system predefined phases--> <!--these phases will run irrespective of the service--> <phase name="PolicyDetermination"/> <phase name="MessageOut"/> </phaseOrder/> <phaseOrder type="INfaultflow"> <!-- user can add his own phases to this area --> <phase name="OperationInFaultPhase"/> <phase name="loggingPhase"/> </phaseOrder> <phaseOrder type="Outfaultflow"> <!-- user can add his own phases to this area --> <phase name="OperationOutFaultPhase"/> <phase name="loggingPhase"/> <phase name="PolicyDetermination"/> <phase name="MessageOut"/> </phaseOrder>
The text in green, the custom phase "loggingPhase" is placed in all the flows, hence that phase will be called in all the message flows in the engine. Since our module is associated with this phase, the LogHandler inside the module will now be executed in this phase.
Up to this point, we have created the required classes and configuration descriptions for the logging module, and by changing the "axis2.xml" we created the required phases for the logging module.
Next step is to "engage" (use) this module in one of our services. For this, let's use the same Web service that we have used throughout the user's guide- MyService. However, since we need to modify the "services.xml" of MyService in order to engage this module, we use a separate Web service, but with similar operations.
The code for this service can be found in the "Axis2_HOME/samples/userguide/src/userguide/example2" directory. The simple changes that we have done to "services.xml' are shown in green in the following lines of xml.
<service name="MyServiceWithModule"> <description> This is a sample Web service with a logging module engaged. </description> <module ref="logging"/> <parameter name="ServiceClass" locked="xsd:false">userguide.example2.MyService</parameter> <operation name="echo"> <messageReceiver class="org.apache.axis2.receivers.RawXMLINOutMessageReceiver"/> </operation> <operation name="ping"> <messageReceiver class="org.apache.axis2.receivers.RawXMLINOutMessageReceiver"/> </operation> </service>
In this example, we have changed the service name (the implementation class is very similar to what we have used earlier, although it is in a different package). In addition we have added the line "<module ref="logging"/>" to "services.xml". This informs the Axis2 engine that the module "logging" should be engaged for this service. The handler inside the module will be executed in their respective phases as described by the "module.xml".
Before deploying the module, we need to create the ".mar" file for this module. This can be done, using the "jar" command and then renaming the created .jar file. Else, you can find the "logging.mar" that has already been created in the "Axis2_HOME/samples/userguide" directory.
Deploying a module in Axis2 requires the user to create a directory with the name "modules" in the "webapps/axis2/WEB-INF" directory of their servlet container, and then copying the ".mar" file to that directory. So let's first create the "modules" directory and drop the "logging.mar" into this directory.
Although the required changes to the "services.xml" is very little, we have created a separate service archive (MyServiceWithModule.aar) for users to deploy the service..
Deploy this service using the same steps used in the 'Step 4: Deploy Web Service' sub section in 'Writing a New Service using Codegeneration', and copy the "logging.mar" file to the "modules" directory.
Then run 'ant run.client.servicewithmodule' from axis2home/samples/userguide directory
Note: To see the logs, the user needs to modify the "log4j.properties" to log INFO. The property file is located in "webapps/axis2/WEB-INF/classes" of your servlet container. Change the line "log4j.rootCategory= ERROR, LOGFILE" to "log4j.rootCategory=INFO, ERROR, LOGFILE".
Note (on samples): All the samples mentioned in the user's guide are located at the "samples\userguide\src" directory of the binary distribution.