I had a request to integrate Jira into company application. The request is to use OAuth, and to be able to use Jira API, with accent to use "create issue" call.
I'll provide source later, just to emphasize that for use a POST call I've encountered problems with json, and I had to use com.google.api.client.util.GenericData
in order to make proper creation of issue.
Code excerpt :
@PropertySource("classpath:/JiraApiCalls/calls.properties")
@Service
public class JiraService {
//<editor-fold desc="infra">
@Autowired
JiraClient jiraClient;
//<editor-fold desc="Api Business Calls">
@Value("${GET_ISSUE_BY_KEY_URL}")
String apiCallIssueByKey;
@Value("${SITE_ID_AND_PORTFOLIO_SEARCH_JQL_WITH_OR}")
String apiCallSiteIdAndPortfolioSearchJQLWithOr;
@Value("${OR_SITE_ID}")
String apiCallOrSiteId;
@Value("${SEARCH_ISSUES_URL}")
String searchIssuesKey;
@Value("${DASHBOARDS}")
String apiCallAllDashboard;
@Value("${PROJECTS}")
String apiCallAllProjects;
@Value("${PROJECT}")
String apiCallProjectById;
@Value("${ISSUETYPES}")
String apiCallAllIssueTypes;
@Value("${ISSUETYPE}")
String apiCallApiIssueType;
@Value("${ISSUE_CREATE}")
String apiCallIssueCreate;
//</editor-fold>
//<editor-fold desc="Definitions : Jira concrete usage">
static final List<String> ISSUE_FIELDS = Arrays.asList(
"status", "creator", "reporter", "assignee", "description",
"summary", "customfield_11110", "customfield_11126", "components"
);
public JiraSingleResultIssueDto getIssueByKey(String key) {
String issueApiMethodCallUrl = MessageFormat.format( apiCallIssueByKey, key );
JiraSingleResultIssueDto dto = jiraClient.executeGet( JiraSingleResultIssueDto.class, issueApiMethodCallUrl );
return dto;
}
public AllDashboardsDto getAllDashboards() {
return jiraClient.executeGet( AllDashboardsDto.class, apiCallAllDashboard );
}
public List<ProjectDto> getAllProjects() {
List<ProjectDto> projects = jiraClient.executeGetExpectingList( apiCallAllProjects );
return projects;
}
public ProjectDto getProjectByKey(Object key) {
ProjectDto project = jiraClient.executeGet( ProjectDto.class, MessageFormat.format( apiCallProjectById, String.valueOf( key ) ) );
return project;
}
public List<JiraIssueTypeDto> getAllIssueTypes() {
List<JiraIssueTypeDto> issueTypes = jiraClient.executeGetExpectingList( apiCallAllIssueTypes );
return issueTypes;
}
public JiraIssueTypeDto getIssueType(Object key) {
JiraIssueTypeDto issueType = jiraClient.executeGet( JiraIssueTypeDto.class, MessageFormat.format( apiCallApiIssueType, String.valueOf( key ) ) );
return issueType;
}
public IssueCreatedResponseDto createIssue(IssueDto issueDto) throws Exception {
GenericData issueData = new GenericData();
try {
// check for existing Project, and carry on if it exists...
ProjectDto projectDto = getProjectByKey( issueDto.getFields().getProject().getId() );
GenericData projectData = new GenericData();
projectData.put( "key", projectDto.getKey() );
// check for existing issue type, and carry on with no errors..
Long issueId = issueDto.getFields().getIssuetype().getId();
getIssueType( issueId );
GenericData issueTypeData = new GenericData();
issueTypeData.put( "id", issueId );
GenericData fieldsData = new GenericData();
fieldsData.set( "summary", issueDto.getFields().getSummary() );
fieldsData.set( "description", issueDto.getFields().getDescription() );
fieldsData.set( "issuetype", issueTypeData );
fieldsData.set( "project", projectData );
issueData.put( "fields", fieldsData );
IssueCreatedResponseDto issueResponse = jiraClient.executePost( IssueCreatedResponseDto.class, apiCallIssueCreate, issueData );
return issueResponse;
} catch (Exception e) {
throw new Exception( e );
}
}
}
Jira client :
@Component
public class JiraClient {
private static Logger LOGGER = Logger.getLogger( JiraClient.class.getName() );
//<editor-fold desc="oauth 1.0 credentials">
@Value("${jira_home}")
String JIRA_HOME_URL;
@Value("${jira_base_url}")
String JIRA_ENDPOINT_URL;
@Value("${jira_access_token}")
String JIRA_ACCESS_TOKEN;
@Value("${jira_secret}")
String JIRA_SECRET_KEY;
@Value("${jira_consumer_key}")
String JIRA_CONSUMER_KEY;
@Value("${jira_private_key}")
String JIRA_PRIVATE_KEY;
//</editor-fold>
@Value("${datetimeformat}")
private String dateTimeFormat;
JSONUtils jsonUtils;
JiraOAuthClient jiraOAuthClient;
@PostConstruct
void jiraOAuthClientInit() {
if (jiraOAuthClient == null) {
try {
jiraOAuthClient = new JiraOAuthClient( JIRA_HOME_URL );
} catch (Exception e) {
String errMsg = "Jira OAuth Client Error.";
LOGGER.log( Level.WARNING, errMsg, e );
throw new RuntimeException( errMsg + e );
}
}
jsonUtils = new JSONUtils( dateTimeFormat );
}
//<editor-fold desc="Infra : Basic Get/Post Request support methods">
public HttpResponse handleGetRequest(String apiMethodCallUrl) {
try {
OAuthParameters parameters = jiraOAuthClient.getParameters( JIRA_ACCESS_TOKEN, JIRA_SECRET_KEY, JIRA_CONSUMER_KEY, JIRA_PRIVATE_KEY );
HttpResponse response = getResponseFromUrl( parameters, new GenericUrl( apiMethodCallUrl ) );
return response;
} catch (Exception e) {
String errMsg = "Handle GetRequest Error.";
LOGGER.log( Level.WARNING, errMsg, e );
return null;
}
}
public HttpResponse handlePostRequest(String apiMethodCallUrl, HttpContent requestContent) {
try {
OAuthParameters parameters = jiraOAuthClient.getParameters( JIRA_ACCESS_TOKEN, JIRA_SECRET_KEY, JIRA_CONSUMER_KEY, JIRA_PRIVATE_KEY );
HttpResponse response = postResponseFromUrl( parameters, new GenericUrl( apiMethodCallUrl ), requestContent );
return response;
} catch (Exception e) {
String errMsg = "Handle PostRequest Error.";
LOGGER.log( Level.WARNING, errMsg, e );
return null;
}
}
private HttpResponse getResponseFromUrl(OAuthParameters parameters, GenericUrl jiraUrl) throws IOException {
HttpRequestFactory requestFactory = new NetHttpTransport().createRequestFactory( parameters );
HttpRequest request = requestFactory.buildGetRequest( jiraUrl );
return request.execute();
}
private HttpResponse postResponseFromUrl(OAuthParameters parameters, GenericUrl jiraUrl, HttpContent requestContent) throws IOException {
HttpRequestFactory requestFactory = new NetHttpTransport().createRequestFactory( parameters );
HttpRequest request = requestFactory.buildPostRequest( jiraUrl, requestContent );
return request.execute();
}
//</editor-fold>
//<editor-fold desc="Advanced Get/Post methods">
//<editor-fold desc="Generic universal call/response">
private HttpResponse executeGetAndReturnHttpResponse(@NonNull String apiMethodCallUrl) {
return handleGetRequest( JIRA_ENDPOINT_URL + apiMethodCallUrl );
}
//</editor-fold>
/**
* Custom GET call, expecting result of a type T<br>
*
* @param apiMethodCallUrl Url defined by the user.<br>
* Usage example :<br>
* Api call, and two parameters defined at {0} and {1} positions:<br>
* SITE_ID_AND_PORTFOLIO_SEARCH_JQL_WITH_OR=Portfolio = {0} AND ("Site ID" ~ "0"{1})<br>
* For proper usage, MessageFormat.format( apiCall_Name, apiCall_Parameters) may be used.<br>
*/
public <T> T executeGet(Class<T> clazz, String apiMethodCallUrl) {
try {
HttpResponse jsonResponse = executeGetAndReturnHttpResponse( apiMethodCallUrl );
if (jsonResponse == null) {
return null;
}
return jsonUtils.parseResponse( jsonResponse, clazz );
} catch (Exception e) {
String errMsg = "Executing Get Request Error.";
LOGGER.log( Level.SEVERE, errMsg, e );
throw new RuntimeException( errMsg, e );
}
}
//<editor-fold desc="Default GET call with path variables injected into call, for returning Lists of objects">
/**
* Custom GET call, expecting list result.<br>
*
* @param apiMethodCallUrl Url defined by user.<br>
* Usage example :<br>
* Api call, with no parameters defined in api call "apiCallAllProjects",<br>
* so there is no need for formating rest method call with parameters.<br>
* If there was a need, look at {@link JiraClient#executeGet)
*/
public <T> List<T> executeGetExpectingList(@NonNull String apiMethodCallUrl) {
try {
HttpResponse jsonResponse = executeGetAndReturnHttpResponse( apiMethodCallUrl );
if (jsonResponse == null) {
return null;
}
return jsonUtils.parseResponseAsList( jsonResponse );
} catch (Exception e) {
String errMsg = "Executing Get Request Error.";
LOGGER.log( Level.SEVERE, errMsg, e );
throw new RuntimeException( errMsg, e );
}
}
//</editor-fold>
//<editor-fold desc="POST">
public HttpResponse executePostRequest(@NonNull String postOperationName, @NonNull GenericData contentGenericData) {
String apiCallUrlPath = JIRA_ENDPOINT_URL + postOperationName;
try {
OAuthParameters parameters = jiraOAuthClient.getParameters( JIRA_ACCESS_TOKEN, JIRA_SECRET_KEY, JIRA_CONSUMER_KEY, JIRA_PRIVATE_KEY );
HttpContent content = new JsonHttpContent( new JacksonFactory(), contentGenericData );
HttpResponse response = postResponseFromUrl( parameters, new GenericUrl( apiCallUrlPath ), content );
return response;
} catch (HttpResponseException hre) {
String errMsg = "Executing Post Request Error. " + hre;
LOGGER.log( Level.SEVERE, errMsg, hre );
throw new RuntimeException( errMsg, hre );
} catch (Exception e) {
String errMsg = "Executing Get Request, no result.";
LOGGER.log( Level.INFO, errMsg, e );
throw new RuntimeException( errMsg, e );
}
}
public <T> T executePost(Class<T> clazz, @NonNull String postOperationName, @NonNull GenericData contentGenericData) {
try {
HttpResponse jsonResponse = executePostRequest( postOperationName, contentGenericData );
if (jsonResponse == null) {
return null;
}
return jsonUtils.parseResponse( jsonResponse, clazz );
} catch (Exception e) {
String errMsg = "Executing Post Request Error.";
LOGGER.log( Level.WARNING, errMsg, e );
throw new RuntimeException( errMsg, e );
}
}
//</editor-fold>
//</editor-fold>
}