From 2e47b63d441c3cfa94f0bcee89bd4dfa9efc00f0 Mon Sep 17 00:00:00 2001 From: marchhead Date: Wed, 8 Mar 2017 16:37:18 +0800 Subject: [PATCH] Fix defect 20170308 (#5) * fix defect 20170308 * resolve conflicts * modify the .properties --- .../versionone/VersionOneConstants.java | 3 +- .../VersionOneExternalWorkItem.java | 25 ++-- .../VersionOneIntegrationConnector.java | 43 +++--- .../VersionOneIntegrationConnector.properties | 32 ++++- .../versionone/VersionOneService.java | 55 +++++--- .../VersionOneTimeSheetIntegration.java | 81 ++++++++---- .../VersionOneWorkPlanIntegration.java | 62 ++++++--- .../versionone/model/VersionOneEntity.java | 44 ++++-- .../versionone/model/VersionOneStory.java | 125 +++++++++++++++++- .../versionone/rest/util/RestWrapper.java | 21 ++- .../util/exception/RestRequestException.java | 25 +++- ...ersionOneConnectivityExceptionHandler.java | 77 +++++++++++ 12 files changed, 470 insertions(+), 123 deletions(-) create mode 100644 src/com/ppm/integration/agilesdk/connector/versionone/rest/util/exception/VersionOneConnectivityExceptionHandler.java diff --git a/src/com/ppm/integration/agilesdk/connector/versionone/VersionOneConstants.java b/src/com/ppm/integration/agilesdk/connector/versionone/VersionOneConstants.java index 4989afc..48dfcca 100644 --- a/src/com/ppm/integration/agilesdk/connector/versionone/VersionOneConstants.java +++ b/src/com/ppm/integration/agilesdk/connector/versionone/VersionOneConstants.java @@ -1,3 +1,4 @@ + package com.ppm.integration.agilesdk.connector.versionone; public class VersionOneConstants { @@ -28,7 +29,7 @@ public class VersionOneConstants { API_VERSION_API_DATA_ROOT + "Scope?sel=Name&where=AssetState='64'&Accept=application/json"; public static final String STORIES_WITH_TIMEBOX_SUFFIX = API_VERSION_API_DATA_ROOT - + "Story?Accept=application/json&sel=Name,Status.Name,Timebox.Name,Timebox.State.Code,Timebox.BeginDate,Timebox.EndDate&where=Scope=$myScope&with=$myScope="; + + "Story?Accept=application/json&sel=Name,Status.Name,Timebox.Name,Timebox.State.Code,Timebox.BeginDate,Timebox.EndDate,CreateDate,ChangeDate,Children.Actuals.Value.@Sum,Children.ToDo.@Sum,Children.DetailEstimate.@Sum&where=Scope=$myScope&with=$myScope="; public static final String ACTUALS_SUFFIX = API_VERSION_API_DATA_ROOT + "Actual?Accept=application/json&sel=Workitem.Parent,Date,Value"; diff --git a/src/com/ppm/integration/agilesdk/connector/versionone/VersionOneExternalWorkItem.java b/src/com/ppm/integration/agilesdk/connector/versionone/VersionOneExternalWorkItem.java index 7a3ef1a..dc3d22b 100644 --- a/src/com/ppm/integration/agilesdk/connector/versionone/VersionOneExternalWorkItem.java +++ b/src/com/ppm/integration/agilesdk/connector/versionone/VersionOneExternalWorkItem.java @@ -1,15 +1,17 @@ -package com.ppm.integration.agilesdk.connector.versionone; -import com.ppm.integration.agilesdk.tm.ExternalWorkItem; -import com.ppm.integration.agilesdk.tm.ExternalWorkItemEffortBreakdown; +package com.ppm.integration.agilesdk.connector.versionone; -import javax.xml.datatype.XMLGregorianCalendar; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.HashMap; import java.util.Map; +import javax.xml.datatype.XMLGregorianCalendar; + +import com.ppm.integration.agilesdk.tm.ExternalWorkItem; +import com.ppm.integration.agilesdk.tm.ExternalWorkItemEffortBreakdown; + public class VersionOneExternalWorkItem extends ExternalWorkItem { private static final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); @@ -26,8 +28,7 @@ public class VersionOneExternalWorkItem extends ExternalWorkItem { private XMLGregorianCalendar dateTo; public VersionOneExternalWorkItem(String name, long totalEffort, String errorMessage, XMLGregorianCalendar dateFrom, - XMLGregorianCalendar dateTo, Map timeSpent) - { + XMLGregorianCalendar dateTo, Map timeSpent) { this.name = name; this.totalEffort = totalEffort; this.errorMessage = errorMessage; @@ -36,15 +37,18 @@ public VersionOneExternalWorkItem(String name, long totalEffort, String errorMes this.timeSpent = timeSpent; } - @Override public String getName() { + @Override + public String getName() { return this.name; } - @Override public Double getTotalEffort() { + @Override + public Double getTotalEffort() { return (double)totalEffort; } - @Override public ExternalWorkItemEffortBreakdown getEffortBreakDown() { + @Override + public ExternalWorkItemEffortBreakdown getEffortBreakDown() { ExternalWorkItemEffortBreakdown effortBreakdown = new ExternalWorkItemEffortBreakdown(); @@ -65,7 +69,8 @@ public VersionOneExternalWorkItem(String name, long totalEffort, String errorMes return effortBreakdown; } - @Override public String getErrorMessage() { + @Override + public String getErrorMessage() { return errorMessage; } diff --git a/src/com/ppm/integration/agilesdk/connector/versionone/VersionOneIntegrationConnector.java b/src/com/ppm/integration/agilesdk/connector/versionone/VersionOneIntegrationConnector.java index a16b4cb..9b7f172 100644 --- a/src/com/ppm/integration/agilesdk/connector/versionone/VersionOneIntegrationConnector.java +++ b/src/com/ppm/integration/agilesdk/connector/versionone/VersionOneIntegrationConnector.java @@ -1,50 +1,55 @@ + package com.ppm.integration.agilesdk.connector.versionone; +import java.util.Arrays; +import java.util.List; import com.ppm.integration.agilesdk.FunctionIntegration; import com.ppm.integration.agilesdk.IntegrationConnector; -import com.ppm.integration.agilesdk.ui.*; - -import java.util.Arrays; -import java.util.List; +import com.ppm.integration.agilesdk.ui.Field; +import com.ppm.integration.agilesdk.ui.PlainText; /** - * @author baijuy - * The connector provides the integration for ppm with VersionOne. The field - * InstanceName and BaseUrl are required and field Proxy is optional. - * Once the connector is saved, it can be used to integrate with - * workplan or timesheet. + * @author baijuy The connector provides the integration for ppm with + * VersionOne. The field InstanceName and BaseUrl are required and field + * Proxy is optional. Once the connector is saved, it can be used to + * integrate with workplan or timesheet. */ public class VersionOneIntegrationConnector extends IntegrationConnector { - @Override public String getExternalApplicationName() { + @Override + public String getExternalApplicationName() { return "VersionOne"; } - @Override public String getExternalApplicationVersionIndication() { + @Override + public String getExternalApplicationVersionIndication() { return "2016 (16.3.5.270+)"; } - @Override public String getConnectorVersion() { + @Override + public String getConnectorVersion() { return "1.0"; } - @Override public String getTargetApplicationIcon() { + @Override + public String getTargetApplicationIcon() { return "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAIWSURBVDhPlVPPa9RQEP5etrvasJLU3Qqe9CT+RLYoWrwo6s1LL4o9ePAvUPQk3q0H6UU8CULxDxD0IuKxUNvLIj2URqXqdn9mm6SuzZps8px5bWJsFfSD5JvMzJv53rw80ajX5bCuQ8YxhBCQUoIMkKGYLJC1kynmb2xAuK4rDcMg1//D8zxoquMfEJMijjEndvZhMIvvQV9WH8/Ar3koFGkr5IzCEBce3FJSeWuapqWLsmAFwnUcaZgmpkfOwXOb2I0iQvyAXjZwp/NOJUZRjNVGA0O5nPoeRAOU95YQhgFtQbmA284siuUSXNRREDoGdohHo2dVbG5+AV27i1arjVazBdteg64PK1UaT5XBhe525jElO9g/fhSCZPftdby6eR+nx89g5fMXNKnAkvUBJ44d2VxESBXwXhP7xuxzdONP0PeMYOHZU7x9/QbOuofaag2jpRLy+bzK4+apAj5X0qQmzjg1MYmg58MsHMD7e0+w5vdgLVu4dPF8OlB+/1KwbcqHr1xGKH3IIQ2F6lcsrli4fu3qVnQTOxVksG/sEJ1GH8hp2BUHCGnylcpJ1eifFLSrFiIECL71sISPmJ56qPyclzTjd/ofpFWJ+cdZfPES7blldRrm8YOoTE6o+ST3hXPoGkA4VMCkAtkggxOyyMaZ+fGogKaRweAF7GTevpiRjTMrEP92ndlBLVRC0ulvzPB9Hz8BEWcv9hHRVP4AAAAASUVORK5CYII="; } - @Override public List getDriverConfigurationFields() { - return Arrays.asList(new Field[] { - new PlainText(VersionOneConstants.KEY_BASE_URL, "BASE_URL", "https://www51.v1host.com/BUAA", true), + @Override + public List getDriverConfigurationFields() { + return Arrays.asList(new Field[] {new PlainText(VersionOneConstants.KEY_BASE_URL, "BASE_URL", "", true), new PlainText(VersionOneConstants.KEY_PROXY_HOST, "PROXY_HOST", "", false), new PlainText(VersionOneConstants.KEY_PROXY_PORT, "PROXY_PORT", "", false), }); } - @Override public List getIntegrations() { - return Arrays.asList(new FunctionIntegration[] {new VersionOneWorkPlanIntegration(), - new VersionOneTimeSheetIntegration()}); + @Override + public List getIntegrations() { + return Arrays.asList( + new FunctionIntegration[] {new VersionOneWorkPlanIntegration(), new VersionOneTimeSheetIntegration()}); } } diff --git a/src/com/ppm/integration/agilesdk/connector/versionone/VersionOneIntegrationConnector.properties b/src/com/ppm/integration/agilesdk/connector/versionone/VersionOneIntegrationConnector.properties index cd80c08..be2a85c 100644 --- a/src/com/ppm/integration/agilesdk/connector/versionone/VersionOneIntegrationConnector.properties +++ b/src/com/ppm/integration/agilesdk/connector/versionone/VersionOneIntegrationConnector.properties @@ -1,6 +1,26 @@ -BASE_URL=Base URL -PROXY_HOST=Proxy Host -PROXY_PORT=Proxy Port -USERNAME=Username -PASSWORD=Password -VERSIONONE_PROJECT=Project \ No newline at end of file +BASE_URL = Base URL +PROXY_HOST = Proxy Host +PROXY_PORT = Proxy Port +USERNAME = Username +PASSWORD = Password + +VERSIONONE_PROJECT=Project + +ERROR_UNKNOWN_HOST_ERROR = Unknown Host \"{0}\" +ERROR_BAD_GETWAY = Jira Server expired \"{0}\" +ERROR_UNKNOWN_ERROR = Unknown Error \"{0}\" +ERROR_CONNECTIVITY_ERROR = Connectivity Error +ERROR_DOMAIN_NOT_FOUND = Cannot found Domain \"{0}\" +ERROR_PROJECT_NOT_FOUND = Cannot found Project \"{0}\" +ERROR_RELEASE_NOT_FOUND = Cannot found Release \"{0}\" +ERROR_AUTHENTICATION_FAILED = Authentication Failed + +ERROR_RELEASE_IS_NOT_STARTED = Release \"{0}\" is not started +ERROR_RELEASE_IS_FINISHED = Release \"{0}\" is finished + +ERROR_CANNOT_GET_CURRENT_SPRINT = Cannot get current sprint + +ERROR_HTTP_CONNECTIVITY_ERROR = Connectivity Error \"{0}\" +ERROR_TIMESHEET_RETRIEVE = time sheet data retrieve error\"{0}\" + +ERROR_ACCESS_TOKEN_RETRIEVE = Could not get access token \ No newline at end of file diff --git a/src/com/ppm/integration/agilesdk/connector/versionone/VersionOneService.java b/src/com/ppm/integration/agilesdk/connector/versionone/VersionOneService.java index e65c606..19ab5d7 100644 --- a/src/com/ppm/integration/agilesdk/connector/versionone/VersionOneService.java +++ b/src/com/ppm/integration/agilesdk/connector/versionone/VersionOneService.java @@ -1,18 +1,27 @@ + package com.ppm.integration.agilesdk.connector.versionone; -import com.ppm.integration.agilesdk.connector.versionone.model.VersionOneActualForTimesheet; -import com.ppm.integration.agilesdk.connector.versionone.model.VersionOneScope; -import com.ppm.integration.agilesdk.connector.versionone.model.VersionOneStory; -import com.ppm.integration.agilesdk.connector.versionone.model.VersionOneTimebox; -import com.ppm.integration.agilesdk.connector.versionone.rest.util.RestWrapper; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.log4j.Logger; import org.apache.wink.client.ClientResponse; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; -import java.util.*; +import com.ppm.integration.agilesdk.connector.versionone.model.VersionOneActualForTimesheet; +import com.ppm.integration.agilesdk.connector.versionone.model.VersionOneScope; +import com.ppm.integration.agilesdk.connector.versionone.model.VersionOneStory; +import com.ppm.integration.agilesdk.connector.versionone.model.VersionOneTimebox; +import com.ppm.integration.agilesdk.connector.versionone.rest.util.RestWrapper; public class VersionOneService { + private final Logger logger = Logger.getLogger(this.getClass()); + private String baseUri; private RestWrapper wrapper; @@ -51,14 +60,13 @@ public List getProjects() { JSONArray jsonArray = new JSONObject(jsonStr).getJSONArray("Assets"); for (int i = 0; i < jsonArray.length(); i++) { JSONObject obj = jsonArray.getJSONObject(i); - VersionOneScope project = - new VersionOneScope(obj.getJSONObject("Attributes").getJSONObject("Name").getString("value"), - obj.getString("id")); + VersionOneScope project = new VersionOneScope( + obj.getJSONObject("Attributes").getJSONObject("Name").getString("value"), obj.getString("id")); list.add(project); } } catch (JSONException e) { - + logger.error("", e); } return list; } @@ -77,8 +85,10 @@ public List getTimeboxes(String scopeId) { return iterationz; } - public Map> getTimeSheet(String startDate, String endDate, String scopeId) { - List list = getActuals(startDate, endDate, scopeId); + public Map> getTimeSheet(String startDate, String endDate, String scopeId, + String username) + { + List list = getActuals(startDate, endDate, scopeId, username); Map> map = new HashMap<>(); for (VersionOneActualForTimesheet vaft : list) { String parentName = vaft.getParentName(); @@ -102,10 +112,13 @@ public Map> getTimeSheet(String startDate, String endD return map; } - private List getActuals(String startDate, String endDate, String scopeId) { + private List getActuals(String startDate, String endDate, String scopeId, + String username) + { List list = new ArrayList<>(); String dest = baseUri + VersionOneConstants.ACTUALS_SUFFIX; - String dateRequestParameter = "&where=Date>='" + startDate + "';Date<='" + endDate + "'"; + String dateRequestParameter = + "&where=Date>='" + startDate + "';Date<='" + endDate + "';Member.Username='" + username + "'"; String projectRequestParameter = ""; if (!"".equals(scopeId)) { projectRequestParameter = VersionOneConstants.SPECIFIC_PROJECT_SUFFIX + scopeId; @@ -127,14 +140,14 @@ private List getActuals(String startDate, String e } } catch (JSONException e) { - + logger.error("", e); } return list; } private String encodeUrl(String url) { - return url.replaceAll(" ", "%20").replaceAll(">", "%3E").replaceAll("<", "%3C"); + return url.replaceAll(" ", "%20").replaceAll(">", "%3E").replaceAll("<", "%3C").replaceAll("@", "%40"); } private Map> getStoriesWithTimebox(String scopeId) { @@ -156,9 +169,15 @@ private Map> getStoriesWithTimebox(Stri String endDate = attributes.getJSONObject("Timebox.EndDate").getString("value"); String iterationName = attributes.getJSONObject("Timebox.Name").getString("value"); String stateCode = attributes.getJSONObject("Timebox.State.Code").getString("value"); + String createDate = attributes.getJSONObject("CreateDate").getString("value"); + String changeDate = attributes.getJSONObject("ChangeDate").getString("value"); + String doneHrs = attributes.getJSONObject("Children.Actuals.Value.@Sum").getString("value"); + String toDoHrs = attributes.getJSONObject("Children.ToDo.@Sum").getString("value"); + String detailEstimateHrs = attributes.getJSONObject("Children.DetailEstimate.@Sum").getString("value"); VersionOneTimebox timebox = new VersionOneTimebox(iterationName, beginDate, endDate, stateCode); - VersionOneStory story = new VersionOneStory(name, beginDate, endDate, statusName); + VersionOneStory story = new VersionOneStory(name, beginDate, endDate, statusName, createDate, + changeDate, detailEstimateHrs, doneHrs, toDoHrs); if (iterations.containsKey(timebox)) { iterations.get(timebox).add(story); } else { @@ -170,7 +189,7 @@ private Map> getStoriesWithTimebox(Stri } } catch (JSONException e) { - + logger.error("", e); } return iterations; } diff --git a/src/com/ppm/integration/agilesdk/connector/versionone/VersionOneTimeSheetIntegration.java b/src/com/ppm/integration/agilesdk/connector/versionone/VersionOneTimeSheetIntegration.java index a902927..27ab0ce 100644 --- a/src/com/ppm/integration/agilesdk/connector/versionone/VersionOneTimeSheetIntegration.java +++ b/src/com/ppm/integration/agilesdk/connector/versionone/VersionOneTimeSheetIntegration.java @@ -1,22 +1,44 @@ + package com.ppm.integration.agilesdk.connector.versionone; -import com.ppm.integration.agilesdk.ValueSet; -import com.ppm.integration.agilesdk.tm.*; -import com.ppm.integration.agilesdk.ui.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import javax.xml.datatype.XMLGregorianCalendar; + +import org.apache.log4j.Logger; +import org.apache.wink.client.ClientRuntimeException; + +import com.ppm.integration.agilesdk.ValueSet; import com.ppm.integration.agilesdk.connector.versionone.model.VersionOneScope; import com.ppm.integration.agilesdk.connector.versionone.rest.util.IRestConfig; import com.ppm.integration.agilesdk.connector.versionone.rest.util.RestWrapper; import com.ppm.integration.agilesdk.connector.versionone.rest.util.VersionOneRestConfig; - -import javax.xml.datatype.XMLGregorianCalendar; -import java.util.*; -import java.util.Map.Entry; +import com.ppm.integration.agilesdk.connector.versionone.rest.util.exception.RestRequestException; +import com.ppm.integration.agilesdk.connector.versionone.rest.util.exception.VersionOneConnectivityExceptionHandler; +import com.ppm.integration.agilesdk.tm.ExternalWorkItem; +import com.ppm.integration.agilesdk.tm.TimeSheetIntegration; +import com.ppm.integration.agilesdk.tm.TimeSheetIntegrationContext; +import com.ppm.integration.agilesdk.ui.DynamicDropdown; +import com.ppm.integration.agilesdk.ui.Field; +import com.ppm.integration.agilesdk.ui.LineBreaker; +import com.ppm.integration.agilesdk.ui.PasswordText; +import com.ppm.integration.agilesdk.ui.PlainText; public class VersionOneTimeSheetIntegration extends TimeSheetIntegration { + + private final Logger logger = Logger.getLogger(this.getClass()); + private VersionOneService service; - @Override public List getExternalWorkItems(TimeSheetIntegrationContext arg0, ValueSet values) { + @Override + public List getExternalWorkItems(TimeSheetIntegrationContext arg0, ValueSet values) { // Synchronized ? final List items = Collections.synchronizedList(new LinkedList()); @@ -27,8 +49,9 @@ public class VersionOneTimeSheetIntegration extends TimeSheetIntegration { values.get(VersionOneConstants.KEY_USERNAME), values.get(VersionOneConstants.KEY_PASSWORD), values.get(VersionOneConstants.KEY_BASE_URL)); String scopeId = values.get(VersionOneConstants.KEY_VERSIONONE_PROJECT_NAME); - Map> map = - service.getTimeSheet(start.toString().substring(0, 10), end.toString().substring(0, 10), scopeId); + String username = values.get(VersionOneConstants.KEY_USERNAME); + Map> map = service.getTimeSheet(start.toString().substring(0, 10), + end.toString().substring(0, 10), scopeId, username); Set>> entrySet = map.entrySet(); @@ -41,34 +64,46 @@ public class VersionOneTimeSheetIntegration extends TimeSheetIntegration { actualEffort += actualEfforts.get(key); } - items.add( - new VersionOneExternalWorkItem(entry.getKey(), actualEffort, entry.getKey() + " error", start, end, - entry.getValue())); + items.add(new VersionOneExternalWorkItem(entry.getKey(), actualEffort, entry.getKey() + " error", start, + end, entry.getValue())); } return items; } - @Override public List getMappingConfigurationFields(ValueSet arg0) { - return Arrays.asList(new Field[] {new PlainText(VersionOneConstants.KEY_USERNAME, "USERNAME", "admin", true), - new PasswordText(VersionOneConstants.KEY_PASSWORD, "PASSWORD", "admin", true), new LineBreaker(), - new DynamicDropdown(VersionOneConstants.KEY_VERSIONONE_PROJECT_NAME, "VersionOne_PROJECT", false) { + @Override + public List getMappingConfigurationFields(ValueSet arg0) { + return Arrays.asList(new Field[] {new PlainText(VersionOneConstants.KEY_USERNAME, "USERNAME", "", true), + new PasswordText(VersionOneConstants.KEY_PASSWORD, "PASSWORD", "", true), new LineBreaker(), + new DynamicDropdown(VersionOneConstants.KEY_VERSIONONE_PROJECT_NAME, "VERSIONONE_PROJECT", false) { - @Override public List getDependencies() { - return Arrays.asList(new String[] {VersionOneConstants.KEY_USERNAME, - VersionOneConstants.KEY_PASSWORD}); + @Override + public List getDependencies() { + return Arrays.asList( + new String[] {VersionOneConstants.KEY_USERNAME, VersionOneConstants.KEY_PASSWORD}); } - @Override public List