/** * jira-client - a simple JIRA REST client * Copyright (c) 2013 Bob Carroll (bob.carroll@alum.rit.edu) *

* This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. *

* This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. *

* You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ package net.rcarz.jiraclient.agile; import net.rcarz.jiraclient.Field; import net.rcarz.jiraclient.JiraException; import net.rcarz.jiraclient.RestClient; import net.sf.json.JSON; import net.sf.json.JSONArray; import net.sf.json.JSONObject; import org.apache.commons.lang.math.NumberUtils; import java.lang.reflect.Constructor; import java.util.ArrayList; import java.util.List; /** * A base class for Agile resources. * * @author pldupont * @see "https://docs.atlassian.com/jira-software/REST/cloud/" */ public abstract class AgileResource { public static final String ATTR_ID = "id"; public static final String ATTR_NAME = "name"; public static final String ATTR_SELF = "self"; public static final String RESOURCE_URI = "/rest/agile/1.0/"; private RestClient restclient = null; private long id = 0; private String name; private String self; private JSONObject attributes = new JSONObject(); /** * Creates a new Agile resource. * * @param restclient REST client instance * @param json JSON payload * @throws JiraException when the retrieval fails */ public AgileResource(RestClient restclient, JSONObject json) throws JiraException { this.restclient = restclient; if (json != null) { deserialize(json); } } /** * Gets an Agile resource from the given object. * * @param type Resource data type * @param r a JSONObject instance * @param restclient REST client instance * @return a Resource instance or null if r isn't a JSONObject instance * @throws JiraException when the retrieval fails */ protected static T getResource( Class type, Object r, RestClient restclient) throws JiraException { if (!(r instanceof JSONObject)) { throw new JiraException("JSON payload is malformed"); } T result = null; if (!((JSONObject) r).isNullObject()) { try { Constructor constructor = type.getDeclaredConstructor(RestClient.class, JSONObject.class); result = constructor.newInstance(restclient, r); } catch (Exception e) { throw new JiraException("Failed to deserialize object array."); } } return result; } /** * Gets a list of GreenHopper resources from the given object. * * @param type Resource data type * @param ra a JSONArray instance * @param restclient REST client instance * @param listName The name of the list of items from the JSON result. * @return a list of Resources found in ra * @throws JiraException when the retrieval fails */ protected static List getResourceArray( Class type, Object ra, RestClient restclient, String listName) throws JiraException { if (!(ra instanceof JSONObject)) { throw new JiraException("JSON payload is malformed"); } JSONObject jo = (JSONObject) ra; if (!jo.containsKey(listName) || !(jo.get(listName) instanceof JSONArray)) { throw new JiraException(type.getSimpleName() + " result is malformed"); } List results = new ArrayList(); for (Object v : (JSONArray) jo.get(listName)) { T item = getResource(type, v, restclient); if (item != null) { results.add(item); } } return results; } /** * Retrieves all boards visible to the session user. * * @param restclient REST client instance * @param type The type of the object to deserialize. * @param url The URL to call. * @return a list of boards * @throws JiraException when the retrieval fails */ static List list( RestClient restclient, Class type, String url) throws JiraException { return list(restclient, type, url, "values"); } /** * Retrieves all boards visible to the session user. * * @param restclient REST client instance * @param type The type of the object to deserialize. * @param url The URL to call. * @param listName The name of the list of items in the JSON response. * @return a list of boards * @throws JiraException when the retrieval fails */ static List list( RestClient restclient, Class type, String url, String listName) throws JiraException { JSON result; try { result = restclient.get(url); } catch (Exception ex) { throw new JiraException("Failed to retrieve a list of " + type.getSimpleName() + " : " + url, ex); } return getResourceArray( type, result, restclient, listName ); } /** * Retrieves all boards visible to the session user. * * @param restclient REST client instance * @return a list of boards * @throws JiraException when the retrieval fails */ static T get(RestClient restclient, Class type, String url) throws JiraException { JSON result; try { result = restclient.get(url); } catch (Exception ex) { throw new JiraException("Failed to retrieve " + type.getSimpleName() + " : " + url, ex); } return getResource( type, result, restclient ); } /** * Extract from a sub list the Resource array, if present. * * @param type Resource data type * @param subJson a JSONObject instance * @param resourceName The name of the list of items from the JSON result. * @param The type of Agile resource to return. * @return The list of resources if present. * @throws JiraException when the retrieval fails */ List getSubResourceArray( Class type, JSONObject subJson, String resourceName) throws JiraException { List result = null; if (subJson.containsKey(resourceName)) { result = getResourceArray(type, subJson.get(resourceName), getRestclient(), resourceName + "s"); } return result; } /** * Extract from a sub list the Resource, if present. * * @param type Resource data type * @param subJson a JSONObject instance * @param resourceName The name of the item from the JSON result. * @param The type of Agile resource to return. * @return The resource if present. * @throws JiraException when the retrieval fails */ T getSubResource( Class type, JSONObject subJson, String resourceName) throws JiraException { T result = null; if (subJson.containsKey(resourceName)) { result = getResource(type, subJson.get(resourceName), getRestclient()); } return result; } /** * @return Internal JIRA ID. */ public long getId() { return id; } /** * @return The resource name. */ public String getName() { return name; } /** * @param name Setter for the resource name. In some case, the name is called something else. */ void setName(String name) { this.name = name; } /** * @return The resource URL. */ public String getSelfURL() { return self; } /** * @return The REST client used to access the current resource. */ protected RestClient getRestclient() { return restclient; } /** * Retrieve the specified attribute as a generic object. * * @param name The name of the attribute to retrieve. * @return The value of the attribute. */ public Object getAttribute(String name) { return (String) attributes.get(name); } /** * Deserialize the json to extract standard attributes and keep a reference of * other attributes. * * @param json The JSON object to read. */ void deserialize(JSONObject json) throws JiraException { id = getLong(json.get("id")); name = Field.getString(json.get("name")); self = Field.getString(json.get("self")); addAttributes(json); } /** * Allow to add more attributes. * * @param json The json object to extract attributes from. */ void addAttributes(JSONObject json) { attributes.putAll(json); } long getLong(Object o) { if (o instanceof Integer || o instanceof Long) { return Field.getLong(o); } else if (o instanceof String && NumberUtils.isDigits((String) o)) { return NumberUtils.toLong((String) o, 0L); } else { return 0L; } } @Override public String toString() { return String.format("%s{id=%s, name='%s'}", getClass().getSimpleName(), id, name); } }