Thursday, September 22, 2011

Creating a JSON client for AXIS2

This post will try to explain how to develop a sample for Axis2 that uses the JSON module in Axis2. Before you read this blog post read this article to get a understanding about Axis2 JSON module
Creating the folder structure

Before we start to do anything lets create the folder structure that will be needed to create the sample. For this sample we will create a folder structure simmilar to the structure given below

The resources folder will contain the axis2.xml and the Java code will be added in to src/samples/googleservices/JSONSearch. We will look into each part separately.

Before we start working on the sample there are a few simple things that we have to do. Since we will be using the Yahoo Boss API to retrive the search results in JSON format, we need to acquire a API-Key that is needed when using the Boss API. You can create a Yahoo Boss API-Key here, this should not take more than 5 minutes if you already have a Yahoo account.
Now that we have a Yahoo Boss API-Key we can go onto implementing the sample. First lets take a look at the java class that does all the logic of the sample we will name the class "JSONSearchModel". 

package sample.yahooservices.JSONSearch;
package sample.yahooservices.JSONSearch;

import org.apache.axis2.Constants;
import org.apache.axis2.transport.http.HTTPConstants;
import org.apache.axis2.context.ConfigurationContextFactory;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.client.Options;
import org.apache.axis2.client.ServiceClient;

import java.util.Iterator;

public class JSONSearchModel {
     * HTML Header to desplay snippet text
    private String beginHTML = "Search Results";

     * HTML footer
    private String endHTML = "";

     * Store the texts read by NavigationURL of soap
    private String snippet;

    * The App id 
    private final static String appIdString = "YOUR_API_KEY";

    public String searchYahoo(String query, String format) {
        try {
            snippet = beginHTML;
     query = query.replaceAll(" ","%20");
            String epr = ""+query;
            File configFile = new File("resources/axis2.xml");
            ConfigurationContext configurationContext = ConfigurationContextFactory
                    .createConfigurationContextFromFileSystem(null, configFile

            ServiceClient client = new ServiceClient(configurationContext, null);
            Options options = new Options();
            options.setTo(new EndpointReference(epr));
            options.setProperty(Constants.Configuration.MESSAGE_TYPE, HTTPConstants.MEDIA_TYPE_X_WWW_FORM);
            options.setProperty(Constants.Configuration.HTTP_METHOD, Constants.Configuration.HTTP_METHOD_GET);
            OMElement response = client.sendReceive(getPayloadForYahooSearchCall(query, format));
            return snippet;

        } catch (Exception e) {
            snippet = "<h2>Error occurred during the invocation to Yahoo search service</h2>" +
                    "" + e.getMessage() + "
" + endHTML;
        return snippet;

    private static OMElement getPayloadForYahooSearchCall(String queryStr, String formatStr) throws UnsupportedEncodingException {
        OMFactory fac = OMAbstractFactory.getOMFactory();
        OMElement rootElement = fac.createOMElement("webSearch", null);

        OMElement appId = fac.createOMElement("appid", null, rootElement);

        OMElement outputType = fac.createOMElement("format", null, rootElement);

        if (formatStr != null && formatStr.length() != 0) {
            OMElement format = fac.createOMElement("format", null, rootElement);
            format.setText(URLEncoder.encode(formatStr, "UTF-8"));
        return rootElement;

    private void generateSnippet(OMElement response) {
        String title = null;
        String summary = null;
        String clickUrl = null;
        String url = null;
        OMElement result = null;
        //get an iterator for Result elements
        Iterator itr = response.getChildElements();
        Iterator innerItr;
        while (itr.hasNext()) {
            result = (OMElement);
            innerItr = result.getChildElements();
            if (innerItr.hasNext()) {
                title = ((OMElement);
                summary = ((OMElement);
                url = ((OMElement);
                clickUrl = ((OMElement);
                if (title != null) {
                    snippet += ""+title+""+summary+url;
        snippet += endHTML;

This is the code snippet for the "JSONSearchModel" class, lets take a look at each part of the class separately. As you can see we have our API-Key as a string that will be used later.
now lets take a look at the method "searchYahoo" this method takes in two String parameters query and format, query is the search query specified by the user and the format is the data retrieval format in this case it would be JSON. Then using the query the endpoint reference is created(this is because the Boss API v1 does not specify the query as a parameter). Then a service client is created using configurations specified in the axis2.xml (we will look at the axis2.xml later) then the options are set such as the message type and Http method in this case that is GET. Then using the "getPayloadForYahooSearchCall" method to create a OMElement that has all the parameter including the API-Key and data format a request is send through the client and a response OMElement is received and this OMElement is parsed using method "generateSnippet" to create a  HTML snippet.

This snippet is displayed in the UI. The following two class are used to generate the user interface i will not go into explaining the logic in these classes.
package sample.yahooservices.JSONSearch;

import javax.swing.*;
import javax.swing.event.HyperlinkListener;
import javax.swing.event.HyperlinkEvent;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

public class UserInterface extends JPanel implements HyperlinkListener {

    private JEditorPane jep;
    private JScrollPane scrollPane;

    private JTextField schField;
    private JTextField formatField;

    private JButton schButton;
    private JButton backButton;

    private JLabel schLabel;
    private JLabel formatLabel;

    private JSONSearchModel model;
    private JSONSearchClient parent;

    private String response;
    public UserInterface(JSONSearchClient parent) {
        this.parent = parent;
        model =  new JSONSearchModel();

        schButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {

        backButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {

        Container pane = parent.getContentPane();


    public void initComponents() {
        schLabel = new JLabel("Search for");
        schLabel.setBounds(20, 10, 80, 25);
        schField = new JTextField();
        schField.setBounds(90, 10, 250, 25);

        formatLabel = new JLabel("format");
        formatLabel.setBounds(350, 10, 50, 25);
        formatField = new JTextField();
        formatField.setBounds(400, 10, 100, 25);

        backButton = new JButton("Back to Results");
        backButton.setBounds(670, 10, 150, 25);

        schButton =  new JButton("Search");
        schButton.setBounds(510, 10, 150, 25);

        jep = new JEditorPane();

        scrollPane = new JScrollPane(jep);
        scrollPane.setBounds(10, 80, (JSONSearchClient.width - 30), (JSONSearchClient.height - 160));


    private void handleSearch(){
        String query = schField.getText();

            response = model.searchYahoo(query, formatField.getText());

    private void handleBack(){

    public void hyperlinkUpdate(HyperlinkEvent he) {
        if (he.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
            try {
            catch (Exception e) {
                  JOptionPane.showMessageDialog(parent, "Page could not be loaded",
                                "Page Error", JOptionPane.ERROR_MESSAGE);


package sample.yahooservices.JSONSearch;

import javax.swing.*;
import java.awt.*;

public class JSONSearchClient extends JFrame {
    public static int width;
    public static int height;

    public JSONSearchClient(String title) throws HeadlessException {

        this.getContentPane().add(new UserInterface(this));

    public static void main(String[] args) {
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        width = screenSize.width;
        height = screenSize.height;
        JSONSearchClient form = new JSONSearchClient("Axis2 Yahoo-JSON Search Client");

        int left = (width) / 2;
        int top = (height) / 2;
        form.setLocation(left, top);
        form.setSize(width, height);


Now lets take a look at the axis2.xml configuration file. This is where all the configuration information is specified. We will look at the important parts of the xml and explain why they are there.I have also removed the comments that were included in the axis2.xml but comments are there in the zip file of the sample.
<axisconfig name="AxisJava2.0">
    <parameter name="hotdeployment">true</parameter>
    <parameter name="hotupdate">false</parameter>
    <parameter name="enableMTOM">false</parameter>
    <parameter name="enableSwA">false</parameter>
    <parameter name="ConfigContextTimeoutInterval">30</parameter>
    <parameter name="sendStacktraceDetailsWithFaults">false</parameter>
    <parameter name="DrillDownToRootCauseForFaultReason">false</parameter>
    <parameter name="userName">admin</parameter>
    <parameter name="password">axis2</parameter>
    <parameter name="manageTransportSession">false</parameter>

    <parameter locked="true" name="enableRESTInAxis2MainServlet">false</parameter>

    <parameter locked="true" name="disableREST">false</parameter>

    <parameter locked="true" name="disableSeparateEndpointForREST">false</parameter>

        <messagereceiver class="org.apache.axis2.receivers.RawXMLINOnlyMessageReceiver" mep="">
        <messagereceiver class="org.apache.axis2.receivers.RawXMLINOutMessageReceiver" mep="">
        <messageformatter class="org.apache.axis2.transport.http.SOAPMessageFormatter" contenttype="application/soap+xml">
        <messageformatter class="org.apache.axis2.json.JSONMessageFormatter" contenttype="application/json">
        <messageformatter class="org.apache.axis2.json.JSONBadgerfishMessageFormatter" contenttype="application/json/badgerfish">
        <messageformatter class="org.apache.axis2.json.JSONMessageFormatter" contenttype="text/javascript">
        <messageformatter class="org.apache.axis2.transport.http.XFormURLEncodedFormatter" contenttype="application/x-www-form-urlencoded">
        <messagebuilder class="org.apache.axis2.json.JSONOMBuilder" contenttype="application/json">
        <messagebuilder class="org.apache.axis2.json.JSONBadgerfishOMBuilder" contenttype="application/json/badgerfish">
        <messagebuilder class="org.apache.axis2.json.JSONOMBuilder" contenttype="text/javascript">
    <transportreceiver class="org.apache.axis2.transport.http.SimpleHTTPServer" name="http">
        <parameter name="port">8080</parameter>
    <transportsender class="org.apache.axis2.transport.local.LocalTransportSender" name="local">
    <transportsender class="org.apache.axis2.transport.http.CommonsHTTPTransportSender" name="http">
        <parameter name="PROTOCOL">HTTP/1.1</parameter>
        <parameter name="Transfer-Encoding">chunked</parameter>
    <transportsender class="org.apache.axis2.transport.http.CommonsHTTPTransportSender" name="https">
        <parameter name="PROTOCOL">HTTP/1.1</parameter>
        <parameter name="Transfer-Encoding">chunked</parameter>

    <phaseorder type="InFlow">
        <phase name="Transport">
            <handler class="org.apache.axis2.dispatchers.RequestURIBasedDispatcher" name="RequestURIBasedDispatcher">
                <order phase="Transport">
            <handler class="org.apache.axis2.dispatchers.SOAPActionBasedDispatcher" name="SOAPActionBasedDispatcher">
                <order phase="Transport">
        <phase name="Security">
        <phase name="PreDispatch">
        <phase class="org.apache.axis2.engine.DispatchPhase" name="Dispatch">
            <handler class="org.apache.axis2.dispatchers.AddressingBasedDispatcher" name="AddressingBasedDispatcher">
            <handler class="org.apache.axis2.dispatchers.RequestURIOperationDispatcher" name="RequestURIOperationDispatcher">

            <handler class="org.apache.axis2.dispatchers.SOAPMessageBodyBasedDispatcher" name="SOAPMessageBodyBasedDispatcher">
        <phase name="OperationInPhase">
 <phase name="soapmonitorPhase">
    <phaseorder type="OutFlow">
 <phase name="soapmonitorPhase">
        <phase name="OperationOutPhase">
        <phase name="PolicyDetermination">
        <phase name="MessageOut">
        <phase name="Security">
    <phaseorder type="InFaultFlow">
        <phase name="PreDispatch">
        <phase class="org.apache.axis2.engine.DispatchPhase" name="Dispatch">
            <handler class="org.apache.axis2.dispatchers.RequestURIBasedDispatcher" name="RequestURIBasedDispatcher">

            <handler class="org.apache.axis2.dispatchers.SOAPActionBasedDispatcher" name="SOAPActionBasedDispatcher">

            <handler class="org.apache.axis2.dispatchers.AddressingBasedDispatcher" name="AddressingBasedDispatcher">
            <handler class="org.apache.axis2.dispatchers.RequestURIOperationDispatcher" name="RequestURIOperationDispatcher">

            <handler class="org.apache.axis2.dispatchers.SOAPMessageBodyBasedDispatcher" name="SOAPMessageBodyBasedDispatcher">
        <phase name="OperationInFaultPhase">
 <phase name="soapmonitorPhase">
    <phaseorder type="OutFaultFlow">
 <phase name="soapmonitorPhase">
        <phase name="OperationOutFaultPhase">
        <phase name="PolicyDetermination">
        <phase name="MessageOut">
Now Lets take a look at some of the important parts of the xml.The first few lines are to set a few parameter that will be needed such as time outs and to enable and disable some parameters.
        <messagereceiver class="org.apache.axis2.receivers.RawXMLINOnlyMessageReceiver" mep=""></messagereceiver>
        <messagereceiver class="org.apache.axis2.receivers.RawXMLINOutMessageReceiver" mep=""></messagereceiver>
This is the tag that sets the default message receivers for this service here "RawXMLINOnlyMessageReceiver" has to be used and the reason is due implementation decision if you want to read more about why "RawXMLINOnlyMessageReceiver" has to be used read this blog post.

        <messageformatter class="org.apache.axis2.transport.http.SOAPMessageFormatter" contenttype="application/soap+xml"></messageformatter>
        <messageformatter class="org.apache.axis2.json.JSONMessageFormatter" contenttype="application/json"></messageformatter>
        <messageformatter class="org.apache.axis2.json.JSONBadgerfishMessageFormatter" contenttype="application/json/badgerfish"></messageformatter>
        <messageformatter class="org.apache.axis2.json.JSONMessageFormatter" contenttype="text/javascript"></messageformatter>
        <messageformatter class="org.apache.axis2.transport.http.XFormURLEncodedFormatter" contenttype="application/x-www-form-urlencoded">


This tag sets the Message formatters in this example we will be using the "XFormURLEncodedFormatter" which is mapped to the message type we set in the "JSONSearchModel" class when setting options for the service client.Although there are a few other message formatters defined in this xml the following part would be sufficent to run the sample
               <messageformatter class="org.apache.axis2.transport.http.XFormURLEncodedFormatter" contenttype="application/x-www-form-urlencoded">

Since we are using a remote service, we have to know the exact JSON content type that is used by that service, and we have to use that content type in your client as well.The Yahoo search service sends the response as a “Mapped” formatted JSON string with the content type “text/javascript”. This content type is mapped with the JSONOMBuilder in the axis2.xml using the following lines.

        <messagebuilder class="org.apache.axis2.json.JSONOMBuilder" contenttype="application/json"></messagebuilder>
        <messagebuilder class="org.apache.axis2.json.JSONBadgerfishOMBuilder" contenttype="application/json/badgerfish"></messagebuilder>
        <messagebuilder class="org.apache.axis2.json.JSONOMBuilder" contenttype="text/javascript"></messagebuilder>
There are a few more tags in the axis2.xml file but i will not try to explain them because they are out of the scope of this tutorial.
Now that we have all the parts ready all we need is the ant script that will run the sample. The ant script for this sample will look like this.
<project default="run.client" name="YahooJSONSearchSample">
 <property environment="env"></property>
 <property name="axis2.home" value="../../"></property>
 <property name="axis2.repo" value="${axis2.home}/repository"></property>
 <property name="build.dir" value="build"></property>
 <property name="client.classes.dir" value="${build.dir}/classes"></property>
 <path id="axis.classpath">
  <fileset dir="${axis2.home}/lib">
   <include name="*.jar">
  <pathelement location="build/yahooJSONSearch.jar">

 <target name="compile">
  <mkdir dir="${client.classes.dir}">
  <javac destdir="${client.classes.dir}" srcdir="src">
   <classpath refid="axis.classpath">
  <jar destfile="${build.dir}/yahooJSONSearch.jar">
   <fileset dir="${build.dir}/classes">
 <target depends="compile" name="run.client">
  <java classname="sample.yahooservices.JSONSearch.JSONSearchClient" classpathref="axis.classpath" fork="true">
   <jvmarg value="-Daxis2.repo=${axis2.repo}">
 <target name="clean">
  <delete dir="build">

You can find the zipped source code of the sample here and you can download the latest Axis2 version here.

Thursday, August 25, 2011

Full featured JIRA Issue Tracking Gadget

During my internship at WSO2 I created a JIRA issue tracking gadget as a small project. This is flexible gadget made according to the Google gadgets API so it works on any gadget container that supports Google gadgets API such as iGoogle, orkut, WSO2 Gadget Server, etc. In my previous post i explained the data retrieval method I used to gather data for the gadget.


  • Allows the user to specify any company or organisation he/she wants to track the JIRA issues.
  • Displays the most important data and provides a link for additional information.
  • Includes a search tab that provides all the search options provided by the JIRA dashboard
The user can specify the URL of the organisation or company he/she wants to track. Lets say you want to track the Issues of you have to set "" as the URL likewise the user can specify any JIRA URL that needs to be tracked.

The interface is created using jQuery UI, jQuery UI is a very nice library that can be used to create interactive user interfaces. I will not go on details about jQuery UI you can find the jQuery UI home page here.

I have also created a search tab that allows the users to filter the data according to the parameters he/she wants. The search tab provides almost all the search options provided by the Atlassian JIRA dashboard.
You can find the gadget in iGoogle here
If you want take a look at the code of the gadget you can get it here

Any comments or suggestions about the gadget are welcome. IF you have any issue about the gadget just leave a comment.

Sunday, March 20, 2011

Retrieving And Filtering JIRA Issue Views Through Request URL

      When developing a JIRA gadget for the WSO2 Gadget Server i found out that some aspects of the JIRA facilities are not well documented. This post will try to help with one such not-well documented service provided by Atlassian JIRA.
      In my gadget i had to filter the data that i needed according to several parameter that would vary from request to request.I decided to use "searchrequest-xml" that is provided by Atlassian JIRA this can be accessed by a simple URL and can also be filtered using parameters in the URL. This will return a XML containing the data that was requested. How the parameters should be defined to filter the request is not clearly documented. The aim of this post to provide a brief documentation as to how the parameters can be set for the "searchrequest-xml" URL request.

What You Need To Know
    The things given below are not that necessary to understand this post as the purpose of the post is to document the format of the "searchrequest-xml" URL. But if you are trying to use this feature (preferably in a gadget) you probably will have some knowledge of list below 
  1. Google Gadgets and the API 
  2. JavaScript
  3. XML
  4. Atlassian JIRA
Getting Started
    What we are trying to accomplish is to retrieve JIRA issue data to be used in our JIRA gadget.Data can be retrived as a xml using the following URL
   This is retrieves all the data related to the organization. It is better if we can retrieve only the data that we need to get by specifying certain parameters with this URL.Here "SearchXML" can be any name you like.

  • Filtering by project
    • You can filter the XML by giving an project id. For example if we are to retrieve the data that is related to the project with project id "ABC" the URL will be as follows.

  • Restricting the maximum number of items return
    • This can be done by using the parameter "tempMax". the following example will only retrieve the first 10 results of the filter.

  • In the same manner the following parameters can be also used to filter the data.
    • issuetype: eg- issuetype=BUG
    • priority: eg- priority=HIGH
    • resolution: eg-  resolution=Unresolved
    • status: eg- status=Open
    • repoter
    • assignee
  •  Searching 
    • This URL can also be used to search the content of the issues and find the related issues for a search query.below is the format of the search query.
              The above URL searches the XML for the word "build" and it looks in environment, comments and summery. Here the param "query" specifies the string to be searched and you can set where you want to search by setting body=true to search in comments.Likewise you can set environment,summery and description true if you want to search them also.

  • Paging 
    • Parameter can be set to do paging for the request. As shown in the following URL
      Here the link retrieves two items from the XMLand it starts with the second item so this can be used to page the request by generating the request URL correctly

  • Searching by dates
    • The request can be also filtered by related dates.As given by the following URL
        This searches for related issues created after 2010/02/12 and before 2010/12/02.the following formats can be used to specify dates.

    • yyyy/MM/dd HH:mm', 'yyyy-MM-dd HH:mm', 'yyyy/MM/dd', 'yyyy-MM-dd or as DD/MMM/YYYY

     This is only a small amount of parameter that i came across. There are many other below are the

  • assigneeSelect
  • created:after
  • created:before
  • created:next
  • created:previous
  • description
  • duedate:after
  • duedate:before
  • duedate:next
  • duedate:previous
  • pid
  • query
  • refreshFilter
  • reporter
  • Selectreset
  • Update
  • resolutiondate:after
  • resolutiondate:before
  • resolutiondate:next
  • resolutiondate:previous
  • showView 
 Discovering On Your Own
     I have not listed all the options that are available in the post there are many other parameters that can be specified. And it is not that hard to figure out how to specify them and what they do. What i did was use the search options given in the dashboard and specifiy a search critiera the link for the search criteria can be found from the permanent link that is in the top right coner of the page. use a little bit of Firebug and you will be able to figure out what you need in no time
Note: Firebug is a Firefox extension that can be used for many purposes in this context it can be used to view the request and response headers.

Example code 
  Lets look at a small example. The following code snippets are part of a gadget description XML and uses the Google Gadgets JavaScript API. This example will demonstrate how to make a search request to JIRA and how to retrieve data.
function makeXMLRequest(){
var params = {};
var prefs=new gadgets.Prefs();
var url= prefs.getString("feedurl");
      params[] =;
   ,processXML, params);
function processXML(obj) {

      var xmldata =;
          document.getElementById('content_div').innerHTML = obj.text;

    Here the UserPref  "feedurl" holds the request URL that is made according to the format described above 


Amazon Deals