From e5b4cf5cf1af0a73a86ebb83ffa4ef017d6b9049 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 49542de481e..b200f8c8170 100644 --- a/api/src/com/cloud/api/response/ExceptionResponse.java +++ b/api/src/com/cloud/api/response/ExceptionResponse.java @@ -17,10 +17,14 @@ */ 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; @@ -42,4 +46,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 b9d3d29ac11..43165f47d70 100755 --- a/server/src/com/cloud/api/ApiServer.java +++ b/server/src/com/cloud/api/ApiServer.java @@ -350,7 +350,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) { @@ -434,7 +434,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; @@ -981,7 +981,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; @@ -1009,12 +1009,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 4e1fe904584..a293df9aa63 100755 --- a/server/src/com/cloud/api/ApiServlet.java +++ b/server/src/com/cloud/api/ApiServlet.java @@ -183,7 +183,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); } } @@ -220,7 +220,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; } @@ -248,7 +248,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; } @@ -259,7 +259,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; } @@ -274,7 +274,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; } @@ -302,7 +302,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()); @@ -316,14 +316,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 920ce58799f..3500a7f9433 100644 --- a/server/src/com/cloud/api/response/ApiResponseSerializer.java +++ b/server/src/com/cloud/api/response/ApiResponseSerializer.java @@ -78,7 +78,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) { @@ -96,9 +96,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 e0baf6859a1..fcd9c936a5c 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -1836,7 +1836,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; } }