General resource code sample

This sample Java code shows the process of:

  • Creating a release, and checking the number of backlog items assigned to the release;
  • Creating a new user story, and assigning it to the release;
  • Deleting the new user story, and then deleting the release.

Note: To run this example, make sure you have access to the Agile Manager server, an application listed on the API configuration page, and the correct client ID and secret. You must define this information at the beginning of the example.

package integration_tests.org.hpe.apm.integrationtest.test.ApmUIServices;


 import org.apache.commons.codec.binary.Base64; 
 import org.apache.http.HttpStatus; 
 import org.json.JSONArray; 
 import org.json.JSONException; 
 import org.json.JSONObject; 

 import javax.ws.rs.HttpMethod; 
 import javax.ws.rs.core.MediaType; 
 import java.io.BufferedReader; 
 import java.io.DataOutputStream; 
 import java.io.IOException; 
 import java.io.InputStreamReader; 
 import java.net.HttpURLConnection; 
 import java.net.URL; 
 import java.text.ParseException; 
 import java.text.SimpleDateFormat; 
 import java.util.ArrayList; 
 import java.util.Date; 
 import java.util.HashMap; 
 import java.util.Map; 

 /** 
 * This Agile Manager public API example does the following: 
 * Create a new release (POST on release) 
 * Check number of backlog items assigned to the release (GET on backlog_item) 
 * Create a new user story (POST on backlog_item) 
 * Assign the user story to the release (PUT on backlog_item) 
 * Delete the user story (DELETE on backlog_item) 
 * Delete the release (DELETE on release) 
 * In order to run this example you must make sure you have access to the Agile Manager server and that you have created an API application
 * and has the correct API secret. You will need to set this information in the static members in the beginning of the example.
 */
 public class PublicAPIExample {
 //Fill in the correct values
 private static String SERVER_URL_PREFIX="<http(s)>://<server>:<port>"; 
 private static String CLIENT_ID = "<client id>"; 
 private static String CLIENT_SECRET = "<secret>"; 

 private static int DEFAULT_WORKSPACE_ID=1000; 
 private static String DATE_FORMAT="yyyy-MM-dd"; 
 private final SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DATE_FORMAT);


 public static void main(String args[]){ 
    PublicAPIExample main= new PublicAPIExample(); 
    try {
        main.start(CLIENT_ID, CLIENT_SECRET); 
    } catch (Exception e) {
          e.printStackTrace(); 
    } 
 } 

 /** 
 * This example does the following: 
 * Create a new release (POST on release) 
 * Check number of backlog items assigned to the release (GET on backlog_item) 
 * Create a new user story (POST on backlog_item) 
 * Assign the user story to the release (PUT on backlog_item) 
 * Delete the user story (DELETE on backlog_item) 
 * Delete the release (DELETE on release) 
 * @param clientId 
 * @param clientSecret 
 * @throws IOException 
 * @throws JSONException 
 * @throws ParseException 
 */
 public void start(String clientId, String clientSecret) throws IOException, JSONException, ParseException {
     //get the token needed for every request 
     AccessToken token = getAccessTokenWithFormFormat(clientId, clientSecret); 
     //create release - POST on release 
     ReleaseEntity release = createRelease(token); 
     //check items on release (should be none - new release) - GET on backlog_item
     ArrayList<UserStoryBacklogItemEntity> itemsInRelease=getItemsInRelease(token,release.getId());
     verifyResult(0,itemsInRelease.size()); 
     //create user story - POST on backlog_item 
     UserStoryBacklogItemEntity userStory = createUserStory(token); 
     //assign user story to release - PUT on backlog_item 
     assignUserStoryToRelease(token, userStory.getId(), release.getId()); 
     //check items on release (should be one) - GET on backlog_item
     itemsInRelease=getItemsInRelease(token,release.getId()); 
     verifyResult(1,itemsInRelease.size()); 
     //delete user story - DELETE on backlog_item 
     deleteUserStory(token, userStory.getId()); 
     //delete release - DELETE on release 
     deleteRelease(token,release.getId()); 
 } 


 /** 
 * Delete a given release using DELETE REST request 
 * @param token the security token needed for every REST request 
 * @param releaseId - the id of the release to be deleted 
 * @throws IOException 
 */
 public void deleteRelease(AccessToken token, int releaseId) throws IOException {
     //http(s)://<server>:<port>/agm/api/workspaces/<workspace_id>/releases/<release_id> 
     String url=String.format("%s/agm/api/workspaces/%d/releases/%d",SERVER_URL_PREFIX,DEFAULT_WORKSPACE_ID,releaseId); 
     Map<String, String> headers = createHeader(token); 
     RestResponse response = sendRequest(url, HttpMethod.DELETE, null, headers);
     verifyResult(HttpStatus.SC_OK,response.getStatusCode()); 
 } 

 /** 
 * Delete a given user story using DELETE REST request 
 * @param token the security token needed for every REST request 
 * @param userStoryId the id of the user story to be deleted 
 * @throws IOException 
 */
 public void deleteUserStory(AccessToken token, int userStoryId) throws IOException {
     //http(s)://<server>:<port>/agm/api/workspaces/<workspace_id>/backlog_items/<user_story_id> 
     String url=String.format("%s/agm/api/workspaces/%d/backlog_items/%d",SERVER_URL_PREFIX,DEFAULT_WORKSPACE_ID,userStoryId); 
     Map<String, String> headers = createHeader(token); 
     RestResponse response = sendRequest(url, HttpMethod.DELETE, null, headers);
     verifyResult(HttpStatus.SC_OK,response.getStatusCode()); 
 } 

 /** 
 * Assign a given user story to a given release using the PUT REST request 
 * @param token the security token needed for every REST request 
 * @param userStoryId the id of the user story needed to be assigned to the release 
 * @param releaseId the id of the release the user story needs to be assigned to 
 * @throws IOException 
 * @throws JSONException 
 */
 public void assignUserStoryToRelease(AccessToken token, int userStoryId, int releaseId) throws IOException, JSONException {
     //http(s)://<server>:<port>/agm/api/workspaces/<workspace_id>/backlog_items/<user_story_id> 
     String url=String.format("%s/agm/api/workspaces/%d/backlog_items/%d",SERVER_URL_PREFIX,DEFAULT_WORKSPACE_ID,userStoryId); 
     //{"release_id": "<release_id>"} 
     String body=String.format("{\"release_id\": \"%s\"}",releaseId); 
     Map<String, String> headers = createHeader(token); 
     RestResponse response = sendRequest(url, HttpMethod.PUT, body, headers);  
     verifyResult(HttpStatus.SC_OK,response.getStatusCode()); 

 } 

 /** 
 * Creates a new user story using the POST REST request 
 * @param token the security token needed for every REST request 
 * @return the new created user story 
 * @throws IOException 
 * @throws JSONException 
 */
 public UserStoryBacklogItemEntity createUserStory(AccessToken token) throws IOException, JSONException, ParseException {
 UserStoryBacklogItemEntity newUserStory=new UserStoryBacklogItemEntity(); 
 newUserStory.setName("my story"); 
     //http(s)://<server>:<port>/agm/api/workspaces/<workspace_id>/backlog_items
     String url=String.format("%s/agm/api/workspaces/%d/backlog_items",SERVER_URL_PREFIX,DEFAULT_WORKSPACE_ID); 
     //{ "data":[{"subtype" : "user_story", "name" : "my story" }]} 
     String body=newUserStory.generateBody(); 
     Map<String, String> headers = createHeader(token); 
     RestResponse response = sendRequest(url, HttpMethod.POST, body, headers); 
     verifyResult(HttpStatus.SC_CREATED,response.getStatusCode()); 
     ArrayList<UserStoryBacklogItemEntity> items = UserStoryBacklogItemEntity.createListFromJson(response.getData());
     return items.get(0);
 } 

 /** 
 * Returns a list of all user stories assigned to a given release. Uses the GET REST request 
 * @param token the security token needed for every REST request 
 * @param releaseId the id of the release from which to get all the user stories 
 * @return a list of all user stories of the release 
 * @throws IOException 
 * @throws JSONException 
 * @throws ParseException 
 */
 public ArrayList<UserStoryBacklogItemEntity> getItemsInRelease(AccessToken token,int releaseId) throws IOException, JSONException, ParseException {
     //http(s)://<server>:<port>/agm/api/workspaces/<workspace_id>/backlog_items?query="release_id=<release_id>" 
     String url=String.format("%s/agm/api/workspaces/%d/backlog_items?query=\"release_id=%d\"",SERVER_URL_PREFIX,DEFAULT_WORKSPACE_ID, releaseId); 
     Map<String, String> headers = createHeader(token); 
     RestResponse response = sendRequest(url, HttpMethod.GET, null, headers);
     verifyResult(HttpStatus.SC_OK,response.getStatusCode()); 
     return UserStoryBacklogItemEntity.createListFromJson(response.getData());
 } 

 /** 
 * Creates a new release starting today ending in 60 days, having a sprint every two weeks. Uses the POST REST request
 * @param token the security token needed for every REST request 
 * @return the newly created release 
 * @throws IOException 
 * @throws JSONException 
 * @throws ParseException 
 */
 public ReleaseEntity createRelease(AccessToken token) throws IOException, JSONException, ParseException {
     ReleaseEntity result=null; 
     ReleaseEntity newRelease=new ReleaseEntity(); 
     newRelease.setName("new release"); 
     newRelease.setDescription("new release description"); 
     newRelease.setStartDate(addToToday(0)); 
     newRelease.setEndDate(addToToday(60)); 
     newRelease.setSprintDuration(2); 
     newRelease.setSprintDurationUnits(SprintDurationUnitsEnum.WEEKS); 
     //http(s)://<server>:<port>/agm/api/workspaces/<workspace_id>/releases
     String url=String.format("%s/agm/api/workspaces/%d/releases",SERVER_URL_PREFIX,DEFAULT_WORKSPACE_ID); 
     //{ "data":[{"name": "new release", "description": "new release description", "start_date": "2015-06-25", "end_date": "2015-08-24", "sprint_duration": "2", "sprint_duration_units" : "Weeks" }]} 
     String body=newRelease.generateBody(); 
     Map<String, String> headers = createHeader(token); 
     RestResponse response = sendRequest(url, HttpMethod.POST, body, headers); 
     verifyResult(HttpStatus.SC_CREATED,response.getStatusCode()); 
     result=ReleaseEntity.createFromJson(response.getData()); 
     return result; 
 } 


 /** 
 * Creates the token needed for all REST requests, using form format 
 * @param clientId the client id of the application wanting to access Agile Manager
 * @param clientSecret the secret of the client 
 * @return an access token object holding the needed token information for all REST requests 
 * @throws IOException 
 * @throws JSONException 
 */
 private AccessToken getAccessTokenWithFormFormat(String clientId, String clientSecret) throws IOException, JSONException {
     //http(s)://<server>:<port>/agm/oauth/token
     String url = String.format("%s/agm/oauth/token",SERVER_URL_PREFIX); 
     //client_id=<client_id>&client_secret=<client_secret>&grant_type=client_credentials
     String data = String.format("client_id=%s&client_secret=%s&grant_type=client_credentials", clientId, clientSecret); 
     Map<String, String> headers = new HashMap<>(); 
     headers.put("Content-Type", MediaType.APPLICATION_FORM_URLENCODED); 
     RestResponse response = sendRequest(url, HttpMethod.POST, data, headers); 
     verifyResult(HttpStatus.SC_OK,response.getStatusCode()); 
     return AccessToken.createFromJson(response.getData());
 } 

 /** 
 * Creates the token needed for all REST requests, using basic authentication 
 * @param clientId the client id of the application wanting to access Agile Manager 
 * @param clientSecret the secret of the client 
 * @return an access token object holding the needed token information for all REST requests 
 * @throws IOException 
 * @throws JSONException 
 */
 private AccessToken getAccessTokenWithBasicAuthentication(String clientId, String clientSecret) throws IOException, JSONException {
     //http(s)://<server>:<port>/agm/oauth/token?grant_type=client_credentials 
     String url = String.format("%s/agm/oauth/token?grant_type=client_credentials",SERVER_URL_PREFIX); 
     Map<String, String> headers = new HashMap<>(); 
     String secret = String.format("%s:%s", clientId, clientSecret); 
     String base64Secret = new String(Base64.encodeBase64(secret.getBytes()));
     headers.put("Authorization", "Basic " + base64Secret); 
     RestResponse response = sendRequest(url, HttpMethod.GET, null, headers);
     verifyResult(HttpStatus.SC_OK,response.getStatusCode()); 
     return AccessToken.createFromJson(response.getData());
 } 


 /** 
 * Sends a request to the server 
 * @param url the url of the request 
 * @param method the REST request method 
 * @param data the data of the request 
 * @param headers the headers of the request 
 * @return the result of the request, as returned from the server 
 * @throws IOException 
 */
 private RestResponse sendRequest(String url, String method, String data, Map<String, String> headers) throws IOException {

     URL obj = new URL(url); 
     HttpURLConnection con = (HttpURLConnection) obj.openConnection(); 
     con.setRequestMethod(method); 

     //set headers
     if (headers != null) {
         for (Map.Entry<String, String> entry : headers.entrySet()) {
             con.setRequestProperty(entry.getKey(), entry.getValue()); 
         } 
      } 

     //set data
     if (data != null) {
         con.setDoOutput(true); 
         DataOutputStream wr = new DataOutputStream(con.getOutputStream());
         wr.writeBytes(data); 
         wr.flush(); 
         wr.close(); 
     } 

     int responseCode = con.getResponseCode(); 
     // System.out.print("Response code is " + responseCode); 

     BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
     String inputLine; 
     StringBuffer response = new StringBuffer(); 

     while ((inputLine = in.readLine()) != null) { 
         response.append(inputLine); 
     } 
     in.close(); 

     String output = response.toString(); 
     return new RestResponse(responseCode, output);

 } 

 private void verifyResult(int expected, int result) {
     if(expected!=result) 
     { 
         throw new RuntimeException(String.format("Incorrect value. Expected:%d, Result:%d", expected, result)); 
     } 
 } 

 /** 
 * Adds the number of days to given date and return the result date as string formatted for the API.
 * 
 * @param days the number of days to be added (can be negative) 
 * @return the new date. 
 */
 private String addToToday(int days) {
     long currentTimeMillis = System.currentTimeMillis(); 
     long dayInMili = 1000 * 60 * 60 * 24;
     long newTime = currentTimeMillis + (days * dayInMili);
     Date date = new Date(newTime); 
     return simpleDateFormat.format(date); 
 } 

 /** 
 * Creates the headers for the REST requests 
 * @param token the security token needed for every REST request 
 * @return a map holding all the header parameters 
 */
 private Map<String, String> createHeader(AccessToken token) {
     Map<String, String> headers = new HashMap<>(); 
     headers.put("Authorization", "bearer " + token.getAccessToken()); 
     headers.put("Content-Type", MediaType.APPLICATION_JSON); 
     return headers; 
 } 

 /** 
 * Holds the rest response data 
 */
 public static class RestResponse{
     private int statusCode;
     private String data; 

     public RestResponse(int statusCode, String data) {
         this.statusCode = statusCode; 
         this.data = data; 
     } 

     public int getStatusCode() {
         return statusCode; 
     } 

     public String getData() { 
         return data; 
     } 
 } 

 /** 
 * Holds access token information 
 */
 public static class AccessToken {

     private String accessToken; 
     private String tokenType; 
     private int expiresIn;       
     private String scope; 

     public AccessToken(String accessToken, String tokenType, int expiresIn, String scope) {
         this.accessToken = accessToken; 
         this.tokenType = tokenType; 
         this.expiresIn = expiresIn; 
         this.scope = scope; 
     } 

     public String getAccessToken() { 
         return accessToken; 
     } 

     public String getTokenType() {   
         return tokenType; 
     } 

     public int getExpiresIn() {
         return expiresIn; 
     } 

     public String getScope() { 
         return scope; 
     } 

     public static AccessToken createFromJson(String json) throws JSONException {
         JSONObject obj = new JSONObject(json); 
         return new AccessToken(obj.getString("access_token"), obj.getString("token_type"), obj.getInt("expires_in"), obj.getString("scope")); 
     } 
 } 

 /** 
 * Holds the release data 
 */
 public static class ReleaseEntity{
     private int id; 
     private String name; 
     private String description; 
     private String startDate; 
     private String endDate; 
     private int sprintDuration;
     private SprintDurationUnitsEnum sprintDurationUnits; 

    public int getId() {
        return id; 
    } 

     public void setId(int id) {
         this.id = id; 
     } 

     public String getName() { 
         return name; 
     } 

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

     public String getDescription() { 
         return description; 
     } 

     public void setDescription(String description) {
         this.description = description; 
     } 

     public String getStartDate() { 
         return startDate; 
     } 

     public void setStartDate(String startDate) {
         this.startDate = startDate; 
     } 

     public String getEndDate() { 
         return endDate; 
     } 

     public void setEndDate(String endDate) {
         this.endDate = endDate; 
     } 

     public int getSprintDuration() {
         return sprintDuration; 
     } 

     public void setSprintDuration(int sprintDuration) {
         this.sprintDuration = sprintDuration; 
     } 

     public SprintDurationUnitsEnum getSprintDurationUnits() {
         return sprintDurationUnits; 
     } 

     public void setSprintDurationUnits(SprintDurationUnitsEnum sprintDurationUnits) {
         this.sprintDurationUnits = sprintDurationUnits; 
     } 


     public String generateBody(){ 
         StringBuffer sb=new StringBuffer(); 
         sb.append("{ \"data\":[{"); 
         sb.append(String.format("\"name\": \"%s\", ",getName())); 
         sb.append(String.format("\"description\": \"%s\", ",getDescription())); 
         sb.append(String.format("\"start_date\": \"%s\", ",getStartDate())); 
         sb.append(String.format("\"end_date\": \"%s\", ",getEndDate())); 
         sb.append(String.format("\"sprint_duration\": \"%d\", ",getSprintDuration())); 
         sb.append(String.format("\"sprint_duration_units\" : \"%s\" ",getSprintDurationUnits().getText())); 
         sb.append("}]}"); 
         return sb.toString(); 
     } 

     public static ReleaseEntity createFromJson(String json) throws JSONException, ParseException {
         JSONObject obj = new JSONObject(json); 
         JSONArray arr = obj.getJSONArray("data"); 
         JSONObject item= (JSONObject) arr.get(0); 
         ReleaseEntity result=new ReleaseEntity(); 
         result.setId(item.getInt("id")); 
         result.setName(item.getString("name")); 
         result.setDescription(item.getString("description")); 
         result.setStartDate(item.getString("start_date")); 
         result.setEndDate(item.getString("end_date")); 
         result.setSprintDuration(item.getInt("sprint_duration")); 
         String sprintDurationUnits = item.getString("sprint_duration_units"); 
         result.setSprintDurationUnits(SprintDurationUnitsEnum.fromText(sprintDurationUnits));
         return result; 
     } 
 } 

 public static enum SprintDurationUnitsEnum{

     DAYS("Days"),WEEKS("Weeks"); 

     private String text; 

     SprintDurationUnitsEnum(String text) { 
         this.text = text; 
     } 

      public String getText() { 
         return text; 
     } 

     public static SprintDurationUnitsEnum fromText(String text){ 
         SprintDurationUnitsEnum result=null; 
         if(text!=null){
             for (SprintDurationUnitsEnum item:SprintDurationUnitsEnum.values()){ 
                 if(text.equalsIgnoreCase(item.getText())){
                     result= item; 
                    break; 
                 } 
             } 
         } 
         return result; 
     } 

 } 

 /** 
 * Holds the user story data 
 */
 public static class UserStoryBacklogItemEntity {
     private final String subtype="user_story"; 
     private int id; 
     private String name; 
     private Integer releaseId; 
     //There are more fields, just used the basic
     public String getSubtype() { 
         return subtype; 
     } 

     public int getId() {
         return id; 
     } 

     public void setId(int id) {
         this.id = id; 
     } 

     public String getName() { 
         return name; 
     } 

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

     public int getReleaseId() {
         return releaseId; 
     } 

     public void setReleaseId(int releaseId) {
         this.releaseId = releaseId; 
     } 

     public String generateBody(){ 
         StringBuffer sb=new StringBuffer(); 
         sb.append("{ \"data\":[{"); 
         sb.append(String.format("\"subtype\" : \"%s\", ",getSubtype())); 
         sb.append(String.format("\"name\" : \"%s\" ",getName())); 
         if(releaseId!=null){ 
             sb.append(String.format("\"release_id\" : \"%d\" ",getReleaseId())); 
         } 
         sb.append("}]}"); 
         return sb.toString(); 
     } 

     public static ArrayList<UserStoryBacklogItemEntity> createListFromJson(String json) throws JSONException, ParseException {
         ArrayList<UserStoryBacklogItemEntity> result=new ArrayList<>(); 
         JSONObject obj = new JSONObject(json); 
         JSONArray arr = obj.getJSONArray("data"); 
         for(int i=0;i<arr.length();i++){ 
             JSONObject rawItem = (JSONObject) arr.get(0);
             result.add(createFromJson(rawItem)); 
         } 
         return result; 
     } 

     public static UserStoryBacklogItemEntity createFromJson(JSONObject obj) throws JSONException {
         UserStoryBacklogItemEntity result=new UserStoryBacklogItemEntity(); 
         result.setId(obj.getInt("id")); 
         result.setName(obj.getString("name")); 
         String releaseString = obj.getString("release_id"); 
         //release is not mandatory for user story therefore can be null
         if(!releaseString.equalsIgnoreCase("null")){ 
             JSONObject releaseObj = new JSONObject(releaseString);
             result.setReleaseId(releaseObj.getInt("id")); 
         } 
        return result; 
     } 

   } 


 }