001: /*
002: * Copyright (c) 2002-2006 by OpenSymphony
003: * All rights reserved.
004: */
005: package com.opensymphony.xwork.interceptor;
006:
007: import com.opensymphony.xwork.Action;
008: import com.opensymphony.xwork.ActionInvocation;
009: import com.opensymphony.xwork.Validateable;
010: import com.opensymphony.xwork.ValidationAware;
011: import org.apache.commons.logging.Log;
012: import org.apache.commons.logging.LogFactory;
013:
014: /**
015: * <!-- START SNIPPET: description -->
016: *
017: * An interceptor that does some basic validation workflow before allowing the interceptor chain to continue.
018: *
019: * <p/>This interceptor does nothing if the name of the method being invoked is specified in the <b>excludeMethods</b>
020: * parameter. <b>excludeMethods</b> accepts a comma-delimited list of method names. For example, requests to
021: * <b>foo!input.action</b> and <b>foo!back.action</b> will be skipped by this interceptor if you set the
022: * <b>excludeMethods</b> parameter to "input, back".
023: *
024: * <p/>The order of execution in the workflow is:
025: *
026: * <ol>
027: *
028: * <li>If the action being executed implements {@link Validateable}, the action's {@link Validateable#validate()
029: * validate} method is called.</li>
030: *
031: * <li>Next, if the action implements {@link ValidationAware}, the action's {@link ValidationAware#hasErrors()
032: * hasErrors} method is called. If this method returns true, this interceptor stops the chain from continuing and
033: * immediately returns {@link Action#INPUT}</li>
034: *
035: * </ol>
036: *
037: * <p/> Note: if the action doesn't implement either interface, this interceptor effectively does nothing. This
038: * interceptor is often used with the <b>validation</b> interceptor. However, it does not have to be, especially if you
039: * wish to write all your validation rules by hand in the validate() method rather than in XML files.
040: *
041: * <p/>
042: *
043: * <b>NOTE:</b> As this method extends off MethodFilterInterceptor, it is capable of
044: * deciding if it is applicable only to selective methods in the action class. See
045: * <code>MethodFilterInterceptor</code> for more info.
046: *
047: * <p/><b>Update:</b> Added logic to execute a validate{MethodName} rather than a general validate method.
048: * This allows us to run some validation logic based on the method name we specify in the
049: * ActionProxy. For example, you can specify a validateInput() method, or even a validateDoInput()
050: * method that will be run before the invocation of the input method.
051: *
052: * <!-- END SNIPPET: description -->
053: *
054: * <p/> <u>Interceptor parameters:</u>
055: *
056: * <!-- START SNIPPET: parameters -->
057: *
058: * <ul>
059: *
060: * <li>alwaysInvokeValidate - Default to true. If true validate() method will always
061: * be invoked, otherwise it will not.</li>
062: *
063: * </ul>
064: *
065: * <!-- END SNIPPET: parameters -->
066: *
067: * <p/> <u>Extending the interceptor:</u>
068: *
069: * <p/>
070: *
071: * <!-- START SNIPPET: extending -->
072: *
073: * There are no known extension points for this interceptor.
074: *
075: * <!-- END SNIPPET: extending -->
076: *
077: * <p/> <u>Example code:</u>
078: *
079: * <pre>
080: * <!-- START SNIPPET: example -->
081: *
082: * <action name="someAction" class="com.examples.SomeAction">
083: * <interceptor-ref name="params"/>
084: * <interceptor-ref name="validation"/>
085: * <interceptor-ref name="workflow"/>
086: * <result name="success">good_result.ftl</result>
087: * </action>
088: *
089: * <-- In this case myMethod of the action class will not pass through
090: * the workflow process -->
091: * <action name="someAction" class="com.examples.SomeAction">
092: * <interceptor-ref name="params"/>
093: * <interceptor-ref name="validation"/>
094: * <interceptor-ref name="workflow">
095: * <param name="excludeMethods">myMethod</param>
096: * </interceptor-ref name="workflow">
097: * <result name="success">good_result.ftl</result>
098: * </action>
099: *
100: * <!-- END SNIPPET: example -->
101: * </pre>
102: *
103: * @author Jason Carreira
104: * @author Rainer Hermanns
105: * @author <a href='mailto:the_mindstorm[at]evolva[dot]ro'>Alexandru Popescu</a>
106: * @author Philip Luppens
107: * @author tm_jee
108: *
109: * @version $Date: 2006-09-14 18:41:07 +0200 (Do, 14 Sep 2006) $ $Id: DefaultWorkflowInterceptor.java 1135 2006-09-14 16:41:07Z tm_jee $
110: */
111: public class DefaultWorkflowInterceptor extends MethodFilterInterceptor {
112:
113: private static final long serialVersionUID = 7563014655616490865L;
114:
115: private static final Log _log = LogFactory
116: .getLog(DefaultWorkflowInterceptor.class);
117:
118: private final static String VALIDATE_PREFIX = "validate";
119: private final static String ALT_VALIDATE_PREFIX = "validateDo";
120:
121: private boolean alwaysInvokeValidate = true;
122:
123: public void setAlwaysInvokeValidate(String alwaysInvokeValidate) {
124: this .alwaysInvokeValidate = Boolean.valueOf(
125: alwaysInvokeValidate).booleanValue();
126: }
127:
128: protected String doIntercept(ActionInvocation invocation)
129: throws Exception {
130: Object action = invocation.getAction();
131:
132: if (action instanceof Validateable) {
133: // keep exception that might occured in validateXXX or validateDoXXX
134: Exception exception = null;
135:
136: Validateable validateable = (Validateable) action;
137: if (_log.isDebugEnabled()) {
138: _log.debug("Invoking validate() on action "
139: + validateable);
140: }
141:
142: try {
143: PrefixMethodInvocationUtil.invokePrefixMethod(
144: invocation, new String[] { VALIDATE_PREFIX,
145: ALT_VALIDATE_PREFIX });
146: } catch (Exception e) {
147: // If any exception occurred while doing reflection, we want
148: // validate() to be executed
149: _log
150: .warn(
151: "an exception occured while executing the prefix method",
152: e);
153: exception = e;
154: }
155:
156: if (alwaysInvokeValidate) {
157: validateable.validate();
158: }
159:
160: if (exception != null) {
161: // rethrow if something is wrong while doing validateXXX / validateDoXXX
162: throw exception;
163: }
164: }
165:
166: if (action instanceof ValidationAware) {
167: ValidationAware validationAwareAction = (ValidationAware) action;
168:
169: if (validationAwareAction.hasErrors()) {
170: if (_log.isDebugEnabled()) {
171: _log.debug("Errors on action "
172: + validationAwareAction
173: + ", returning result name 'input'");
174: }
175: return Action.INPUT;
176: }
177: }
178:
179: return invocation.invoke();
180: }
181: }
|