From 7ea32a4471f094fa62b9c74e060f9632a1501e2d Mon Sep 17 00:00:00 2001 From: Vijayendra Bhamidipati Date: Wed, 15 Feb 2012 19:20:04 -0800 Subject: [PATCH] Bug 13127: API error text refer to database ids instead of uuids Description: 1) Put in an IdentityProxy object in the ExceptionResponse class. This allows us to copy over the IdentityProxy object contained in the exception caught by handlerequest() when thrown by the command's execute() method, into the Response object that is prepared to return an exception response to the calling API invocation. 2) Modified the GSON serialization method to conver the entire exception object into JSON format and not just the error text. 3) Modify the updateDomain API to populate the exception it throws upon detecting a duplicate domain to include the tablename and domain db id in the exception's IdentityProxy object. NOTE: 1) We can modify the base exception classes and the ExceptionResponse class to contain a list of IdentityProxy objects rather than a single one. 2) We will need to modify all commands such that wherever applicable (wherever a db id is involved), they populate the IdentityProxy object(s) before throwing an exception. --- .../cloud/api/response/ExceptionResponse.java | 15 +++++++ server/src/com/cloud/api/ApiServer.java | 39 ++++++++++++++++--- server/src/com/cloud/api/ApiServlet.java | 16 ++++---- .../api/response/ApiResponseSerializer.java | 9 +++-- .../cloud/server/ManagementServerImpl.java | 4 +- 5 files changed, 65 insertions(+), 18 deletions(-) diff --git a/api/src/com/cloud/api/response/ExceptionResponse.java b/api/src/com/cloud/api/response/ExceptionResponse.java index 93ecad5abbc..c1f065fd013 100644 --- a/api/src/com/cloud/api/response/ExceptionResponse.java +++ b/api/src/com/cloud/api/response/ExceptionResponse.java @@ -12,10 +12,14 @@ // Automatically generated by addcopyright.py at 04/03/2012 package com.cloud.api.response; +import com.cloud.utils.IdentityProxy; import com.cloud.serializer.Param; import com.google.gson.annotations.SerializedName; public class ExceptionResponse extends BaseResponse { + @SerializedName("uuid") @Param(description="uuid associated with this error") + private IdentityProxy id; + @SerializedName("errorcode") @Param(description="numeric code associated with this error") private Integer errorCode; @@ -37,4 +41,15 @@ public class ExceptionResponse extends BaseResponse { public void setErrorText(String errorText) { this.errorText = errorText; } + + public void setProxyObject(String table_name, Long id) { + this.id = new IdentityProxy(); + this.id.setTableName(table_name); + this.id.setValue(id); + return; + } + + public IdentityProxy getProxyObject() { + return id; + } } diff --git a/server/src/com/cloud/api/ApiServer.java b/server/src/com/cloud/api/ApiServer.java index 073a16f2d5a..5031a01b335 100755 --- a/server/src/com/cloud/api/ApiServer.java +++ b/server/src/com/cloud/api/ApiServer.java @@ -349,7 +349,7 @@ public class ApiServer implements HttpRequestHandler { writeResponse(response, responseText, HttpStatus.SC_OK, responseType, null); } catch (ServerApiException se) { - String responseText = getSerializedApiError(se.getErrorCode(), se.getDescription(), parameterMap, responseType); + String responseText = getSerializedApiError(se.getErrorCode(), se.getDescription(), parameterMap, responseType, se); writeResponse(response, responseText, se.getErrorCode(), responseType, se.getDescription()); sb.append(" " + se.getErrorCode() + " " + se.getDescription()); } catch (RuntimeException e) { @@ -433,7 +433,7 @@ public class ApiServer implements HttpRequestHandler { IdentityProxy id = ref.getProxyObject(); if (id != null) { e.setProxyObject(id.getTableName(), id.getValue()); - } + } throw e; } else if (ex instanceof PermissionDeniedException) { PermissionDeniedException ref = (PermissionDeniedException)ex; @@ -1002,7 +1002,7 @@ public class ApiServer implements HttpRequestHandler { } } - public String getSerializedApiError(int errorCode, String errorText, Map apiCommandParams, String responseType) { + public String getSerializedApiError(int errorCode, String errorText, Map apiCommandParams, String responseType, Exception ex) { String responseName = null; String cmdClassName = null; @@ -1030,12 +1030,41 @@ public class ApiServer implements HttpRequestHandler { apiResponse.setErrorCode(errorCode); apiResponse.setErrorText(errorText); apiResponse.setResponseName(responseName); - + // Also copy over the IdentityProxy object into this new apiResponse, from + // the exception caught. When invoked from handle(), the exception here can + // be either ServerApiException, PermissionDeniedException or InvalidParameterValue + // Exception. When invoked from ApiServlet's processRequest(), this can be + // a standard exception like NumberFormatException. We'll leave standard ones alone. + if (ex != null) { + if (ex instanceof ServerApiException || ex instanceof PermissionDeniedException + || ex instanceof InvalidParameterValueException) { + // Cast the exception appropriately and retrieve the IdentityProxy + if (ex instanceof ServerApiException) { + ServerApiException ref = (ServerApiException) ex; + IdentityProxy uuidproxy = ref.getProxyObject(); + if (uuidproxy != null) { + apiResponse.setProxyObject(uuidproxy.getTableName(), uuidproxy.getValue()); + } + } else if (ex instanceof PermissionDeniedException) { + PermissionDeniedException ref = (PermissionDeniedException) ex; + IdentityProxy uuidproxy = ref.getProxyObject(); + if (uuidproxy != null) { + apiResponse.setProxyObject(uuidproxy.getTableName(), uuidproxy.getValue()); + } + } else if (ex instanceof InvalidParameterValueException) { + InvalidParameterValueException ref = (InvalidParameterValueException) ex; + IdentityProxy uuidproxy = ref.getProxyObject(); + if (uuidproxy != null) { + apiResponse.setProxyObject(uuidproxy.getTableName(), uuidproxy.getValue()); + } + } + } + } SerializationContext.current().setUuidTranslation(true); responseText = ApiResponseSerializer.toSerializedString(apiResponse, responseType); } catch (Exception e) { - s_logger.error("Exception responding to http request", e); + s_logger.error("Exception responding to http request", e); } return responseText; } diff --git a/server/src/com/cloud/api/ApiServlet.java b/server/src/com/cloud/api/ApiServlet.java index 5442e6c7753..b7b7fff8cb0 100755 --- a/server/src/com/cloud/api/ApiServlet.java +++ b/server/src/com/cloud/api/ApiServlet.java @@ -181,7 +181,7 @@ public class ApiServlet extends HttpServlet { s_logger.warn("Invalid domain id entered by user"); auditTrailSb.append(" " + HttpServletResponse.SC_UNAUTHORIZED + " " + "Invalid domain id entered, please enter a valid one"); String serializedResponse = _apiServer.getSerializedApiError(HttpServletResponse.SC_UNAUTHORIZED, "Invalid domain id entered, please enter a valid one", params, - responseType); + responseType, null); writeResponse(resp, serializedResponse, HttpServletResponse.SC_UNAUTHORIZED, responseType); } } @@ -218,7 +218,7 @@ public class ApiServlet extends HttpServlet { auditTrailSb.append(" " + BaseCmd.ACCOUNT_ERROR + " " + ex.getMessage() != null ? ex.getMessage() : "failed to authenticate user, check if username/password are correct"); String serializedResponse = _apiServer.getSerializedApiError(BaseCmd.ACCOUNT_ERROR, ex.getMessage() != null ? ex.getMessage() - : "failed to authenticate user, check if username/password are correct", params, responseType); + : "failed to authenticate user, check if username/password are correct", params, responseType, null); writeResponse(resp, serializedResponse, BaseCmd.ACCOUNT_ERROR, responseType); return; } @@ -246,7 +246,7 @@ public class ApiServlet extends HttpServlet { } catch (IllegalStateException ise) { } auditTrailSb.append(" " + HttpServletResponse.SC_UNAUTHORIZED + " " + "unable to verify user credentials"); - String serializedResponse = _apiServer.getSerializedApiError(HttpServletResponse.SC_UNAUTHORIZED, "unable to verify user credentials", params, responseType); + String serializedResponse = _apiServer.getSerializedApiError(HttpServletResponse.SC_UNAUTHORIZED, "unable to verify user credentials", params, responseType, null); writeResponse(resp, serializedResponse, HttpServletResponse.SC_UNAUTHORIZED, responseType); return; } @@ -257,7 +257,7 @@ public class ApiServlet extends HttpServlet { if (command == null) { s_logger.info("missing command, ignoring request..."); auditTrailSb.append(" " + HttpServletResponse.SC_BAD_REQUEST + " " + "no command specified"); - String serializedResponse = _apiServer.getSerializedApiError(HttpServletResponse.SC_BAD_REQUEST, "no command specified", params, responseType); + String serializedResponse = _apiServer.getSerializedApiError(HttpServletResponse.SC_BAD_REQUEST, "no command specified", params, responseType, null); writeResponse(resp, serializedResponse, HttpServletResponse.SC_BAD_REQUEST, responseType); return; } @@ -272,7 +272,7 @@ public class ApiServlet extends HttpServlet { } auditTrailSb.append(" " + HttpServletResponse.SC_UNAUTHORIZED + " " + "unable to verify user credentials"); - String serializedResponse = _apiServer.getSerializedApiError(HttpServletResponse.SC_UNAUTHORIZED, "unable to verify user credentials", params, responseType); + String serializedResponse = _apiServer.getSerializedApiError(HttpServletResponse.SC_UNAUTHORIZED, "unable to verify user credentials", params, responseType, null); writeResponse(resp, serializedResponse, HttpServletResponse.SC_UNAUTHORIZED, responseType); return; } @@ -300,7 +300,7 @@ public class ApiServlet extends HttpServlet { String response = _apiServer.handleRequest(params, false, responseType, auditTrailSb); writeResponse(resp, response != null ? response : "", HttpServletResponse.SC_OK, responseType); } catch (ServerApiException se) { - String serializedResponseText = _apiServer.getSerializedApiError(se.getErrorCode(), se.getDescription(), params, responseType); + String serializedResponseText = _apiServer.getSerializedApiError(se.getErrorCode(), se.getDescription(), params, responseType, null); resp.setHeader("X-Description", se.getDescription()); writeResponse(resp, serializedResponseText, se.getErrorCode(), responseType); auditTrailSb.append(" " + se.getErrorCode() + " " + se.getDescription()); @@ -314,14 +314,14 @@ public class ApiServlet extends HttpServlet { } auditTrailSb.append(" " + HttpServletResponse.SC_UNAUTHORIZED + " " + "unable to verify user credentials and/or request signature"); - String serializedResponse = _apiServer.getSerializedApiError(HttpServletResponse.SC_UNAUTHORIZED, "unable to verify user credentials and/or request signature", params, responseType); + String serializedResponse = _apiServer.getSerializedApiError(HttpServletResponse.SC_UNAUTHORIZED, "unable to verify user credentials and/or request signature", params, responseType, null); writeResponse(resp, serializedResponse, HttpServletResponse.SC_UNAUTHORIZED, responseType); } } catch (Exception ex) { if (ex instanceof ServerApiException && ((ServerApiException) ex).getErrorCode() == BaseCmd.UNSUPPORTED_ACTION_ERROR) { ServerApiException se = (ServerApiException) ex; - String serializedResponseText = _apiServer.getSerializedApiError(se.getErrorCode(), se.getDescription(), params, responseType); + String serializedResponseText = _apiServer.getSerializedApiError(se.getErrorCode(), se.getDescription(), params, responseType, null); resp.setHeader("X-Description", se.getDescription()); writeResponse(resp, serializedResponseText, se.getErrorCode(), responseType); auditTrailSb.append(" " + se.getErrorCode() + " " + se.getDescription()); diff --git a/server/src/com/cloud/api/response/ApiResponseSerializer.java b/server/src/com/cloud/api/response/ApiResponseSerializer.java index 5c162b7339c..d0ba680ea74 100644 --- a/server/src/com/cloud/api/response/ApiResponseSerializer.java +++ b/server/src/com/cloud/api/response/ApiResponseSerializer.java @@ -72,7 +72,7 @@ public class ApiResponseSerializer { if ((responses != null) && !responses.isEmpty()) { Integer count = ((ListResponse) result).getCount(); - String jsonStr = gson.toJson(responses.get(0)); + String jsonStr = gson.toJson(responses.get(0)); jsonStr = unescape(jsonStr); if (count != null && count != 0) { @@ -90,9 +90,10 @@ public class ApiResponseSerializer { } else if (result instanceof SuccessResponse) { sb.append("{ \"success\" : \"" + ((SuccessResponse) result).getSuccess() + "\"} "); } else if (result instanceof ExceptionResponse) { - String jsonErrorText =gson.toJson(((ExceptionResponse) result).getErrorText()); - jsonErrorText = unescape(jsonErrorText); - sb.append("{\"errorcode\" : " + ((ExceptionResponse) result).getErrorCode() + ", \"errortext\" : " + jsonErrorText + "} "); + // Convert into json the whole exception object and not just the error text. + String jsonErrorText = gson.toJson((ExceptionResponse) result); + jsonErrorText = unescape(jsonErrorText); + sb.append(jsonErrorText); } else { String jsonStr = gson.toJson(result); if ((jsonStr != null) && !"".equals(jsonStr)) { diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index 8f5871fd21b..0d5fb465942 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -1888,7 +1888,9 @@ public class ManagementServerImpl implements ManagementServer { boolean sameDomain = (domains.size() == 1 && domains.get(0).getId() == domainId); if (!domains.isEmpty() && !sameDomain) { - throw new InvalidParameterValueException("Failed to update domain id=" + domainId + "; domain with name " + domainName + " already exists in the system"); + InvalidParameterValueException ex = new InvalidParameterValueException("Failed to update specified domain id with name '" + domainName + "' since it already exists in the system"); + ex.setProxyObject("domain", domainId); + throw ex; } }