001: /*
002: * Copyright 2004-2007 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.springframework.webflow.action;
017:
018: import org.springframework.validation.BindException;
019: import org.springframework.validation.Errors;
020: import org.springframework.webflow.execution.RequestContext;
021: import org.springframework.webflow.execution.ScopeType;
022:
023: /**
024: * Convenience helper that encapsulates logic on how to retrieve and expose form
025: * objects and associated errors to and from a flow execution request context.
026: * <p>
027: * <b>Note</b>: The form object available under the well known attribute name
028: * {@link #CURRENT_FORM_OBJECT_ATTRIBUTE} will be the last ("current") form
029: * object set in the request context. The same is true for the associated errors
030: * object. This implies that special care should be taken when accessing the
031: * form object using this alias if there are multiple form objects available in
032: * the flow execution request context!
033: *
034: * @see org.springframework.webflow.execution.RequestContext
035: * @see org.springframework.validation.Errors
036: *
037: * @author Keith Donald
038: * @author Erwin Vervaet
039: */
040: public class FormObjectAccessor {
041:
042: /**
043: * The form object instance is aliased under this attribute name in the flow
044: * context by the default form setup and bind and validate actions.
045: * <p>
046: * Note that if you would have multiple form objects in the request context,
047: * the last one that was used would be available using this alias!
048: * <p>
049: * We need to keep track of the 'current form object' using this attribute
050: * to be able to deal with the limitations of some clients that can only
051: * deal with a single form backing object, e.g. Struts when using the Struts
052: * FlowAction.
053: */
054: private static final String CURRENT_FORM_OBJECT_ATTRIBUTE = "currentFormObject";
055:
056: /**
057: * The errors prefix.
058: */
059: //use deprecated API to remain compatible with Spring 1.2.x
060: private static final String ERRORS_PREFIX = BindException.ERROR_KEY_PREFIX;
061:
062: /**
063: * The wrapped request context.
064: */
065: private RequestContext context;
066:
067: /**
068: * Creates a form object accessor that wraps the given context.
069: * @param context the flow execution request context
070: */
071: public FormObjectAccessor(RequestContext context) {
072: this .context = context;
073: }
074:
075: /**
076: * Returns the current form object name.
077: * @return the current form object name
078: */
079: public static String getCurrentFormObjectName() {
080: return CURRENT_FORM_OBJECT_ATTRIBUTE;
081: }
082:
083: /**
084: * Returns the current form object errors attribute name.
085: * @return the current form object errors attribute name
086: */
087: public static String getCurrentFormErrorsName() {
088: return ERRORS_PREFIX + getCurrentFormObjectName();
089: }
090:
091: /**
092: * Gets the form object from the context, using the well-known attribute
093: * name {@link #CURRENT_FORM_OBJECT_ATTRIBUTE}. Will try all scopes.
094: * @return the form object, or null if not found
095: */
096: public Object getCurrentFormObject() {
097: Object formObject = getCurrentFormObject(ScopeType.REQUEST);
098: if (formObject != null) {
099: return formObject;
100: }
101: formObject = getCurrentFormObject(ScopeType.FLASH);
102: if (formObject != null) {
103: return formObject;
104: }
105: formObject = getCurrentFormObject(ScopeType.FLOW);
106: if (formObject != null) {
107: return formObject;
108: }
109: return getCurrentFormObject(ScopeType.CONVERSATION);
110: }
111:
112: /**
113: * Gets the form object from the context, using the well-known attribute
114: * name {@link #CURRENT_FORM_OBJECT_ATTRIBUTE}.
115: * @param scopeType the scope to obtain the form object from
116: * @return the form object, or null if not found
117: */
118: public Object getCurrentFormObject(ScopeType scopeType) {
119: return getFormObject(getCurrentFormObjectName(), scopeType);
120: }
121:
122: /**
123: * Expose given form object using the well known alias
124: * {@link #CURRENT_FORM_OBJECT_ATTRIBUTE} in the specified scope.
125: * @param formObject the form object
126: * @param scopeType the scope in which to expose the form object
127: */
128: public void setCurrentFormObject(Object formObject,
129: ScopeType scopeType) {
130: //don't call setFormObject since that would cause infinite recursion!
131: scopeType.getScope(context).put(getCurrentFormObjectName(),
132: formObject);
133: }
134:
135: /**
136: * Gets the form object from the context, using the specified name.
137: * @param formObjectName the name of the form object in the context
138: * @param scopeType the scope to obtain the form object from
139: * @return the form object, or null if not found
140: */
141: public Object getFormObject(String formObjectName,
142: ScopeType scopeType) {
143: return scopeType.getScope(context).get(formObjectName);
144: }
145:
146: /**
147: * Gets the form object from the context, using the specified name.
148: * @param formObjectName the name of the form in the context
149: * @param formObjectClass the class of the form object, which will be
150: * verified
151: * @param scopeType the scope to obtain the form object from
152: * @return the form object, or null if not found
153: */
154: public Object getFormObject(String formObjectName,
155: Class formObjectClass, ScopeType scopeType) {
156: return scopeType.getScope(context).get(formObjectName,
157: formObjectClass);
158: }
159:
160: /**
161: * Expose given form object using given name in specified scope. Given
162: * object will become the <i>current</i> form object.
163: * @param formObject the form object
164: * @param formObjectName the name of the form object
165: * @param scopeType the scope in which to expose the form object
166: */
167: public void putFormObject(Object formObject, String formObjectName,
168: ScopeType scopeType) {
169: scopeType.getScope(context).put(formObjectName, formObject);
170: setCurrentFormObject(formObject, scopeType);
171: }
172:
173: /**
174: * Gets the form object <code>Errors</code> tracker from the context,
175: * using the form object name {@link #CURRENT_FORM_OBJECT_ATTRIBUTE}. This
176: * method will search all scopes.
177: * @return the form object Errors tracker, or null if not found
178: */
179: public Errors getCurrentFormErrors() {
180: Errors errors = getCurrentFormErrors(ScopeType.REQUEST);
181: if (errors != null) {
182: return errors;
183: }
184: errors = getCurrentFormErrors(ScopeType.FLASH);
185: if (errors != null) {
186: return errors;
187: }
188: errors = getCurrentFormErrors(ScopeType.FLOW);
189: if (errors != null) {
190: return errors;
191: }
192: return getCurrentFormErrors(ScopeType.CONVERSATION);
193: }
194:
195: /**
196: * Gets the form object <code>Errors</code> tracker from the context,
197: * using the form object name {@link #CURRENT_FORM_OBJECT_ATTRIBUTE}.
198: * @param scopeType the scope to obtain the errors from
199: * @return the form object Errors tracker, or null if not found
200: */
201: public Errors getCurrentFormErrors(ScopeType scopeType) {
202: return getFormErrors(getCurrentFormObjectName(), scopeType);
203: }
204:
205: /**
206: * Expose given errors instance using the well known alias
207: * {@link #CURRENT_FORM_OBJECT_ATTRIBUTE} in the specified scope.
208: * @param errors the errors instance
209: * @param scopeType the scope in which to expose the errors instance
210: */
211: public void setCurrentFormErrors(Errors errors, ScopeType scopeType) {
212: scopeType.getScope(context).put(getCurrentFormErrorsName(),
213: errors);
214: }
215:
216: /**
217: * Gets the form object <code>Errors</code> tracker from the context,
218: * using the specified form object name.
219: * @param formObjectName the name of the Errors object, which will be
220: * prefixed with {@link BindException#ERROR_KEY_PREFIX}
221: * @param scopeType the scope to obtain the errors from
222: * @return the form object errors instance, or null if not found
223: */
224: public Errors getFormErrors(String formObjectName,
225: ScopeType scopeType) {
226: return (Errors) scopeType.getScope(context).get(
227: ERRORS_PREFIX + formObjectName, Errors.class);
228: }
229:
230: /**
231: * Expose given errors instance in the specified scope. Given errors
232: * instance will become the <i>current</i> form errors instance.
233: * @param errors the errors object
234: * @param scopeType the scope to expose the errors in
235: */
236: public void putFormErrors(Errors errors, ScopeType scopeType) {
237: scopeType.getScope(context).put(
238: ERRORS_PREFIX + errors.getObjectName(), errors);
239: setCurrentFormErrors(errors, scopeType);
240: }
241: }
|