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.util.OgnlValueStack;
011: import com.opensymphony.xwork.util.XWorkConverter;
012:
013: import java.util.HashMap;
014: import java.util.Iterator;
015: import java.util.Map;
016:
017: /**
018: * <!-- START SNIPPET: description -->
019: *
020: * This interceptor adds any error found in the {@link ActionContext}'s conversionErrors map as a field error (provided
021: * that the action implements {@link ValidationAware}). In addition, any field that contains a validation error has its
022: * original value saved such that any subsequent requests for that value return the original value rather than the value
023: * in the action. This is important because if the value "abc" is submitted and can't be converted to an int, we want to
024: * display the original string ("abc") again rather than the int value (likely 0, which would make very little sense to
025: * the user).
026: *
027: *
028: * <!-- END SNIPPET: description -->
029: *
030: * <p/> <u>Interceptor parameters:</u>
031: *
032: * <!-- START SNIPPET: parameters -->
033: *
034: * <ul>
035: *
036: * <li>None</li>
037: *
038: * </ul>
039: *
040: * <!-- END SNIPPET: parameters -->
041: *
042: * <p/> <u>Extending the interceptor:</u>
043: *
044: * <p/>
045: *
046: * <!-- START SNIPPET: extending -->
047: *
048: * Because this interceptor is not web-specific, it abstracts the logic for whether an error should be added. This
049: * allows for web-specific interceptors to use more complex logic in the {@link #shouldAddError} method for when a value
050: * has a conversion error but is null or empty or otherwise indicates that the value was never actually entered by the
051: * user.
052: *
053: * <!-- END SNIPPET: extending -->
054: *
055: * <p/> <u>Example code:</u>
056: *
057: * <pre>
058: * <!-- START SNIPPET: example -->
059: * <action name="someAction" class="com.examples.SomeAction">
060: * <interceptor-ref name="params"/>
061: * <interceptor-ref name="conversionError"/>
062: * <result name="success">good_result.ftl</result>
063: * </action>
064: * <!-- END SNIPPET: example -->
065: * </pre>
066: *
067: * ConversionErrorInterceptor adds conversion errors from the ActionContext to the Action's field errors.
068: *
069: * @author Jason Carreira
070: */
071: public class ConversionErrorInterceptor extends AroundInterceptor {
072: public static final String ORIGINAL_PROPERTY_OVERRIDE = "original.property.override";
073:
074: protected Object getOverrideExpr(ActionInvocation invocation,
075: Object value) {
076: return "'" + value + "'";
077: }
078:
079: protected void after(ActionInvocation dispatcher, String result)
080: throws Exception {
081: }
082:
083: protected void before(ActionInvocation invocation) throws Exception {
084: ActionContext invocationContext = invocation
085: .getInvocationContext();
086: Map conversionErrors = invocationContext.getConversionErrors();
087: OgnlValueStack stack = invocationContext.getValueStack();
088:
089: HashMap fakie = null;
090:
091: for (Iterator iterator = conversionErrors.entrySet().iterator(); iterator
092: .hasNext();) {
093: Map.Entry entry = (Map.Entry) iterator.next();
094: String propertyName = (String) entry.getKey();
095: Object value = entry.getValue();
096:
097: if (shouldAddError(propertyName, value)) {
098: String message = XWorkConverter
099: .getConversionErrorMessage(propertyName, stack);
100:
101: Object action = invocation.getAction();
102: if (action instanceof ValidationAware) {
103: ValidationAware va = (ValidationAware) action;
104: va.addFieldError(propertyName, message);
105: }
106:
107: if (fakie == null) {
108: fakie = new HashMap();
109: }
110:
111: fakie.put(propertyName, getOverrideExpr(invocation,
112: value));
113: }
114: }
115:
116: if (fakie != null) {
117: // if there were some errors, put the original (fake) values in place right before the result
118: stack.getContext().put(ORIGINAL_PROPERTY_OVERRIDE, fakie);
119: invocation.addPreResultListener(new PreResultListener() {
120: public void beforeResult(ActionInvocation invocation,
121: String resultCode) {
122: Map fakie = (Map) invocation.getInvocationContext()
123: .get(ORIGINAL_PROPERTY_OVERRIDE);
124:
125: if (fakie != null) {
126: invocation.getStack().setExprOverrides(fakie);
127: }
128: }
129: });
130: }
131: }
132:
133: protected boolean shouldAddError(String propertyName, Object value) {
134: return true;
135: }
136: }
|