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.ActionContext;
008: import com.opensymphony.xwork.ActionInvocation;
009: import com.opensymphony.xwork.ValidationAware;
010: import com.opensymphony.xwork.XworkException;
011: import com.opensymphony.xwork.util.*;
012:
013: import java.util.Iterator;
014: import java.util.Map;
015: import java.util.TreeMap;
016:
017: import org.apache.commons.logging.Log;
018: import org.apache.commons.logging.LogFactory;
019:
020: /**
021: * <!-- START SNIPPET: description -->
022: * This interceptor sets all parameters on the value stack.
023: * <p/>
024: * This interceptor gets all parameters from {@link ActionContext#getParameters()} and sets them on the value stack by
025: * calling {@link OgnlValueStack#setValue(String, Object)}, typically resulting in the values submitted in a form
026: * request being applied to an action in the value stack. Note that the parameter map must contain a String key and
027: * often containers a String[] for the value.
028: *
029: * <p/> Because parameter names are effectively OGNL statements, it is important that security be taken in to account.
030: * This interceptor will not apply any values in the parameters map if the expression contains an assignment (=),
031: * multiple expressions (,), or references any objects in the context (#). This is all done in the {@link
032: * #acceptableName(String)} method. In addition to this method, if the action being invoked implements the {@link
033: * ParameterNameAware} interface, the action will be consulted to determine if the parameter should be set.
034: *
035: * <p/> In addition to these restrictions, a flag ({@link XWorkMethodAccessor#DENY_METHOD_EXECUTION}) is set such that
036: * no methods are allowed to be invoked. That means that any expression such as <i>person.doSomething()</i> or
037: * <i>person.getName()</i> will be explicitely forbidden. This is needed to make sure that your application is not
038: * exposed to attacks by malicious users.
039: *
040: * <p/> While this interceptor is being invoked, a flag ({@link InstantiatingNullHandler#CREATE_NULL_OBJECTS}) is turned
041: * on to ensure that any null reference is automatically created - if possible. See the type conversion documentation
042: * and the {@link InstantiatingNullHandler} javadocs for more information.
043: *
044: * <p/> Finally, a third flag ({@link XWorkConverter#REPORT_CONVERSION_ERRORS}) is set that indicates any errors when
045: * converting the the values to their final data type (String[] -> int) an unrecoverable error occured. With this
046: * flag set, the type conversion errors will be reported in the action context. See the type conversion documentation
047: * and the {@link XWorkConverter} javadocs for more information.
048: *
049: * <p/> If you are looking for detailed logging information about your parameters, turn on DEBUG level logging for this
050: * interceptor. A detailed log of all the parameter keys and values will be reported.
051: *
052: * <!-- END SNIPPET: description -->
053: *
054: * <p/> <u>Interceptor parameters:</u>
055: *
056: * <!-- START SNIPPET: parameters -->
057: *
058: * <ul>
059: *
060: * <li>None</li>
061: *
062: * </ul>
063: *
064: * <!-- END SNIPPET: parameters -->
065: *
066: * <p/> <u>Extending the interceptor:</u>
067: *
068: * <!-- START SNIPPET: extending -->
069: *
070: * <p/> The best way to add behavior to this interceptor is to utilize the {@link ParameterNameAware} interface in your
071: * actions. However, if you wish to apply a global rule that isn't implemented in your action, then you could extend
072: * this interceptor and override the {@link #acceptableName(String)} method.
073: *
074: * <!-- END SNIPPET: extending -->
075: *
076: * <p/> <u>Example code:</u>
077: *
078: * <pre>
079: * <!-- START SNIPPET: example -->
080: * <action name="someAction" class="com.examples.SomeAction">
081: * <interceptor-ref name="params"/>
082: * <result name="success">good_result.ftl</result>
083: * </action>
084: * <!-- END SNIPPET: example -->
085: * </pre>
086: *
087: * @author Patrick Lightbody
088: * @author tmjee
089: *
090: * @version $Date: 2007-05-31 05:05:34 +0200 (Thu, 31 May 2007) $ $Id: ParametersInterceptor.java 1530 2007-05-31 03:05:34Z tm_jee $
091: */
092: public class ParametersInterceptor extends AroundInterceptor {
093:
094: private static final long serialVersionUID = 1939469770555684892L;
095:
096: private static final Log LOG = LogFactory
097: .getLog(ParametersInterceptor.class);
098:
099: protected void after(ActionInvocation dispatcher, String result)
100: throws Exception {
101: }
102:
103: protected void before(ActionInvocation invocation) throws Exception {
104: if (!(invocation.getAction() instanceof NoParameters)) {
105: ActionContext ac = invocation.getInvocationContext();
106: final Map parameters = ac.getParameters();
107:
108: if (log.isDebugEnabled()) {
109: log.debug("Setting params "
110: + getParameterLogMap(parameters));
111: }
112:
113: if (parameters != null) {
114: Map contextMap = ac.getContextMap();
115: try {
116: OgnlContextState.setCreatingNullObjects(contextMap,
117: true);
118: OgnlContextState.setDenyMethodExecution(contextMap,
119: true);
120: OgnlContextState.setReportingConversionErrors(
121: contextMap, true);
122:
123: OgnlValueStack stack = ac.getValueStack();
124: setParameters(invocation.getAction(), stack,
125: parameters);
126: } finally {
127: OgnlContextState.setCreatingNullObjects(contextMap,
128: false);
129: OgnlContextState.setDenyMethodExecution(contextMap,
130: false);
131: OgnlContextState.setReportingConversionErrors(
132: contextMap, false);
133: }
134: }
135: }
136: }
137:
138: protected void setParameters(Object action, OgnlValueStack stack,
139: final Map parameters) {
140: ParameterNameAware parameterNameAware = (action instanceof ParameterNameAware) ? (ParameterNameAware) action
141: : null;
142:
143: for (Iterator iterator = (new TreeMap(parameters)).entrySet()
144: .iterator(); iterator.hasNext();) {
145: Map.Entry entry = (Map.Entry) iterator.next();
146: String name = entry.getKey().toString();
147:
148: boolean acceptableName = acceptableName(name)
149: && (parameterNameAware == null || parameterNameAware
150: .acceptableParameterName(name));
151:
152: if (acceptableName) {
153: Object value = entry.getValue();
154: try {
155: stack.setValue(name, value);
156: } catch (XworkException e) {
157: final Boolean devMode = (Boolean) stack
158: .getContext().get(ActionContext.DEV_MODE);
159: if (devMode != null && devMode.booleanValue()) {
160: String developerNotification = LocalizedTextUtil
161: .findText(
162: ParametersInterceptor.class,
163: "webwork.messages.devmode.notification",
164: ActionContext.getContext()
165: .getLocale(),
166: "Developer Notification (set webwork.devMode to false to disable this message):\n{0}",
167: new Object[] { e.getMessage() });
168: LOG.error(developerNotification);
169: if (action instanceof ValidationAware) {
170: ((ValidationAware) action)
171: .addActionMessage(developerNotification);
172: }
173: } else {
174: LOG
175: .error("ParametersInterceptor - [setParameters]: Unexpected Exception catched: "
176: + e.getMessage());
177: }
178: }
179: }
180: }
181: }
182:
183: private String getParameterLogMap(Map parameters) {
184: if (parameters == null) {
185: return "NONE";
186: }
187:
188: StringBuffer logEntry = new StringBuffer();
189: for (Iterator paramIter = parameters.entrySet().iterator(); paramIter
190: .hasNext();) {
191: Map.Entry entry = (Map.Entry) paramIter.next();
192: logEntry.append(String.valueOf(entry.getKey()));
193: logEntry.append(" => ");
194: if (entry.getValue() instanceof Object[]) {
195: Object[] valueArray = (Object[]) entry.getValue();
196: logEntry.append("[ ");
197: for (int indexA = 0; indexA < (valueArray.length - 1); indexA++) {
198: Object valueAtIndex = valueArray[indexA];
199: logEntry.append(String.valueOf(valueAtIndex));
200: logEntry.append(", ");
201: }
202: logEntry.append(String
203: .valueOf(valueArray[valueArray.length - 1]));
204: logEntry.append(" ] ");
205: } else {
206: logEntry.append(String.valueOf(entry.getValue()));
207: }
208: }
209:
210: return logEntry.toString();
211: }
212:
213: protected boolean acceptableName(String name) {
214: if (name.indexOf('=') != -1 || name.indexOf(',') != -1
215: || name.indexOf('#') != -1 || name.indexOf(':') != -1) {
216: return false;
217: } else {
218: return true;
219: }
220: }
221: }
|