org.apache.struts2.rest.RestWorkflowInterceptor Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.struts2.rest;
import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.ValidationAware;
import com.opensymphony.xwork2.inject.Inject;
import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.dispatcher.mapper.ActionMapping;
import java.util.HashMap;
import java.util.Map;
import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
/**
*
*
* An interceptor that makes sure there are not validation errors before allowing the interceptor chain to continue.
* This interceptor does not perform any validation.
*
*
* Copied from the {@link com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor}, this interceptor adds support for error handling of Restful
* operations. For example, if an validation error is discovered, a map of errors is created and processed to be
* returned, using the appropriate content handler for rendering the body.
*
* This interceptor does nothing if the name of the method being invoked is specified in the excludeMethods
* parameter. excludeMethods accepts a comma-delimited list of method names. For example, requests to
* foo!input.action and foo!back.action will be skipped by this interceptor if you set the
* excludeMethods parameter to "input, back".
*
*
*
* Note: As this method extends off MethodFilterInterceptor, it is capable of
* deciding if it is applicable only to selective methods in the action class. This is done by adding param tags
* for the interceptor element, naming either a list of excluded method names and/or a list of included method
* names, whereby includeMethods overrides excludedMethods. A single * sign is interpreted as wildcard matching
* all methods for both parameters.
* See {@link MethodFilterInterceptor} for more info.
*
*
*
* Interceptor parameters:
*
*
*
*
*
* - inputResultName - Default to "input". Determine the result name to be returned when
* an action / field error is found.
*
*
*
*
*
* Extending the interceptor:
*
*
*
* There are no known extension points for this interceptor.
*
*
*
* Example code:
*
*
*
*
* <action name="someAction" class="com.examples.SomeAction">
* <interceptor-ref name="params"/>
* <interceptor-ref name="validation"/>
* <interceptor-ref name="workflow"/>
* <result name="success">good_result.ftl</result>
* </action>
*
* <-- In this case myMethod as well as mySecondMethod of the action class
* will not pass through the workflow process -->
* <action name="someAction" class="com.examples.SomeAction">
* <interceptor-ref name="params"/>
* <interceptor-ref name="validation"/>
* <interceptor-ref name="workflow">
* <param name="excludeMethods">myMethod,mySecondMethod</param>
* </interceptor-ref name="workflow">
* <result name="success">good_result.ftl</result>
* </action>
*
* <-- In this case, the result named "error" will be used when
* an action / field error is found -->
* <-- The Interceptor will only be applied for myWorkflowMethod method of action
* classes, since this is the only included method while any others are excluded -->
* <action name="someAction" class="com.examples.SomeAction">
* <interceptor-ref name="params"/>
* <interceptor-ref name="validation"/>
* <interceptor-ref name="workflow">
* <param name="inputResultName">error</param>
* <param name="excludeMethods">*</param>
* <param name="includeMethods">myWorkflowMethod</param>
* </interceptor-ref>
* <result name="success">good_result.ftl</result>
* </action>
*
*
*
*
* @author Jason Carreira
* @author Rainer Hermanns
* @author Alexandru Popescu
* @author Philip Luppens
* @author tm_jee
*/
public class RestWorkflowInterceptor extends MethodFilterInterceptor {
private static final long serialVersionUID = 7563014655616490865L;
private static final Logger LOG = LogManager.getLogger(RestWorkflowInterceptor.class);
private String inputResultName = Action.INPUT;
private ContentTypeHandlerManager manager;
private String postMethodName = "create";
private String editMethodName = "edit";
private String newMethodName = "editNew";
private String putMethodName = "update";
private int validationFailureStatusCode = SC_BAD_REQUEST;
@Inject(required=false,value="struts.mapper.postMethodName")
public void setPostMethodName(String postMethodName) {
this.postMethodName = postMethodName;
}
@Inject(required=false,value="struts.mapper.editMethodName")
public void setEditMethodName(String editMethodName) {
this.editMethodName = editMethodName;
}
@Inject(required=false,value="struts.mapper.newMethodName")
public void setNewMethodName(String newMethodName) {
this.newMethodName = newMethodName;
}
@Inject(required=false,value="struts.mapper.putMethodName")
public void setPutMethodName(String putMethodName) {
this.putMethodName = putMethodName;
}
@Inject(required=false,value="struts.rest.validationFailureStatusCode")
public void setValidationFailureStatusCode(String code) {
this.validationFailureStatusCode = Integer.parseInt(code);
}
@Inject
public void setContentTypeHandlerManager(ContentTypeHandlerManager mgr) {
this.manager = mgr;
}
/**
* Set the inputResultName
(result name to be returned when
* a action / field error is found registered). Default to {@link Action#INPUT}
*
* @param inputResultName what result name to use when there was validation error(s).
*/
public void setInputResultName(String inputResultName) {
this.inputResultName = inputResultName;
}
/**
* Intercept {@link ActionInvocation} and processes the errors using the {@link org.apache.struts2.rest.handler.ContentTypeHandler}
* appropriate for the request.
*
* @return String result name
*/
protected String doIntercept(ActionInvocation invocation) throws Exception {
Object action = invocation.getAction();
if (action instanceof ValidationAware) {
ValidationAware validationAwareAction = (ValidationAware) action;
if (validationAwareAction.hasErrors()) {
LOG.debug("Errors on action {}, returning result name 'input'", validationAwareAction);
ActionMapping mapping = (ActionMapping) ActionContext.getContext().get(ServletActionContext.ACTION_MAPPING);
String method = inputResultName;
if (postMethodName.equals(mapping.getMethod())) {
method = newMethodName;
} else if (putMethodName.equals(mapping.getMethod())) {
method = editMethodName;
}
HttpHeaders info = new DefaultHttpHeaders()
.disableCaching()
.renderResult(method)
.withStatus(validationFailureStatusCode);
Map errors = new HashMap<>();
errors.put("actionErrors", validationAwareAction.getActionErrors());
errors.put("fieldErrors", validationAwareAction.getFieldErrors());
return manager.handleResult(invocation, info, errors);
}
}
return invocation.invoke();
}
}