mirror of https://github.com/apache/cloudstack.git
226 lines
10 KiB
Java
226 lines
10 KiB
Java
package com.cloud.api.response;
|
|
|
|
import java.lang.reflect.Field;
|
|
import java.lang.reflect.InvocationTargetException;
|
|
import java.lang.reflect.Method;
|
|
import java.lang.reflect.Modifier;
|
|
import java.util.Date;
|
|
import java.util.List;
|
|
import java.util.regex.Matcher;
|
|
import java.util.regex.Pattern;
|
|
|
|
import org.apache.log4j.Logger;
|
|
|
|
import com.cloud.api.ApiDBUtils;
|
|
import com.cloud.api.ApiGsonHelper;
|
|
import com.cloud.api.BaseCmd;
|
|
import com.cloud.api.ResponseObject;
|
|
import com.google.gson.Gson;
|
|
import com.google.gson.annotations.SerializedName;
|
|
|
|
public class ApiResponseSerializer {
|
|
private static final Logger s_logger = Logger.getLogger(ApiResponseSerializer.class.getName());
|
|
|
|
public static String toSerializedString(ResponseObject result, String responseType) {
|
|
if (BaseCmd.RESPONSE_TYPE_JSON.equalsIgnoreCase(responseType)) {
|
|
return toJSONSerializedString(result);
|
|
} else {
|
|
return toXMLSerializedString(result);
|
|
}
|
|
}
|
|
|
|
private static final Pattern s_unicodeEscapePattern = Pattern.compile("\\\\u([0-9A-Fa-f]{4})");
|
|
public static String unescape(String escaped) {
|
|
String str = escaped;
|
|
Matcher matcher = s_unicodeEscapePattern.matcher(str);
|
|
while(matcher.find()) {
|
|
str = str.replaceAll("\\" + matcher.group(0), Character.toString((char)Integer.parseInt(matcher.group(1), 16)));
|
|
}
|
|
return str;
|
|
}
|
|
|
|
private static String toJSONSerializedString(ResponseObject result) {
|
|
if (result != null) {
|
|
Gson gson = ApiGsonHelper.getBuilder().excludeFieldsWithModifiers(Modifier.TRANSIENT).setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").create();
|
|
StringBuilder sb = new StringBuilder();
|
|
|
|
sb.append("{ \"" + result.getResponseName() + "\" : ");
|
|
if (result instanceof ListResponse) {
|
|
List<? extends ResponseObject> responses = ((ListResponse)result).getResponses();
|
|
if ((responses != null) && !responses.isEmpty()) {
|
|
int count = responses.size();
|
|
String jsonStr = gson.toJson(responses.get(0));;
|
|
jsonStr = unescape(jsonStr);
|
|
sb.append("{ \"" + responses.get(0).getObjectName() + "\" : [ " + jsonStr);
|
|
for (int i = 1; i < count; i++) {
|
|
jsonStr = gson.toJson(responses.get(i));
|
|
jsonStr = unescape(jsonStr);
|
|
sb.append(", " + jsonStr);
|
|
}
|
|
sb.append(" ] }");
|
|
} else {
|
|
sb.append("{ }");
|
|
}
|
|
} else if (result instanceof SuccessResponse) {
|
|
sb.append("{ \"success\" : \""+((SuccessResponse)result).getSuccess()+"\"} ");
|
|
} else if (result instanceof ExceptionResponse) {
|
|
sb.append("{\"errorcode\" : "+((ExceptionResponse)result).getErrorCode() + ", \"errortext\" : \""+ ((ExceptionResponse)result).getErrorText() +"\"} ");
|
|
}else {
|
|
String jsonStr = gson.toJson(result);
|
|
if ((jsonStr != null) && !"".equals(jsonStr)) {
|
|
jsonStr = unescape(jsonStr);
|
|
if (result instanceof AsyncJobResponse || result instanceof CreateCmdResponse) {
|
|
sb.append(jsonStr);
|
|
} else {
|
|
sb.append(" { \"" + result.getObjectName() + "\" : " + jsonStr + " } ");
|
|
}
|
|
} else {
|
|
sb.append("{ }");
|
|
}
|
|
}
|
|
sb.append(" }");
|
|
return sb.toString();
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private static String toXMLSerializedString(ResponseObject result) {
|
|
StringBuilder sb = new StringBuilder();
|
|
sb.append("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>");
|
|
sb.append("<" + result.getResponseName() + " cloud-stack-version=\""+ApiDBUtils.getVersion()+ "\">");
|
|
|
|
if (result instanceof ListResponse) {
|
|
List<? extends ResponseObject> responses = ((ListResponse)result).getResponses();
|
|
if ((responses != null) && !responses.isEmpty()) {
|
|
for (ResponseObject obj : responses) {
|
|
serializeResponseObjXML(sb, obj);
|
|
}
|
|
}
|
|
} else {
|
|
if (result instanceof CreateCmdResponse || result instanceof AsyncJobResponse) {
|
|
serializeResponseObjFieldsXML(sb, result);
|
|
} else {
|
|
serializeResponseObjXML(sb, result);
|
|
}
|
|
}
|
|
|
|
sb.append("</" + result.getResponseName() + ">");
|
|
return sb.toString();
|
|
}
|
|
|
|
private static void serializeResponseObjXML(StringBuilder sb, ResponseObject obj){
|
|
if (!(obj instanceof SuccessResponse)&& !(obj instanceof ExceptionResponse)){
|
|
sb.append("<" + obj.getObjectName() + ">");
|
|
}
|
|
serializeResponseObjFieldsXML(sb, obj);
|
|
if (!(obj instanceof SuccessResponse) && !(obj instanceof ExceptionResponse)){
|
|
sb.append("</" + obj.getObjectName() + ">");
|
|
}
|
|
}
|
|
|
|
private static void serializeResponseObjFieldsXML(StringBuilder sb, ResponseObject obj){
|
|
boolean isAsync = false;
|
|
if (obj instanceof AsyncJobResponse)
|
|
isAsync = true;
|
|
|
|
Field[] fields = obj.getClass().getDeclaredFields();
|
|
for (Field field : fields) {
|
|
if ((field.getModifiers() & Modifier.TRANSIENT) != 0) {
|
|
continue; // skip transient fields
|
|
}
|
|
|
|
SerializedName serializedName = field.getAnnotation(SerializedName.class);
|
|
if (serializedName == null) {
|
|
continue; // skip fields w/o serialized name
|
|
}
|
|
|
|
String propName = field.getName();
|
|
Method method = getGetMethod(obj, propName);
|
|
if (method != null) {
|
|
try {
|
|
Object fieldValue = method.invoke(obj);
|
|
if (fieldValue != null) {
|
|
if (fieldValue instanceof ResponseObject) {
|
|
ResponseObject subObj = (ResponseObject)fieldValue;
|
|
if (isAsync) {
|
|
sb.append("<jobresult>");
|
|
}
|
|
serializeResponseObjXML(sb, subObj);
|
|
if (isAsync) {
|
|
sb.append("</jobresult>");
|
|
}
|
|
} else if (fieldValue instanceof List<?>){
|
|
List<?> subResponseList = (List<Object>)fieldValue;
|
|
for (Object value: subResponseList) {
|
|
if (value instanceof ResponseObject){
|
|
ResponseObject subObj = (ResponseObject)value;
|
|
if (serializedName != null) {
|
|
subObj.setObjectName(serializedName.value());
|
|
}
|
|
serializeResponseObjXML(sb, subObj);
|
|
}
|
|
}
|
|
|
|
}else if (fieldValue instanceof Date) {
|
|
sb.append("<" + serializedName.value() + ">" + BaseCmd.getDateString((Date)fieldValue) + "</" + serializedName.value() + ">");
|
|
} else {
|
|
sb.append("<" + serializedName.value() + ">" + fieldValue.toString() + "</" + serializedName.value() + ">");
|
|
}
|
|
}
|
|
} catch (IllegalArgumentException e) {
|
|
s_logger.error("Illegal argument exception when calling ResponseObject " + obj.getClass().getName() + " get method for property: " + propName);
|
|
} catch (IllegalAccessException e) {
|
|
s_logger.error("Illegal access exception when calling ResponseObject " + obj.getClass().getName() + " get method for property: " + propName);
|
|
} catch (InvocationTargetException e) {
|
|
s_logger.error("Invocation target exception when calling ResponseObject " + obj.getClass().getName() + " get method for property: " + propName);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private static Method getGetMethod(Object o, String propName) {
|
|
Method method = null;
|
|
String methodName = getGetMethodName("get", propName);
|
|
try {
|
|
method = o.getClass().getMethod(methodName);
|
|
} catch (SecurityException e1) {
|
|
s_logger.error("Security exception in getting ResponseObject " + o.getClass().getName() + " get method for property: "
|
|
+ propName);
|
|
} catch (NoSuchMethodException e1) {
|
|
if (s_logger.isTraceEnabled()) {
|
|
s_logger.trace("ResponseObject " + o.getClass().getName() + " does not have " + methodName
|
|
+ "() method for property: " + propName
|
|
+ ", will check is-prefixed method to see if it is boolean property");
|
|
}
|
|
}
|
|
|
|
if (method != null)
|
|
return method;
|
|
|
|
methodName = getGetMethodName("is", propName);
|
|
try {
|
|
method = o.getClass().getMethod(methodName);
|
|
} catch (SecurityException e1) {
|
|
s_logger.error("Security exception in getting ResponseObject " + o.getClass().getName() + " get method for property: "
|
|
+ propName);
|
|
} catch (NoSuchMethodException e1) {
|
|
s_logger.warn("ResponseObject " + o.getClass().getName() + " does not have " + methodName + "() method for property: "
|
|
+ propName);
|
|
}
|
|
return method;
|
|
}
|
|
|
|
private static String getGetMethodName(String prefix, String fieldName) {
|
|
StringBuffer sb = new StringBuffer(prefix);
|
|
|
|
if (fieldName.length() >= prefix.length() && fieldName.substring(0, prefix.length()).equals(prefix)) {
|
|
return fieldName;
|
|
} else {
|
|
sb.append(fieldName.substring(0, 1).toUpperCase());
|
|
sb.append(fieldName.substring(1));
|
|
}
|
|
|
|
return sb.toString();
|
|
}
|
|
}
|