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.
This commit is contained in:
Vijayendra Bhamidipati 2012-02-15 19:20:04 -08:00
parent c3fbe29cf8
commit e5b4cf5cf1
5 changed files with 65 additions and 18 deletions

View File

@ -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;
}
}

View File

@ -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<String, Object[]> apiCommandParams, String responseType) {
public String getSerializedApiError(int errorCode, String errorText, Map<String, Object[]> 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;
}

View File

@ -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());

View File

@ -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)) {

View File

@ -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;
}
}