WW-4684 Uses Content-Type to perform action based on defined type

This commit is contained in:
Lukasz Lenart
2016-09-05 12:02:00 +02:00
parent 7dbe3ea8bb
commit 547718fcc6
2 changed files with 116 additions and 100 deletions
@@ -70,20 +70,17 @@ public class JSONInterceptor extends AbstractInterceptor {
private boolean noCache = false;
private boolean excludeNullProperties;
private String callbackParameter;
private String accept;
private String jsonContentType = "application/json";
private String jsonRpcContentType = "application/json-rpc";
@SuppressWarnings("unchecked")
public String intercept(ActionInvocation invocation) throws Exception {
HttpServletRequest request = ServletActionContext.getRequest();
HttpServletResponse response = ServletActionContext.getResponse();
//parameter wasn't set by the interceptor
if (accept == null) {
accept = request.getHeader("accept");
}
String[] accepts = accept.split(",");
String requestContentType = readContentType(request);
String requestContentTypeEncoding = readContentTypeEncoding(request);
Object rootObject = null;
final ValueStack stack = invocation.getStack();
if (this.root != null) {
@@ -94,103 +91,118 @@ public class JSONInterceptor extends AbstractInterceptor {
}
}
for (String accept : accepts) {
if ((accept != null) && accept.equalsIgnoreCase("application/json")) {
if (jsonContentType.equalsIgnoreCase(requestContentType)) {
// load JSON object
Object obj = JSONUtil.deserialize(request.getReader());
// JSON array (this.root cannot be null in this case)
if(obj instanceof List && this.root != null) {
String mapKey = this.root;
rootObject = null;
if(this.root.indexOf('.') != -1) {
mapKey = this.root.substring(this.root.lastIndexOf('.') + 1);
rootObject = stack.findValue(this.root.substring(0, this.root.lastIndexOf('.')));
if (rootObject == null) {
throw new RuntimeException("JSON array: Invalid root expression: '" + this.root + "'.");
}
}
// create a map with a list inside
Map m = new HashMap();
m.put(mapKey, new ArrayList((List) obj));
obj = m;
}
if (obj instanceof Map) {
Map json = (Map) obj;
// clean up the values
if (dataCleaner != null)
dataCleaner.clean("", json);
if (rootObject == null) // model overrides action
rootObject = invocation.getStack().peek();
// populate fields
populator.populateObject(rootObject, json);
} else {
LOG.error("Unable to deserialize JSON object from request");
throw new JSONException("Unable to deserialize JSON object from request");
}
} else if (jsonRpcContentType.equalsIgnoreCase(requestContentType)) {
Object result;
if (this.enableSMD) {
// load JSON object
Object obj = JSONUtil.deserialize(request.getReader());
// JSON array (this.root cannot be null in this case)
if(obj instanceof List && this.root != null) {
String mapKey = this.root;
rootObject = null;
if (obj instanceof Map) {
Map smd = (Map) obj;
if(this.root.indexOf('.') != -1) {
mapKey = this.root.substring(this.root.lastIndexOf('.') + 1);
rootObject = stack.findValue(this.root.substring(0, this.root.lastIndexOf('.')));
if (rootObject == null) {
throw new RuntimeException("JSON array: Invalid root expression: '" + this.root + "'.");
}
if (rootObject == null) { // model makes no sense when using RPC
rootObject = invocation.getAction();
}
// create a map with a list inside
Map m = new HashMap();
m.put(mapKey, new ArrayList((List) obj));
obj = m;
}
if (obj instanceof Map) {
Map json = (Map) obj;
// clean up the values
if (dataCleaner != null)
dataCleaner.clean("", json);
if (rootObject == null) // model overrides action
rootObject = invocation.getStack().peek();
// populate fields
populator.populateObject(rootObject, json);
} else {
LOG.error("Unable to deserialize JSON object from request");
throw new JSONException("Unable to deserialize JSON object from request");
}
} else if ((accept != null) && accept.equalsIgnoreCase("application/json-rpc")) {
Object result;
if (this.enableSMD) {
// load JSON object
Object obj = JSONUtil.deserialize(request.getReader());
if (obj instanceof Map) {
Map smd = (Map) obj;
if (rootObject == null) { // model makes no sense when using RPC
rootObject = invocation.getAction();
}
// invoke method
try {
result = this.invoke(rootObject, smd);
} catch (Exception e) {
RPCResponse rpcResponse = new RPCResponse();
rpcResponse.setId(smd.get("id").toString());
rpcResponse.setError(new RPCError(e, RPCErrorCode.EXCEPTION, getDebug()));
result = rpcResponse;
}
} else {
String message = "SMD request was not in the right format. See http://json-rpc.org";
// invoke method
try {
result = this.invoke(rootObject, smd);
} catch (Exception e) {
RPCResponse rpcResponse = new RPCResponse();
rpcResponse.setError(new RPCError(message, RPCErrorCode.INVALID_PROCEDURE_CALL));
rpcResponse.setId(smd.get("id").toString());
rpcResponse.setError(new RPCError(e, RPCErrorCode.EXCEPTION, getDebug()));
result = rpcResponse;
}
} else {
String message = "Request with content type of 'application/json-rpc' was received but SMD is "
+ "not enabled for this interceptor. Set 'enableSMD' to true to enable it";
String message = "SMD request was not in the right format. See http://json-rpc.org";
RPCResponse rpcResponse = new RPCResponse();
rpcResponse.setError(new RPCError(message, RPCErrorCode.SMD_DISABLED));
rpcResponse.setError(new RPCError(message, RPCErrorCode.INVALID_PROCEDURE_CALL));
result = rpcResponse;
}
} else {
String message = "Request with content type of 'application/json-rpc' was received but SMD is "
+ "not enabled for this interceptor. Set 'enableSMD' to true to enable it";
String json = JSONUtil.serialize(result, excludeProperties, getIncludeProperties(),
ignoreHierarchy, excludeNullProperties);
json = addCallbackIfApplicable(request, json);
boolean writeGzip = enableGZIP && JSONUtil.isGzipInRequest(request);
JSONUtil.writeJSONToResponse(new SerializationParams(response, this.defaultEncoding,
this.wrapWithComments, json, true, writeGzip, noCache, -1, -1, prefix, "application/json"));
return Action.NONE;
} else {
LOG.debug("Accept header parameter must be 'application/json' or 'application/json-rpc'. Ignoring request with accept ", accept);
break;
RPCResponse rpcResponse = new RPCResponse();
rpcResponse.setError(new RPCError(message, RPCErrorCode.SMD_DISABLED));
result = rpcResponse;
}
String json = JSONUtil.serialize(result, excludeProperties, getIncludeProperties(),
ignoreHierarchy, excludeNullProperties);
json = addCallbackIfApplicable(request, json);
boolean writeGzip = enableGZIP && JSONUtil.isGzipInRequest(request);
JSONUtil.writeJSONToResponse(new SerializationParams(response, requestContentTypeEncoding,
this.wrapWithComments, json, true, writeGzip, noCache, -1, -1, prefix, "application/json"));
return Action.NONE;
} else {
LOG.debug("Accept header parameter must be '{}' or '{}'. Ignoring request with Content Type '{}'", jsonContentType, jsonRpcContentType, requestContentType);
}
return invocation.invoke();
}
protected String readContentType(HttpServletRequest request) {
String contentType = request.getHeader("Content-Type");
if (contentType != null && contentType.contains(";")) {
contentType = contentType.substring(0, contentType.indexOf(";"));
}
return contentType;
}
protected String readContentTypeEncoding(HttpServletRequest request) {
String contentTypeEncoding = request.getHeader("Content-Type");
if (contentTypeEncoding != null && contentTypeEncoding.contains(";encoding=")) {
contentTypeEncoding = contentTypeEncoding.substring(contentTypeEncoding.indexOf(";encoding=") + ";encoding=".length());
} else {
contentTypeEncoding = defaultEncoding;
}
return contentTypeEncoding;
}
@SuppressWarnings("unchecked")
public RPCResponse invoke(Object object, Map data) throws IllegalArgumentException,
IllegalAccessException, InvocationTargetException, JSONException, InstantiationException,
@@ -539,7 +551,11 @@ public class JSONInterceptor extends AbstractInterceptor {
this.prefix = prefix;
}
public void setAccept(String accept) {
this.accept = accept;
public void setJsonContentType(String jsonContentType) {
this.jsonContentType = jsonContentType;
}
public void setJsonRpcContentType(String jsonRpcContentType) {
this.jsonRpcContentType = jsonRpcContentType;
}
}
@@ -71,7 +71,7 @@ public class JSONInterceptorTest extends StrutsTestCase {
private void tryBadJSON(String fileName) throws Exception {
// request
setRequestContent(fileName);
this.request.addHeader("accept", "application/json-rpc, text/plain, */*");
this.request.addHeader("Content-Type", "application/json;encoding=UTF-8");
JSONInterceptor interceptor = new JSONInterceptor();
interceptor.setEnableSMD(true);
@@ -92,7 +92,7 @@ public class JSONInterceptorTest extends StrutsTestCase {
public void testSMDDisabledSMD() throws Exception {
// request
setRequestContent("smd-3.txt");
this.request.addHeader("accept", "application/json-rpc, text/plain, */*");
this.request.addHeader("Content-Type", "application/json-rpc");
JSONInterceptor interceptor = new JSONInterceptor();
SMDActionTest1 action = new SMDActionTest1();
@@ -111,7 +111,7 @@ public class JSONInterceptorTest extends StrutsTestCase {
public void testSMDAliasedMethodCall1() throws Exception {
// request
setRequestContent("smd-14.txt");
this.request.addHeader("accept", "application/json-rpc, text/plain, */*");
this.request.addHeader("Content-Type", "application/json-rpc");
JSONInterceptor interceptor = new JSONInterceptor();
interceptor.setEnableSMD(true);
@@ -129,7 +129,7 @@ public class JSONInterceptorTest extends StrutsTestCase {
public void testSMDAliasedMethodCall2() throws Exception {
// request
setRequestContent("smd-15.txt");
this.request.addHeader("accept", "application/json-rpc, text/plain, */*");
this.request.addHeader("Content-Type", "application/json-rpc");
JSONInterceptor interceptor = new JSONInterceptor();
interceptor.setEnableSMD(true);
@@ -147,7 +147,7 @@ public class JSONInterceptorTest extends StrutsTestCase {
public void testSMDNoMethod() throws Exception {
// request
setRequestContent("smd-4.txt");
this.request.addHeader("accept", "application/json-rpc, text/plain, */*");
this.request.addHeader("Content-Type", "application/json-rpc");
JSONInterceptor interceptor = new JSONInterceptor();
interceptor.setEnableSMD(true);
@@ -171,7 +171,7 @@ public class JSONInterceptorTest extends StrutsTestCase {
public void testSMDMethodWithoutAnnotations() throws Exception {
// request
setRequestContent("smd-9.txt");
this.request.addHeader("accept", "application/json-rpc, text/plain, */*");
this.request.addHeader("Content-Type", "application/json-rpc");
JSONInterceptor interceptor = new JSONInterceptor();
interceptor.setEnableSMD(true);
@@ -192,7 +192,7 @@ public class JSONInterceptorTest extends StrutsTestCase {
public void testSMDPrimitivesNoResult() throws Exception {
// request
setRequestContent("smd-6.txt");
this.request.addHeader("accept", "application/json-rpc, text/plain, */*");
this.request.addHeader("Content-Type", "application/json-rpc");
JSONInterceptor interceptor = new JSONInterceptor();
interceptor.setEnableSMD(true);
@@ -227,7 +227,7 @@ public class JSONInterceptorTest extends StrutsTestCase {
public void testSMDReturnObject() throws Exception {
// request
setRequestContent("smd-10.txt");
this.request.addHeader("accept", "application/json-rpc, text/plain, */*");
this.request.addHeader("Content-Type", "application/json-rpc");
JSONInterceptor interceptor = new JSONInterceptor();
interceptor.setEnableSMD(true);
@@ -252,7 +252,7 @@ public class JSONInterceptorTest extends StrutsTestCase {
public void testSMDObjectsNoResult() throws Exception {
// request
setRequestContent("smd-7.txt");
this.request.addHeader("accept", "application/json-rpc, text/plain, */*");
this.request.addHeader("Content-Type", "application/json-rpc");
JSONInterceptor interceptor = new JSONInterceptor();
interceptor.setEnableSMD(true);
@@ -300,7 +300,7 @@ public class JSONInterceptorTest extends StrutsTestCase {
public void testReadEmpty() throws Exception {
// request
setRequestContent("json-6.txt");
this.request.addHeader("accept", "application/json, text/plain, */*");
this.request.addHeader("Content-Type", "application/json");
// interceptor
JSONInterceptor interceptor = new JSONInterceptor();
@@ -315,7 +315,7 @@ public class JSONInterceptorTest extends StrutsTestCase {
public void test() throws Exception {
// request
setRequestContent("json-1.txt");
this.request.addHeader("accept", "application/json, text/plain, */*");
this.request.addHeader("Content-Type", "application/json");
// interceptor
JSONInterceptor interceptor = new JSONInterceptor();
@@ -437,7 +437,7 @@ public class JSONInterceptorTest extends StrutsTestCase {
public void testRoot() throws Exception {
setRequestContent("json-5.txt");
this.request.addHeader("accept", "application/json, text/plain, */*");
this.request.addHeader("Content-Type", "application/json");
// interceptor
JSONInterceptor interceptor = new JSONInterceptor();
@@ -462,7 +462,7 @@ public class JSONInterceptorTest extends StrutsTestCase {
public void testJSONArray() throws Exception {
setRequestContent("json-12.txt");
this.request.addHeader("accept", "application/json, text/plain, */*");
this.request.addHeader("Content-Type", "application/json");
// interceptor
JSONInterceptor interceptor = new JSONInterceptor();
@@ -488,7 +488,7 @@ public class JSONInterceptorTest extends StrutsTestCase {
public void testJSONArray2() throws Exception {
setRequestContent("json-12.txt");
this.request.addHeader("accept", "application/json, text/plain, */*");
this.request.addHeader("Content-Type", "application/json");
// interceptor
JSONInterceptor interceptor = new JSONInterceptor();