Merge pull request #1104 from apache/WW-5468-modeldriven-strutsparameter-fix

This commit is contained in:
Kusal Kithul-Godage
2024-11-01 23:19:43 +11:00
committed by GitHub
17 changed files with 252 additions and 219 deletions
@@ -42,7 +42,7 @@ public class ModelDrivenAction extends ActionSupport implements ModelDriven {
}
@Override
public Object getModel() {
public Gangster getModel() {
return new Gangster();
}
}
@@ -18,6 +18,8 @@
*/
package org.apache.struts2;
import org.apache.struts2.interceptor.parameter.StrutsParameter;
/**
* ModelDriven Actions provide a model object to be pushed onto the ValueStack
* in addition to the Action itself, allowing a FormBean type approach like Struts.
@@ -28,9 +30,13 @@ public interface ModelDriven<T> {
/**
* Gets the model to be pushed onto the ValueStack instead of the Action itself.
* <p>
* Please be aware that all setters and getters of every depth on the object returned by this method are available
* for user parameter injection!
*
* @return the model
*/
@StrutsParameter(depth = Integer.MAX_VALUE)
T getModel();
}
@@ -35,6 +35,7 @@ import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.ClassUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.struts2.ModelDriven;
import org.apache.struts2.StrutsConstants;
import org.apache.struts2.action.NoParameters;
import org.apache.struts2.action.ParameterNameAware;
@@ -348,7 +349,15 @@ public class ParametersInterceptor extends MethodFilterInterceptor {
}
long paramDepth = name.codePoints().mapToObj(c -> (char) c).filter(NESTING_CHARS::contains).count();
if (action instanceof ModelDriven<?> && !ActionContext.getContext().getValueStack().peek().equals(action)) {
LOG.debug("Model driven Action detected, exempting from @StrutsParameter annotation requirement and OGNL allowlisting model type");
// (Exempted by annotation on com.opensymphony.xwork2.ModelDriven#getModel)
return hasValidAnnotatedMember("model", action, paramDepth + 1);
}
if (requireAnnotationsTransitionMode && paramDepth == 0) {
LOG.debug("Annotation transition mode enabled, exempting non-nested parameter [{}] from @StrutsParameter annotation requirement", name);
return true;
}
@@ -365,6 +374,8 @@ public class ParametersInterceptor extends MethodFilterInterceptor {
* save computation by checking this last.
*/
protected boolean hasValidAnnotatedMember(String rootProperty, Object action, long paramDepth) {
LOG.debug("Checking Action [{}] for a matching, correctly annotated member for property [{}]",
action.getClass().getSimpleName(), rootProperty);
BeanInfo beanInfo = getBeanInfo(action);
if (beanInfo == null) {
return hasValidAnnotatedField(action, rootProperty, paramDepth);
@@ -399,7 +410,7 @@ public class ParametersInterceptor extends MethodFilterInterceptor {
}
if (getPermittedInjectionDepth(relevantMethod) < paramDepth) {
String logMessage = format(
"Parameter injection for method [%s] on action [%s] rejected. Ensure it is annotated with @StrutsParameter with an appropriate 'depth'.",
"Parameter injection for method [%s] on Action [%s] rejected. Ensure it is annotated with @StrutsParameter with an appropriate 'depth'.",
relevantMethod.getName(),
relevantMethod.getDeclaringClass().getName());
if (devMode) {
@@ -409,8 +420,10 @@ public class ParametersInterceptor extends MethodFilterInterceptor {
}
return false;
}
LOG.debug("Success: Matching annotated method [{}] found for property [{}] of depth [{}] on Action [{}]",
relevantMethod.getName(), propDesc.getName(), paramDepth, action.getClass().getSimpleName());
if (paramDepth >= 1) {
allowlistClass(relevantMethod.getReturnType());
allowlistClass(propDesc.getPropertyType());
}
if (paramDepth >= 2) {
allowlistReturnTypeIfParameterized(relevantMethod);
@@ -447,19 +460,23 @@ public class ParametersInterceptor extends MethodFilterInterceptor {
}
protected boolean hasValidAnnotatedField(Object action, String fieldName, long paramDepth) {
LOG.debug("No matching annotated method found for property [{}] of depth [{}] on Action [{}], now also checking for public field",
fieldName, paramDepth, action.getClass().getSimpleName());
Field field;
try {
field = action.getClass().getDeclaredField(fieldName);
} catch (NoSuchFieldException e) {
LOG.debug("Matching field for property [{}] not found on Action [{}]", fieldName, action.getClass().getSimpleName());
return false;
}
if (!Modifier.isPublic(field.getModifiers())) {
LOG.debug("Matching field [{}] is not public on Action [{}]", field.getName(), action.getClass().getSimpleName());
return false;
}
if (getPermittedInjectionDepth(field) < paramDepth) {
String logMessage = format(
"Parameter injection for field [%s] on action [%s] rejected. Ensure it is annotated with @StrutsParameter with an appropriate 'depth'.",
fieldName,
"Parameter injection for field [%s] on Action [%s] rejected. Ensure it is annotated with @StrutsParameter with an appropriate 'depth'.",
field.getName(),
action.getClass().getName());
if (devMode) {
notifyDeveloperOfError(LOG, action, logMessage);
@@ -468,6 +485,8 @@ public class ParametersInterceptor extends MethodFilterInterceptor {
}
return false;
}
LOG.debug("Success: Matching annotated public field [{}] found for property of depth [{}] on Action [{}]",
field.getName(), paramDepth, action.getClass().getSimpleName());
if (paramDepth >= 1) {
allowlistClass(field.getType());
}
@@ -629,7 +648,7 @@ public class ParametersInterceptor extends MethodFilterInterceptor {
if (!result.isAccepted()) {
if (devMode) {
LOG.warn("Parameter [{}] didn't match accepted pattern [{}]! See Accepted / Excluded patterns at\n" +
"https://struts.apache.org/security/#accepted--excluded-patterns",
"https://struts.apache.org/security/#accepted--excluded-patterns",
paramName, result.getAcceptedPattern());
} else {
LOG.debug("Parameter [{}] didn't match accepted pattern [{}]!", paramName, result.getAcceptedPattern());
@@ -644,8 +663,8 @@ public class ParametersInterceptor extends MethodFilterInterceptor {
if (result.isExcluded()) {
if (devMode) {
LOG.warn("Parameter [{}] matches excluded pattern [{}]! See Accepted / Excluded patterns at\n" +
"https://struts.apache.org/security/#accepted--excluded-patterns",
paramName, result.getExcludedPattern());
"https://struts.apache.org/security/#accepted--excluded-patterns",
paramName, result.getExcludedPattern());
} else {
LOG.debug("Parameter [{}] matches excluded pattern [{}]!", paramName, result.getExcludedPattern());
}
@@ -663,8 +682,8 @@ public class ParametersInterceptor extends MethodFilterInterceptor {
if (excludedValuePattern.matcher(value).matches()) {
if (devMode) {
LOG.warn("Parameter value [{}] matches excluded pattern [{}]! See Accepting/Excluding parameter values at\n" +
"https://struts.apache.org/core-developers/parameters-interceptor#excluding-parameter-values",
value, excludedValuePatterns);
"https://struts.apache.org/core-developers/parameters-interceptor#excluding-parameter-values",
value, excludedValuePatterns);
} else {
LOG.debug("Parameter value [{}] matches excluded pattern [{}]", value, excludedValuePattern);
}
@@ -686,8 +705,8 @@ public class ParametersInterceptor extends MethodFilterInterceptor {
}
if (devMode) {
LOG.warn("Parameter value [{}] didn't match accepted pattern [{}]! See Accepting/Excluding parameter values at\n" +
"https://struts.apache.org/core-developers/parameters-interceptor#excluding-parameter-values",
value, acceptedValuePatterns);
"https://struts.apache.org/core-developers/parameters-interceptor#excluding-parameter-values",
value, acceptedValuePatterns);
} else {
LOG.debug("Parameter value [{}] was not accepted!", value);
}
@@ -757,7 +776,7 @@ public class ParametersInterceptor extends MethodFilterInterceptor {
LOG.debug("Sets accepted value patterns to [{}], note this may impact the safety of your application!", patterns);
} else {
LOG.warn("Replacing accepted patterns [{}] with [{}], be aware that this may impact safety of your application!",
acceptedValuePatterns, patterns);
acceptedValuePatterns, patterns);
}
acceptedValuePatterns = new HashSet<>(patterns.size());
try {
@@ -782,7 +801,7 @@ public class ParametersInterceptor extends MethodFilterInterceptor {
LOG.debug("Setting excluded value patterns to [{}]", patterns);
} else {
LOG.warn("Replacing excluded value patterns [{}] with [{}], be aware that this may impact safety of your application!",
excludedValuePatterns, patterns);
excludedValuePatterns, patterns);
}
excludedValuePatterns = new HashSet<>(patterns.size());
try {
@@ -44,9 +44,8 @@ public class ModelDrivenAction extends ActionSupport implements ModelDriven {
/**
* @return the model to be pushed onto the ValueStack after the Action itself
*/
@StrutsParameter(depth = 2)
@Override
public Object getModel() {
public TestBean getModel() {
return model;
}
}
@@ -44,9 +44,8 @@ public class ModelDrivenAnnotationAction extends ActionSupport implements ModelD
/**
* @return the model to be pushed onto the ValueStack after the Action itself
*/
@StrutsParameter(depth = 2)
@Override
public Object getModel() {
public AnnotatedTestBean getModel() {
return model;
}
}
@@ -178,7 +178,7 @@ public class ModelDrivenInterceptorTest extends XWorkTestCase {
}
public class ModelDrivenAction extends ActionSupport implements ModelDriven {
public class ModelDrivenAction extends ActionSupport implements ModelDriven<Object> {
@Override
public Object getModel() {
@@ -19,7 +19,6 @@
package com.opensymphony.xwork2.test;
import com.opensymphony.xwork2.ModelDrivenAction;
import org.apache.struts2.interceptor.parameter.StrutsParameter;
/**
@@ -35,9 +34,8 @@ public class ModelDrivenAction2 extends ModelDrivenAction {
/**
* @return the model to be pushed onto the ValueStack after the Action itself
*/
@StrutsParameter(depth = 3)
@Override
public Object getModel() {
public TestBean2 getModel() {
return model;
}
}
@@ -19,7 +19,6 @@
package com.opensymphony.xwork2.test;
import com.opensymphony.xwork2.ModelDrivenAnnotationAction;
import org.apache.struts2.interceptor.parameter.StrutsParameter;
/**
@@ -36,9 +35,8 @@ public class ModelDrivenAnnotationAction2 extends ModelDrivenAnnotationAction {
/**
* @return the model to be pushed onto the ValueStack after the Action itself
*/
@StrutsParameter(depth = 3)
@Override
public Object getModel() {
public AnnotationTestBean2 getModel() {
return model;
}
}
@@ -19,6 +19,7 @@
package com.opensymphony.xwork2.test.subtest;
import com.opensymphony.xwork2.ModelDrivenAction;
import com.opensymphony.xwork2.TestBean;
/**
* Extends ModelDrivenAction to return a null model.
@@ -31,7 +32,7 @@ public class NullModelDrivenAction extends ModelDrivenAction {
* @return the model to be pushed onto the ValueStack instead of the Action itself
*/
@Override
public Object getModel() {
public TestBean getModel() {
return null;
}
}
@@ -19,7 +19,7 @@
package com.opensymphony.xwork2.validator;
import com.opensymphony.xwork2.ModelDriven;
import org.apache.struts2.interceptor.parameter.StrutsParameter;
import com.opensymphony.xwork2.TestBean;
/**
@@ -33,9 +33,8 @@ public class VisitorValidatorModelAction extends VisitorValidatorTestAction impl
/**
* @return the model to be pushed onto the ValueStack instead of the Action itself
*/
@StrutsParameter(depth = 2)
@Override
public Object getModel() {
public TestBean getModel() {
return getBean();
}
}
@@ -18,8 +18,12 @@
*/
package org.apache.struts2.interceptor.parameter;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ModelDriven;
import com.opensymphony.xwork2.StubValueStack;
import com.opensymphony.xwork2.security.AcceptedPatternsChecker;
import com.opensymphony.xwork2.security.NotExcludedAcceptedPatternsChecker;
import com.opensymphony.xwork2.util.ValueStack;
import org.apache.commons.lang3.ClassUtils;
import org.apache.struts2.dispatcher.HttpParameters;
import org.apache.struts2.dispatcher.Parameter;
@@ -63,6 +67,7 @@ public class StrutsParameterAnnotationTest {
@After
public void tearDown() throws Exception {
threadAllowlist.clearAllowlist();
ActionContext.clear();
}
private void testParameter(Object action, String paramName, boolean shouldContain) {
@@ -80,7 +85,7 @@ public class StrutsParameterAnnotationTest {
}
}
private Set<Class<?>> getParentClasses(Class<?> ...clazzes) {
private Set<Class<?>> getParentClasses(Class<?>... clazzes) {
Set<Class<?>> set = new HashSet<>();
for (Class<?> clazz : clazzes) {
set.add(clazz);
@@ -258,8 +263,21 @@ public class StrutsParameterAnnotationTest {
testParameter(new MethodAction(), "publicStrNotAnnotated", true);
}
@Test
public void publicModelPojo() {
ModelAction action = new ModelAction();
class FieldAction {
// Emulate ModelDrivenInterceptor running previously
ValueStack valueStack = new StubValueStack();
valueStack.push(action.getModel());
ActionContext.of().withValueStack(valueStack).bind();
testParameter(action, "name", true);
testParameter(action, "name.nested", true);
assertThat(threadAllowlist.getAllowlist()).containsExactlyInAnyOrderElementsOf(getParentClasses(Object.class, Pojo.class));
}
static class FieldAction {
@StrutsParameter
private String privateStr;
@@ -275,7 +293,7 @@ public class StrutsParameterAnnotationTest {
public Pojo publicPojoDepthZero;
@StrutsParameter(depth = 1)
public Pojo publicPojoDepthOne ;
public Pojo publicPojoDepthOne;
@StrutsParameter(depth = 2)
public Pojo publicPojoDepthTwo;
@@ -290,7 +308,7 @@ public class StrutsParameterAnnotationTest {
public Map<String, Pojo> publicPojoMapDepthTwo;
}
class MethodAction {
static class MethodAction {
@StrutsParameter
private void setPrivateStr(String str) {
@@ -343,6 +361,14 @@ public class StrutsParameterAnnotationTest {
}
}
class Pojo {
static class ModelAction implements ModelDriven<Pojo> {
@Override
public Pojo getModel() {
return new Pojo();
}
}
static class Pojo {
}
}
@@ -37,7 +37,6 @@ import static com.opensymphony.xwork2.security.DefaultNotExcludedAcceptedPattern
/**
* Unit test for {@link StreamResult}.
*
*/
public class StreamResultTest extends StrutsInternalTestCase {
@@ -126,12 +125,12 @@ public class StreamResultTest extends StrutsInternalTestCase {
result.doExecute("helloworld", mai);
//check that that headers are not set by default
//check that that headers are not set by default
assertNull(response.getHeader("Pragma"));
assertNull(response.getHeader("Cache-Control"));
}
public void testAllowCacheFalse() throws Exception {
public void testAllowCacheFalse() throws Exception {
result.setInputName("streamForImage");
result.setAllowCaching(false);
result.doExecute("helloworld", mai);
@@ -266,7 +265,6 @@ public class StreamResultTest extends StrutsInternalTestCase {
}
protected void tearDown() throws Exception {
super.tearDown();
response = null;
@@ -21,7 +21,6 @@ package org.apache.struts.beanvalidation.actions;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
import org.apache.struts.beanvalidation.models.Person;
import org.apache.struts2.interceptor.parameter.StrutsParameter;
import javax.validation.Valid;
@@ -30,7 +29,6 @@ public class ModelDrivenAction extends ActionSupport implements ModelDriven<Pers
@Valid
private final Person model = new Person();
@StrutsParameter(depth = 2)
@Override
public Person getModel() {
return model;
@@ -22,7 +22,6 @@ import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
import org.apache.struts.beanvalidation.constraints.ValidationGroup;
import org.apache.struts.beanvalidation.models.Person;
import org.apache.struts2.interceptor.parameter.StrutsParameter;
import javax.validation.Valid;
@@ -31,7 +30,6 @@ public class ValidateGroupAction extends ActionSupport implements ModelDriven<Pe
@Valid
private final Person model = new Person();
@StrutsParameter(depth = 2)
@Override
public Person getModel() {
return model;
@@ -23,7 +23,6 @@ import com.opensymphony.xwork2.ActionProxy;
import com.opensymphony.xwork2.ActionProxyFactory;
import com.opensymphony.xwork2.config.Configuration;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.dispatcher.Dispatcher;
import org.apache.struts2.dispatcher.HttpParameters;
import org.apache.struts2.dispatcher.mapper.ActionMapping;
import org.springframework.mock.web.MockHttpServletRequest;
@@ -75,7 +74,7 @@ public class StrutsRestTestCase<T> extends StrutsJUnit4TestCase<T> {
ActionMapping mapping = getActionMapping(request);
assertNotNull(mapping);
Dispatcher.getInstance().serviceAction(request, response, mapping);
dispatcher.serviceAction(request, response, mapping);
if (response.getStatus() != HttpServletResponse.SC_OK)
throw new ServletException("Error code [" + response.getStatus() + "], Error: ["
@@ -32,7 +32,6 @@ import com.opensymphony.xwork2.ognl.OgnlUtil;
import com.opensymphony.xwork2.util.XWorkTestCaseHelper;
import junit.framework.TestCase;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.interceptor.parameter.StrutsParameter;
import org.apache.struts2.result.HttpHeaderResult;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
@@ -47,97 +46,97 @@ import static javax.servlet.http.HttpServletResponse.SC_NOT_MODIFIED;
public class RestActionInvocationTest extends TestCase {
RestActionInvocation restActionInvocation;
MockHttpServletRequest request;
MockHttpServletResponse response;
RestActionInvocation restActionInvocation;
MockHttpServletRequest request;
MockHttpServletResponse response;
@Override
protected void setUp() throws Exception {
super.setUp();
@Override
protected void setUp() throws Exception {
super.setUp();
restActionInvocation = new RestActionInvocationTester();
request = new MockHttpServletRequest();
response = new MockHttpServletResponse();
ServletActionContext.setRequest(request);
ServletActionContext.setResponse(response);
restActionInvocation = new RestActionInvocationTester();
request = new MockHttpServletRequest();
response = new MockHttpServletResponse();
ServletActionContext.setRequest(request);
ServletActionContext.setResponse(response);
}
}
/**
* Test the correct action results: null, String, HttpHeaders, Result
* @throws Exception
*/
public void testSaveResult() throws Exception {
/**
* Test the correct action results: null, String, HttpHeaders, Result
* @throws Exception
*/
public void testSaveResult() throws Exception {
Object methodResult = "index";
ActionConfig actionConfig = restActionInvocation.getProxy().getConfig();
assertEquals("index", restActionInvocation.saveResult(actionConfig, methodResult));
Object methodResult = "index";
ActionConfig actionConfig = restActionInvocation.getProxy().getConfig();
assertEquals("index", restActionInvocation.saveResult(actionConfig, methodResult));
setUp();
methodResult = new DefaultHttpHeaders("show");
assertEquals("show", restActionInvocation.saveResult(actionConfig, methodResult));
assertEquals(methodResult, restActionInvocation.httpHeaders);
setUp();
methodResult = new DefaultHttpHeaders("show");
assertEquals("show", restActionInvocation.saveResult(actionConfig, methodResult));
assertEquals(methodResult, restActionInvocation.httpHeaders);
setUp();
methodResult = new HttpHeaderResult(HttpServletResponse.SC_ACCEPTED);
assertEquals(null, restActionInvocation.saveResult(actionConfig, methodResult));
assertEquals(methodResult, restActionInvocation.createResult());
setUp();
methodResult = new HttpHeaderResult(HttpServletResponse.SC_ACCEPTED);
assertEquals(null, restActionInvocation.saveResult(actionConfig, methodResult));
assertEquals(methodResult, restActionInvocation.createResult());
setUp();
try {
methodResult = new Object();
restActionInvocation.saveResult(actionConfig, methodResult);
setUp();
try {
methodResult = new Object();
restActionInvocation.saveResult(actionConfig, methodResult);
// ko
assertFalse(true);
// ko
assertFalse(true);
} catch (ConfigurationException c) {
// ok, object not allowed
}
}
} catch (ConfigurationException c) {
// ok, object not allowed
}
}
/**
* Test the target selection: exception, error messages, model and null
* @throws Exception
*/
public void testSelectTarget() throws Exception {
/**
* Test the target selection: exception, error messages, model and null
* @throws Exception
*/
public void testSelectTarget() throws Exception {
// Exception
Exception e = new Exception();
restActionInvocation.getStack().set("exception", e);
restActionInvocation.selectTarget();
assertEquals(e, restActionInvocation.target);
// Exception
Exception e = new Exception();
restActionInvocation.getStack().set("exception", e);
restActionInvocation.selectTarget();
assertEquals(e, restActionInvocation.target);
// Error messages
setUp();
String actionMessage = "Error!";
RestActionSupport action = (RestActionSupport)restActionInvocation.getAction();
action.addActionError(actionMessage);
Map<String, Object> errors = new HashMap<String, Object>();
List<String> list = new ArrayList<String>();
list.add(actionMessage);
errors.put("actionErrors", list);
restActionInvocation.selectTarget();
assertEquals(errors, restActionInvocation.target);
// Error messages
setUp();
String actionMessage = "Error!";
RestActionSupport action = (RestActionSupport)restActionInvocation.getAction();
action.addActionError(actionMessage);
Map<String, Object> errors = new HashMap<String, Object>();
List<String> list = new ArrayList<String>();
list.add(actionMessage);
errors.put("actionErrors", list);
restActionInvocation.selectTarget();
assertEquals(errors, restActionInvocation.target);
// Model with get and no content in post, put, delete
setUp();
RestAction restAction = (RestAction)restActionInvocation.getAction();
List<String> model = new ArrayList<String>();
model.add("Item");
restAction.model = model;
request.setMethod("GET");
restActionInvocation.selectTarget();
assertEquals(model, restActionInvocation.target);
request.setMethod("POST");
restActionInvocation.selectTarget();
assertEquals(null, restActionInvocation.target);
request.setMethod("PUT");
restActionInvocation.selectTarget();
assertEquals(null, restActionInvocation.target);
request.setMethod("DELETE");
restActionInvocation.selectTarget();
assertEquals(null, restActionInvocation.target);
// Model with get and no content in post, put, delete
setUp();
RestAction restAction = (RestAction)restActionInvocation.getAction();
List<String> model = new ArrayList<String>();
model.add("Item");
restAction.model = model;
request.setMethod("GET");
restActionInvocation.selectTarget();
assertEquals(model, restActionInvocation.target);
request.setMethod("POST");
restActionInvocation.selectTarget();
assertEquals(null, restActionInvocation.target);
request.setMethod("PUT");
restActionInvocation.selectTarget();
assertEquals(null, restActionInvocation.target);
request.setMethod("DELETE");
restActionInvocation.selectTarget();
assertEquals(null, restActionInvocation.target);
// disable content restriction to GET only
model = new ArrayList<String>();
@@ -151,102 +150,100 @@ public class RestActionInvocationTest extends TestCase {
assertEquals(model.get(0), "Item1");
}
/**
* Test the not modified status code.
* @throws Exception
*/
public void testResultNotModified() throws Exception {
/**
* Test the not modified status code.
* @throws Exception
*/
public void testResultNotModified() throws Exception {
request.addHeader("If-None-Match", "123");
request.setMethod("GET");
request.addHeader("If-None-Match", "123");
request.setMethod("GET");
RestAction restAction = (RestAction)restActionInvocation.getAction();
List<String> model = new ArrayList<String>() {
@Override
public int hashCode() {
return 123;
}
};
model.add("Item");
restAction.model = model;
RestAction restAction = (RestAction)restActionInvocation.getAction();
List<String> model = new ArrayList<String>() {
@Override
public int hashCode() {
return 123;
}
};
model.add("Item");
restAction.model = model;
restActionInvocation.processResult();
assertEquals(SC_NOT_MODIFIED, response.getStatus());
restActionInvocation.processResult();
assertEquals(SC_NOT_MODIFIED, response.getStatus());
}
/**
* Test the default error result.
* @throws Exception
*/
public void testDefaultErrorResult() throws Exception {
/**
* Test the default error result.
* @throws Exception
*/
public void testDefaultErrorResult() throws Exception {
// Exception
Exception e = new Exception();
restActionInvocation.getStack().set("exception", e);
request.setMethod("GET");
// Exception
Exception e = new Exception();
restActionInvocation.getStack().set("exception", e);
request.setMethod("GET");
RestAction restAction = (RestAction)restActionInvocation.getAction();
List<String> model = new ArrayList<String>();
model.add("Item");
restAction.model = model;
RestAction restAction = (RestAction)restActionInvocation.getAction();
List<String> model = new ArrayList<String>();
model.add("Item");
restAction.model = model;
restActionInvocation.setDefaultErrorResultName("default-error");
ResultConfig resultConfig = new ResultConfig.Builder("default-error",
"org.apache.struts2.result.HttpHeaderResult")
.addParam("status", "123").build();
ActionConfig actionConfig = new ActionConfig.Builder("org.apache.rest",
"RestAction", "org.apache.rest.RestAction")
.addResultConfig(resultConfig)
.build();
((MockActionProxy)restActionInvocation.getProxy()).setConfig(actionConfig);
restActionInvocation.setDefaultErrorResultName("default-error");
ResultConfig resultConfig = new ResultConfig.Builder("default-error",
"org.apache.struts2.result.HttpHeaderResult")
.addParam("status", "123").build();
ActionConfig actionConfig = new ActionConfig.Builder("org.apache.rest",
"RestAction", "org.apache.rest.RestAction")
.addResultConfig(resultConfig)
.build();
((MockActionProxy)restActionInvocation.getProxy()).setConfig(actionConfig);
restActionInvocation.processResult();
assertEquals(123, response.getStatus());
restActionInvocation.processResult();
assertEquals(123, response.getStatus());
}
}
public void testNoResult() throws Exception {
public void testNoResult() throws Exception {
RestAction restAction = (RestAction)restActionInvocation.getAction();
List<String> model = new ArrayList<String>();
model.add("Item");
restAction.model = model;
request.setMethod("GET");
restActionInvocation.setResultCode("index");
RestAction restAction = (RestAction)restActionInvocation.getAction();
List<String> model = new ArrayList<String>();
model.add("Item");
restAction.model = model;
request.setMethod("GET");
restActionInvocation.setResultCode("index");
try {
restActionInvocation.processResult();
try {
restActionInvocation.processResult();
// ko
assertFalse(true);
// ko
assertFalse(true);
} catch (ConfigurationException c) {
// ok, no result
}
} catch (ConfigurationException c) {
// ok, no result
}
}
}
/**
* Test the global execution
* @throws Exception
*/
public void testInvoke() throws Exception {
/**
* Test the global execution
* @throws Exception
*/
public void testInvoke() throws Exception {
// Default index method return 'success'
((MockActionProxy)restActionInvocation.getProxy()).setMethod("index");
// Default index method return 'success'
((MockActionProxy)restActionInvocation.getProxy()).setMethod("index");
// Define result 'success'
ResultConfig resultConfig = new ResultConfig.Builder("success",
"org.apache.struts2.result.HttpHeaderResult")
.addParam("status", "123").build();
ActionConfig actionConfig = new ActionConfig.Builder("org.apache.rest",
"RestAction", "org.apache.rest.RestAction")
.addResultConfig(resultConfig)
.build();
((MockActionProxy)restActionInvocation.getProxy()).setConfig(actionConfig);
// Define result 'success'
ResultConfig resultConfig = new ResultConfig.Builder("success", "org.apache.struts2.result.HttpHeaderResult")
.addParam("status", "123").build();
ActionConfig actionConfig = new ActionConfig.Builder("org.apache.rest", "RestAction", "org.apache.rest.RestAction")
.addResultConfig(resultConfig)
.build();
((MockActionProxy)restActionInvocation.getProxy()).setConfig(actionConfig);
request.setMethod("GET");
request.setMethod("GET");
restActionInvocation.setOgnlUtil(new OgnlUtil());
restActionInvocation.invoke();
@@ -256,31 +253,31 @@ public class RestActionInvocationTest extends TestCase {
class RestActionInvocationTester extends RestActionInvocation {
RestActionInvocationTester() {
super(new HashMap<String, Object>(), true);
List<InterceptorMapping> interceptorMappings = new ArrayList<InterceptorMapping>();
RestActionInvocationTester() {
super(new HashMap<>(), true);
List<InterceptorMapping> interceptorMappings = new ArrayList<>();
MockInterceptor mockInterceptor = new MockInterceptor();
mockInterceptor.setFoo("interceptor");
mockInterceptor.setExpectedFoo("interceptor");
interceptorMappings.add(new InterceptorMapping("interceptor", mockInterceptor));
interceptors = interceptorMappings.iterator();
MockActionProxy actionProxy = new MockActionProxy();
ActionConfig actionConfig = new ActionConfig.Builder("org.apache.rest",
"RestAction", "org.apache.rest.RestAction").build();
ActionConfig actionConfig = new ActionConfig.Builder(
"org.apache.rest", "RestAction", "org.apache.rest.RestAction").build();
actionProxy.setConfig(actionConfig);
proxy = actionProxy;
action = new RestAction();
setMimeTypeHandlerSelector(new DefaultContentTypeHandlerManager());
unknownHandlerManager = new DefaultUnknownHandlerManager();
try {
XWorkTestCaseHelper.setUp();
} catch (Exception e) {
throw new RuntimeException(e);
}
invocationContext = ActionContext.getContext();
container = ActionContext.getContext().getContainer();
stack = ActionContext.getContext().getValueStack();
objectFactory = container.getInstance(ObjectFactory.class);
try {
XWorkTestCaseHelper.setUp();
} catch (Exception e) {
throw new RuntimeException(e);
}
invocationContext = ActionContext.getContext();
container = ActionContext.getContext().getContainer();
stack = ActionContext.getContext().getValueStack();
objectFactory = container.getInstance(ObjectFactory.class);
}
@@ -288,13 +285,12 @@ public class RestActionInvocationTest extends TestCase {
static class RestAction extends RestActionSupport implements ModelDriven<List<String>> {
List<String> model;
List<String> model;
@StrutsParameter(depth = 1)
@Override
public List<String> getModel() {
return model;
}
@Override
public List<String> getModel() {
return model;
}
}
}
@@ -44,9 +44,8 @@ public class ModelDrivenAction extends ActionSupport implements ModelDriven {
/**
* @return the model to be pushed onto the ValueStack after the Action itself
*/
@StrutsParameter(depth = 2)
@Override
public Object getModel() {
public TestBean getModel() {
return model;
}
}