Tuesday, September 3, 2013

Custom JIRA REST JAVA CLIENT (JRJC) using Jersey


JIRA Setup:

JIRA is not an acronym; it’s a word in itself and an Atlassian product used for issue tracking. You might have used lots of bug (issue) tracking tool like BugZilla, HP QC, IBM Rational ClearQuest, Team Foundation Server (TFS), etc. from a long list of tracking tools. JIRA is one among them.

If you want to practice on your system before hitting the production server, you can get the evaluation licensed JIRA server from here.

You have to register your email id and you will get 30 days license, to start working with JIRA.

Once downloaded, you can install JIRA on your machine following this.

After installation, you can configure your JIRA server using this.

Once setup is done, you can follow this guide to create projects, users, roles, tasks, bugs etc. things involved in project management.

If you are a normal user of JIRA (not an administrator), this guide could be useful.

I am hoping everything is set and you have JIRA installed, configured, TESTJIRA project created.

pics of my project:



Web Services via REST (Representational State Transfer):

We term any service provided via web as web service; it is not a new technology, since the invention of internet we are doing this only, servicing via web. Google, IRCTC, Yahoo, WebMail are the famous web services we are using, without knowledge (it’s amazing  J J).

Now if we are using web services since 1960s than why this buzz for SOAP and REST Web Services? What is so special in it and why I am writing for JRJC?

Previously in the web world we were accessing a complete web site of each provider and fill the forms and get our work done. To build those web sites each and every provider has to follow a pre-set rules to build a web site (site should follow this design pattern, should use this technology, should be hosted on this container and so on), means a full-fledged solution.

Now suppose, IRCTC wants to provide a search service to users. Previously, either it has to create a search engine by itself or integrate Google search API (obviously provided by Goole- hypothetical assumption), which is going to be either tedious task and also might be costly solution.

“It’s always good to use existing wheels instead of reinventing“ – this is the philosophy of web Services.

You want to use Google search, just use the services provided by Google in the form of REST Service.
REST follows our age old client-server (service provider) model. Server will create the service and client will consume it and to facilitate this process we have our java api named JAX-RS. JAX-RS is only standard, we have to use some implementation API like Jersey, Restlet, CXF etc. here I am using Jersey.

As service provider has to expose its services via set of URIs i.e REST URIs for client to consume it, here in our case JIRA is service provider and JIRA has provided a REST API which contain set of URIs to consume the services provided by it.

The general REST URI architecture for JIRA services is as below

http://hostname/rest/<api-name>/<api-version>/<resource-name>

*  The current version of the JIRA REST API is "2".
The <api-name> part of the URI is the name of the JIRA REST API, which is simply api.
*  JIRA's REST API resources have names like "issue", "user" or "attachment".
 For instance, putting all of the above together, the URI to an issue with the key TJ-1 would look like:

                                      http://lacalhost:9090/rest/api/2/issue/TJ-1
 
For detailed JIRA REST API tutorial refer this.
 

Now let’s start Coding.

Create a basic java project and add required maven dependencies.

Code Structure:

POM.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd">

  <modelVersion>4.0.0</modelVersion>
  <groupId>JiraRestExample</groupId>
  <artifactId>JiraRestExample</artifactId>
  <version>0.0.1-SNAPSHOT</version>

  <dependencies>
        <dependency>
                <groupId>com.sun.jersey</groupId>
                <artifactId>jersey-client</artifactId>
                <version>1.16</version>
        </dependency>
        <dependency>
               <groupId>net.sf.json-lib</groupId>
               <artifactId>json-lib</artifactId>
               <version>2.4</version>
               <classifier>jdk15</classifier>
        </dependency>
</dependencies>

<build>
    <sourceDirectory>src</sourceDirectory>
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.1</version>
        <configuration>
          <source>1.6</source>
          <target>1.6</target>
        </configuration>
      </plugin>
    </plugins>
     </build>
</project>
 
Client1.java

/*
*
* Custom JIRA REST JAVA CLIENT (JRJC) using Jersey
* Created by: Sushil K Madwani
* Date: 09/03/2013
* 
*/

package com.apollo.jiraRest;

import javax.naming.AuthenticationException;
import net.sf.json.JSONObject;
import net.sf.json.JSONSerializer;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientHandlerException;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.core.util.Base64;

class Client1 {
 
               /*
                  provide admin / user credentials to access the JIRA.
                */
             static String auth = new String(Base64.encode("smadwani:12071985"));

           /*
                * url for creating an issue using REST API ---- C of CRUD
                * */
              static String url = "http://localhost:9090/rest/api/2/issue";
              
               /*
                * JSON for creating an issue using REST API 
                *
                * */
                          static String data = "{\"fields\"" +
                                                            ":{\"project\"" +
                                                                  ":{\"key\":\"TJ\"}," +
                                                                 "\"summary\":\"REST Test \",\"issuetype\":{\"name\":\"Task\"}}}";
     
               /*
                * url for retrieving an issue using REST API ---- R of CRUD
                *
                * */
              static String url1 = "http://localhost:9090/rest/api/2/issue/TJ-1";
                /*
                * url for updating an issue using REST API ---- U of CRUD
                *
                * */
               static String url2 = "http://localhost:9090/rest/api/2/issue/TJ-1";
              
               /*
                * JSON data to be updated for an issue using RESP API                
                * 
                * */
                 static String data1 = "{\"fields\":{\"assignee\":{\"name\":\"vinodh\"}}}";
            
               /*
                * url for deleting an issue using RESP API ---- D of CRUD
                *
                * */
              static String url3 = "http://localhost:9090/rest/api/2/issue/TJ-1";
             /*
                * HTTP POST method is used to create the issue
                * 
                * */
                private static String invokePostMethod(String auth, String url, String data) throws AuthenticationException, ClientHandlerException {
                   Client client = Client.create();
                   WebResource webResource = client.resource(url);
                   ClientResponse response = webResource.header("Authorization", "Basic " + auth).type("application/json").accept("application/json").post(ClientResponse.class, data);
                   int statusCode = response.getStatus();
                   if (statusCode == 401) {
                       throw new AuthenticationException("Invalid Username or Password");
                   }
                   return "issue successfully created";   
               }
                           
               /*
                * HTTP GET method is used to get the issue
                * 
                * */
               private static String invokeGetMethod(String auth, String url) throws AuthenticationException, ClientHandlerException {
                   Client client = Client.create();
                   WebResource webResource = client.resource(url);
                   ClientResponse response = webResource.header("Authorization", "Basic " + auth).type("application/json").accept("application/json").get(ClientResponse.class);
                   int statusCode = response.getStatus();
                   if (statusCode == 401) {
                       throw new AuthenticationException("Invalid Username or Password");
                   }
                   return response.getEntity(String.class);
               }
            
               /*
                * HTTP PUT method is used to update the issue
                * 
                * */
            private static String invokePutMethod(String auth, String url, String data1) throws AuthenticationException, ClientHandlerException {
                                   Client client = Client.create();
                                   WebResource webResource = client.resource(url);
                                   ClientResponse response = webResource.header("Authorization", "Basic " + auth).type("application/json").accept("application/json").put(ClientResponse.class, data1);
                                   int statusCode = response.getStatus();
                                   if (statusCode == 401) {
                                       throw new AuthenticationException("Invalid Username or Password");
                                   }
                                   return "success";
                               }             
              /*
                * HTTP DELETE method is used to delete the issue
                * 
                * */
              private static String invokeDeleteMethod(String auth, String url) throws AuthenticationException, ClientHandlerException {
                   Client client = Client.create();
                   WebResource webResource = client.resource(url);
                   ClientResponse response = webResource.header("Authorization", "Basic " + auth).type("application/json").accept("application/json").delete(ClientResponse.class);
                   int statusCode = response.getStatus();
                   if (statusCode == 401) {
                       throw new AuthenticationException("Invalid Username or Password");
                   }
                   return "successfully deleted";
               }             
        
              public static void main(String[] args) throws Exception {
                              /*
                                * 1. Creating an JIRA issue in project with key TJ using REST API
                                * 
                                */
                            
                              System.out.println(invokePostMethod(auth, url, data));
                                                   
                                /*
                                * 2. Getting details of an JIRA issue in project with issue no TJ-1 using REST API
                                */
                               
                              String resp=invokeGetMethod(auth, url1);                        
                              
                              JSONObject jo=(JSONObject)JSONSerializer.toJSON(resp);
                             
                               JSONObject sum=jo.getJSONObject("fields");
                             
                               System.out.println(sum.getString("summary"));
                                                           
                               /*
                                * 3. Updating details of an JIRA issue in project with issue no TJ-1 using REST API
                              */
                          
                               System.out.println(invokePutMethod(auth, url2, data1));
                                                          
                               /*
                                * 4. Deleting an JIRA issue in project with issue no TJ-1 using REST API
                                */                           
                               
                               System.out.println(invokeDeleteMethod(auth, url3));
                   }
}
 
 OUTPUT :

Creating an issue

i.               JIRA status before creating an Issue
ii.             Code to create an issue.
 
iii.           JIRA status after creating issue.
 
 Retrieving an Issue
 
i.               Code to retrieve the issue in JSON format.

Updating an Issue
i.               JIRA Status before updating 

ii.             Code to update the Issue.
iii.       JIRA Status after update
Deleting an Issue
i.               JIRA Status before deleting 
ii.             Code to delete the Issue. 
iii.           JIRA Status after delete.

For detailed JIRA REST API, please go here.

1 comment:

Anonymous said...

Please help me..
When I'm trying to copy pom.xml code, it shows me error on element. The error is as follows:

Multiple annotations found at this line:
- Plugin execution not covered by lifecycle configuration: org.apache.maven.plugins:maven-compiler-plugin:3.2:compile (execution: default-compile, phase: compile)
- CoreException: Could not calculate build plan: Plugin org.apache.maven.plugins:maven-compiler-plugin:3.2 or one of its dependencies could not be resolved: Failure to find
org.apache.maven.plugins:maven-compiler-plugin:jar:3.2 in http://repo.maven.apache.org/maven2 was cached in the local repository, resolution will not be reattempted until the update
interval of central has elapsed or updates are forced
- Plugin execution not covered by lifecycle configuration: org.apache.maven.plugins:maven-compiler-plugin:3.2:testCompile (execution: default-testCompile, phase: test-compile)


Again, there is another error on 1st line