Tuesday, May 29, 2012

Writing a Apache Axis2 Module

As intern at WSO2 we learn lot about Apache Axis 2, because my team at WSO2 works on a product called Application Server  which is based on Axis2. So we have to play a lot with Axis2. The most interesting thing I have done with Axis2 is extending by writing a module to it. Here I am going to talk about how to do it. I will explain how I did it.

Before read this article about Writing a Module, Better you read these articles to get a better picture about Apache Axis 2 and it's underlining architecture,

What is Apache Axis2 :
http://axis.apache.org/axis2/java/core/

How to write a Apache Axis2 Web Service :
http://wso2.org/library/95

What is a Apache Axis2 Module :
http://axis.apache.org/axis2/java/core/docs/Axis2ArchitectureGuide.html

Also there is a interesting book written by Mr Afkham Azeez and Mr Deepal Jayasinghe. It explain all about Apache Axis2. Please read it to have 100% understanding about Axis 2. The book is Apache Axis2 Web Services, 2nd Edition.

If you have read those articles or had prior knowledge you can understand that a module will add some functionality to the execution chain of axis2 handlers. Single module can have more than one handler. So here in this example I will explain how I wrote my simple axis2 module 2 print the SOAP message content to the info log.

To follow this article you need to have a web services hosted in the simple axis2 server provided by the axis2 distribution. I have add a simple web service to my axis2 server and it is up and running when I start writing the module.  Here are the steps I followed to create and run my web Service.

Definition of My Web Services :

package org.wso2.testws;
public class TestWebService {
    public String sayHello(String name) {
        return "Hello " + name;
    }
    public int add(int x,int y){
        return x+y;
    }
}


My services.xml file :

<service name="TestWebService" >
    <Description>
        This web Service is written for test the functionlity of a AXIS2 Module
    </Description>
    <messageReceivers>
        <messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-only" class="org.apache.axis2.rpc.receivers.RPCInOnlyMessageReceiver" />
        <messageReceiver  mep="http://www.w3.org/2004/08/wsdl/in-out"  class="org.apache.axis2.rpc.receivers.RPCMessageReceiver"/>
    </messageReceivers>
    <parameter name="ServiceClass" locked="false">org.wso2.testws.TestWebService</parameter>
</service>


My Folder Stricture :

TestWebService >
      TestWebService.java
      Temp>
           META-INF>
                services.xml
           org>
                wso2>
                     testws>
                          TestWebService.class

After having all these I build my TestWebService.aar file using this command,

jar -cvf TestWebService.aar *

Then I copied that archive to the repository/services folder of the axis2 home folder. Then I run the axis2server.sh script to run the simple server. Then you can see that my new service is successfully deployed.

After that we can start the development of the Axis2 Module. For that purpose I use the Eclipse IDE. Create a new java project in Eclipse and have the following structure in your project.

Here you can see that Axis2 has been added as a library to the project. To do it, right click on the project and got to Build Path > Configure Build Path. There you can find a button called Add Library, click on it and select User Library in the appearing screen. There go to new and add all the jar files in the lib folder in the axis2 home folder.

Then the definition of the TestModule.java is this,

package org.wso2.testa2m;

import org.apache.axis2.AxisFault;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.description.AxisDescription;
import org.apache.axis2.description.AxisModule;
import org.apache.axis2.modules.Module;
import org.apache.neethi.Assertion;
import org.apache.neethi.Policy;

public class TestModule implements Module{

    public void init(ConfigurationContext configContext, AxisModule module) throws AxisFault {
    }

    public void engageNotify(AxisDescription axisDescription) throws AxisFault {
    }

    public void shutdown(ConfigurationContext configurationContext) throws AxisFault {
    }
    
    public String[] getPolicyNamespaces() {
        return null;    
    }

    public void applyPolicy(Policy policy, AxisDescription axisDescription) throws AxisFault {
    }
           
    public boolean canSupportAssertion(Assertion assertion) {
        return true;
    }
}

The definition of the TestHandler.java is this,

package org.wso2.testa2m;

import org.apache.axis2.AxisFault;
import org.apache.axis2.context.MessageContext;
import org.apache.axis2.engine.Handler;
import org.apache.axis2.handlers.AbstractHandler;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class TestHandler extends AbstractHandler implements Handler{
    private static final Log log = LogFactory.getLog(TestHandler.class);
    private String name;

    public String getName() {
        return name;
    }

    public InvocationResponse invoke(MessageContext msgContext) throws AxisFault {
        log.info("The web service "+msgContext.getAxisService().toString()+".");
        log.info("The operation is "+msgContext.getAxisOperation().toString()+".");
        log.info("This is the SOAP envelop : "+msgContext.getEnvelope().toString());
        return InvocationResponse.CONTINUE;        
    }

    public void revoke(MessageContext msgContext) {
        log.info("The web service "+msgContext.getAxisService().toString()+".");
        log.info("The operation is "+msgContext.getAxisOperation().toString()+".");
        log.info("This is the SOAP envelop : "+msgContext.getEnvelope().toString());
    }

    public void setName(String name) {
        this.name = name;
    }
}


After doing these, go the eclipse project folder in your machine, then in the TestModule folder you can find a folder called bin which has the generated class files of the project. Go inside it and create a folder called META-INF. In side it create the module.xml file. This is the definition of that file,

<module name="TestModule" class="org.wso2.testa2m.TestModule">
    <InFlow>
        <handler name="InFlowLogHandler" class="org.wso2.testa2m.TestHandler">
            <order phase="TestPhase"/>
        </handler>
    </InFlow>

    <OutFlow>
        <handler name="OutFlowLogHandler" class="org.wso2.testa2m.TestHandler">
            <order phase="TestPhase"/>
        </handler>
    </OutFlow>

    <OutFaultFlow>
        <handler name="FaultOutFlowLogHandler" class="org.wso2.testa2m.TestHandler">
            <order phase="TestPhase"/>
        </handler>
    </OutFaultFlow>

    <InFaultFlow>
        <handler name="FaultInFlowLogHandler" class="org.wso2.testa2m.TestHandler">
            <order phase="TestPhase"/>
        </handler>
    </InFaultFlow>
</module>

After doing that your now in a position to create your module archive file. Go to bin folder of your project using terminal and execute foll wing command,

jar -cvf TestModule.mar *

It will create the archive file needed. Copy it to the repository/modules folder of your axis2 home folder. Now your module is ready to be deployed. Now you have to do some configuration to execute your module. Conceptually Apache Axis2 modules can be executed in two ways,
  • Globally for all the services hosted in Axis2. To do this you have to edit the axis2.xml file
  • Per Service. To do this you have to edit the services.xml file also.
You can find axis2.xml file in the conf folder of axis2 home folder. Edit it like this to add your custom phases to the configuration. In the phases section add the entries which are highlighted to add your definition of custom phase called "TestPhase",

    <!-- ================================================= -->
    <!-- Phases  -->
    <!-- ================================================= -->
    <phaseOrder type="InFlow">
        <!--  System predefined phases       -->
        <phase name="Transport">
            <handler name="RequestURIBasedDispatcher"
                     class="org.apache.axis2.dispatchers.RequestURIBasedDispatcher">
                <order phase="Transport"/>
            </handler>
            <handler name="SOAPActionBasedDispatcher"
                     class="org.apache.axis2.dispatchers.SOAPActionBasedDispatcher">
                <order phase="Transport"/>
            </handler>
        </phase>
        <phase name="Addressing">
            <handler name="AddressingBasedDispatcher"
                     class="org.apache.axis2.dispatchers.AddressingBasedDispatcher">
                <order phase="Addressing"/>
            </handler>
        </phase>
        <phase name="Security"/>
    <!-- +++++++Cutome Pahse I have Added+++++++  -->
     <phase name="TestPhase"/>
    <!-- +++++++++++++++++++++++++++++++++++++++ -->
        <phase name="PreDispatch"/>
        <phase name="Dispatch" class="org.apache.axis2.engine.DispatchPhase">
            <handler name="RequestURIBasedDispatcher"
                     class="org.apache.axis2.dispatchers.RequestURIBasedDispatcher"/>
            <handler name="SOAPActionBasedDispatcher"
                     class="org.apache.axis2.dispatchers.SOAPActionBasedDispatcher"/>
            <handler name="RequestURIOperationDispatcher"
                     class="org.apache.axis2.dispatchers.RequestURIOperationDispatcher"/>
            <handler name="SOAPMessageBodyBasedDispatcher"
                     class="org.apache.axis2.dispatchers.SOAPMessageBodyBasedDispatcher"/>
            <handler name="HTTPLocationBasedDispatcher"
                     class="org.apache.axis2.dispatchers.HTTPLocationBasedDispatcher"/>
            <handler name="GenericProviderDispatcher"
                     class="org.apache.axis2.jaxws.dispatchers.GenericProviderDispatcher"/>
            <handler name="MustUnderstandValidationDispatcher"
                     class="org.apache.axis2.jaxws.dispatchers.MustUnderstandValidationDispatcher"/>
        </phase>
        <phase name="RMPhase"/>
        <!--  System predefined phases       -->
        <!--   After Postdispatch phase module author or service author can add any phase he want      -->
        <phase name="OperationInPhase">
            <handler name="MustUnderstandChecker"
                     class="org.apache.axis2.jaxws.dispatchers.MustUnderstandChecker">
                <order phase="OperationInPhase"/>
            </handler>
        </phase>
        <phase name="soapmonitorPhase"/>
    </phaseOrder>
    <phaseOrder type="OutFlow">
        <!--      user can add his own phases to this area  -->
        <phase name="soapmonitorPhase"/>
        <phase name="OperationOutPhase"/>
        <!--system predefined phase-->
        <!--these phase will run irrespective of the service-->
        <phase name="RMPhase"/>
        <phase name="PolicyDetermination"/>
        <phase name="MessageOut"/>
        <phase name="Security"/>
    <!-- +++++++Cutome Pahse I have Added+++++++  -->
     <phase name="TestPhase"/>
    <!-- +++++++++++++++++++++++++++++++++++++++ -->
    </phaseOrder>
    <phaseOrder type="InFaultFlow">
        <phase name="Addressing">
            <handler name="AddressingBasedDispatcher"
                     class="org.apache.axis2.dispatchers.AddressingBasedDispatcher">
                <order phase="Addressing"/>
            </handler>
        </phase>
        <phase name="Security"/>
    <!-- +++++++Cutome Pahse I have Added+++++++  -->
     <phase name="TestPhase"/>
    <!-- +++++++++++++++++++++++++++++++++++++++ -->
        <phase name="PreDispatch"/>
        <phase name="Dispatch" class="org.apache.axis2.engine.DispatchPhase">
            <handler name="RequestURIBasedDispatcher"
                     class="org.apache.axis2.dispatchers.RequestURIBasedDispatcher"/>
            <handler name="SOAPActionBasedDispatcher"
                     class="org.apache.axis2.dispatchers.SOAPActionBasedDispatcher"/>
            <handler name="RequestURIOperationDispatcher"
                     class="org.apache.axis2.dispatchers.RequestURIOperationDispatcher"/>
            <handler name="SOAPMessageBodyBasedDispatcher"
                     class="org.apache.axis2.dispatchers.SOAPMessageBodyBasedDispatcher"/>
            <handler name="HTTPLocationBasedDispatcher"
                     class="org.apache.axis2.dispatchers.HTTPLocationBasedDispatcher"/>
            <handler name="GenericProviderDispatcher"
                     class="org.apache.axis2.jaxws.dispatchers.GenericProviderDispatcher"/>
            <handler name="MustUnderstandValidationDispatcher"
                     class="org.apache.axis2.jaxws.dispatchers.MustUnderstandValidationDispatcher"/>
        </phase>
        <phase name="RMPhase"/>
        <!--      user can add his own phases to this area  -->
        <phase name="OperationInFaultPhase"/>
        <phase name="soapmonitorPhase"/>
    </phaseOrder>
    <phaseOrder type="OutFaultFlow">
        <!--      user can add his own phases to this area  -->
        <phase name="soapmonitorPhase"/>
        <phase name="OperationOutFaultPhase"/>
        <phase name="RMPhase"/>
        <phase name="PolicyDetermination"/>
        <phase name="MessageOut"/>
        <phase name="Security"/>
    <!-- +++++++Cutome Pahse I have Added+++++++  -->
     <phase name="TestPhase"/>
    <!-- +++++++++++++++++++++++++++++++++++++++ -->
    </phaseOrder>

After doing that you are successfully introduced the phase you have created manually, Now it is time to define the execution type of your module,
To excute it globally, add the <module ref="TestModule"/> entry to to the Global section of the axis2.xml.

    <!-- ================================================= -->
    <!-- Global Modules  -->
    <!-- ================================================= -->
    <!-- Comment this to disable Addressing -->
    <module ref="addressing"/>
    <module ref="TestModule"/>
    <!--Configuring module , providing parameters for modules whether they refer or not-->
    <!--<moduleConfig name="addressing">-->
    <!--<parameter name="addressingPara">N/A</parameter>-->
    <!--</moduleConfig>--> 

If you want to add a module specially for a service, add <module ref="TestModule"/> to the service.xml file. Then it will only executed only for that service.
Now your custom module is sucessfully deployed. Now you can start your axis2server again. It will show following log message if your module is successfully loaded. 

[INFO] Deploying module: TestModule - file:/home/andunslg/My_Works/Axis2_Code/modules/distribution/target/axis2-1.7.0-SNAPSHOT/repository/modules/TestModule.mar

After that to check it's functionality use the soapUI. Copy your web service's WSDL files link and create a soapUI project using that. If you are successful you will have a project which looks like this,


Double click on add,  it will show you are SOAP message. Add parameters to the add function and send it. The web service will reply to your message if you have successfully did all the things. If it is this kind of reply will come,


To see what your module to you have to see in to your terminal where you run the axis2server. In that you can see that following log entries are shown. Those are generated by the module you have created.

[INFO] The web service TestWebService.
[INFO] The operation is org.apache.axis2.description.InOutAxisOperation@2ce99681.
[INFO] This is the SOAP envelop : <?xml version='1.0' encoding='utf-8'?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tes="http://testws.wso2.org"><soapenv:Body>
      <tes:add>
         <tes:args0>3</tes:args0>
         <tes:args1>2</tes:args1>
      </tes:add>
   </soapenv:Body></soapenv:Envelope>
[INFO] The web service TestWebService.
[INFO] The operation is org.apache.axis2.description.InOutAxisOperation@2ce99681.
[INFO] This is the SOAP envelop : <?xml version='1.0' encoding='utf-8'?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Body><ns:addResponse xmlns:ns="http://testws.wso2.org"><ns:return>5</ns:return></ns:addResponse></soapenv:Body></soapenv:Envelope>


Up to now you have added custom module to AXIS2 to extend it. You can define any task in side your handler definition to o in your module. If you have any problem please contact me.

Saturday, May 26, 2012

What is Remote Debugging - Java, Eclipse,IntelliJ IDEA, AXIS2

Now I am working as a Software Engineering Intern at WSO2. At the first week of internship with the WSO2 Application Server team, I have learned a pretty cool concept in software development called Remote Debugging of application. I feel that is a pretty strong concept which I should talk about. To learn about remote debugging I have gone through lot of articles all around the Internet. So I thought that getting all those information to one place.
If we look at to the Remote Debugging scenario it will look like this,


Some times you have to debug a application which is not running from it's source code in a IDE. So to do it we use this remote debug concept. In the scenario which is shown above the application runs in a remote machine, but when it runs it will broadcast debug information via a socket deployed. The IDE running locally will capture those broadcast debug information through that socket and it will do the debug through the source code.

JAVA language provides this in its JVM. We can use commands like this to run a application in the remote debug mode in java.

java -Xdebug -Xrunjdwp:transport=dt_socket,address=8000,suspend=n,server=y -jar Name_of_Your_Jar.jar

Then it will broadcast some debug information and will wait until some IDE capture those debug information and start debugging the source code. When Some IDE connects to the Socket specified it will start the debugging process.

Configuring the IDEs will depend on them. The links given below will give you a good understanding about those concepts. Hope you learn some thing from this post. Following links are really interesting to learn about remote debugging.

What is Remote Debugging :
http://www.javabeat.net/2010/12/what-is-remote-debugging-in-java/

Remote Debugging with Eclipse :
http://www.eclipsezone.com/eclipse/forums/t53459.html
http://java.dzone.com/articles/how-debug-remote-java-applicat
http://www.myeclipseide.com/documentation/quickstarts/remotedebugging/

Remote Debugging with IntelliJ IDEA :
http://www.javaranch.com/journal/200408/DebuggingServer-sideCode.html

Remote Debugging Web Services, Apache Axis 2 :
http://wso2.org/library/225
http://wso2.org/library/3851
http://amilamanoj.blogspot.com/2011/09/running-debugging-apache-axis2-inside.html
http://shameerarathnayaka.blogspot.com/2011/09/remote-debugging-apache-axis2-with.html