Source Code Cross Referenced for AbstractWizardFormController.java in  » J2EE » spring-framework-2.0.6 » org » springframework » web » portlet » mvc » 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 » J2EE » spring framework 2.0.6 » org.springframework.web.portlet.mvc 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Copyright 2002-2005 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:
0017:        package org.springframework.web.portlet.mvc;
0018:
0019:        import java.util.Enumeration;
0020:        import java.util.HashMap;
0021:        import java.util.Iterator;
0022:        import java.util.Map;
0023:
0024:        import javax.portlet.ActionRequest;
0025:        import javax.portlet.ActionResponse;
0026:        import javax.portlet.PortletException;
0027:        import javax.portlet.PortletRequest;
0028:        import javax.portlet.RenderRequest;
0029:        import javax.portlet.RenderResponse;
0030:
0031:        import org.springframework.validation.BindException;
0032:        import org.springframework.validation.Errors;
0033:        import org.springframework.web.portlet.ModelAndView;
0034:        import org.springframework.web.portlet.util.PortletUtils;
0035:        import org.springframework.web.util.WebUtils;
0036:
0037:        /**
0038:         * Form controller for typical wizard-style workflows.
0039:         *
0040:         * <p>In contrast to classic forms, wizards have more than one form view page.
0041:         * Therefore, there are various actions instead of one single submit action:
0042:         * <ul>
0043:         * <li>finish: trying to leave the wizard successfully, i.e. performing its
0044:         * final action, and thus needing a valid state;
0045:         * <li>cancel: leaving the wizard without performing its final action, and
0046:         * thus without regard to the validity of its current state;
0047:         * <li>page change: showing another wizard page, e.g. the next or previous
0048:         * one, with regard to "dirty back" and "dirty forward".
0049:         * </ul>
0050:         *
0051:         * <p>Finish and cancel actions can be triggered by request parameters, named
0052:         * PARAM_FINISH ("_finish") and PARAM_CANCEL ("_cancel"), ignoring parameter
0053:         * values to allow for HTML buttons. The target page for page changes can be
0054:         * specified by PARAM_TARGET, appending the page number to the parameter name
0055:         * (e.g. "_target1"). The action parameters are recognized when triggered by
0056:         * image buttons too (via "_finish.x", "_abort.x", or "_target1.x").
0057:         *
0058:         * <p>The current page number will be stored in the session. It can also be
0059:         * specified as request parameter PARAM_PAGE, to properly handle usage of
0060:         * the back button in a browser: In this case, a submission always contains
0061:         * the correct page number, even if the user submitted from an old view.
0062:         *
0063:         * <p>The page can only be changed if it validates correctly, except if a
0064:         * "dirty back" or "dirty forward" is allowed. At finish, all pages get
0065:         * validated again to guarantee a consistent state.
0066:         *
0067:         * <p>Note that a validator's default validate method is not executed when using
0068:         * this class! Rather, the <code>validatePage</code> implementation should call
0069:         * special <code>validateXXX</code> methods that the validator needs to provide,
0070:         * validating certain pieces of the object. These can be combined to validate
0071:         * the elements of individual pages.
0072:         *
0073:         * <p>Note: Page numbering starts with 0, to be able to pass an array
0074:         * consisting of the corresponding view names to the "pages" bean property.
0075:         *
0076:         * <p>Parameters indicated with <code>setPassRenderParameters</code> will be present
0077:         * for each page.  If there are render parameters you need in <code>renderFinish</code>
0078:         * or <code>renderCancel</code>, then you need to pass those forward from the
0079:         * <code>processFinish</code> or <code>processCancel</code> methods, respectively.
0080:
0081:         * @author Juergen Hoeller
0082:         * @author John A. Lewis
0083:         * @since 2.0
0084:         * @see #setPages
0085:         * @see #validatePage
0086:         * @see #processFinish
0087:         * @see #processCancel
0088:         */
0089:        public abstract class AbstractWizardFormController extends
0090:                AbstractFormController {
0091:
0092:            /**
0093:             * Parameter triggering the finish action.
0094:             * Can be called from any wizard page!
0095:             */
0096:            public static final String PARAM_FINISH = "_finish";
0097:
0098:            /**
0099:             * Parameter triggering the cancel action.
0100:             * Can be called from any wizard page!
0101:             */
0102:            public static final String PARAM_CANCEL = "_cancel";
0103:
0104:            /**
0105:             * Parameter specifying the target page,
0106:             * appending the page number to the name.
0107:             */
0108:            public static final String PARAM_TARGET = "_target";
0109:
0110:            /**
0111:             * Parameter specifying the current page as value. Not necessary on
0112:             * form pages, but allows to properly handle usage of the back button.
0113:             * @see #setPageAttribute
0114:             */
0115:            public static final String PARAM_PAGE = "_page";
0116:
0117:            private String[] pages;
0118:
0119:            private String pageAttribute;
0120:
0121:            private boolean allowDirtyBack = true;
0122:
0123:            private boolean allowDirtyForward = false;
0124:
0125:            /**
0126:             * Create a new AbstractWizardFormController.
0127:             * <p>"sessionForm" is automatically turned on, "validateOnBinding"
0128:             * turned off, and "cacheSeconds" set to 0 by the base class
0129:             * (-> no caching for all form controllers).
0130:             */
0131:            public AbstractWizardFormController() {
0132:                // AbstractFormController sets default cache seconds to 0.
0133:                super ();
0134:
0135:                // Always needs session to keep data from all pages.
0136:                setSessionForm(true);
0137:
0138:                // Never validate everything on binding ->
0139:                // wizards validate individual pages.
0140:                setValidateOnBinding(false);
0141:            }
0142:
0143:            /**
0144:             * Set the wizard pages, i.e. the view names for the pages.
0145:             * The array index is interpreted as page number.
0146:             * @param pages view names for the pages
0147:             */
0148:            public final void setPages(String[] pages) {
0149:                if (pages == null || pages.length == 0) {
0150:                    throw new IllegalArgumentException(
0151:                            "No wizard pages defined");
0152:                }
0153:                this .pages = pages;
0154:            }
0155:
0156:            /**
0157:             * Return the wizard pages, i.e. the view names for the pages.
0158:             * The array index corresponds to the page number.
0159:             * <p>Note that a concrete wizard form controller might override
0160:             * <code>getViewName(PortletRequest, Object, int)</code> to
0161:             * determine the view name for each page dynamically.
0162:             * @see #getViewName(PortletRequest, Object, int)
0163:             */
0164:            public final String[] getPages() {
0165:                return pages;
0166:            }
0167:
0168:            /**
0169:             * Return the number of wizard pages.
0170:             * Useful to check whether the last page has been reached.
0171:             * <p>Note that a concrete wizard form controller might override
0172:             * <code>getPageCount(PortletRequest, Object)</code> to determine
0173:             * the page count dynamically.
0174:             * @see #getPageCount(PortletRequest, Object)
0175:             */
0176:            protected final int getPageCount() {
0177:                return this .pages.length;
0178:            }
0179:
0180:            /**
0181:             * Set the name of the page attribute in the model, containing
0182:             * an Integer with the current page number.
0183:             * <p>This will be necessary for single views rendering multiple view pages.
0184:             * It also allows for specifying the optional "_page" parameter.
0185:             * @param pageAttribute name of the page attribute
0186:             * @see #PARAM_PAGE
0187:             */
0188:            public final void setPageAttribute(String pageAttribute) {
0189:                this .pageAttribute = pageAttribute;
0190:            }
0191:
0192:            /**
0193:             * Return the name of the page attribute in the model.
0194:             */
0195:            public final String getPageAttribute() {
0196:                return pageAttribute;
0197:            }
0198:
0199:            /**
0200:             * Set if "dirty back" is allowed, i.e. if moving to a former wizard
0201:             * page is allowed in case of validation errors for the current page.
0202:             * @param allowDirtyBack if "dirty back" is allowed
0203:             */
0204:            public final void setAllowDirtyBack(boolean allowDirtyBack) {
0205:                this .allowDirtyBack = allowDirtyBack;
0206:            }
0207:
0208:            /**
0209:             * Return whether "dirty back" is allowed.
0210:             */
0211:            public final boolean isAllowDirtyBack() {
0212:                return allowDirtyBack;
0213:            }
0214:
0215:            /**
0216:             * Set if "dirty forward" is allowed, i.e. if moving to a later wizard
0217:             * page is allowed in case of validation errors for the current page.
0218:             * @param allowDirtyForward if "dirty forward" is allowed
0219:             */
0220:            public final void setAllowDirtyForward(boolean allowDirtyForward) {
0221:                this .allowDirtyForward = allowDirtyForward;
0222:            }
0223:
0224:            /**
0225:             * Return whether "dirty forward" is allowed.
0226:             */
0227:            public final boolean isAllowDirtyForward() {
0228:                return allowDirtyForward;
0229:            }
0230:
0231:            /**
0232:             * Calls page-specific onBindAndValidate method.
0233:             */
0234:            protected final void onBindAndValidate(PortletRequest request,
0235:                    Object command, BindException errors) throws Exception {
0236:
0237:                onBindAndValidate(request, command, errors,
0238:                        getCurrentPage(request));
0239:            }
0240:
0241:            /**
0242:             * Callback for custom post-processing in terms of binding and validation.
0243:             * Called on each submit, after standard binding but before page-specific
0244:             * validation of this wizard form controller.
0245:             * <p>Note: AbstractWizardFormController does not perform standard
0246:             * validation on binding but rather applies page-specific validation
0247:             * on processing the form submission.
0248:             * @param request current portlet request
0249:             * @param command bound command
0250:             * @param errors Errors instance for additional custom validation
0251:             * @param page current wizard page
0252:             * @throws Exception in case of invalid state or arguments
0253:             * @see #bindAndValidate
0254:             * @see #processFormSubmission
0255:             * @see org.springframework.validation.Errors
0256:             */
0257:            protected void onBindAndValidate(PortletRequest request,
0258:                    Object command, BindException errors, int page)
0259:                    throws Exception {
0260:            }
0261:
0262:            /**
0263:             * Consider an explicit finish or cancel request as a form submission too.
0264:             * @see #isFinishRequest(PortletRequest)
0265:             * @see #isCancelRequest(PortletRequest)
0266:             */
0267:            protected boolean isFormSubmission(PortletRequest request) {
0268:                return super .isFormSubmission(request)
0269:                        || isFinishRequest(request) || isCancelRequest(request);
0270:            }
0271:
0272:            /**
0273:             * Calls page-specific referenceData method.
0274:             */
0275:            protected final Map referenceData(PortletRequest request,
0276:                    Object command, Errors errors) throws Exception {
0277:
0278:                return referenceData(request, command, errors,
0279:                        getCurrentPage(request));
0280:            }
0281:
0282:            /**
0283:             * Create a reference data map for the given request, consisting of
0284:             * bean name/bean instance pairs as expected by ModelAndView.
0285:             * <p>Default implementation delegates to referenceData(HttpServletRequest, int).
0286:             * Subclasses can override this to set reference data used in the view.
0287:             * @param request current portlet request
0288:             * @param command form object with request parameters bound onto it
0289:             * @param errors validation errors holder
0290:             * @param page current wizard page
0291:             * @return a Map with reference data entries, or null if none
0292:             * @throws Exception in case of invalid state or arguments
0293:             * @see #referenceData(PortletRequest, int)
0294:             * @see org.springframework.web.portlet.ModelAndView
0295:             */
0296:            protected Map referenceData(PortletRequest request, Object command,
0297:                    Errors errors, int page) throws Exception {
0298:
0299:                return referenceData(request, page);
0300:            }
0301:
0302:            /**
0303:             * Create a reference data map for the given request, consisting of
0304:             * bean name/bean instance pairs as expected by ModelAndView.
0305:             * <p>Default implementation returns null.
0306:             * Subclasses can override this to set reference data used in the view.
0307:             * @param request current portlet request
0308:             * @param page current wizard page
0309:             * @return a Map with reference data entries, or null if none
0310:             * @throws Exception in case of invalid state or arguments
0311:             * @see org.springframework.web.portlet.ModelAndView
0312:             */
0313:            protected Map referenceData(PortletRequest request, int page)
0314:                    throws Exception {
0315:                return null;
0316:            }
0317:
0318:            /**
0319:             * Show first page as form view.
0320:             */
0321:            protected final ModelAndView showForm(RenderRequest request,
0322:                    RenderResponse response, BindException errors)
0323:                    throws Exception {
0324:
0325:                return showPage(request, errors, getInitialPage(request, errors
0326:                        .getTarget()));
0327:            }
0328:
0329:            /**
0330:             * Prepare the form model and view, including reference and error data,
0331:             * for the given page. Can be used in <code>processFinish</code> implementations,
0332:             * to show the corresponding page in case of validation errors.
0333:             * @param request current portlet render request
0334:             * @param errors validation errors holder
0335:             * @param page number of page to show
0336:             * @return the prepared form view
0337:             * @throws Exception in case of invalid state or arguments
0338:             */
0339:            protected final ModelAndView showPage(RenderRequest request,
0340:                    BindException errors, int page) throws Exception {
0341:
0342:                if (page >= 0
0343:                        && page < getPageCount(request, errors.getTarget())) {
0344:                    if (logger.isDebugEnabled()) {
0345:                        logger.debug("Showing wizard page " + page
0346:                                + " for form bean '" + getCommandName() + "'");
0347:                    }
0348:
0349:                    // Set page session attribute, expose overriding request attribute.
0350:                    Integer pageInteger = new Integer(page);
0351:                    String pageAttrName = getPageSessionAttributeName(request);
0352:                    if (isSessionForm()) {
0353:                        if (logger.isDebugEnabled()) {
0354:                            logger.debug("Setting page session attribute ["
0355:                                    + pageAttrName + "] to: " + pageInteger);
0356:                        }
0357:                        request.getPortletSession().setAttribute(pageAttrName,
0358:                                pageInteger);
0359:                    }
0360:                    request.setAttribute(pageAttrName, pageInteger);
0361:
0362:                    // Set page request attribute for evaluation by views.
0363:                    Map controlModel = new HashMap();
0364:                    if (this .pageAttribute != null) {
0365:                        controlModel.put(this .pageAttribute, new Integer(page));
0366:                    }
0367:                    String viewName = getViewName(request, errors.getTarget(),
0368:                            page);
0369:                    return showForm(request, errors, viewName, controlModel);
0370:                }
0371:
0372:                else {
0373:                    throw new PortletException("Invalid wizard page number: "
0374:                            + page);
0375:                }
0376:            }
0377:
0378:            /**
0379:             * Return the page count for this wizard form controller.
0380:             * Default implementation delegates to <code>getPageCount()</code>.
0381:             * <p>Can be overridden to dynamically adapt the page count.
0382:             * @param request current portlet request
0383:             * @param command the command object as returned by formBackingObject
0384:             * @return the current page count
0385:             * @see #getPageCount
0386:             */
0387:            protected int getPageCount(PortletRequest request, Object command) {
0388:                return getPageCount();
0389:            }
0390:
0391:            /**
0392:             * Return the name of the view for the specified page of this wizard form controller.
0393:             * Default implementation takes the view name from the <code>getPages()</code> array.
0394:             * <p>Can be overridden to dynamically switch the page view or to return view names
0395:             * for dynamically defined pages.
0396:             * @param request current portlet request
0397:             * @param command the command object as returned by formBackingObject
0398:             * @return the current page count
0399:             * @see #getPageCount
0400:             */
0401:            protected String getViewName(PortletRequest request,
0402:                    Object command, int page) {
0403:                return getPages()[page];
0404:            }
0405:
0406:            /**
0407:             * Return the initial page of the wizard, i.e. the page shown at wizard startup.
0408:             * Default implementation delegates to <code>getInitialPage(PortletRequest)</code>.
0409:             * @param request current portlet request
0410:             * @param command the command object as returned by formBackingObject
0411:             * @return the initial page number
0412:             * @see #getInitialPage(PortletRequest)
0413:             * @see #formBackingObject
0414:             */
0415:            protected int getInitialPage(PortletRequest request, Object command) {
0416:                return getInitialPage(request);
0417:            }
0418:
0419:            /**
0420:             * Return the initial page of the wizard, i.e. the page shown at wizard startup.
0421:             * Default implementation returns 0 for first page.
0422:             * @param request current portlet request
0423:             * @return the initial page number
0424:             */
0425:            protected int getInitialPage(PortletRequest request) {
0426:                return 0;
0427:            }
0428:
0429:            /**
0430:             * Return the name of the PortletSession attribute that holds the page object
0431:             * for this wizard form controller.
0432:             * <p>Default implementation delegates to the <code>getPageSessionAttributeName</code>
0433:             * version without arguments.
0434:             * @param request current portlet request
0435:             * @return the name of the form session attribute, or null if not in session form mode
0436:             * @see #getPageSessionAttributeName
0437:             * @see #getFormSessionAttributeName
0438:             * @see javax.portlet.PortletSession#getAttribute
0439:             */
0440:            protected String getPageSessionAttributeName(PortletRequest request) {
0441:                return getPageSessionAttributeName();
0442:            }
0443:
0444:            /**
0445:             * Return the name of the PortletSession attribute that holds the page object
0446:             * for this wizard form controller.
0447:             * <p>Default is an internal name, of no relevance to applications, as the form
0448:             * session attribute is not usually accessed directly. Can be overridden to use
0449:             * an application-specific attribute name, which allows other code to access
0450:             * the session attribute directly.
0451:             * @return the name of the page session attribute
0452:             * @see #getFormSessionAttributeName
0453:             * @see javax.portlet.PortletSession#getAttribute
0454:             */
0455:            protected String getPageSessionAttributeName() {
0456:                return getClass().getName() + ".PAGE." + getCommandName();
0457:            }
0458:
0459:            /**
0460:             * Pass the page number to the render phase by setting a render parameter.
0461:             * This method may not be called when the action calls
0462:             * {@link javax.portlet.ActionResponse#sendRedirect(String)}.
0463:             * @param response the current action response
0464:             * @param page the page number
0465:             * @see ActionResponse#setRenderParameter
0466:             */
0467:            protected void setPageRenderParameter(ActionResponse response,
0468:                    int page) {
0469:                if (logger.isDebugEnabled())
0470:                    logger.debug("Setting page number render parameter ["
0471:                            + PARAM_PAGE + "] to [" + page + "]");
0472:                try {
0473:                    response.setRenderParameter(PARAM_PAGE, new Integer(page)
0474:                            .toString());
0475:                } catch (IllegalStateException ex) {
0476:                    // ignore in case sendRedirect was already set
0477:                }
0478:            }
0479:
0480:            /**
0481:             * Pass the the parameter that indicates the target page of the request
0482:             * forward to the render phase. If the <code>getTargetPage<code> method
0483:             * was overridden, this may need to be overriden as well.
0484:             * @param request the current action request
0485:             * @param response the current action response
0486:             * @see #PARAM_TARGET
0487:             * @see #getTargetPage(PortletRequest, int)
0488:             * @see #getTargetPage(PortletRequest, Object, Errors, int)
0489:             * @see ActionResponse#setRenderParameter
0490:             */
0491:            protected void setTargetRenderParameter(ActionRequest request,
0492:                    ActionResponse response) {
0493:                try {
0494:                    Iterator it = PortletUtils.getParametersStartingWith(
0495:                            request, PARAM_TARGET).entrySet().iterator();
0496:                    while (it.hasNext()) {
0497:                        Map.Entry entry = (Map.Entry) it.next();
0498:                        String param = PARAM_TARGET + (String) entry.getKey();
0499:                        Object value = entry.getValue();
0500:                        if (logger.isDebugEnabled())
0501:                            logger.debug("Setting target render parameter ["
0502:                                    + param + "]");
0503:                        if (value instanceof  String)
0504:                            response.setRenderParameter(param, (String) value);
0505:                        if (value instanceof  String[])
0506:                            response
0507:                                    .setRenderParameter(param, (String[]) value);
0508:                    }
0509:                } catch (IllegalStateException ex) {
0510:                    // ignore in case sendRedirect was already set
0511:                }
0512:            }
0513:
0514:            /**
0515:             * Pass the the parameter that indicates a finish request forward to the
0516:             * render phase. If the <code>isFinishRequest</code> method
0517:             * was overridden, this may need to be overriden as well.
0518:             * @param request the current action request
0519:             * @param response the current action response
0520:             * @see #PARAM_FINISH
0521:             * @see #isFinishRequest
0522:             * @see ActionResponse#setRenderParameter
0523:             */
0524:            protected void setFinishRenderParameter(ActionRequest request,
0525:                    ActionResponse response) {
0526:                if (logger.isDebugEnabled())
0527:                    logger.debug("Setting cancel render parameter ["
0528:                            + PARAM_FINISH + "]");
0529:                try {
0530:                    String name = PortletUtils.getSubmitParameter(request,
0531:                            PARAM_FINISH);
0532:                    if (name != null)
0533:                        response.setRenderParameter(name, request
0534:                                .getParameter(name));
0535:                } catch (IllegalStateException ex) {
0536:                    // ignore in case sendRedirect was already set
0537:                }
0538:            }
0539:
0540:            /**
0541:             * Pass the the parameter that indicates a cancel request forward to the
0542:             * render phase. If the <code>isCancelRequest</code> method
0543:             * was overridden, this may need to be overriden as well.
0544:             * @param request the current action request
0545:             * @param response the current action response
0546:             * @see #PARAM_CANCEL
0547:             * @see #isCancelRequest
0548:             * @see ActionResponse#setRenderParameter
0549:             */
0550:            protected void setCancelRenderParameter(ActionRequest request,
0551:                    ActionResponse response) {
0552:                if (logger.isDebugEnabled())
0553:                    logger.debug("Setting cancel render parameter ["
0554:                            + PARAM_CANCEL + "]");
0555:                try {
0556:                    String name = PortletUtils.getSubmitParameter(request,
0557:                            PARAM_CANCEL);
0558:                    if (name != null)
0559:                        response.setRenderParameter(name, request
0560:                                .getParameter(name));
0561:                } catch (IllegalStateException ex) {
0562:                    // ignore in case sendRedirect was already set
0563:                }
0564:            }
0565:
0566:            /**
0567:             * Handle an invalid submit request, e.g. when in session form mode but no form object
0568:             * was found in the session (like in case of an invalid resubmit by the browser).
0569:             * <p>Default implementation for wizard form controllers simply shows the initial page
0570:             * of a new wizard form. If you want to show some "invalid submit" message, you need
0571:             * to override this method.
0572:             * @param request current portlet render request
0573:             * @param response current portlet render response
0574:             * @return a prepared view, or null if handled directly
0575:             * @throws Exception in case of errors
0576:             * @see #showNewForm
0577:             * @see #setBindOnNewForm
0578:             * @see #handleInvalidSubmit
0579:             */
0580:            protected ModelAndView renderInvalidSubmit(RenderRequest request,
0581:                    RenderResponse response) throws Exception {
0582:
0583:                return showNewForm(request, response);
0584:            }
0585:
0586:            /**
0587:             * Handle an invalid submit request, e.g. when in session form mode but no form object
0588:             * was found in the session (like in case of an invalid resubmit by the browser).
0589:             * <p>Default implementation for wizard form controllers simply shows the initial page
0590:             * of a new wizard form, so here in the action phase this method does nothing. If you
0591:             * want to take some action on an invalid submit, you need to override this method.
0592:             * @param request current portlet action request
0593:             * @param response current portlet action response
0594:             * @throws Exception in case of errors
0595:             * @see #renderInvalidSubmit
0596:             */
0597:            protected void handleInvalidSubmit(ActionRequest request,
0598:                    ActionResponse response) throws Exception {
0599:            }
0600:
0601:            /**
0602:             * Apply wizard workflow: finish, cancel, page change.
0603:             * @see #processFormSubmission
0604:             */
0605:            protected final ModelAndView renderFormSubmission(
0606:                    RenderRequest request, RenderResponse response,
0607:                    Object command, BindException errors) throws Exception {
0608:
0609:                int currentPage = getCurrentPage(request);
0610:                String pageAttrName = getPageSessionAttributeName(request);
0611:                request.setAttribute(pageAttrName, new Integer(currentPage));
0612:
0613:                // cancel?
0614:                if (isCancelRequest(request)) {
0615:                    if (logger.isDebugEnabled()) {
0616:                        logger.debug("Cancelling wizard for form bean '"
0617:                                + getCommandName() + "'");
0618:                    }
0619:                    return renderCancel(request, response, command, errors);
0620:                }
0621:
0622:                // finish?
0623:                if (isFinishRequest(request)) {
0624:                    if (logger.isDebugEnabled()) {
0625:                        logger.debug("Finishing wizard for form bean '"
0626:                                + getCommandName() + "'");
0627:                    }
0628:                    return renderValidatePagesAndFinish(request, response,
0629:                            command, errors, currentPage);
0630:                }
0631:
0632:                // Normal submit: show specified target page.
0633:                int targetPage = getTargetPage(request, command, errors,
0634:                        currentPage);
0635:                if (logger.isDebugEnabled()) {
0636:                    logger.debug("Target page " + targetPage + " requested");
0637:                }
0638:                if (targetPage != currentPage) {
0639:                    if (!errors.hasErrors()
0640:                            || (this .allowDirtyBack && targetPage < currentPage)
0641:                            || (this .allowDirtyForward && targetPage > currentPage)) {
0642:                        // Allowed to go to target page.
0643:                        return showPage(request, errors, targetPage);
0644:                    }
0645:                }
0646:
0647:                // Show current page again
0648:                return showPage(request, errors, currentPage);
0649:            }
0650:
0651:            /**
0652:             * Apply wizard workflow: finish, cancel, page change.
0653:             * @see #renderFormSubmission
0654:             */
0655:            protected final void processFormSubmission(ActionRequest request,
0656:                    ActionResponse response, Object command,
0657:                    BindException errors) throws Exception {
0658:
0659:                int currentPage = getCurrentPage(request);
0660:                // Remove page session attribute, provide copy as request attribute.
0661:                String pageAttrName = getPageSessionAttributeName(request);
0662:                if (isSessionForm()) {
0663:                    if (logger.isDebugEnabled()) {
0664:                        logger.debug("Removing page session attribute ["
0665:                                + pageAttrName + "]");
0666:                    }
0667:                    request.getPortletSession().removeAttribute(pageAttrName);
0668:                }
0669:                request.setAttribute(pageAttrName, new Integer(currentPage));
0670:
0671:                // cancel?
0672:                if (isCancelRequest(request)) {
0673:                    if (logger.isDebugEnabled()) {
0674:                        logger.debug("Cancelling wizard for form bean '"
0675:                                + getCommandName() + "'");
0676:                    }
0677:                    setPageRenderParameter(response, currentPage);
0678:                    setCancelRenderParameter(request, response);
0679:                    processCancel(request, response, command, errors);
0680:                    return;
0681:                }
0682:
0683:                // finish?
0684:                if (isFinishRequest(request)) {
0685:                    if (logger.isDebugEnabled()) {
0686:                        logger.debug("Finishing wizard for form bean '"
0687:                                + getCommandName() + "'");
0688:                    }
0689:                    if (!isRedirectAction()) {
0690:                        setPageRenderParameter(response, currentPage);
0691:                        setFinishRenderParameter(request, response);
0692:                    }
0693:                    validatePagesAndFinish(request, response, command, errors,
0694:                            currentPage);
0695:                    return;
0696:                }
0697:
0698:                // Normal submit: validate current page
0699:                if (!suppressValidation(request)) {
0700:                    if (logger.isDebugEnabled()) {
0701:                        logger.debug("Validating wizard page " + currentPage
0702:                                + " for form bean '" + getCommandName() + "'");
0703:                    }
0704:                    validatePage(command, errors, currentPage, false);
0705:                }
0706:
0707:                setPageRenderParameter(response, currentPage);
0708:                setTargetRenderParameter(request, response);
0709:                passRenderParameters(request, response);
0710:
0711:                // Give subclasses a change to perform custom post-procession
0712:                // of the current page and its command object.
0713:                postProcessPage(request, command, errors, currentPage);
0714:
0715:            }
0716:
0717:            /**
0718:             * Return the current page number. Used by processFormSubmission.
0719:             * <p>The default implementation checks the page session attribute.
0720:             * Subclasses can override this for customized page determination.
0721:             * @see #processFormSubmission
0722:             * @see #getPageSessionAttributeName
0723:             */
0724:            protected int getCurrentPage(PortletRequest request) {
0725:                // Check for overriding attribute in request.
0726:                String pageAttrName = getPageSessionAttributeName(request);
0727:                Integer pageAttr = (Integer) request.getAttribute(pageAttrName);
0728:                if (pageAttr != null) {
0729:                    return pageAttr.intValue();
0730:                }
0731:                // Check for explicit request parameter.
0732:                String pageParam = request.getParameter(PARAM_PAGE);
0733:                if (pageParam != null) {
0734:                    return Integer.parseInt(pageParam);
0735:                }
0736:                // Check for original attribute in session.
0737:                if (isSessionForm()) {
0738:                    pageAttr = (Integer) request.getPortletSession()
0739:                            .getAttribute(pageAttrName);
0740:                    if (pageAttr != null) {
0741:                        return pageAttr.intValue();
0742:                    }
0743:                }
0744:                throw new IllegalStateException("Page attribute ["
0745:                        + pageAttrName
0746:                        + "] neither found in session nor in request");
0747:            }
0748:
0749:            /**
0750:             * Determine whether the incoming request is a request to finish the
0751:             * processing of the current form.
0752:             * <p>By default, this method returns <code>true</code> if a parameter
0753:             * matching the "_finish" key is present in the request, otherwise it
0754:             * returns <code>false</code>. Subclasses may override this method
0755:             * to provide custom logic to detect a finish request.
0756:             * <p>The parameter is recognized both when sent as a plain parameter
0757:             * ("_finish") or when triggered by an image button ("_finish.x").
0758:             * @param request current portlet request
0759:             * @see #PARAM_FINISH
0760:             */
0761:            protected boolean isFinishRequest(PortletRequest request) {
0762:                return PortletUtils.hasSubmitParameter(request, PARAM_FINISH);
0763:            }
0764:
0765:            /**
0766:             * Determine whether the incoming request is a request to cancel the
0767:             * processing of the current form.
0768:             * <p>By default, this method returns <code>true</code> if a parameter
0769:             * matching the "_cancel" key is present in the request, otherwise it
0770:             * returns <code>false</code>. Subclasses may override this method
0771:             * to provide custom logic to detect a cancel request.
0772:             * <p>The parameter is recognized both when sent as a plain parameter
0773:             * ("_cancel") or when triggered by an image button ("_cancel.x").
0774:             * @param request current portlet request
0775:             * @see #PARAM_CANCEL
0776:             */
0777:            protected boolean isCancelRequest(PortletRequest request) {
0778:                return PortletUtils.hasSubmitParameter(request, PARAM_CANCEL);
0779:            }
0780:
0781:            /**
0782:             * Return the target page specified in the request.
0783:             * <p>Default implementation delegates to
0784:             * <code>getTargetPage(PortletRequest, int)</code>.
0785:             * Subclasses can override this for customized target page determination.
0786:             * @param request current portlet request
0787:             * @param command form object with request parameters bound onto it
0788:             * @param errors validation errors holder
0789:             * @param currentPage the current page, to be returned as fallback
0790:             * if no target page specified
0791:             * @return the page specified in the request, or current page if not found
0792:             * @see #getTargetPage(PortletRequest, int)
0793:             */
0794:            protected int getTargetPage(PortletRequest request, Object command,
0795:                    Errors errors, int currentPage) {
0796:                return getTargetPage(request, currentPage);
0797:            }
0798:
0799:            /**
0800:             * Return the target page specified in the request.
0801:             * <p>Default implementation examines "_target" parameter (e.g. "_target1").
0802:             * Subclasses can override this for customized target page determination.
0803:             * @param request current portlet request
0804:             * @param currentPage the current page, to be returned as fallback
0805:             * if no target page specified
0806:             * @return the page specified in the request, or current page if not found
0807:             * @see #PARAM_TARGET
0808:             */
0809:            protected int getTargetPage(PortletRequest request, int currentPage) {
0810:                Enumeration paramNames = request.getParameterNames();
0811:                while (paramNames.hasMoreElements()) {
0812:                    String paramName = (String) paramNames.nextElement();
0813:                    if (paramName.startsWith(PARAM_TARGET)) {
0814:                        for (int i = 0; i < WebUtils.SUBMIT_IMAGE_SUFFIXES.length; i++) {
0815:                            String suffix = WebUtils.SUBMIT_IMAGE_SUFFIXES[i];
0816:                            if (paramName.endsWith(suffix)) {
0817:                                paramName = paramName.substring(0, paramName
0818:                                        .length()
0819:                                        - suffix.length());
0820:                            }
0821:                        }
0822:                        return Integer.parseInt(paramName
0823:                                .substring(PARAM_TARGET.length()));
0824:                    }
0825:                }
0826:                return currentPage;
0827:            }
0828:
0829:            /**
0830:             * Validate all pages and process finish.
0831:             * If there are page validation errors, show the corresponding view page.
0832:             * @see #validatePagesAndFinish
0833:             */
0834:            private ModelAndView renderValidatePagesAndFinish(
0835:                    RenderRequest request, RenderResponse response,
0836:                    Object command, BindException errors, int currentPage)
0837:                    throws Exception {
0838:
0839:                // In case of any errors -> show current page.
0840:                if (errors.hasErrors())
0841:                    return showPage(request, errors, currentPage);
0842:
0843:                // No remaining errors -> proceed with finish.
0844:                return renderFinish(request, response, command, errors);
0845:            }
0846:
0847:            /**
0848:             * Validate all pages and process finish.
0849:             * If there are page validation errors, show the corresponding view page.
0850:             * @see #renderValidatePagesAndFinish
0851:             */
0852:            private void validatePagesAndFinish(ActionRequest request,
0853:                    ActionResponse response, Object command,
0854:                    BindException errors, int currentPage) throws Exception {
0855:
0856:                // In case of binding errors -> show current page.
0857:                if (errors.hasErrors()) {
0858:                    setPageRenderParameter(response, currentPage);
0859:                    passRenderParameters(request, response);
0860:                    return;
0861:                }
0862:
0863:                if (!suppressValidation(request)) {
0864:                    // In case of remaining errors on a page -> show the page.
0865:                    for (int page = 0; page < getPageCount(request, command); page++) {
0866:                        validatePage(command, errors, page, true);
0867:                        if (errors.hasErrors()) {
0868:                            setPageRenderParameter(response, currentPage);
0869:                            passRenderParameters(request, response);
0870:                            return;
0871:                        }
0872:                    }
0873:                }
0874:
0875:                // No remaining errors -> proceed with finish.
0876:                if (!isRedirectAction())
0877:                    setPageRenderParameter(response, currentPage);
0878:                processFinish(request, response, command, errors);
0879:
0880:            }
0881:
0882:            /**
0883:             * Template method for custom validation logic for individual pages.
0884:             * Default implementation calls <code>validatePage(command, errors, page)</code>.
0885:             * <p>Implementations will typically call fine-granular <code>validateXXX</code>
0886:             * methods of this instance's Validator, combining them to validation of the
0887:             * corresponding pages. The Validator's default <code>validate</code> method
0888:             * will not be called by a wizard form controller!
0889:             * @param command form object with the current wizard state
0890:             * @param errors validation errors holder
0891:             * @param page number of page to validate
0892:             * @param finish whether this method is called during final revalidation on finish
0893:             * (else, it is called for validating the current page)
0894:             * @see #validatePage(Object, Errors, int)
0895:             * @see org.springframework.validation.Validator#validate
0896:             */
0897:            protected void validatePage(Object command, Errors errors,
0898:                    int page, boolean finish) {
0899:                validatePage(command, errors, page);
0900:            }
0901:
0902:            /**
0903:             * Template method for custom validation logic for individual pages.
0904:             * Default implementation is empty.
0905:             * <p>Implementations will typically call fine-granular validateXXX methods of this
0906:             * instance's validator, combining them to validation of the corresponding pages.
0907:             * The validator's default <code>validate</code> method will not be called by a
0908:             * wizard form controller!
0909:             * @param command form object with the current wizard state
0910:             * @param errors validation errors holder
0911:             * @param page number of page to validate
0912:             * @see org.springframework.validation.Validator#validate
0913:             */
0914:            protected void validatePage(Object command, Errors errors, int page) {
0915:            }
0916:
0917:            /**
0918:             * Post-process the given page after binding and validation, potentially
0919:             * updating its command object. The passed-in request might contain special
0920:             * parameters sent by the page.
0921:             * <p>Only invoked when displaying another page or the same page again,
0922:             * not when finishing or cancelling.
0923:             * @param request current action request
0924:             * @param command form object with request parameters bound onto it
0925:             * @param errors validation errors holder
0926:             * @param page number of page to post-process
0927:             * @throws Exception in case of invalid state or arguments
0928:             */
0929:            protected void postProcessPage(ActionRequest request,
0930:                    Object command, Errors errors, int page) throws Exception {
0931:            }
0932:
0933:            /**
0934:             * Template method for the render phase of the finish action of this wizard.
0935:             * <p>Default implementation throws a PortletException, saying that a finish
0936:             * render request is not supported by this controller. Thus, you do not need to
0937:             * implement this template method if you do not need to render after a finish.
0938:             * <p>Call <code>errors.getModel()</code> to populate the ModelAndView model
0939:             * with the command and the Errors instance, under the specified command name,
0940:             * as expected by the "spring:bind" tag.
0941:             * @param request current portlet render request
0942:             * @param response current portlet render response
0943:             * @param command form object with the current wizard state
0944:             * @param errors validation errors holder
0945:             * @return the finish view
0946:             * @throws Exception in case of invalid state or arguments
0947:             * @see #processFinish
0948:             * @see org.springframework.validation.Errors
0949:             * @see org.springframework.validation.BindException#getModel
0950:             */
0951:            protected ModelAndView renderFinish(RenderRequest request,
0952:                    RenderResponse response, Object command,
0953:                    BindException errors) throws Exception {
0954:
0955:                throw new PortletException("Wizard form controller class ["
0956:                        + getClass().getName()
0957:                        + "] does not support a finish render request");
0958:            }
0959:
0960:            /**
0961:             * Template method for the action phase of the finish action of this wizard.
0962:             * <p>Default implementation throws a PortletException, saying that a finish
0963:             * action request is not supported by this controller. You will almost certainly
0964:             * need to override this method.
0965:             * @param request current portlet action request
0966:             * @param response current portlet action response
0967:             * @param command form object with the current wizard state
0968:             * @param errors validation errors holder
0969:             * @throws Exception in case of invalid state or arguments
0970:             * @see #renderFinish
0971:             * @see org.springframework.validation.Errors
0972:             */
0973:            protected void processFinish(ActionRequest request,
0974:                    ActionResponse response, Object command,
0975:                    BindException errors) throws Exception {
0976:
0977:                throw new PortletException("Wizard form controller class ["
0978:                        + getClass().getName()
0979:                        + "] does not support a finish action request");
0980:            }
0981:
0982:            /**
0983:             * Template method for the render phase of the cancel action of this wizard.
0984:             * <p>Default implementation throws a PortletException, saying that a cancel
0985:             * render request is not supported by this controller. Thus, you do not need to
0986:             * implement this template method if you do not support a cancel operation.
0987:             * <p>Call <code>errors.getModel()</code> to populate the ModelAndView model
0988:             * with the command and the Errors instance, under the specified command name,
0989:             * as expected by the "spring:bind" tag.
0990:             * @param request current portlet render request
0991:             * @param response current portlet render response
0992:             * @param command form object with the current wizard state
0993:             * @param errors Errors instance containing errors
0994:             * @return the cancellation view
0995:             * @throws Exception in case of invalid state or arguments
0996:             * @see #processCancel
0997:             * @see org.springframework.validation.Errors
0998:             * @see org.springframework.validation.BindException#getModel
0999:             */
1000:            protected ModelAndView renderCancel(RenderRequest request,
1001:                    RenderResponse response, Object command,
1002:                    BindException errors) throws Exception {
1003:
1004:                throw new PortletException("Wizard form controller class ["
1005:                        + getClass().getName()
1006:                        + "] does not support a cancel render request");
1007:            }
1008:
1009:            /**
1010:             * Template method for the action phase of the cancel action of this wizard.
1011:             * <p>Default implementation throws a PortletException, saying that a cancel
1012:             * action request is not supported by this controller. Thus, you do not need to
1013:             * implement this template method if you do not support a cancel operation.
1014:             * @param request current portlet action request
1015:             * @param response current portlet action response
1016:             * @param command form object with the current wizard state
1017:             * @param errors Errors instance containing errors
1018:             * @throws Exception in case of invalid state or arguments
1019:             * @see #renderCancel
1020:             * @see org.springframework.validation.Errors
1021:             */
1022:            protected void processCancel(ActionRequest request,
1023:                    ActionResponse response, Object command,
1024:                    BindException errors) throws Exception {
1025:
1026:                throw new PortletException("Wizard form controller class ["
1027:                        + getClass().getName()
1028:                        + "] does not support a cancel action request");
1029:            }
1030:
1031:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.