Some quick notes on Maven Eclipse Plugin

Install Plugin
Google “Maven Eclipse Plugin Download”

Find the page: http://eclipse.org/m2e/download/

This sites shows:
Latest m2e release (recommended)
http://download.eclipse.org/technology/m2e/releases

In Eclipse, go to Help->Install New Software
Enter http://download.eclipse.org/technology/m2e/releases in the Work with field
Click Add, Enter a Name “M2E”, Click OK, Check “Maven Integration for Eclipse” and click Next.
Go through pages, accept agreement and click finish

Enable and Disable Maven Project Nature
Sometimes you have to first, Right click->Configure->Convert to Maven Project
Then, you can Maven->Update Project

This is the opposite of Right click->Maven->Disable Maven Nature

Maven Error: Project configuration is not up-to-date with pom.xml
See “Enable and Disable Maven Project Nature”. Sometimes this is caused by ‘mvn eclipse:clean’ command.

Error: Enabling Maven Dependency management has encountered a problem
Error: Updating Maven Project has encountered a problem

Maven Repo for plugin is org.apache.maven.plugins maven-eclipse-plugins

Summary
When you perform ‘mvn eclipse:clean’ this modifies the .classpath file. Perhaps ‘mvn eclipse:eclipse’ does so as well
In order to not get any errors, you need to remove dependencies:
“I just went to Properties -> Java Build Path -> Libraries and removed the blue entries starting with “M2_REPO”. After that, I could use Maven -> Update Project again” from http://stackoverflow.com/questions/15065093/an-internal-error-occurred-during-updating-maven-project-unsupported-iclassp
Then, you can Right click->Configure->Convert to Maven Project
Then, you can Right click->Maven->Update Project

You can also, right click the Referenced Libraries->Configure Build Path.
Remove M2_REPO
Then, you can Right click->Configure->Convert to Maven Project
Then, you can Right click->Maven->Update Project
You will then see “Maven Dependencies” where you saw “Referenced Libraries”.

Additional Notes
The “Maven Eclipse Plugin” has help at maven.apache.org. This allows the commands ‘mvn eclipse:clean’ and ‘mvn eclipse:eclipse’.

The “m2e – Maven Integration for Eclipse” has help at maven.apache.org. This allows cleaning and building from within Eclipse.

I am not quite sure exactly how these two differ in terms of cleaning and compiling the project. However, you will know which one you used last because if you used the “Maven Eclipse Plugin”, you will see “Referenced Libraries” in Eclipse. If you used the “Maven Integration for Eclipse”, you will see “Maven Dependencies”.

Advertisements

Accessing the JIRA Rest API via Jersey Client and JSON

In general, this type of command would work from Git Bash


curl http://my.jira.com/rest/api/2/project

This is shown in the following article www.j-tricks.com.

Most of the code to connect to the JIRA Rest API is demonstrated using the JiraRestClient class and typically demos include authentication. However, most of the time you can browse projects or issues, using read capability without logging in. This article demonstrates how to connect to the JIRA Rest API in Java, using the Jersey Client to connect and using a JSON parser to read the response.

In typical, fashion, this is added in a single file to run and here is the dependency. You need a JIRA server running and a url for jira.


<dependency>
   <groupId>com.sun.jersey</groupId>
   <artifactId>jersey-client</artifactId>
   <version>1.5</version>
</dependency>

import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;

public class CheckJiraConnectivity {
	// These fields were generated using the login credentials
	private static String URL = "http://my.jira.com";
	
	public static void main(String[] args) {
		Client client = Client.create();
		WebResource webResource = client.resource(URL+"/rest/api/2/project");
		ClientResponse response = webResource.type("application/json").accept("application/json").get(ClientResponse.class);
		String jsonResponse = response.getEntity(String.class);
		try {
			JSONArray projectArray = new JSONArray(jsonResponse);
			for (int i = 0; i < projectArray.length(); i++) {
			    JSONObject proj = projectArray.getJSONObject(i);
				System.out.println("Project Name:"+proj.getString("name"));
			}
		} catch (JSONException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		client.destroy();
	}
}

Getting Started with the JIRA API

The pom.xml dependencies needed for this are:


  <dependency>
    <groupId>com.atlassian.jira</groupId>
    <artifactId>jira-rest-java-client-core</artifactId>
    <version>2.0.0-m25</version>
  </dependency>
			  
  <dependency>
    <groupId>com.atlassian.jira</groupId>
    <artifactId>jira-rest-java-client-api</artifactId>
    <version>2.0.0-m25</version>
  </dependency>

My experience with this was that there was quite a bit of dependency conflicts that needed to get worked out for this to work. Here is a list of various other dependencies which I had to include in the pom.xml file.


classMissing:groupId:artifactId:version
com.atlassian.util.concurrent.Promise:com.atlassian.util.concurrent:atlassian-util-concurrent:2.4.0-M9
com.google.common.util.concurrent.ListenableFuture:com.google.guava:guava:10.0.1
com.atlassian.event.api.EventPublisher:com.atlassian.event:atlassian-event:2.2.0
com.atlassian.sal.api.ApplicationProperties:com.atlassian.sal:sal-api:2.7.0
com.atlassian.httpclient.api.HttpClient:com.atlassian.httpclient:atlassian-httpclient-api:0.13.2
com.atlassian.httpclient.apache.httpcomponents.DefaultHttpClient:com.atlassian.httpclient:atlassian-httpclient-apache-httpcomponents:0.13.2
org.springframework.beans.factory.DisposableBean:org.springframework:spring-context:3.1.1.RELEASE
javax.ws.rs.core.UriBuilder:com.sun.jersey:jersey-json:1.5
com.sun.ws.rs.ext.RuntimeDelegateImpl:com.sun.jersey:jersey-client:1.5
org.apache.http.impl.client.cache.CachingHttpAsyncClient:org.apache.httpcomponents:httpasyncclient-cache:4.0-beta3-atlassian-1
org.apache.http.impl.nio.conn.PoolingClientAsyncConnectionManager:org.apache.httpcomponents:httpasyncclient:4.0-beta3-atlassian-1
org.apache.http.client.cache.HttpCacheStorage:org.apache.httpcomponents:httpclient-cache:4.2.1-atlassian-2
org.apache.http.conn.routing.HttpRoutePlanner:org.apache.httpcomponents:httpclient:4.3.1
org.apache.http.nio.reactor.IOReactorExceptionHandler:org.apache.httpcomponents:httpcore-nio:4.2.2
com.atlassian.httpclient.spi.ThreadLocalContextManagers:com.atlassian.httpclient:atlassian-httpclient-spi:0.13.2
org.slf4j.LoggerFactory:org.slf4j:slf4j-api:1.6.4
org.apache.http.entity.mime.content.ContentBody:org.apache.httpcomponents:httpmime:4.1.2
org.joda.time.ReadableInstant:joda-time:joda-time:1.6
org.apache.commons.lang.StringUtils:org.apache.commons:com.springsource.org.apache.commons.lang:2.5.0

If this code compiles, you should be able to run this basic demo to list the projects in Jira. You will need to give the Jira URL, username and password.


import java.net.URI;
import com.atlassian.jira.rest.client.api.JiraRestClient;
import com.atlassian.jira.rest.client.api.JiraRestClientFactory;
import com.atlassian.jira.rest.client.api.domain.BasicProject;
import com.atlassian.jira.rest.client.internal.async.AsynchronousJiraRestClientFactory;

/**
 * See also https://developer.atlassian.com/display/JIRADEV/Performing+Issue+Operations
 * 
 * Run 3/4/2014, listed projects
 *
 */
public class JiraProjectsListDemo {
	// These fields were generated using the login credentials
	public static String URL = "http://my.jira.url.com";
	public static String USERNAME = "username";
	public static String PASSWORD = "password";
	
	public static void main(String[] args) {
		// Connect to JIRA
		final JiraRestClientFactory jiraRestClientFactory = new AsynchronousJiraRestClientFactory();
		JiraRestClient jiraRestClient = jiraRestClientFactory
				.createWithBasicHttpAuthentication(URI.create(URL),
						USERNAME, PASSWORD);
		
		// List Projects
		try {
			Iterable projects = jiraRestClient.getProjectClient().getAllProjects().get();
			for(BasicProject project: projects) {
				System.out.println("Project Name:"+project.getName());
			}
		} catch (Exception e) {
			e.printStackTrace();
		} 
		
		// Close connection
		try {
			jiraRestClient.close();
		} catch (Exception ex) { }
	}
}

If this compiles, you will find this one file adapter useful to get up and running quickly. This code grabs a default project, then grabs a default issueType, then fills in the required fields and creates a new issue.


import java.net.URI;
import java.util.Arrays;
import com.atlassian.jira.rest.client.api.GetCreateIssueMetadataOptions;
import com.atlassian.jira.rest.client.api.GetCreateIssueMetadataOptionsBuilder;
import com.atlassian.jira.rest.client.api.IssueRestClient;
import com.atlassian.jira.rest.client.api.JiraRestClient;
import com.atlassian.jira.rest.client.api.JiraRestClientFactory;
import com.atlassian.jira.rest.client.api.SearchRestClient;
import com.atlassian.jira.rest.client.api.domain.BasicIssue;
import com.atlassian.jira.rest.client.api.domain.BasicIssueType;
import com.atlassian.jira.rest.client.api.domain.BasicProject;
import com.atlassian.jira.rest.client.api.domain.CimFieldInfo;
import com.atlassian.jira.rest.client.api.domain.CimIssueType;
import com.atlassian.jira.rest.client.api.domain.CimProject;
import com.atlassian.jira.rest.client.api.domain.Comment;
import com.atlassian.jira.rest.client.api.domain.CustomFieldOption;
import com.atlassian.jira.rest.client.api.domain.EntityHelper;
import com.atlassian.jira.rest.client.api.domain.Issue;
import com.atlassian.jira.rest.client.api.domain.SearchResult;
import com.atlassian.jira.rest.client.api.domain.input.ComplexIssueInputFieldValue;
import com.atlassian.jira.rest.client.api.domain.input.IssueInput;
import com.atlassian.jira.rest.client.api.domain.input.IssueInputBuilder;
import com.atlassian.jira.rest.client.internal.async.AsynchronousJiraRestClientFactory;

/**
 * This class can be used to check connectivity with Jira and create an issue
 * @author sizu
 *
 */
public class JiraController {
	public static JiraLoginCredentials LC = new JiraLoginCredentials(
			"http://my.jira.url.com",
			"username",
			"password"
			);
	public static void main(String[] args) {
		BasicProject dummyProject = findProjects(LC).iterator().next();
		BasicIssueType dummyIssueType = findIssueTypesByProjectKey(LC, dummyProject.getKey()).iterator().next();
		CimIssueType issueType = JiraController.findIssueTypeByIssueID(LC, dummyProject.getKey(), dummyIssueType.getId());

		// Create New Issue
		IssueInputBuilder issueBuilder = new IssueInputBuilder(dummyProject.getKey(), dummyIssueType.getId());
		for (String key : issueType.getFields().keySet()) {
			CimFieldInfo issueField = issueType.getFields().get(key);
			String fieldID = issueField.getId();
			if(fieldID.equals("project")) { // Skip the project field since it is already filled when issueBuilder was created
				continue;
			}
			
			if (issueField.isRequired()) {
				try {
					// Get allowed value for the required field
					String allowedValue = null;
					for(Object object: issueField.getAllowedValues()) {
						if(object instanceof CustomFieldOption) {
							CustomFieldOption cfo = (CustomFieldOption) object;
							allowedValue = ""+cfo.getId(); // Convert Long to String format
						}
					}
					
					ComplexIssueInputFieldValue value = ComplexIssueInputFieldValue.with("id", allowedValue);
					if(issueField.getSchema().getType().equals("array")) {
						issueBuilder.setFieldValue(fieldID, Arrays.asList(value));
					} else {
						issueBuilder.setFieldValue(fieldID, value);
					}
				} catch (Exception ex) {
					// Does not have allowed value
					issueBuilder.setFieldValue(fieldID, "Test");
				}
			}
		}
		BasicIssue basicIssue = JiraController.createIssue(LC, issueBuilder.build());
		System.out.println("Key:"+basicIssue.getKey()+" ID:"+basicIssue.getId());
	}
	
	public static BasicIssue createIssue(JiraLoginCredentials lc, IssueInput newIssue) {
		JiraRestClient jiraRestClient = createJiraRestClient(lc);
		BasicIssue basicIssue = jiraRestClient.getIssueClient().createIssue(newIssue).claim();
		destroyJiraRestClient(jiraRestClient);
		return basicIssue;
	}
	
	public static void addCommentToIssue(JiraLoginCredentials lc, Issue issue, String comment) {
		JiraRestClient jiraRestClient = createJiraRestClient(lc);
		IssueRestClient issueClient = jiraRestClient.getIssueClient();
		issueClient.addComment(issue.getCommentsUri(), Comment.valueOf(comment)).claim();
		destroyJiraRestClient(jiraRestClient);
	}
	
	public static void deleteIssue(JiraLoginCredentials lc, Issue issue) {
		JiraRestClient jiraRestClient = createJiraRestClient(lc);
		IssueRestClient issueClient = jiraRestClient.getIssueClient();
		issueClient.deleteIssue(issue.getKey(), false).claim();
		destroyJiraRestClient(jiraRestClient);
	}

	public static Iterable findIssuesByLabel(JiraLoginCredentials lc, String label) {
		JiraRestClient jiraRestClient = createJiraRestClient(lc);
		SearchRestClient searchClient = jiraRestClient.getSearchClient();
		String jql = "labels%3D"+label;
		SearchResult results = searchClient.searchJql(jql).claim();
		destroyJiraRestClient(jiraRestClient);
    	return results.getIssues();
	}

	public static Issue findIssueByIssueKey(JiraLoginCredentials lc, String issueKey) {
		JiraRestClient jiraRestClient = createJiraRestClient(lc);
		SearchRestClient searchClient = jiraRestClient.getSearchClient();
		String jql = "issuekey = \"" + issueKey + "\"";
		SearchResult results = searchClient.searchJql(jql).claim();
		destroyJiraRestClient(jiraRestClient);
    	return results.getIssues().iterator().next();
	}

	public static Iterable findProjects(JiraLoginCredentials lc) {
		JiraRestClient jiraRestClient = createJiraRestClient(lc);
		Iterable projects = null;
		try {
			projects = jiraRestClient.getProjectClient().getAllProjects().get();
		} catch (Exception e) {
			e.printStackTrace();
		}
		destroyJiraRestClient(jiraRestClient);
		return projects;
	}

	public static Iterable findIssueTypesByProjectKey(JiraLoginCredentials lc,
			String projectKey) {
		JiraRestClient jiraRestClient = createJiraRestClient(lc);
		GetCreateIssueMetadataOptions options = new GetCreateIssueMetadataOptionsBuilder()
				.withExpandedIssueTypesFields()
				.withProjectKeys(projectKey)
				.build();

		Iterable cimProjects = jiraRestClient.getIssueClient()
				.getCreateIssueMetadata(options).claim();

		CimProject project = cimProjects.iterator().next();
		Iterable issueTypes = project.getIssueTypes();
		destroyJiraRestClient(jiraRestClient);
		return issueTypes;
	}

	public static CimIssueType findIssueTypeByIssueID(JiraLoginCredentials lc,
			String projectKey, Long issueTypeID) {
		Iterable issueTypes = (Iterable) findIssueTypesByProjectKey(lc, projectKey);
		return EntityHelper.findEntityById(issueTypes, issueTypeID);
	}

	public static CimFieldInfo findIssueFieldByIssueFieldID(JiraLoginCredentials lc,
			String projectKey, Long issueTypeID, String issueFieldID) {
		CimIssueType issueType = findIssueTypeByIssueID(lc,projectKey, issueTypeID);
		return issueType.getFields().get(issueFieldID);
	}
	
	private static JiraRestClient createJiraRestClient(JiraLoginCredentials lc) {
		final JiraRestClientFactory jiraRestClientFactory = new AsynchronousJiraRestClientFactory();
		return jiraRestClientFactory
				.createWithBasicHttpAuthentication(URI.create(lc.getUrl()),
						lc.getUsername(), lc.getPassword());
	}

	private static void destroyJiraRestClient(JiraRestClient jiraRestClient) {
		try {
			jiraRestClient.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public static class JiraLoginCredentials {
		private String url;
		private String username;
		private String password;
		public JiraLoginCredentials(String url, String username, String password) {
			super();
			this.url = url;
			this.username = username;
			this.password = password;
		}
		public String getUrl() {
			return url;
		}
		public String getUsername() {
			return username;
		}
		public String getPassword() {
			return password;
		}
		
	}
}

It may be that you would like your code to make a connection one time, then leave that connection open and reuse it. This code encapsulates the jiraClient connection, creating the client and destroying the client on demand.