Source Code Cross Referenced for FormAction.java in  » Workflow-Engines » spring-webflow-1.0.4 » org » springframework » webflow » action » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Workflow Engines » spring webflow 1.0.4 » org.springframework.webflow.action 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Copyright 2004-2007 the original author or authors.
0003:         *
0004:         * Licensed under the Apache License, Version 2.0 (the "License");
0005:         * you may not use this file except in compliance with the License.
0006:         * You may obtain a copy of the License at
0007:         *
0008:         *      http://www.apache.org/licenses/LICENSE-2.0
0009:         *
0010:         * Unless required by applicable law or agreed to in writing, software
0011:         * distributed under the License is distributed on an "AS IS" BASIS,
0012:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013:         * See the License for the specific language governing permissions and
0014:         * limitations under the License.
0015:         */
0016:        package org.springframework.webflow.action;
0017:
0018:        import java.lang.reflect.Method;
0019:
0020:        import org.springframework.beans.MutablePropertyValues;
0021:        import org.springframework.beans.PropertyEditorRegistrar;
0022:        import org.springframework.beans.PropertyEditorRegistry;
0023:        import org.springframework.beans.factory.InitializingBean;
0024:        import org.springframework.beans.propertyeditors.PropertiesEditor;
0025:        import org.springframework.core.style.StylerUtils;
0026:        import org.springframework.util.Assert;
0027:        import org.springframework.util.ClassUtils;
0028:        import org.springframework.util.StringUtils;
0029:        import org.springframework.validation.BindException;
0030:        import org.springframework.validation.DataBinder;
0031:        import org.springframework.validation.Errors;
0032:        import org.springframework.validation.MessageCodesResolver;
0033:        import org.springframework.validation.Validator;
0034:        import org.springframework.web.bind.WebDataBinder;
0035:        import org.springframework.webflow.execution.Event;
0036:        import org.springframework.webflow.execution.RequestContext;
0037:        import org.springframework.webflow.execution.ScopeType;
0038:        import org.springframework.webflow.util.DispatchMethodInvoker;
0039:        import org.springframework.webflow.util.ReflectionUtils;
0040:
0041:        /**
0042:         * Multi-action that implements common logic dealing with input forms. This
0043:         * class leverages the Spring Web data binding code to do binding and
0044:         * validation.
0045:         * <p>
0046:         * Several action execution methods are provided:
0047:         * <ul>
0048:         * <li> {@link #setupForm(RequestContext)} - Prepares the form object for
0049:         * display on a form, {@link #createFormObject(RequestContext) creating it} and
0050:         * an associated {@link Errors errors object} if necessary, then caching them in
0051:         * the configured {@link #getFormObjectScope() form object scope} and
0052:         * {@link #getFormErrorsScope() form errors scope}, respectively. Also
0053:         * {@link #registerPropertyEditors(PropertyEditorRegistry) installs} any custom
0054:         * property editors for formatting form object field values. This action method
0055:         * will return the "success" event unless an exception is thrown. </li>
0056:         * <li> {@link #bindAndValidate(RequestContext)} - Binds all incoming request
0057:         * parameters to the form object and then validates the form object using a
0058:         * {@link #setValidator(Validator) registered validator}. This action method
0059:         * will return the "success" event if there are no binding or validation errors,
0060:         * otherwise it will return the "error" event. </li>
0061:         * <li> {@link #bind(RequestContext)} - Binds all incoming request parameters to
0062:         * the form object. No additional validation is performed. This action method
0063:         * will return the "success" event if there are no binding errors, otherwise it
0064:         * will return the "error" event. </li>
0065:         * <li> {@link #validate(RequestContext)} - Validates the form object using a
0066:         * registered validator. No data binding is performed. This action method will
0067:         * return the "success" event if there are no validation errors, otherwise it
0068:         * will return the "error" event. </li>
0069:         * <li> {@link #resetForm(RequestContext)} - Resets the form by reloading the
0070:         * backing form object and reinstalling any custom property editors. Returns
0071:         * "success" on completion, an exception is thrown when a failure occurs. </li>
0072:         * </ul>
0073:         * <p>
0074:         * Since this is a multi-action a subclass could add any number of additional
0075:         * action execution methods, e.g. "setupReferenceData(RequestContext)", or
0076:         * "processSubmit(RequestContext)".
0077:         * <p>
0078:         * Using this action, it becomes very easy to implement form preparation and
0079:         * submission logic in your flow. One way to do this follows:
0080:         * <ol>
0081:         * <li> Create a view state to display the form. In a render action of that
0082:         * state, invoke {@link #setupForm(RequestContext) setupForm} to prepare the new
0083:         * form for display. </li>
0084:         * <li> On a matching "submit" transition execute an action that invokes
0085:         * {@link #bindAndValidate(RequestContext) bindAndValidate} to bind incoming
0086:         * request parameters to the form object and validate the form object. </li>
0087:         * <li> If there are binding or validation errors, the transition will not be
0088:         * allowed and the view state will automatically be re-entered.
0089:         * <li> If binding and validation is successful go to an action state called
0090:         * "processSubmit" (or any other appropriate name). This will invoke an action
0091:         * method called "processSubmit" you must provide on a subclass to process form
0092:         * submission, e.g. interacting with the business logic. </li>
0093:         * <li> If business processing is ok, continue to a view state to display the
0094:         * success view. </li>
0095:         * </ol>
0096:         * <p>
0097:         * Here is an example implementation of such a compact form flow:
0098:         * 
0099:         * <pre>
0100:         *     &lt;view-state id=&quot;displayCriteria&quot; view=&quot;searchCriteria&quot;&gt;
0101:         *         &lt;render-actions&gt;
0102:         *             &lt;action bean=&quot;formAction&quot; method=&quot;setupForm&quot;/&gt;
0103:         *         &lt;/render-actions&gt;
0104:         *         &lt;transition on=&quot;search&quot; to=&quot;executeSearch&quot;&gt;
0105:         *             &lt;action bean=&quot;formAction&quot; method=&quot;bindAndValidate&quot;/&gt;
0106:         *         &lt;/transition&gt;
0107:         *     &lt;/view-state&gt;
0108:         *                                                                                
0109:         *     &lt;action-state id=&quot;executeSearch&quot;&gt;
0110:         *         &lt;action bean=&quot;formAction&quot; method=&quot;executeSearch&quot;/&gt;
0111:         *         &lt;transition on=&quot;success&quot; to=&quot;displayResults&quot;/&gt;
0112:         *     &lt;/action-state&gt;
0113:         * </pre>
0114:         * 
0115:         * <p>
0116:         * When you need additional flexibility consider splitting the view state above
0117:         * acting as a single logical <i>form state</i> into multiple states. For
0118:         * example, you could have one action state handle form setup, a view state
0119:         * trigger form display, another action state handle data binding and
0120:         * validation, and another process form submission. This would be a bit more
0121:         * verbose but would also give you more control over how you respond to specific
0122:         * results of fine-grained actions that occur within the flow.
0123:         * <p>
0124:         * <b>Subclassing hooks:</b>
0125:         * <ul>
0126:         * <li>A important hook is
0127:         * {@link #createFormObject(RequestContext) createFormObject}. You may override
0128:         * this to customize where the backing form object instance comes from (e.g
0129:         * instantiated transiently in memory or loaded from a database).</li>
0130:         * <li>An optional hook method provided by this class is
0131:         * {@link #initBinder(RequestContext, DataBinder) initBinder}. This is called
0132:         * after a new data binder is created.
0133:         * <li>Another optional ook method is
0134:         * {@link #registerPropertyEditors(PropertyEditorRegistry)}. By overriding it
0135:         * you can register any required property editors for your form. Instead of
0136:         * overriding this method, consider setting an explicit
0137:         * {@link org.springframework.beans.PropertyEditorRegistrar} strategy as a more
0138:         * reusable way to encapsulate custom PropertyEditor installation logic.</li>
0139:         * <li>Override {@link #validationEnabled(RequestContext)} to dynamically
0140:         * decide whether or not to do validation based on data available in the request
0141:         * context.
0142:         * </ul>
0143:         * <p>
0144:         * Note that this action does not provide a <i>referenceData()</i> hook method
0145:         * similar to that of Spring MVC's <code>SimpleFormController</code>. If you
0146:         * wish to expose reference data to populate form drop downs you can define a
0147:         * custom action method in your FormAction subclass that does just that. Simply
0148:         * invoke it as either a chained action as part of the setupForm state, or as a
0149:         * fine grained state definition itself.
0150:         * <p>
0151:         * For example, you might create this method in your subclass:
0152:         * 
0153:         * <pre>
0154:         * public Event setupReferenceData(RequestContext context) throws Exception {
0155:         *     MutableAttributeMap requestScope = context.getRequestScope();
0156:         *     requestScope.put(&quot;refData&quot;, lookupService.getSupportingFormData());
0157:         *     return success();
0158:         * }
0159:         * </pre>
0160:         * 
0161:         * ... and then invoke it like this:
0162:         * 
0163:         * <pre>
0164:         *     &lt;view-state id=&quot;displayCriteria&quot; view=&quot;searchCriteria&quot;&gt;
0165:         *         &lt;render-actions&gt;
0166:         *             &lt;action bean=&quot;searchFormAction&quot; method=&quot;setupForm&quot;/&gt;
0167:         *             &lt;action bean=&quot;searchFormAction&quot; method=&quot;setupReferenceData&quot;/&gt;
0168:         *         &lt;/render-actions&gt;
0169:         *         ...
0170:         *     &lt;/view-state&gt;
0171:         * </pre>
0172:         * 
0173:         * This style of calling multiple action methods in a chain (Chain of
0174:         * Responsibility) is preferred to overridding a single action method. In
0175:         * general, action method overriding is discouraged.
0176:         * <p>
0177:         * When it comes to validating submitted input data using a registered
0178:         * {@link org.springframework.validation.Validator}, this class offers the
0179:         * following options:
0180:         * <ul>
0181:         * <li>If you don't want validation at all, just call
0182:         * {@link #bind(RequestContext)} instead of
0183:         * {@link #bindAndValidate(RequestContext)} or don't register a validator.</li>
0184:         * <li>If you want piecemeal validation, e.g. in a multi-page wizard, call
0185:         * {@link #bindAndValidate(RequestContext)} or {@link #validate(RequestContext)}
0186:         * and specify a {@link #VALIDATOR_METHOD_ATTRIBUTE validatorMethod} action
0187:         * execution attribute. This will invoke the identified custom validator method
0188:         * on the validator. The validator method signature should follow the following
0189:         * pattern:
0190:         * 
0191:         * <pre>
0192:         *     public void ${validateMethodName}(${formObjectClass}, Errors)
0193:         * </pre>
0194:         * 
0195:         * For instance, having a action definition like this:
0196:         * 
0197:         * <pre>
0198:         *     &lt;action bean=&quot;searchFormAction&quot; method=&quot;bindAndValidate&quot;&gt;
0199:         *         &lt;attribute name=&quot;validatorMethod&quot; value=&quot;validateSearchCriteria&quot;/&gt;
0200:         *     &lt;/action&gt;
0201:         * </pre>
0202:         * 
0203:         * Would result in the
0204:         * <tt>public void validateSearchCriteria(SearchCriteria, Errors)</tt> method
0205:         * of the registered validator being called if the form object class would be
0206:         * <code>SearchCriteria</code>.</li>
0207:         * <li>If you want to do full validation using the
0208:         * {@link org.springframework.validation.Validator#validate(java.lang.Object, org.springframework.validation.Errors) validate}
0209:         * method of the registered validator, call
0210:         * {@link #bindAndValidate(RequestContext)} or {@link #validate(RequestContext)}
0211:         * without specifying a "validatorMethod" action execution attribute.</li>
0212:         * </ul>
0213:         * 
0214:         * <p>
0215:         * <b>FormAction configurable properties</b><br>
0216:         * <table border="1">
0217:         * <tr>
0218:         * <td><b>name</b></td>
0219:         * <td><b>default</b></td>
0220:         * <td><b>description</b></td>
0221:         * </tr>
0222:         * <tr>
0223:         * <td>formObjectName</td>
0224:         * <td>formObject</td>
0225:         * <td>The name of the form object. The form object will be set in the
0226:         * configured scope using this name.</td>
0227:         * </tr>
0228:         * <tr>
0229:         * <td>formObjectClass</td>
0230:         * <td>null</td>
0231:         * <td>The form object class for this action. An instance of this class will
0232:         * get populated and validated. Required when using a validator.</td>
0233:         * </tr>
0234:         * <tr>
0235:         * <td>formObjectScope</td>
0236:         * <td>{@link org.springframework.webflow.execution.ScopeType#FLOW flow}</td>
0237:         * <td>The scope in which the form object will be put. If put in flow scope the
0238:         * object will be cached and reused over the life of the flow, preserving
0239:         * previous values. Request scope will cause a new fresh form object instance to
0240:         * be created on each request into the flow execution.</td>
0241:         * </tr>
0242:         * <tr>
0243:         * <td>formErrorsScope</td>
0244:         * <td>{@link org.springframework.webflow.execution.ScopeType#FLASH flash}</td>
0245:         * <td>The scope in which the form object errors instance will be put. If put
0246:         * in flash scope form errors will be cached until the next user event is signaled.
0247:         * </td>
0248:         * </tr>
0249:         * <tr>
0250:         * <td>propertyEditorRegistrar</td>
0251:         * <td>null</td>
0252:         * <td>The strategy used to register custom property editors with the data
0253:         * binder. This is an alternative to overriding the
0254:         * {@link #registerPropertyEditors(PropertyEditorRegistry)} hook method. </td>
0255:         * </tr>
0256:         * <tr>
0257:         * <td>validator</td>
0258:         * <td>null</td>
0259:         * <td>The validator for this action. The validator must support the specified
0260:         * form object class. </td>
0261:         * </tr>
0262:         * <tr>
0263:         * <td>messageCodesResolver</td>
0264:         * <td>null</td>
0265:         * <td>Set the strategy to use for resolving errors into message codes. </td>
0266:         * </tr>
0267:         * </table>
0268:         * 
0269:         * @see org.springframework.beans.PropertyEditorRegistrar
0270:         * @see org.springframework.validation.DataBinder
0271:         * @see ScopeType
0272:         * 
0273:         * @author Erwin Vervaet
0274:         * @author Keith Donald
0275:         */
0276:        public class FormAction extends MultiAction implements  InitializingBean {
0277:
0278:            /*
0279:             * Implementation note: Uses deprecated DataBinder.getErrors() to remain
0280:             * compatible with Spring 1.2.x.
0281:             */
0282:
0283:            /*
0284:             * Implementation note: Introspects BindException at class init time to
0285:             * preserve 1.2.x compatability.
0286:             */
0287:            private static boolean hasPropertyEditorRegistryAccessor;
0288:
0289:            static {
0290:                hasPropertyEditorRegistryAccessor = ClassUtils.hasMethod(
0291:                        BindException.class, "getPropertyEditorRegistry", null);
0292:            }
0293:
0294:            /**
0295:             * The default form object name ("formObject").
0296:             */
0297:            public static final String DEFAULT_FORM_OBJECT_NAME = "formObject";
0298:
0299:            /**
0300:             * Optional attribute that identifies the method that should be invoked on
0301:             * the configured validator instance, to support piecemeal wizard page
0302:             * validation ("validatorMethod").
0303:             */
0304:            public static final String VALIDATOR_METHOD_ATTRIBUTE = "validatorMethod";
0305:
0306:            /**
0307:             * The name the form object should be exposed under. Default is
0308:             * {@link #DEFAULT_FORM_OBJECT_NAME}.
0309:             */
0310:            private String formObjectName = DEFAULT_FORM_OBJECT_NAME;
0311:
0312:            /**
0313:             * The type of form object, typically an instantiable class. Required if
0314:             * {@link #createFormObject(RequestContext)} is not overidden or when
0315:             * a validator is used.
0316:             */
0317:            private Class formObjectClass;
0318:
0319:            /**
0320:             * The scope in which the form object should be exposed. Default is
0321:             * {@link ScopeType#FLOW}.
0322:             */
0323:            private ScopeType formObjectScope = ScopeType.FLOW;
0324:
0325:            /**
0326:             * The scope in which the form object errors holder should be exposed.
0327:             * Default is {@link ScopeType#FLASH}.
0328:             */
0329:            private ScopeType formErrorsScope = ScopeType.FLASH;
0330:
0331:            /**
0332:             * A centralized service for property editor registration, for applying type
0333:             * conversion during form object data binding. Can be used as an alternative
0334:             * to overriding {@link #registerPropertyEditors(PropertyEditorRegistry)}.
0335:             */
0336:            private PropertyEditorRegistrar propertyEditorRegistrar;
0337:
0338:            /**
0339:             * A validator for the form's form object.
0340:             */
0341:            private Validator validator;
0342:
0343:            /**
0344:             * Strategy for resolving error message codes.
0345:             */
0346:            private MessageCodesResolver messageCodesResolver;
0347:
0348:            /**
0349:             * A cache for dispatched validator methods.
0350:             */
0351:            private DispatchMethodInvoker validateMethodInvoker;
0352:
0353:            /**
0354:             * Bean-style default constructor; creates a initially unconfigured
0355:             * FormAction instance relying on default property values. Clients invoking
0356:             * this constructor directly must set the formObjectClass property
0357:             * or override {@link #createFormObject(RequestContext)}.
0358:             * @see #setFormObjectClass(Class)
0359:             */
0360:            public FormAction() {
0361:            }
0362:
0363:            /**
0364:             * Creates a new form action that manages instance(s) of the specified form
0365:             * object class.
0366:             * @param formObjectClass the class of the form object (must be instantiable)
0367:             */
0368:            public FormAction(Class formObjectClass) {
0369:                setFormObjectClass(formObjectClass);
0370:            }
0371:
0372:            /**
0373:             * Return the name of the form object in the configured scope.
0374:             */
0375:            public String getFormObjectName() {
0376:                return formObjectName;
0377:            }
0378:
0379:            /**
0380:             * Set the name of the form object in the configured scope. The form object
0381:             * will be included in the configured scope under this name.
0382:             */
0383:            public void setFormObjectName(String formObjectName) {
0384:                this .formObjectName = formObjectName;
0385:            }
0386:
0387:            /**
0388:             * Return the form object class for this action.
0389:             */
0390:            public Class getFormObjectClass() {
0391:                return formObjectClass;
0392:            }
0393:
0394:            /**
0395:             * Set the form object class for this action. An instance of this class will
0396:             * get populated and validated. This is a required property if you register
0397:             * a validator with the form action ({@link #setValidator(Validator)})!
0398:             * <p>
0399:             * If no form object name is set at the moment this method is called, a
0400:             * form object name will be automatically generated based on the provided
0401:             * form object class using
0402:             * {@link ClassUtils#getShortNameAsProperty(java.lang.Class)}.
0403:             */
0404:            public void setFormObjectClass(Class formObjectClass) {
0405:                this .formObjectClass = formObjectClass;
0406:                // generate a default form object name
0407:                if ((getFormObjectName() == null || getFormObjectName() == DEFAULT_FORM_OBJECT_NAME)
0408:                        && formObjectClass != null) {
0409:                    setFormObjectName(ClassUtils
0410:                            .getShortNameAsProperty(formObjectClass));
0411:                }
0412:            }
0413:
0414:            /**
0415:             * Get the scope in which the form object will be placed.
0416:             */
0417:            public ScopeType getFormObjectScope() {
0418:                return formObjectScope;
0419:            }
0420:
0421:            /**
0422:             * Set the scope in which the form object will be placed.  The default 
0423:             * if not set is {@link ScopeType#FLOW flow scope}.
0424:             */
0425:            public void setFormObjectScope(ScopeType scopeType) {
0426:                this .formObjectScope = scopeType;
0427:            }
0428:
0429:            /**
0430:             * Get the scope in which the Errors object will be placed.
0431:             */
0432:            public ScopeType getFormErrorsScope() {
0433:                return formErrorsScope;
0434:            }
0435:
0436:            /**
0437:             * Set the scope in which the Errors object will be placed.  The default 
0438:             * if not set is {@link ScopeType#FLASH flash scope}.
0439:             */
0440:            public void setFormErrorsScope(ScopeType errorsScope) {
0441:                this .formErrorsScope = errorsScope;
0442:            }
0443:
0444:            /**
0445:             * Get the property editor registration strategy for this action's data
0446:             * binders.
0447:             */
0448:            public PropertyEditorRegistrar getPropertyEditorRegistrar() {
0449:                return propertyEditorRegistrar;
0450:            }
0451:
0452:            /**
0453:             * Set a property editor registration strategy for this action's data
0454:             * binders. This is an alternative to overriding the
0455:             * {@link #registerPropertyEditors(PropertyEditorRegistry)} method.
0456:             */
0457:            public void setPropertyEditorRegistrar(
0458:                    PropertyEditorRegistrar propertyEditorRegistrar) {
0459:                this .propertyEditorRegistrar = propertyEditorRegistrar;
0460:            }
0461:
0462:            /**
0463:             * Returns the validator for this action.
0464:             */
0465:            public Validator getValidator() {
0466:                return validator;
0467:            }
0468:
0469:            /**
0470:             * Set the validator for this action. When setting a validator, you must also
0471:             * set the {@link #setFormObjectClass(Class) form object class}. The validator
0472:             * must support the specified form object class.
0473:             */
0474:            public void setValidator(Validator validator) {
0475:                this .validator = validator;
0476:            }
0477:
0478:            /**
0479:             * Return the strategy to use for resolving errors into message codes.
0480:             */
0481:            public MessageCodesResolver getMessageCodesResolver() {
0482:                return messageCodesResolver;
0483:            }
0484:
0485:            /**
0486:             * Set the strategy to use for resolving errors into message codes. Applies
0487:             * the given strategy to all data binders used by this action.
0488:             * <p>
0489:             * Default is null, i.e. using the default strategy of the data binder.
0490:             * @see #createBinder(RequestContext, Object)
0491:             * @see org.springframework.validation.DataBinder#setMessageCodesResolver(org.springframework.validation.MessageCodesResolver)
0492:             */
0493:            public void setMessageCodesResolver(
0494:                    MessageCodesResolver messageCodesResolver) {
0495:                this .messageCodesResolver = messageCodesResolver;
0496:            }
0497:
0498:            protected void initAction() {
0499:                if (getValidator() != null) {
0500:                    if (getFormObjectClass() != null
0501:                            && !getValidator().supports(getFormObjectClass())) {
0502:                        throw new IllegalArgumentException("Validator ["
0503:                                + getValidator()
0504:                                + "] does not support form object class ["
0505:                                + getFormObjectClass() + "]");
0506:                    }
0507:                    // signature: public void ${validateMethodName}(${formObjectClass}, Errors)
0508:                    validateMethodInvoker = new DispatchMethodInvoker(
0509:                            getValidator(), new Class[] { getFormObjectClass(),
0510:                                    Errors.class });
0511:                }
0512:            }
0513:
0514:            // action methods
0515:
0516:            /**
0517:             * Prepares a form object for display in a new form, creating it and caching
0518:             * it in the {@link #getFormObjectScope()} if necessary. Also installs
0519:             * custom property editors for formatting form object values in UI controls
0520:             * such as text fields.
0521:             * <p>
0522:             * A new form object instance will only be created (or more generally
0523:             * acquired) with a call to {@link #createFormObject(RequestContext)},
0524:             * if the form object does not yet exist in the configured 
0525:             * {@link #getFormObjectScope() scope}. If you want to reset the form
0526:             * handling machinery, including creation or loading of a fresh form object
0527:             * instance, call {@link #resetForm(RequestContext)} instead.
0528:             * <p>
0529:             * NOTE: This action method is not designed to be overidden and might
0530:             * become <code>final</code> in a future version of Spring Web Flow. If
0531:             * you need to execute custom form setup logic have your flow call this
0532:             * method along with your own custom methods as part of a single action
0533:             * chain.
0534:             * @param context the action execution context, for accessing and setting
0535:             * data in "flow scope" or "request scope"
0536:             * @return "success" when binding and validation is successful
0537:             * @throws Exception an <b>unrecoverable</b> exception occurs, either
0538:             * checked or unchecked
0539:             * @see #createFormObject(RequestContext)
0540:             */
0541:            public Event setupForm(RequestContext context) throws Exception {
0542:                if (logger.isDebugEnabled()) {
0543:                    logger.debug("Executing setupForm");
0544:                }
0545:                // retrieve the form object, creating it if necessary
0546:                Object formObject = getFormObject(context);
0547:                ensureFormErrorsExposed(context, formObject);
0548:                return success();
0549:            }
0550:
0551:            /**
0552:             * Bind incoming request parameters to allowed fields of the form object and
0553:             * then validate the bound form object if a validator is configured.
0554:             * <p>
0555:             * NOTE: This action method is not designed to be overidden and might
0556:             * become <code>final</code> in a future version of Spring Web Flow. If
0557:             * you need to execute custom bind and validate logic have your flow call
0558:             * this method along with your own custom methods as part of a single action
0559:             * chain. Alternatively, override the
0560:             * {@link #doBind(RequestContext, DataBinder)} or
0561:             * {@link #doValidate(RequestContext, Object, Errors)} hooks.
0562:             * @param context the action execution context, for accessing and setting
0563:             * data in "flow scope" or "request scope"
0564:             * @return "success" when binding and validation is successful, "error" if
0565:             * there were binding and/or validation errors
0566:             * @throws Exception an <b>unrecoverable</b> exception occured, either
0567:             * checked or unchecked
0568:             */
0569:            public Event bindAndValidate(RequestContext context)
0570:                    throws Exception {
0571:                if (logger.isDebugEnabled()) {
0572:                    logger.debug("Executing bind");
0573:                }
0574:                Object formObject = getFormObject(context);
0575:                DataBinder binder = createBinder(context, formObject);
0576:                doBind(context, binder);
0577:                if (getValidator() != null && validationEnabled(context)) {
0578:                    if (logger.isDebugEnabled()) {
0579:                        logger.debug("Executing validation");
0580:                    }
0581:                    doValidate(context, formObject, binder.getErrors());
0582:                } else {
0583:                    if (logger.isDebugEnabled()) {
0584:                        if (getValidator() == null) {
0585:                            logger
0586:                                    .debug("No validator is configured, no validation will occur after binding");
0587:                        } else {
0588:                            logger
0589:                                    .debug("Validation was disabled for this bindAndValidate request");
0590:                        }
0591:                    }
0592:                }
0593:                putFormErrors(context, binder.getErrors());
0594:                return binder.getErrors().hasErrors() ? error() : success();
0595:            }
0596:
0597:            /**
0598:             * Bind incoming request parameters to allowed fields of the form object.
0599:             * <p>
0600:             * NOTE: This action method is not designed to be overidden and might
0601:             * become <code>final</code> in a future version of Spring Web Flow. If
0602:             * you need to execute custom data binding logic have your flow call this
0603:             * method along with your own custom methods as part of a single action
0604:             * chain. Alternatively, override the
0605:             * {@link #doBind(RequestContext, DataBinder)} hook.
0606:             * @param context the action execution context, for accessing and setting
0607:             * data in "flow scope" or "request scope"
0608:             * @return "success" if there are no binding errors, "error" otherwise
0609:             * @throws Exception an <b>unrecoverable</b> exception occured, either
0610:             * checked or unchecked
0611:             */
0612:            public Event bind(RequestContext context) throws Exception {
0613:                if (logger.isDebugEnabled()) {
0614:                    logger.debug("Executing bind");
0615:                }
0616:                Object formObject = getFormObject(context);
0617:                DataBinder binder = createBinder(context, formObject);
0618:                doBind(context, binder);
0619:                putFormErrors(context, binder.getErrors());
0620:                return binder.getErrors().hasErrors() ? error() : success();
0621:            }
0622:
0623:            /**
0624:             * Validate the form object by invoking the validator if configured.
0625:             * <p>
0626:             * NOTE: This action method is not designed to be overidden and might
0627:             * become <code>final</code> in a future version of Spring Web Flow. If
0628:             * you need to execute custom validation logic have your flow call this
0629:             * method along with your own custom methods as part of a single action
0630:             * chain. Alternatively, override the
0631:             * {@link #doValidate(RequestContext, Object, Errors)} hook.
0632:             * @param context the action execution context, for accessing and setting
0633:             * data in "flow scope" or "request scope"
0634:             * @return "success" if there are no validation errors, "error" otherwise
0635:             * @throws Exception an <b>unrecoverable</b> exception occured, either
0636:             * checked or unchecked
0637:             * @see #getValidator()
0638:             */
0639:            public Event validate(RequestContext context) throws Exception {
0640:                if (getValidator() != null && validationEnabled(context)) {
0641:                    if (logger.isDebugEnabled()) {
0642:                        logger.debug("Executing validation");
0643:                    }
0644:                    Object formObject = getFormObject(context);
0645:                    Errors errors = getFormErrors(context);
0646:                    doValidate(context, formObject, errors);
0647:                    return errors.hasErrors() ? error() : success();
0648:                } else {
0649:                    if (logger.isDebugEnabled()) {
0650:                        if (getValidator() == null) {
0651:                            logger
0652:                                    .debug("No validator is configured, no validation will occur");
0653:                        } else {
0654:                            logger
0655:                                    .debug("Validation was disabled for this request");
0656:                        }
0657:                    }
0658:                    return success();
0659:                }
0660:            }
0661:
0662:            /**
0663:             * Resets the form by clearing out the form object in the specified scope
0664:             * and recreating it.
0665:             * <p>
0666:             * NOTE: This action method is not designed to be overidden and might
0667:             * become <code>final</code> in a future version of Spring Web Flow. If
0668:             * you need to execute custom reset logic have your flow call this method
0669:             * along with your own custom methods as part of a single action chain.
0670:             * @param context the request context
0671:             * @return "success" if the reset action completed successfully
0672:             * @throws Exception if an exception occured
0673:             * @see #createFormObject(RequestContext)
0674:             */
0675:            public Event resetForm(RequestContext context) throws Exception {
0676:                Object formObject = initFormObject(context);
0677:                initFormErrors(context, formObject);
0678:                return success();
0679:            }
0680:
0681:            // internal helpers
0682:
0683:            /**
0684:             * Create the new form object and put it in the configured
0685:             * {@link #getFormObjectScope() scope}.
0686:             * @param context the flow execution request context
0687:             * @return the new form object
0688:             * @throws Exception an exception occured creating the form object
0689:             */
0690:            private Object initFormObject(RequestContext context)
0691:                    throws Exception {
0692:                if (logger.isDebugEnabled()) {
0693:                    logger.debug("Creating new form object with name '"
0694:                            + getFormObjectName() + "'");
0695:                }
0696:                Object formObject = createFormObject(context);
0697:                putFormObject(context, formObject);
0698:                return formObject;
0699:            }
0700:
0701:            /**
0702:             * Put given form object in the configured scope of given context.
0703:             */
0704:            private void putFormObject(RequestContext context, Object formObject) {
0705:                if (logger.isDebugEnabled()) {
0706:                    logger.debug("Putting form object of type ["
0707:                            + formObject.getClass() + "] in scope "
0708:                            + getFormObjectScope() + " with name '"
0709:                            + getFormObjectName() + "'");
0710:                }
0711:                getFormObjectAccessor(context).putFormObject(formObject,
0712:                        getFormObjectName(), getFormObjectScope());
0713:            }
0714:
0715:            /**
0716:             * Initialize a new form object {@link Errors errors} instance in the
0717:             * configured {@link #getFormErrorsScope() scope}. This method also
0718:             * registers any {@link PropertiesEditor property editors} used to format
0719:             * form object property values.
0720:             * @param context the current flow execution request context
0721:             * @param formObject the form object for which errors will be tracked
0722:             */
0723:            private Errors initFormErrors(RequestContext context,
0724:                    Object formObject) throws Exception {
0725:                if (logger.isDebugEnabled()) {
0726:                    logger
0727:                            .debug("Creating new form errors for object with name '"
0728:                                    + getFormObjectName() + "'");
0729:                }
0730:                Errors errors = createBinder(context, formObject).getErrors();
0731:                putFormErrors(context, errors);
0732:                return errors;
0733:            }
0734:
0735:            /**
0736:             * Put given errors instance in the configured scope of given context.
0737:             */
0738:            private void putFormErrors(RequestContext context, Errors errors) {
0739:                if (logger.isDebugEnabled()) {
0740:                    logger.debug("Putting form errors instance in scope "
0741:                            + getFormErrorsScope());
0742:                }
0743:                getFormObjectAccessor(context).putFormErrors(errors,
0744:                        getFormErrorsScope());
0745:            }
0746:
0747:            /**
0748:             * Make sure a <i>valid</i> Errors instance for given form object is exposed
0749:             * in given context.
0750:             */
0751:            private void ensureFormErrorsExposed(RequestContext context,
0752:                    Object formObject) throws Exception {
0753:                if (!formErrorsExposed(context)) {
0754:                    // initialize and expose a fresh errors instance to the flow with
0755:                    // editors applied
0756:                    initFormErrors(context, formObject);
0757:                } else {
0758:                    // trying to reuse an existing errors instance
0759:                    if (formErrorsValid(context, formObject)) {
0760:                        // reapply property editors against the existing errors instance
0761:                        reinstallPropertyEditors(context);
0762:                    } else {
0763:                        // the existing errors instance seems to be invalid
0764:                        // initialize a new errors instance, but copy over error information
0765:                        if (logger.isInfoEnabled()) {
0766:                            logger
0767:                                    .info("Fixing inconsistent Errors instance: initializing a new Errors instance "
0768:                                            + "wrapping from object '"
0769:                                            + formObject
0770:                                            + "' in scope '"
0771:                                            + getFormErrorsScope()
0772:                                            + "' and copying over all existing error information.");
0773:                        }
0774:                        Errors invalidExistingErrors = getFormObjectAccessor(
0775:                                context).getFormErrors(getFormObjectName(),
0776:                                getFormErrorsScope());
0777:                        Errors newErrors = initFormErrors(context, formObject);
0778:                        newErrors.addAllErrors(invalidExistingErrors);
0779:                    }
0780:                }
0781:            }
0782:
0783:            /**
0784:             * Check if there is an Errors instance available in given
0785:             * context for given form object.
0786:             */
0787:            private boolean formErrorsExposed(RequestContext context) {
0788:                return getFormObjectAccessor(context).getFormErrors(
0789:                        getFormObjectName(), getFormErrorsScope()) != null;
0790:            }
0791:
0792:            /**
0793:             * Check if the Errors instance available in given context is valid for
0794:             * given form object.
0795:             */
0796:            private boolean formErrorsValid(RequestContext context,
0797:                    Object formObject) {
0798:                Errors errors = getFormObjectAccessor(context).getFormErrors(
0799:                        getFormObjectName(), getFormErrorsScope());
0800:                if (errors instanceof  BindException) {
0801:                    BindException be = (BindException) errors;
0802:                    if (be.getTarget() != formObject) {
0803:                        if (logger.isInfoEnabled()) {
0804:                            logger
0805:                                    .info("Inconsistency detected: the Errors instance in '"
0806:                                            + getFormErrorsScope()
0807:                                            + "' does NOT wrap the current form object '"
0808:                                            + formObject
0809:                                            + "' of class "
0810:                                            + formObject.getClass()
0811:                                            + "; instead this Errors instance unexpectedly wraps the target object '"
0812:                                            + be.getTarget()
0813:                                            + "' of class: "
0814:                                            + be.getTarget().getClass() + ".");
0815:                        }
0816:                        return false;
0817:                    } else {
0818:                        return true;
0819:                    }
0820:                } else {
0821:                    return true;
0822:                }
0823:            }
0824:
0825:            /**
0826:             * Re-registers property editors against the current form errors instance.
0827:             * @param context the flow execution request context
0828:             */
0829:            private void reinstallPropertyEditors(RequestContext context) {
0830:                BindException errors = (BindException) getFormObjectAccessor(
0831:                        context).getFormErrors(getFormObjectName(),
0832:                        getFormErrorsScope());
0833:                registerPropertyEditors(context,
0834:                        getPropertyEditorRegistry(errors));
0835:            }
0836:
0837:            /**
0838:             * Obtain a property editor registry from given bind exception (errors
0839:             * instance).
0840:             */
0841:            private PropertyEditorRegistry getPropertyEditorRegistry(
0842:                    BindException errors) {
0843:                Method accessor;
0844:                try {
0845:                    if (hasPropertyEditorRegistryAccessor) {
0846:                        accessor = errors.getClass().getMethod(
0847:                                "getPropertyEditorRegistry", null);
0848:                    } else {
0849:                        // only way to get at the registry in 1.2.8 or <.
0850:                        accessor = errors.getClass().getDeclaredMethod(
0851:                                "getBeanWrapper", null);
0852:                        accessor.setAccessible(true);
0853:                    }
0854:                } catch (NoSuchMethodException e) {
0855:                    throw new IllegalStateException(
0856:                            "Unable to resolve property editor registry accessor method as expected - this should not happen");
0857:                }
0858:                return (PropertyEditorRegistry) ReflectionUtils.invokeMethod(
0859:                        accessor, errors);
0860:            }
0861:
0862:            /**
0863:             * Invoke specified validator method on the validator registered with this
0864:             * action. The validator method for piecemeal validation should have the
0865:             * following signature:
0866:             * <pre>
0867:             *     public void ${validateMethodName}(${formObjectClass}, Errors)
0868:             * </pre>
0869:             * @param validatorMethod the name of the validator method to invoke
0870:             * @param formObject the form object
0871:             * @param errors possible binding errors
0872:             * @throws Exception when an unrecoverable exception occurs
0873:             */
0874:            private void invokeValidatorMethod(String validatorMethod,
0875:                    Object formObject, Errors errors) throws Exception {
0876:                if (logger.isDebugEnabled()) {
0877:                    logger.debug("Invoking piecemeal validator method '"
0878:                            + validatorMethod + "(" + getFormObjectClass()
0879:                            + ", Errors)'");
0880:                }
0881:                getValidateMethodInvoker().invoke(validatorMethod,
0882:                        new Object[] { formObject, errors });
0883:            }
0884:
0885:            // accessible helpers (subclasses could override if necessary)
0886:
0887:            /**
0888:             * Convenience method that returns the form object for this form action. If
0889:             * not found in the configured scope, a new form object will be created by a
0890:             * call to {@link #createFormObject(RequestContext)} and exposed in the
0891:             * configured {@link #getFormObjectScope() scope}.
0892:             * <p>
0893:             * The returned form object will become the
0894:             * {@link FormObjectAccessor#setCurrentFormObject(Object, ScopeType) current}
0895:             * form object.
0896:             * @param context the flow execution request context
0897:             * @return the form object
0898:             * @throws Exception when an unrecoverable exception occurs
0899:             */
0900:            protected Object getFormObject(RequestContext context)
0901:                    throws Exception {
0902:                FormObjectAccessor accessor = getFormObjectAccessor(context);
0903:                Object formObject = accessor.getFormObject(getFormObjectName(),
0904:                        getFormObjectScope());
0905:                if (formObject == null) {
0906:                    formObject = initFormObject(context);
0907:                } else {
0908:                    if (logger.isDebugEnabled()) {
0909:                        logger.debug("Found existing form object with name '"
0910:                                + getFormObjectName() + "' of type ["
0911:                                + formObject.getClass() + "] in scope "
0912:                                + getFormObjectScope());
0913:                    }
0914:                    accessor.setCurrentFormObject(formObject,
0915:                            getFormObjectScope());
0916:                }
0917:                return formObject;
0918:            }
0919:
0920:            /**
0921:             * Convenience method that returns the form object errors for this form
0922:             * action. If not found in the configured scope, a new form object errors
0923:             * will be created, initialized, and exposed in the confgured
0924:             * {@link #getFormErrorsScope() scope}.
0925:             * <p>
0926:             * Keep in mind that an Errors instance wraps a form object, so a form
0927:             * object will also be created if required
0928:             * (see {@link #getFormObject(RequestContext)}).
0929:             * @param context the flow request context
0930:             * @return the form errors
0931:             * @throws Exception when an unrecoverable exception occurs
0932:             */
0933:            protected Errors getFormErrors(RequestContext context)
0934:                    throws Exception {
0935:                Object formObject = getFormObject(context);
0936:                ensureFormErrorsExposed(context, formObject);
0937:                return getFormObjectAccessor(context).getFormErrors(
0938:                        getFormObjectName(), getFormErrorsScope());
0939:            }
0940:
0941:            /**
0942:             * Create a new binder instance for the given form object and request
0943:             * context. Can be overridden to plug in custom DataBinder subclasses.
0944:             * <p>
0945:             * Default implementation creates a standard WebDataBinder, and invokes
0946:             * {@link #initBinder(RequestContext, DataBinder)} and
0947:             * {@link #registerPropertyEditors(PropertyEditorRegistry)}.
0948:             * @param context the action execution context, for accessing and setting
0949:             * data in "flow scope" or "request scope"
0950:             * @param formObject the form object to bind onto
0951:             * @return the new binder instance
0952:             * @throws Exception when an unrecoverable exception occurs
0953:             * @see WebDataBinder
0954:             * @see #initBinder(RequestContext, DataBinder)
0955:             * @see #setMessageCodesResolver(MessageCodesResolver)
0956:             */
0957:            protected DataBinder createBinder(RequestContext context,
0958:                    Object formObject) throws Exception {
0959:                DataBinder binder = new WebDataBinder(formObject,
0960:                        getFormObjectName());
0961:                if (getMessageCodesResolver() != null) {
0962:                    binder.setMessageCodesResolver(getMessageCodesResolver());
0963:                }
0964:                initBinder(context, binder);
0965:                registerPropertyEditors(context, binder);
0966:                return binder;
0967:            }
0968:
0969:            /**
0970:             * Bind allowed parameters in the external context request parameter map to
0971:             * the form object using given binder.
0972:             * @param context the action execution context, for accessing and setting
0973:             * data in "flow scope" or "request scope"
0974:             * @param binder the data binder to use
0975:             * @throws Exception when an unrecoverable exception occurs
0976:             */
0977:            protected void doBind(RequestContext context, DataBinder binder)
0978:                    throws Exception {
0979:                if (logger.isDebugEnabled()) {
0980:                    logger.debug("Binding allowed request parameters in "
0981:                            + StylerUtils.style(context.getExternalContext()
0982:                                    .getRequestParameterMap())
0983:                            + " to form object with name '"
0984:                            + binder.getObjectName()
0985:                            + "', pre-bind formObject toString = "
0986:                            + binder.getTarget());
0987:                    if (binder.getAllowedFields() != null
0988:                            && binder.getAllowedFields().length > 0) {
0989:                        logger.debug("(Allowed fields are "
0990:                                + StylerUtils.style(binder.getAllowedFields())
0991:                                + ")");
0992:                    } else {
0993:                        logger.debug("(Any field is allowed)");
0994:                    }
0995:                }
0996:                binder.bind(new MutablePropertyValues(context
0997:                        .getRequestParameters().asMap()));
0998:                if (logger.isDebugEnabled()) {
0999:                    logger
1000:                            .debug("Binding completed for form object with name '"
1001:                                    + binder.getObjectName()
1002:                                    + "', post-bind formObject toString = "
1003:                                    + binder.getTarget());
1004:                    logger.debug("There are ["
1005:                            + binder.getErrors().getErrorCount()
1006:                            + "] errors, details: "
1007:                            + binder.getErrors().getAllErrors());
1008:                }
1009:            }
1010:
1011:            /**
1012:             * Validate given form object using a registered validator. If a
1013:             * "validatorMethod" action property is specified for the currently
1014:             * executing action, the identified validator method will be invoked. When
1015:             * no such property is found, the defualt <code>validate()</code> method
1016:             * is invoked.
1017:             * @param context the action execution context, for accessing and setting
1018:             * data in "flow scope" or "request scope"
1019:             * @param formObject the form object
1020:             * @param errors the errors instance to record validation errors in
1021:             * @throws Exception when an unrecoverable exception occurs
1022:             */
1023:            protected void doValidate(RequestContext context,
1024:                    Object formObject, Errors errors) throws Exception {
1025:                Assert
1026:                        .notNull(getValidator(),
1027:                                "The validator must not be null when attempting validation -- programmer error");
1028:                String validatorMethodName = context.getAttributes().getString(
1029:                        VALIDATOR_METHOD_ATTRIBUTE);
1030:                if (StringUtils.hasText(validatorMethodName)) {
1031:                    if (logger.isDebugEnabled()) {
1032:                        logger.debug("Invoking validation method '"
1033:                                + validatorMethodName + "' on validator "
1034:                                + getValidator());
1035:                    }
1036:                    invokeValidatorMethod(validatorMethodName, formObject,
1037:                            errors);
1038:                } else {
1039:                    if (logger.isDebugEnabled()) {
1040:                        logger.debug("Invoking validator " + getValidator());
1041:                    }
1042:                    getValidator().validate(formObject, errors);
1043:                }
1044:                if (logger.isDebugEnabled()) {
1045:                    logger.debug("Validation completed for form object");
1046:                    logger.debug("There are [" + errors.getErrorCount()
1047:                            + "] errors, details: " + errors.getAllErrors());
1048:                }
1049:            }
1050:
1051:            /**
1052:             * Returns a dispatcher to invoke validation methods. Subclasses could
1053:             * override this to return a custom dispatcher.
1054:             */
1055:            protected DispatchMethodInvoker getValidateMethodInvoker() {
1056:                return validateMethodInvoker;
1057:            }
1058:
1059:            /**
1060:             * Factory method that returns a new form object accessor for accessing form
1061:             * objects in the provided request context.
1062:             * @param context the flow request context
1063:             * @return the accessor
1064:             */
1065:            protected FormObjectAccessor getFormObjectAccessor(
1066:                    RequestContext context) {
1067:                return new FormObjectAccessor(context);
1068:            }
1069:
1070:            // common subclassing hook methods
1071:
1072:            /**
1073:             * Create the backing form object instance that should be managed by this
1074:             * {@link FormAction form action}. By default, will attempt to instantiate
1075:             * a new form object instance of type {@link #getFormObjectClass()}
1076:             * transiently in memory.
1077:             * <p>
1078:             * Subclasses should override if they need to load the form object from a
1079:             * specific location or resource such as a database or filesystem.
1080:             * <p>
1081:             * Subclasses should override if they need to customize how a transient form
1082:             * object is assembled during creation.
1083:             * @param context the action execution context for accessing flow data
1084:             * @return the form object
1085:             * @throws IllegalStateException if the {@link #getFormObjectClass()}
1086:             * property is not set and this method has not been overridden
1087:             * @throws Exception when an unrecoverable exception occurs
1088:             */
1089:            protected Object createFormObject(RequestContext context)
1090:                    throws Exception {
1091:                if (getFormObjectClass() == null) {
1092:                    throw new IllegalStateException(
1093:                            "Cannot create form object without formObjectClass property being set -- "
1094:                                    + "either set formObjectClass or override createFormObject");
1095:                }
1096:                if (logger.isDebugEnabled()) {
1097:                    logger.debug("Creating new instance of form object class ["
1098:                            + getFormObjectClass() + "]");
1099:                }
1100:                return getFormObjectClass().newInstance();
1101:            }
1102:
1103:            /**
1104:             * Initialize a new binder instance. This hook allows customization of
1105:             * binder settings such as the {@link DataBinder#getAllowedFields() allowed fields},
1106:             * {@link DataBinder#getRequiredFields() required fields} and
1107:             * {@link DataBinder#initDirectFieldAccess() direct field access}. Called by
1108:             * {@link #createBinder(RequestContext, Object)}.
1109:             * <p>
1110:             * Note that registration of custom property editors should be done in
1111:             * {@link #registerPropertyEditors(PropertyEditorRegistry)}, not here! This
1112:             * method will only be called when a <b>new</b> data binder is created.
1113:             * @param context the action execution context, for accessing and setting
1114:             * data in "flow scope" or "request scope"
1115:             * @param binder new binder instance
1116:             * @see #createBinder(RequestContext, Object)
1117:             */
1118:            protected void initBinder(RequestContext context, DataBinder binder) {
1119:            }
1120:
1121:            /**
1122:             * Register custom editors to perform type conversion on fields of your form
1123:             * object during data binding and form display. This method is called on
1124:             * form errors initialization and
1125:             * {@link #initBinder(RequestContext, DataBinder) data binder} initialization.
1126:             * <p>
1127:             * Property editors give you full control over how objects are transformed
1128:             * to and from a formatted String form for display on a user interface such
1129:             * as a HTML page.
1130:             * <p>
1131:             * This default implementation will call the
1132:             * {@link #registerPropertyEditors(PropertyEditorRegistry) simpler form} of
1133:             * the method not taking a <tt>RequestContext</tt> parameter.
1134:             * @param context the action execution context, for accessing and setting
1135:             * data in "flow scope" or "request scope"
1136:             * @param registry the property editor registry to register editors in
1137:             * @see #registerPropertyEditors(PropertyEditorRegistry)
1138:             */
1139:            protected void registerPropertyEditors(RequestContext context,
1140:                    PropertyEditorRegistry registry) {
1141:                registerPropertyEditors(registry);
1142:            }
1143:
1144:            /**
1145:             * Register custom editors to perform type conversion on fields of your form
1146:             * object during data binding and form display. This method is called on
1147:             * form errors initialization and
1148:             * {@link #initBinder(RequestContext, DataBinder) data binder} initialization.
1149:             * <p>
1150:             * Property editors give you full control over how objects are transformed
1151:             * to and from a formatted String form for display on a user interface such
1152:             * as a HTML page.
1153:             * <p>
1154:             * This default implementation will simply call <tt>registerCustomEditors</tt>
1155:             * on the {@link #getPropertyEditorRegistrar() propertyEditorRegistrar} object
1156:             * that has been set for the action, if any.
1157:             * @param registry the property editor registry to register editors in
1158:             */
1159:            protected void registerPropertyEditors(
1160:                    PropertyEditorRegistry registry) {
1161:                if (getPropertyEditorRegistrar() != null) {
1162:                    if (logger.isDebugEnabled()) {
1163:                        logger
1164:                                .debug("Registering custom property editors using configured registrar");
1165:                    }
1166:                    getPropertyEditorRegistrar()
1167:                            .registerCustomEditors(registry);
1168:                } else {
1169:                    if (logger.isDebugEnabled()) {
1170:                        logger
1171:                                .debug("No property editor registrar set, no custom editors to register");
1172:                    }
1173:                }
1174:            }
1175:
1176:            /**
1177:             * Return whether validation should be performed given the state of the flow
1178:             * request context. Default implementation always returns true.
1179:             * @param context the request context, for accessing and setting data in
1180:             * "flow scope" or "request scope"
1181:             * @return whether or not validation is enabled
1182:             */
1183:            protected boolean validationEnabled(RequestContext context) {
1184:                return true;
1185:            }
1186:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.