Source Code Cross Referenced for Controller.java in  » J2EE » Expresso » com » jcorporate » expresso » core » controller » 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 » Expresso » com.jcorporate.expresso.core.controller 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /* ====================================================================
0002:         * The Jcorporate Apache Style Software License, Version 1.2 05-07-2002
0003:         *
0004:         * Copyright (c) 1995-2002 Jcorporate Ltd. All rights reserved.
0005:         *
0006:         * Redistribution and use in source and binary forms, with or without
0007:         * modification, are permitted provided that the following conditions
0008:         * are met:
0009:         *
0010:         * 1. Redistributions of source code must retain the above copyright
0011:         *    notice, this list of conditions and the following disclaimer.
0012:         *
0013:         * 2. Redistributions in binary form must reproduce the above copyright
0014:         *    notice, this list of conditions and the following disclaimer in
0015:         *    the documentation and/or other materials provided with the
0016:         *    distribution.
0017:         *
0018:         * 3. The end-user documentation included with the redistribution,
0019:         *    if any, must include the following acknowledgment:
0020:         *       "This product includes software developed by Jcorporate Ltd.
0021:         *        (http://www.jcorporate.com/)."
0022:         *    Alternately, this acknowledgment may appear in the software itself,
0023:         *    if and wherever such third-party acknowledgments normally appear.
0024:         *
0025:         * 4. "Jcorporate" and product names such as "Expresso" must
0026:         *    not be used to endorse or promote products derived from this
0027:         *    software without prior written permission. For written permission,
0028:         *    please contact info@jcorporate.com.
0029:         *
0030:         * 5. Products derived from this software may not be called "Expresso",
0031:         *    or other Jcorporate product names; nor may "Expresso" or other
0032:         *    Jcorporate product names appear in their name, without prior
0033:         *    written permission of Jcorporate Ltd.
0034:         *
0035:         * 6. No product derived from this software may compete in the same
0036:         *    market space, i.e. framework, without prior written permission
0037:         *    of Jcorporate Ltd. For written permission, please contact
0038:         *    partners@jcorporate.com.
0039:         *
0040:         * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
0041:         * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0042:         * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
0043:         * DISCLAIMED.  IN NO EVENT SHALL JCORPORATE LTD OR ITS CONTRIBUTORS
0044:         * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
0045:         * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
0046:         * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
0047:         * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0048:         * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
0049:         * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
0050:         * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0051:         * SUCH DAMAGE.
0052:         * ====================================================================
0053:         *
0054:         * This software consists of voluntary contributions made by many
0055:         * individuals on behalf of the Jcorporate Ltd. Contributions back
0056:         * to the project(s) are encouraged when you make modifications.
0057:         * Please send them to support@jcorporate.com. For more information
0058:         * on Jcorporate Ltd. and its products, please see
0059:         * <http://www.jcorporate.com/>.
0060:         *
0061:         * Portions of this software are based upon other open source
0062:         * products and are subject to their respective licenses.
0063:         */
0064:
0065:        package com.jcorporate.expresso.core.controller;
0066:
0067:        import com.jcorporate.expresso.core.ExpressoConstants;
0068:        import com.jcorporate.expresso.core.ExpressoSchema;
0069:        import com.jcorporate.expresso.core.controller.session.PersistentSession;
0070:        import com.jcorporate.expresso.core.db.DBException;
0071:        import com.jcorporate.expresso.core.dbobj.Schema;
0072:        import com.jcorporate.expresso.core.dbobj.SchemaFactory;
0073:        import com.jcorporate.expresso.core.i18n.Messages;
0074:        import com.jcorporate.expresso.core.jsdkapi.GenericDispatcher;
0075:        import com.jcorporate.expresso.core.misc.ConfigManager;
0076:        import com.jcorporate.expresso.core.misc.ConfigurationException;
0077:        import com.jcorporate.expresso.core.misc.DateTime;
0078:        import com.jcorporate.expresso.core.misc.EventHandler;
0079:        import com.jcorporate.expresso.core.misc.SerializableString;
0080:        import com.jcorporate.expresso.core.misc.StringUtil;
0081:        import com.jcorporate.expresso.core.security.DelayThread;
0082:        import com.jcorporate.expresso.core.security.User;
0083:        import com.jcorporate.expresso.core.servlet.CheckLogin;
0084:        import com.jcorporate.expresso.kernel.util.ClassLocator;
0085:        import com.jcorporate.expresso.kernel.util.FastStringBuffer;
0086:        import com.jcorporate.expresso.services.dbobj.ControllerSecurity;
0087:        import com.jcorporate.expresso.services.dbobj.RegistrationDomain;
0088:        import com.jcorporate.expresso.services.dbobj.Setup;
0089:        import org.apache.commons.beanutils.BeanUtils;
0090:        import org.apache.log4j.Logger;
0091:        import org.apache.struts.Globals;
0092:        import org.apache.struts.action.Action;
0093:        import org.apache.struts.action.ActionForm;
0094:        import org.apache.struts.action.ActionForward;
0095:        import org.apache.struts.action.ActionMapping;
0096:        import org.apache.struts.config.ActionConfig;
0097:        import org.apache.struts.config.ForwardConfig;
0098:        import org.apache.struts.upload.MultipartRequestHandler;
0099:
0100:        import javax.servlet.ServletException;
0101:        import javax.servlet.http.HttpServletRequest;
0102:        import javax.servlet.http.HttpServletResponse;
0103:        import java.io.ByteArrayOutputStream;
0104:        import java.io.IOException;
0105:        import java.io.PrintStream;
0106:        import java.io.Serializable;
0107:        import java.lang.reflect.InvocationTargetException;
0108:        import java.lang.reflect.Method;
0109:        import java.util.ArrayList;
0110:        import java.util.Enumeration;
0111:        import java.util.Hashtable;
0112:        import java.util.Iterator;
0113:        import java.util.Locale;
0114:        import java.util.Stack;
0115:        import java.util.Vector;
0116:
0117:        /**
0118:         * A sequence of interaction with a user is defined as a &quot;Controller&quot;.
0119:         * <p/>
0120:         * An Expresso controller is best thought of as a finite state machine.  The only
0121:         * real difference is that because of the stateless nature of the web, anybody
0122:         * can reach any state with using the &quot;state&quot; parameter in the URL.
0123:         * </p>
0124:         * <p/>
0125:         * Usually for a web deployment environment, you would derive your own controller
0126:         * from DBController, which adds a database-backed Security matrix to the
0127:         * controller's base capabilities.  Controllers (and DBControllers) do not necessarily
0128:         * need to be run inside a servlet environment.  If they never downcast their ControllerResponse
0129:         * object to ServletControllerResponse, the Controller can also be used in products
0130:         * such as Expresso Webservices, or
0131:         * </p>
0132:         * <p>See the <em>Expresso Developer's Guide</em> for more information on creating
0133:         * and using a Controller.</p>
0134:         * <p/>
0135:         * A Controller takes a series of parameters (optional) and then provides
0136:         * a series of Blocks, Inputs, Outputs, and Transitions to the client</p>
0137:         * <itemizedlist>
0138:         * <listitem>An Input specifies a piece of information we want FROM the client</listitem>
0139:         * <listitem>An Output is a piece of information we supply TO the client</listitem>
0140:         * <listitem>A Transition is an action the client can take from this point - e.g.
0141:         * further controllers that are followups to this controller</listitem>
0142:         * <listitem>A Block is a collection of Inputs, Outputs, Transitions or other Blocks</listitem>
0143:         * </itemizedlist>
0144:         *
0145:         * @see com.jcorporate.expresso.core.controller.DBController
0146:         * @see com.jcorporate.expresso.core.controller.SecureIfSetController
0147:         */
0148:        public abstract class Controller extends Action implements  Serializable {
0149:            /**
0150:             * log for methods in this class alone
0151:             */
0152:            private static Logger log = Logger.getLogger(Controller.class);
0153:
0154:            /**
0155:             * if subclass calls getLogger(), this will create logger with
0156:             * subclass name
0157:             */
0158:            protected Logger mLog = null;
0159:
0160:            /**
0161:             * Controller response key
0162:             */
0163:            public final static String RESPONSE_KEY = ExpressoConstants.CONTROLLER_RESPONSE_KEY;
0164:            /**
0165:             * Controller original URL key
0166:             */
0167:            public final static String ORIGINAL_URL_KEY = ExpressoConstants.CONTROLLER_ORIGINAL_URL_KEY;
0168:            /**
0169:             * Controller request key
0170:             */
0171:            public final static String REQUEST_KEY = ExpressoConstants.CONTROLLER_REQUEST_KEY;
0172:
0173:            /**
0174:             * New state exception key
0175:             */
0176:            public final static String NEWSTATE_EXCEPTION_KEY = ExpressoConstants.NEWSTATE_EXCEPTION_KEY;
0177:
0178:            // *PP* I have not deprecated these at all Tue Jun 24 20:09:00 BST 2003
0179:            public final static String CTL_SUCC_TRAN = "controllerSuccessReturn";
0180:            public final static String CTL_SUCC_CTL = "controllerSuccessReturnController";
0181:            public final static String CTL_SUCC_STATE = "controllerSuccessReturnState";
0182:            public final static String STATE_SUCC_TRAN = "stateSuccessReturn";
0183:            public final static String STATE_SUCC_CTL = "stateSuccessReturnController";
0184:            public final static String STATE_SUCC_STATE = "stateSuccessReturnState";
0185:            public final static String STATE_ERR_TRAN = "stateErrorReturn";
0186:            public final static String STATE_ERR_CTL = "stateErrorReturnController";
0187:            public final static String STATE_ERR_STATE = "stateErrorReturnState";
0188:            public final static String RETURN_TO_SENDER_TRAN = "returnToSender";
0189:
0190:            /**
0191:             * key for putting state into parameter map
0192:             */
0193:            public static final String STATE_PARAM_KEY = "state";
0194:
0195:            /**
0196:             * key for putting controller into parameter map
0197:             */
0198:            public static final String CONTROLLER_PARAM_KEY = "controller";
0199:
0200:            /* The name of the state which is the "initial" state of this controller */
0201:            /* E.g. where the controller starts if no state parameter is specified */
0202:            private static Hashtable initialStates = new Hashtable();
0203:
0204:            /**
0205:             * Static map of classes to schema instances
0206:             */
0207:            private static Hashtable schemas = new Hashtable();
0208:
0209:            /**
0210:             * States is a hashtable of hashtables, e.g. the states hashtable itself
0211:             * is indexed by controller class name. Each entry against a classname is itself a hashtable
0212:             * with a list of the valid state objects for the given controller
0213:             */
0214:            private static Hashtable states = new Hashtable();
0215:
0216:            /**
0217:             * used to specify the classes of parameters for introspection;
0218:             * since these classes are constant across all controllers, we use a static
0219:             */
0220:            private static final Class[] newStateParams = {
0221:                    java.lang.String.class,
0222:                    com.jcorporate.expresso.core.controller.ControllerRequest.class };
0223:
0224:            /**
0225:             * used for reflection into the state handlers
0226:             */
0227:            private static final Class[] stateHandlerParams = {
0228:                    com.jcorporate.expresso.core.controller.ControllerRequest.class,
0229:                    com.jcorporate.expresso.core.controller.ControllerResponse.class };
0230:
0231:            /**
0232:             * used for reflection into the state handlers
0233:             */
0234:            private static final Class[] servletStateHandlerParams = {
0235:                    com.jcorporate.expresso.core.controller.ServletControllerRequest.class,
0236:                    com.jcorporate.expresso.core.controller.ControllerResponse.class };
0237:
0238:            /**
0239:             * promptStates is only updated in the constructor.  The instantiation of Controller by Struts is
0240:             * synchronized so we don't need to worry about threadsafety while updating this collection even
0241:             * though it is shared by many threads(singleton).  However, Controller is also instantiated by Transition and
0242:             * Controller itself and unlike Struts these are not synchronized.  Luckily, unlike Struts, these
0243:             * instances are not shared between threads.  So we should be OK with no sychronized access and
0244:             * also with using a non-synchronized collection (ArrayList).
0245:             * The main reason this collection was not static like most of the other fields in this class
0246:             * is because of the way this collection is populated.  Unlike the 'states' collection, this one
0247:             * appends new items to the collection rather than overwriting (hashing).  So if this had been
0248:             * static, every time Transition/Controller instantiated a new instance of this class it would
0249:             * try to append the same states to the collection making the collection inaccurate (and big).
0250:             */
0251:            private ArrayList promptStates = new ArrayList(3);
0252:
0253:            /**
0254:             * handleStates is only updated in the constructor.  The instantiation of Controller by Struts is
0255:             * synchronized so we don't need to worry about threadsafety while updating this collection even
0256:             * though it is shared by many threads(singleton).  However, Controller is also instantiated by Transition and
0257:             * Controller itself and unlike Struts these are not synchronized.  Luckily, unlike Struts, these
0258:             * instances are not shared between threads.  So we should be OK with no sychronized access and
0259:             * also with using a non-synchronized collection (ArrayList).
0260:             * The main reason this collection was not static like most of the other fields in this class
0261:             * is because of the way this collection is populated.  Unlike the 'states' collection, this one
0262:             * appends new items to the collection rather than overwriting (hashing).  So if this had been
0263:             * static, every time Transition/Controller instantiated a new instance of this class it would
0264:             * try to append the same states to the collection making the collection inaccurate (and big).
0265:             */
0266:            private ArrayList handleStates = new ArrayList(3);
0267:
0268:            private State finalState;
0269:
0270:            private Transition controllerChainingTransition = null;
0271:
0272:            private Transition controllerSecurityTransition = null;
0273:
0274:            /**
0275:             * Default constructor
0276:             */
0277:            public Controller() {
0278:
0279:            } /* Controller() */
0280:
0281:            /**
0282:             * The constructor of the child object should call addFinalState to define
0283:             * the last state to be executed for this controller.
0284:             * Once the final state is added then no other states can be added via the
0285:             * addStatePairing method.
0286:             *
0287:             * @param newFinalState the new state to use as your final state.
0288:             * @throws NonHandleableException if you send it an improper final state.
0289:             */
0290:            protected void addFinalState(State newFinalState)
0291:                    throws NonHandleableException {
0292:                if (promptStates.contains(newFinalState)
0293:                        || handleStates.contains(newFinalState)) {
0294:                    throw new NonHandleableException(
0295:                            "Final state must not be the same as any of the paired states.");
0296:                }
0297:
0298:                finalState = newFinalState;
0299:                addState(newFinalState);
0300:
0301:                //Set the initial state to this final state only if it is the only state in this controller.
0302:                if (StringUtil.notNull(getInitialState()).equals("")) {
0303:                    setInitialState(newFinalState.getName());
0304:                }
0305:            }
0306:
0307:            /**
0308:             * If nextState is a prompt state (as determined by the addStatePairing method)
0309:             * then add a 'next' and 'previous' transitions as required.
0310:             * A 'next' transition will refer to a prompt state's associated validate state.
0311:             * A 'previous' transition will refer to the prompt state that precedes the
0312:             * passed in state.  The 'previous' state will not be added to the response if
0313:             * if the passed in state is the first one (iniial state) in this controller.
0314:             *
0315:             * @param nextState in this controller the new state add
0316:             * @param response  the ControllerResponse that these transitions will be
0317:             *                  added to.
0318:             * @throws ControllerException upon error.
0319:             */
0320:            protected void addPromptTransitions(State nextState,
0321:                    ControllerResponse response) throws ControllerException {
0322:
0323:                //Tack on the wizards Prev/Next/Finish transitions to any promptStates.
0324:                if (isPromptState(nextState)) {
0325:                    String previousPromptState = previousPromptState(nextState);
0326:
0327:                    if (previousPromptState != null) {
0328:                        Transition previousTransition = new Transition();
0329:                        previousTransition.setControllerObject(getClass()
0330:                                .getName());
0331:                        previousTransition.setState(previousPromptState);
0332:                        previousTransition.setName("previous");
0333:                        previousTransition.setLabel("Previous");
0334:                        response.addTransition(previousTransition);
0335:                    }
0336:
0337:                    //Add the 'Next' or 'Done' buttons ('Done' is replaced with the name of the final state)
0338:                    Transition nextTransition = null;
0339:                    String nextPromptState = nextPromptState(nextState);
0340:
0341:                    if (nextPromptState != null) { //Would not exist if this is the last screen in wizard
0342:                        String nextHandleState = nextHandleState(nextState);
0343:
0344:                        //Safer to use no-arg constructor, this prevents the transition's ownerObject from being set.
0345:                        //Setting this can prevent the getParamString() method from returning a 'controller' param.
0346:                        //This can be problematic in situations, eg - DefaultViewHandler uses the getRequestPath()
0347:                        //of a request to set the form's 'action' attribute which could be a different controller
0348:                        //from the state's controller.  This would raise an exception because no controller parm passed.
0349:                        nextTransition = new Transition();
0350:                        nextTransition
0351:                                .setControllerObject(getClass().getName());
0352:                        nextTransition.setState(nextHandleState);
0353:                        nextTransition.setName("next");
0354:                        nextTransition.setLabel("Next");
0355:                        nextTransition.addParam(STATE_SUCC_STATE,
0356:                                nextPromptState); //ie transition to next screen in wizard
0357:                        nextTransition.addParam(STATE_SUCC_CTL, response
0358:                                .getControllerClass());
0359:                    } else { //Final state will be last and must exist - It will auto rerun any handler states
0360:                        State finalState = getFinalState();
0361:
0362:                        if (finalState == null) {
0363:                            throw new ControllerException(
0364:                                    "Final state must exist.");
0365:                        }
0366:
0367:                        nextTransition = new Transition();
0368:                        nextTransition
0369:                                .setControllerObject(getClass().getName());
0370:                        nextTransition.setState(finalState.getName());
0371:                        nextTransition.setName("next");
0372:                        nextTransition.setLabel(finalState.getDescription());
0373:                    }
0374:
0375:                    response.addTransition(nextTransition);
0376:                }
0377:            }
0378:
0379:            /**
0380:             * The constructor of the child object should call addState to define
0381:             * each of the states available in this method.
0382:             *
0383:             * @param newState The State object to be added to the list of states for this
0384:             *                 controller
0385:             */
0386:            protected void addState(State newState) {
0387:                try {
0388:                    newState.setController(this );
0389:                } catch (ControllerException ce) {
0390:                    log.error("Unable to set controller", ce);
0391:                }
0392:
0393:                Hashtable myStateList = (Hashtable) states.get(getClass()
0394:                        .getName());
0395:
0396:                if (myStateList == null) {
0397:                    myStateList = new Hashtable();
0398:                    states.put(getClass().getName(), myStateList);
0399:                }
0400:
0401:                myStateList.put(newState.getName(), newState);
0402:            } /* addState(State) */
0403:
0404:            /**
0405:             * The constructor of the child object should call this method with a pairing of State objects.
0406:             * The sequence of calls to this method determine the runtime ordering of states.
0407:             *
0408:             * @param promptState    The state that is part of the 'prompting' workflow
0409:             * @param handleState    The state that is part of the 'processing' workflow
0410:             * @param stateFormClass The <code>ActionForm</code> name to use
0411:             * @throws NonHandleableException if there's an error in pairing.  Usually
0412:             *                                caused by a java.lang.IllegalArumentException
0413:             */
0414:            protected void addStatePairing(State promptState,
0415:                    State handleState, String stateFormClass)
0416:                    throws NonHandleableException {
0417:                if (promptState == null || handleState == null) {
0418:                    throw new NonHandleableException(
0419:                            "Can't add null state in pairing.");
0420:                }
0421:                //This check helps ensure that initialState is set correctly (ie to 1st prompt state if it exists,
0422:                //otherwise it will be set to the lone state).  That lone state will be the final state.
0423:                if (finalState != null) {
0424:                    throw new NonHandleableException(
0425:                            "Can't add states once final state has been added.");
0426:                }
0427:                if (promptStates.contains(promptState)
0428:                        || promptStates.contains(handleState)
0429:                        || handleStates.contains(promptState)
0430:                        || handleStates.contains(handleState)) {
0431:                    throw new NonHandleableException(
0432:                            "Paired states must be unique.");
0433:                }
0434:
0435:                promptState.setStateFormClass(stateFormClass);
0436:                handleState.setStateFormClass(stateFormClass);
0437:                promptStates.add(promptState);
0438:                handleStates.add(handleState);
0439:                addState(promptState);
0440:                addState(handleState);
0441:
0442:                //Let's enter via the 1st prompt state in the controller if the value hasn't already been explicitly set.
0443:                if (StringUtil.notNull(getInitialState()).equals("")) {
0444:                    setInitialState(promptState.getName());
0445:                }
0446:
0447:                //Set the default transition to return to prompt the user if any errors generated
0448:                //within the handler state.  This setting can be overriden at state-runtime.
0449:                Transition errorTransition = new Transition();
0450:                errorTransition.setState(promptState.getName());
0451:                errorTransition.setControllerObject(getClass().getName());
0452:                handleState.setErrorTransition(errorTransition);
0453:            }
0454:
0455:            /**
0456:             * Return the Struts ActionForm associated with this controller as specified
0457:             * in the Struts config file.  Struts would have already created and populated
0458:             * this form and put it either in the request or session scope.
0459:             *
0460:             * @param request The ControllerRequest object
0461:             * @return The appropriate <code>ActionForm</code> for this controller request
0462:             * @throws ControllerException if unable to find the Controller Form.
0463:             */
0464:            protected ActionForm findControllerForm(ControllerRequest request)
0465:                    throws ControllerException {
0466:                ActionConfig config = ConfigManager.getActionConfig("",
0467:                        getClass().getName(), null);
0468:                //        ActionMapping mapping = ConfigManager.getMapping(getClass().getName(),
0469:                //                null);
0470:                if (config == null) {
0471:                    return null;
0472:                }
0473:
0474:                String controllerFormAttribute = config.getAttribute();
0475:
0476:                if (controllerFormAttribute == null) { //no form associated with this controller
0477:                    return null;
0478:                }
0479:
0480:                // Find the controller's form.  It would have been created by Strut's form logic before getting here.
0481:                PersistentSession session = request.getSession();
0482:
0483:                if ("request".equals(config.getScope())) {
0484:
0485:                    //The getAttribute() method appears to read attributes from the HTTPRequest scope!!
0486:                    return (ActionForm) session
0487:                            .getAttribute(controllerFormAttribute);
0488:                } else {
0489:                    return (ActionForm) session
0490:                            .getPersistentAttribute(controllerFormAttribute);
0491:                }
0492:            }
0493:
0494:            /**
0495:             * Return the transition that will be executed once this controller
0496:             * completes without errors.  The controller 'completes' once the
0497:             * final state (as defined using addFinalState) returns without errors
0498:             * in the error collection.
0499:             *
0500:             * @return The Transition for this controller chaining setup.
0501:             */
0502:            protected Transition getControllerChainingTransition() {
0503:                return controllerChainingTransition;
0504:            }
0505:
0506:            /**
0507:             * Return the transition that will be executed if any state in this controller
0508:             * cannot be run because the user does not have sufficient authorization.
0509:             *
0510:             * @return The ControllerSecurity Transition
0511:             */
0512:            protected Transition getControllerSecurityTransition() {
0513:                return controllerSecurityTransition;
0514:            }
0515:
0516:            /**
0517:             * Return the final state for this controller.  See addFinalState().
0518:             *
0519:             * @return the &quot;Final&quot; state for this workflow.
0520:             */
0521:            public State getFinalState() {
0522:                return finalState;
0523:            }
0524:
0525:            /**
0526:             * Get the initial state in a controller.  This is the state to use if there
0527:             * is no <code>state</code> parameter specified in the requesting URL or
0528:             * execution container.
0529:             *
0530:             * @return The name of the State to use as default for this controller
0531:             */
0532:            public String getInitialState() {
0533:                return (String) initialStates.get(getClass().getName());
0534:            } /* getInitialState() */
0535:
0536:            /**
0537:             * Get the name of the schema object that this Controller belongs to
0538:             *
0539:             * @return The schema class name associated with this controller
0540:             */
0541:            protected final String getSchema() {
0542:                Stack mySchemaStack = (Stack) schemas.get(getClass().getName());
0543:
0544:                if (mySchemaStack == null) {
0545:                    setSchema(ExpressoSchema.class.getName());
0546:                    mySchemaStack = (Stack) schemas.get(getClass().getName());
0547:                }
0548:
0549:                String returnValue = (String) mySchemaStack.peek();
0550:                return returnValue;
0551:            } /* getSchema() */
0552:
0553:            /**
0554:             * Retrieve a full instance of the Schema object that is associated with
0555:             * this controller
0556:             *
0557:             * @return Schema instance.
0558:             */
0559:            protected Schema getSchemaInstance() {
0560:                return SchemaFactory.getInstance().getSchema(this .getSchema());
0561:            }
0562:
0563:            /**
0564:             * Retrieve a stack of all schemas in a 'derived sense'
0565:             *
0566:             * @return java.util.Stack with the schema hierarchy ending in ExpressoSchema
0567:             *         at the bottom.
0568:             * @deprecated 7/04; v5.5.  just name changed.  see getSchemaStack
0569:             */
0570:            public synchronized Stack getSchemaHierarchy() {
0571:                return getSchemaStack();
0572:            }
0573:
0574:            /**
0575:             * Retrieve a stack of all schemas. hands out actual object instance; singleton for this controller.
0576:             *
0577:             * @return java.util.Stack with the schema hierarchy ending in ExpressoSchema at the bottom. never null.
0578:             */
0579:            public synchronized Stack getSchemaStack() {
0580:                Stack s = (Stack) schemas.get(getClass().getName());
0581:                if (s == null) {
0582:                    s = new Stack();
0583:                    schemas.put(this .getClass().getName(), s);
0584:                }
0585:
0586:                if (s.isEmpty()) {
0587:                    s.push(com.jcorporate.expresso.core.ExpressoSchema.class
0588:                            .getName());
0589:                }
0590:
0591:                return s;
0592:            }
0593:
0594:            /**
0595:             * Return a specific state
0596:             *
0597:             * @param stateName The name of the state to retrieve
0598:             * @return the Instantiated State.
0599:             */
0600:            public final State getState(String stateName) {
0601:                Hashtable myStateList = (Hashtable) states.get(getClass()
0602:                        .getName());
0603:
0604:                if (myStateList == null) {
0605:                    return null;
0606:                }
0607:
0608:                State stateClass = (State) myStateList.get(stateName);
0609:
0610:                if (stateClass == null) {
0611:                    return null;
0612:                }
0613:                try {
0614:                    State newStateClass = (State) stateClass.clone();
0615:                    newStateClass.setController(this );
0616:
0617:                    return newStateClass;
0618:                } catch (CloneNotSupportedException cne) {
0619:                    log.error("Unable to clone  " + "State object '"
0620:                            + stateClass + "'", cne);
0621:                } catch (ControllerException ce) {
0622:                    log.error("Unable to clone  " + "State object '"
0623:                            + stateClass + "'", ce);
0624:                }
0625:
0626:                return null;
0627:            } /* getState(String) */
0628:
0629:            /**
0630:             * Return the hashtable of valid states for this controller
0631:             *
0632:             * @return a Hashtable of states for this controller
0633:             */
0634:            public final Hashtable getStates() {
0635:                Hashtable myStateList = (Hashtable) states.get(getClass()
0636:                        .getName());
0637:
0638:                if (myStateList == null) {
0639:                    return null;
0640:                }
0641:
0642:                return myStateList;
0643:            } /* getStates() */
0644:
0645:            /**
0646:             * Convenience version, uses default locale of default db context
0647:             * <p/>
0648:             * IMPORTANT: in general, if there's a ControllerResponse object available,
0649:             * use ControllerResponse.getString(String) instead, this is able
0650:             * to return the local language by considering the user's locale.
0651:             *
0652:             * @param stringCode The properties file string code to retrieve
0653:             * @return translated string, or if not found, the stringCode
0654:             */
0655:            protected String getString(String stringCode) {
0656:                return this .getString(stringCode, new Object[0]);
0657:            } /* getString(String) */
0658:
0659:            /**
0660:             * Convenience version, uses default locale of default db context
0661:             * <p/>
0662:             * IMPORTANT: In general, if there's a ControllerResponse object available,
0663:             * use ControllerResponse.getString(String) instead, this is able
0664:             * to return the local language by considering the user's locale.
0665:             *
0666:             * @param stringCode The properties file string code to retrieve
0667:             * @param args       The Object array for i18n formatting.
0668:             * @return translated string, or if not found, the stringCode
0669:             */
0670:            protected String getString(String stringCode, Object[] args) {
0671:                String result = stringCode;
0672:                Stack s = (Stack) schemas.get(this .getClass().getName());
0673:
0674:                if (s == null || s.isEmpty()) {
0675:                    result = Messages.getString(getSchema(), stringCode, args);
0676:                } else {
0677:                    Locale theLocale = Messages.getDefaultLocale();
0678:                    result = Messages.getString(s, theLocale, stringCode, args);
0679:                }
0680:
0681:                return result;
0682:            }
0683:
0684:            /**
0685:             * Return the title of this Controller
0686:             *
0687:             * @return java.lang.String The Title of the controller
0688:             */
0689:            public String getTitle() {
0690:                return ("No Title");
0691:            } /* getTitle() */
0692:
0693:            /**
0694:             * Handle an exception error that is not otherwise caught or handled
0695:             * by the Controller instance itself. Typically, these will be reserved
0696:             * for "system failure" type of situations, as anything that the user
0697:             * can reasonable be expected to correct should be reported in the ErrorCollection
0698:             * instead.
0699:             *
0700:             * @param req          The HTTPServletRequest
0701:             * @param creq         The ControllerRequest Object
0702:             * @param dbName       The current data context
0703:             * @param userName     The currently logged in Username
0704:             * @param theException The <code>java.lang.Throwable</code> object that
0705:             *                     was caught
0706:             * @throws ServletException upon fatal error for handling the exception
0707:             */
0708:            protected void handleException(HttpServletRequest req,
0709:                    ControllerRequest creq, String dbName, String userName,
0710:                    Throwable theException) throws ServletException {
0711:                if (StringUtil.notNull(dbName).equals("")) {
0712:                    dbName = "default";
0713:                }
0714:
0715:                if (creq == null || dbName == null || req == null
0716:                        || userName == null) {
0717:                    log.error("Error handling exception", theException);
0718:                    throw new ServletException("ControllerRequest Error",
0719:                            theException);
0720:                }
0721:
0722:                try {
0723:                    ControllerResponse errorResponse = new ControllerResponse();
0724:                    errorResponse.setRequest(creq);
0725:                    errorResponse.setTitle(getTitle());
0726:                    errorResponse.setSchemaStack((java.util.Stack) this 
0727:                            .getSchemaStack().clone());
0728:                    errorResponse.setControllerClass(getClass().getName());
0729:
0730:                    /* Stash the stackTrace, if available, in an output */
0731:                    boolean showStack = true;
0732:
0733:                    try {
0734:                        if (ConfigManager.getContext(dbName) != null) {
0735:                            showStack = ConfigManager.getContext(dbName)
0736:                                    .showStackTrace();
0737:                        }
0738:                    } catch (ConfigurationException ce) {
0739:                        throw new ServletException(ce);
0740:                    }
0741:                    if (showStack) {
0742:                        if (theException != null) {
0743:                            ByteArrayOutputStream bos = new ByteArrayOutputStream();
0744:                            theException.printStackTrace(new PrintStream(bos));
0745:                            errorResponse.addOutput(new Output("stackTrace",
0746:                                    bos.toString()));
0747:                        } else {
0748:                            errorResponse.addOutput(new Output("stackTrace",
0749:                                    "No stack trace was available"));
0750:                        }
0751:                    } else {
0752:                        errorResponse.addOutput(new Output("stackTrace",
0753:                                "Stack trace display is not " + "enabled."));
0754:                    }
0755:
0756:                    errorResponse.addOutput(new Output("exceptionMessage",
0757:                            theException.getMessage()));
0758:
0759:                    if (theException instanceof  com.jcorporate.expresso.kernel.exception.ChainedException) {
0760:                        com.jcorporate.expresso.kernel.exception.ChainedException c = (com.jcorporate.expresso.kernel.exception.ChainedException) theException;
0761:                        Throwable nestedException = c.getNested();
0762:
0763:                        if (nestedException != null) {
0764:                            String nested = StringUtil.notNull(c.getNested()
0765:                                    .getMessage());
0766:
0767:                            if (theException.getMessage().indexOf(nested) == -1) {
0768:                                errorResponse.addOutput(new Output(
0769:                                        "nestedMessage", nested));
0770:                            }
0771:                        }
0772:                        if (c.getErrorNumber() != 0) {
0773:                            errorResponse.addOutput(new Output("errorNumber",
0774:                                    Integer.toString(c.getErrorNumber())));
0775:                        }
0776:                    }
0777:
0778:                    errorResponse.addOutput(new Output("requestedURL",
0779:                            StringUtil.notNull(req.getRequestURI())));
0780:                    errorResponse.addOutput(new Output("queryString",
0781:                            StringUtil.notNull(req.getQueryString())));
0782:                    errorResponse.addOutput(new Output("db", dbName));
0783:                    errorResponse.addOutput(new Output("userName", userName));
0784:                    errorResponse.addOutput(new Output("dbDescrip",
0785:                            ConfigManager.getContext(dbName).getDescription()));
0786:                    errorResponse.addOutput(new Output("errorClass",
0787:                            theException.getClass().getName()));
0788:
0789:                    if (theException instanceof  SecurityException) {
0790:                        errorResponse.addOutput(new Output("errorType",
0791:                                "security"));
0792:                        addRequestedURLtoSession(req, creq);
0793:                    } else if (theException instanceof  DBException) {
0794:                        errorResponse.addOutput(new Output("errorType",
0795:                                "database"));
0796:
0797:                        DBException de = (DBException) theException;
0798:                        errorResponse.addOutput(new Output("dbMessage", de
0799:                                .getDBMessage()));
0800:                    } else {
0801:                        errorResponse
0802:                                .addOutput(new Output("errorType", "other"));
0803:                    }
0804:
0805:                    errorResponse.addOutput(new Output("controllerClass",
0806:                            getClass().getName()));
0807:                    req.setAttribute(ExpressoConstants.CONTROLLER_RESPONSE_KEY,
0808:                            errorResponse);
0809:
0810:                    /* Now see if we also email the error anywhere */
0811:                    boolean mailError = false;
0812:
0813:                    try {
0814:                        String servletEventFlag = StringUtil.notNull(Setup
0815:                                .getValue(dbName, "ServletEvent"));
0816:
0817:                        if (StringUtil.toBoolean(servletEventFlag)) {
0818:                            mailError = true;
0819:                        } else if (servletEventFlag.equalsIgnoreCase("E")) {
0820:                            if (!(theException instanceof  SecurityException)) {
0821:                                mailError = true;
0822:                            }
0823:                        }
0824:                    } catch (Exception e) {
0825:                        log.error("Unable to email error correctly", e);
0826:                    }
0827:                    if (!mailError) {
0828:                        log.info("Sending of '"
0829:                                + theException.getClass().getName()
0830:                                + "' errors via email is not enabled in "
0831:                                + "db/context '" + dbName + "'");
0832:                    } else {
0833:                        FastStringBuffer theMessage = FastStringBuffer
0834:                                .getInstance();
0835:                        try {
0836:                            theMessage.append("Error:\n");
0837:                            theMessage.append("\tA "
0838:                                    + theException.getClass().getName()
0839:                                    + " Error occurred at "
0840:                                    + DateTime.getDateTimeForDB(dbName)
0841:                                    + " in database/context '" + dbName
0842:                                    + "' to user '" + userName + "'\n");
0843:                            theMessage.append("\tThe requested URL was '");
0844:                            theMessage.append(getRequestURL(req));
0845:                            theMessage.append("'\n");
0846:
0847:                            String errorMessage = theException.getMessage();
0848:
0849:                            if (errorMessage != null) {
0850:                                theMessage.append("\t");
0851:                                theMessage.append(errorMessage);
0852:                            } else {
0853:                                theMessage
0854:                                        .append("No error message was available");
0855:                            }
0856:
0857:                            theMessage.append(errorResponse.getOutput(
0858:                                    "stackTrace").getContent());
0859:                            String finalMessage = theMessage.toString();
0860:                            log.error(finalMessage, theException);
0861:                            EventHandler.Event(dbName, "SYSERROR",
0862:                                    finalMessage, false);
0863:                        } catch (Exception ee) {
0864:                            log.error("Unable to send error email", ee);
0865:                        } finally {
0866:                            theMessage.release();
0867:                            theMessage = null;
0868:                        }
0869:
0870:                    } /* if we send an email */
0871:
0872:                } catch (NullPointerException npe) {
0873:                    log.error("Null Pointer Exception while handling error",
0874:                            npe);
0875:                    throw new ServletException(npe);
0876:                } catch (ControllerException ce) {
0877:                    log.error("ControllerException while handling error", ce);
0878:                    throw new ServletException(ce);
0879:                } catch (Exception ee) {
0880:                    log.error("Exception while handling error", ee);
0881:                    throw new ServletException(ee);
0882:                }
0883:            } /* handleException */
0884:
0885:            /* Stash the original URL that we asked for in the session,
0886:             * so that if we log in and want to try again, it's available
0887:             */
0888:            protected void addRequestedURLtoSession(HttpServletRequest req,
0889:                    ControllerRequest creq) throws ControllerException {
0890:                PersistentSession session = creq.getSession();
0891:
0892:                if (session != null) {
0893:                    String origUrl = getRequestURL(req);
0894:                    session.setPersistentAttribute(
0895:                            ExpressoConstants.CONTROLLER_ORIGINAL_URL_KEY,
0896:                            new SerializableString(origUrl));
0897:                }
0898:            }
0899:
0900:            /**
0901:             * recreate requested URL; never null, though could be empty string
0902:             */
0903:            protected String getRequestURL(HttpServletRequest req) {
0904:                String origUrl = StringUtil.notNull(req.getRequestURI());
0905:
0906:                if (req.getQueryString() != null) {
0907:                    origUrl = origUrl + "?" + req.getQueryString();
0908:                }
0909:                return origUrl;
0910:            }
0911:
0912:            /**
0913:             * ???????????????????????
0914:             *
0915:             * @param req       ?
0916:             * @param creq      ?
0917:             * @param regDomain ?
0918:             */
0919:            protected void addRegDomainParamtoSession(HttpServletRequest req,
0920:                    ControllerRequest creq, String regDomain)
0921:                    throws ControllerException {
0922:                PersistentSession session = creq.getSession();
0923:
0924:                if (session != null) {
0925:                    session.setPersistentAttribute("regDomain",
0926:                            new SerializableString(regDomain));
0927:                }
0928:            }
0929:
0930:            /**
0931:             * Factory method to create an Controller from it's name
0932:             * Do not call this function directly!  Use <code>ConfigManager.getControllerFactory()
0933:             * .getInstance(java.lang.String)</code> instead.
0934:             *
0935:             * @param className The classname of the controller to instantiated
0936:             * @return a fully instantiated Controller Object
0937:             * @throws ControllerException upon construction failure
0938:             */
0939:            public static synchronized Controller instantiate(String className)
0940:                    throws ControllerException {
0941:                StringUtil.assertNotBlank(className, "Controller class name "
0942:                        + " may not be blank or null here");
0943:
0944:                try {
0945:
0946:                    Class c = ClassLocator.loadClass(className);
0947:                    return (Controller) c.newInstance();
0948:                } catch (ClassNotFoundException cn) {
0949:                    throw new ControllerException("Controller object '"
0950:                            + className + "' not found", cn);
0951:                } catch (InstantiationException ie) {
0952:                    throw new ControllerException("Controller object '"
0953:                            + className + "' cannot be instantiated", ie);
0954:                } catch (IllegalArgumentException e) {
0955:                    throw new ControllerException(
0956:                            "Controller object '"
0957:                                    + className
0958:                                    + "' cannot be instantiated (IllegalArgumentException",
0959:                            e);
0960:                } catch (IllegalAccessException iae) {
0961:                    throw new ControllerException("llegal access loading "
0962:                            + "Controller object '" + className + "'", iae);
0963:                }
0964:            } /* instantiate(String) */
0965:
0966:            /**
0967:             * Return True if the passed in state was added to this controller
0968:             * as a final state.
0969:             *
0970:             * @param newState the state name to use as the final state.
0971:             * @return true if this is the final state.
0972:             */
0973:            protected boolean isFinalState(String newState) {
0974:                if (finalState == null) {
0975:                    return false;
0976:                }
0977:
0978:                return finalState.getName().equals(newState);
0979:            }
0980:
0981:            /**
0982:             * Return True if the passed in state was added to this controller
0983:             * as a handle state.
0984:             *
0985:             * @param nextState the state name to check against
0986:             * @return true if it is supposed to handle the state.
0987:             */
0988:            protected boolean isHandleState(State nextState) {
0989:                return handleStates.contains(nextState);
0990:            }
0991:
0992:            /**
0993:             * Return True if the passed in state was added to this controller
0994:             * as a prompt state.
0995:             *
0996:             * @param nextState the state name to check against
0997:             * @return true if it is the prompt state.
0998:             */
0999:            protected boolean isPromptState(State nextState) {
1000:                return promptStates.contains(nextState);
1001:            }
1002:
1003:            /**
1004:             * Return the state's form with data from the controller's form.
1005:             * The controller's form is specified in the struts config file.  The state
1006:             * form is specified in the state's stateFormClass attribute.
1007:             *
1008:             * @param nextState      The next state to use
1009:             * @param controllerForm the ControllerForm as specified in the struts config file.
1010:             * @return a fully instantiated StateForm
1011:             * @throws ControllerException if there is an error instantiating the State Form
1012:             */
1013:            protected StateForm loadStateForm(State nextState,
1014:                    ActionForm controllerForm) throws ControllerException {
1015:                StateForm stateForm = null;
1016:                String stateFormClass = StringUtil.notNull(nextState
1017:                        .getStateFormClass());
1018:
1019:                if (controllerForm == null) {
1020:                    if (!stateFormClass.equals("")) {
1021:                        throw new ControllerException(
1022:                                "Controller needs ActionForm because it's state expects one.");
1023:                    }
1024:
1025:                    return (null);
1026:                } else {
1027:
1028:                    //If the state's form is blank then use the controller's form - if it's of ControllerForm type
1029:                    if (stateFormClass.equals("")) {
1030:                        /** changed instanceof ControllerForm for instanceof DefaultForm  *RD* Mon Jul 27 2004 */
1031:                        if (controllerForm instanceof  DefaultForm) {
1032:                            return (StateForm) controllerForm;
1033:                        } else {
1034:                            return (null); //backwards compatible reqt
1035:                        }
1036:                    } else {
1037:
1038:                        //Populate a new instance of the state's form from the controller's form.
1039:                        try {
1040:
1041:                            Class clazz = ClassLocator.loadClass(nextState
1042:                                    .getStateFormClass());
1043:                            stateForm = (StateForm) clazz.newInstance();
1044:
1045:                            try {
1046:                                BeanUtils.populate(stateForm, BeanUtils
1047:                                        .describe(controllerForm));
1048:                            } catch (Exception e) {
1049:                                throw new ControllerException(e);
1050:                            }
1051:                        } catch (Throwable t) {
1052:                            throw new ControllerException(t);
1053:                        }
1054:
1055:                        return (stateForm);
1056:                    }
1057:                }
1058:            }
1059:
1060:            /**
1061:             * This is the method where all of the real work of the controller
1062:             * is done. The client calls this to indicate what state the
1063:             * controller is transitioning into.
1064:             * <p/>
1065:             * This is normally what is called from the command line when driving a
1066:             * Controller object.  If running in a struts environment, this function call
1067:             * is wrapped by execute() method which does the actual running, plus then
1068:             * performs tasks such as finding the next forward etc.
1069:             * </p>
1070:             *
1071:             * @param newState  The new state to transition to
1072:             * @param myRequest The calling controllerRequest object.
1073:             * @return a newly instantiated ControllerResponse for this state.
1074:             * @throws ControllerException    on Error
1075:             * @throws NonHandleableException if the error should not be handled
1076:             *                                by an error controller
1077:             */
1078:            public ControllerResponse newState(String newState,
1079:                    ControllerRequest myRequest) throws ControllerException,
1080:                    NonHandleableException {
1081:                newState = StringUtil.notNull(newState);
1082:
1083:                if (log.isDebugEnabled()) {
1084:                    log.debug("Transitioning to state '" + newState
1085:                            + "' in controller '" + getClass().getName() + "'");
1086:                }
1087:                if (newState.length() == 0) {
1088:                    if (getInitialState() != null) {
1089:                        return newState(getInitialState(), myRequest);
1090:                    } else {
1091:                        throw new ControllerException(
1092:                                "You must specify a "
1093:                                        + "non-blank state. No default initial state is specified.");
1094:                    }
1095:                } /* if state blank */
1096:
1097:                //Used to ensure the state we are executing "newState" is in fact the one used to lookup
1098:                //the controller security matrix.  This should not be needed but is added for 'comfort'.
1099:                String entryState = newState;
1100:
1101:                /* Is this a valid state for this controller? */
1102:                State nextState = getState(newState);
1103:
1104:                if (nextState == null) {
1105:                    throw new ControllerException("State '" + newState
1106:                            + "' is unknown for Controller "
1107:                            + getClass().getName());
1108:                } /* if new state exists */
1109:
1110:                /* Is the user permitted to access this state? */
1111:                // todo what does newstate=="" mean?
1112:                if (!newState.equals("")) {
1113:                    if (controllerSecurityTransition == null
1114:                            && !stateAllowed(newState, myRequest)) {
1115:                        DelayThread.delay();
1116:                        throw new SecurityException("State '"
1117:                                + nextState.getDescription()
1118:                                + "' is not allowed for user '"
1119:                                + myRequest.getUser() + "' ("
1120:                                + myRequest.getUid() + ")" + " in controller '"
1121:                                + getTitle() + "' (" + getClass().getName()
1122:                                + ") in context '" + myRequest.getDataContext()
1123:                                + "'");
1124:                    } /* user not allowed */
1125:
1126:                } /* if state not empty */
1127:
1128:                setupReturnToSender(nextState, myRequest);
1129:
1130:                /** added to help struts validator to find the state to go back to
1131:                 * if an error is found in the form  *RD* Mon Jul 27 2004 */
1132:                PersistentSession mySession = myRequest.getSession();
1133:                mySession.removePersistentAttribute("previousState");
1134:                mySession.setPersistentAttribute("previousState", newState);
1135:                mySession.removePersistentAttribute("previousController");
1136:                mySession.setPersistentAttribute("previousController", this 
1137:                        .getClass().getName());
1138:
1139:                //We have reached the final state so rerun any handler states before continuing.
1140:                //If a handler state had to transition to some external state then it would likely set
1141:                //returnToSender=True.  So breaking out of the loop below and returning works great
1142:                //because external state will reinvoke this Final state when it is done successfully.
1143:                //If a handler state had to transition to some internal state then it would likely set
1144:                //returnToSender=False because it has returned the user into some earlier screen in the
1145:                //'wizard' to correct any errors.  The user would then continue forward through the all
1146:                //these wizard screens until the final screen which would reinvoke this Final state once again.
1147:                if (isFinalState(newState)) {
1148:                    //Get the xml version of the return to sender transition
1149:                    FastStringBuffer fsb = FastStringBuffer.getInstance();
1150:                    String returnToSender = null;
1151:                    try {
1152:                        Transition t = nextState.getReturnToSender();
1153:                        returnToSender = t.toXML(fsb).toString();
1154:                    } finally {
1155:                        fsb.release();
1156:                        fsb = null;
1157:                    }
1158:
1159:                    for (Iterator i = handleStates.iterator(); i.hasNext();) {
1160:                        State oneHandleState = (State) i.next();
1161:
1162:                        //Any return to sender transitions while in 'final mode' will return to the 'final' state.
1163:                        myRequest.setParameter(RETURN_TO_SENDER_TRAN,
1164:                                returnToSender);
1165:
1166:                        ControllerResponse statusResponse = newState(
1167:                                oneHandleState.getName(), myRequest);
1168:
1169:                        if (!statusResponse.getCurrentState().getName().equals(
1170:                                oneHandleState.getName())) {
1171:                            return statusResponse; //The handler didn't return cleanly so bail out.
1172:                        }
1173:                    } //End loop on all handler states
1174:
1175:                }
1176:
1177:                // Use the Servlet controller response to help pure Struts developers
1178:                // Peter Pilgrim Fri Nov 22 03:15:58 GMT 2002
1179:                ServletControllerResponse myResponse = new ServletControllerResponse();
1180:
1181:                if (myRequest == null) {
1182:                    throw new NonHandleableException(
1183:                            "Request cannot be null here");
1184:                }
1185:
1186:                myResponse.setRequest(myRequest);
1187:                myResponse.setTitle(getTitle());
1188:                myResponse.setCurrentState(nextState);
1189:                myResponse.setSchemaStack((java.util.Stack) this 
1190:                        .getSchemaStack().clone());
1191:                myResponse.setControllerClass(getClass().getName());
1192:
1193:                /* Do we have all of the required parameters for this state */
1194:                String oneParamName = null;
1195:                String oneParamValue = null;
1196:
1197:                for (Enumeration pe = nextState.getParameters().elements(); pe
1198:                        .hasMoreElements();) {
1199:                    oneParamName = (String) pe.nextElement();
1200:                    oneParamValue = StringUtil.notNull(
1201:                            myRequest.getParameter(oneParamName)).trim();
1202:
1203:                    if (oneParamValue.equals("")) {
1204:                        throw new ControllerException("Value for parameter '"
1205:                                + oneParamName + "' is required for state "
1206:                                + nextState.getDescription() + " ("
1207:                                + nextState.getName() + ")");
1208:                    } /* if parameter is empty */
1209:
1210:                } /* for each required parameter */
1211:
1212:                processRequestTransitions(nextState, myRequest);
1213:
1214:                /* Now execute the "run" method of the state */
1215:
1216:                //Setup the controller and state forms
1217:                ActionForm controllerForm = findControllerForm(myRequest);
1218:                StateForm stateForm = loadStateForm(nextState, controllerForm);
1219:                //        populateStateForm(stateForm, myRequest); //This will add other params (eg hidden fields)
1220:
1221:                ControllerResponse cr = null;
1222:
1223:                //Double-check that our newState was not accidentally changed since we started this method.
1224:                if (!newState.equals(entryState)) {
1225:                    throw new ControllerException(
1226:                            "newState was modified between method entry and security check!");
1227:                }
1228:
1229:                /* Is the user permitted to access this state? */
1230:                if (controllerSecurityTransition != null
1231:                        && !stateAllowed(newState, myRequest)) {
1232:                    //Make it thread-safe
1233:                    Transition securityTransition = null;
1234:
1235:                    try {
1236:                        securityTransition = (Transition) controllerSecurityTransition
1237:                                .clone();
1238:                    } catch (CloneNotSupportedException cne) {
1239:                        throw new ControllerException(
1240:                                "Cannot clone the securityTransition class");
1241:                    }
1242:
1243:                    //Could also add a 'security-related' message in the ErrorCollection and set the
1244:                    //nextState.setErrorTransition(securityTransition) to display on the other screen.
1245:                    nextState.setSuccessTransition(securityTransition);
1246:                    cr = myResponse;
1247:                } else { /* user allowed */
1248:                    //Now execute the "perform" method of the state
1249:                    prePerform(nextState, myRequest, myResponse);
1250:                    nextState.perform(stateForm, myRequest, myResponse);
1251:
1252:                    cr = nextState.getResponse();
1253:                }
1254:
1255:                //Move the state form back into the controller form
1256:                unloadStateForm(stateForm, controllerForm);
1257:
1258:                if (processTransitions(myRequest, cr, nextState) != null) {
1259:                    return cr;
1260:                }
1261:
1262:                addPromptTransitions(nextState, cr);
1263:
1264:                //Don't call the derived class if a derived State class has already
1265:                //been provided.
1266:                if (nextState.getClass().getName().equals(
1267:                        "com.jcorporate.expresso.core.controller.State")) {
1268:                    Class this Class = this .getClass();
1269:                    Class tryClass = this Class; //For walking up the object hierarchy
1270:
1271:                    try {
1272:
1273:                        boolean methodFound = false;
1274:                        Method m = null;
1275:
1276:                        //
1277:                        //New as of v4.1 - Attempts to walk up the class hierarchy
1278:                        //to find an applicable class to execute.  This should allow
1279:                        //better templating capabilities for deriving controllers from one another.
1280:                        //
1281:                        while (!methodFound) {
1282:                            try {
1283:                                m = tryClass.getDeclaredMethod(nextState
1284:                                        .getHandlerName(), stateHandlerParams);
1285:                                methodFound = true;
1286:                            } catch (NoSuchMethodException nsme) {
1287:                                if (myRequest instanceof  ServletControllerRequest) {
1288:                                    //As of 5.3: Now try a signature for ServletControllerRequest
1289:                                    //instead.
1290:                                    try {
1291:                                        m = tryClass.getDeclaredMethod(
1292:                                                nextState.getHandlerName(),
1293:                                                servletStateHandlerParams);
1294:                                        methodFound = true;
1295:                                    } catch (NoSuchMethodException ex) {
1296:                                        if (log.isDebugEnabled()) {
1297:                                            log
1298:                                                    .debug("Didn't find ServletControllerRequest method");
1299:                                        }
1300:                                    }
1301:                                }
1302:
1303:                                if (!methodFound) {
1304:                                    tryClass = tryClass.getSuperclass();
1305:
1306:                                    if (tryClass == null) {
1307:                                        throw nsme;
1308:                                    }
1309:                                }
1310:                            }
1311:                        }
1312:                        if (m == null) {
1313:                            throw new NonHandleableException(
1314:                                    "Null pointer when we should have a method object");
1315:                        }
1316:
1317:                        Object[] invokeParams = { myRequest, cr };
1318:                        m.setAccessible(true);
1319:
1320:                        ControllerResponse cr2 = (ControllerResponse) m.invoke(
1321:                                this , invokeParams);
1322:
1323:                        if (cr2 != null) {
1324:                            ErrorCollection eold = cr.getErrors();
1325:                            cr = cr2;
1326:                            cr.saveErrors(eold);
1327:                        }
1328:
1329:                        postPerform(nextState, myRequest, myResponse);
1330:                    } catch (SecurityException se) {
1331:                        log
1332:                                .error(
1333:                                        "Unable to reflect to method: "
1334:                                                + this .getClass().getName()
1335:                                                + "."
1336:                                                + nextState.getHandlerName()
1337:                                                + " setAccessible permissions need to be allowed from your security policy",
1338:                                        se);
1339:                        throw new NonHandleableException(se);
1340:                    } catch (IllegalAccessException illae) {
1341:                        log.error("Unable to reflect to method: "
1342:                                + this .getClass().getName() + "."
1343:                                + nextState.getHandlerName()
1344:                                + "illegal access Exception", illae);
1345:                        throw new NonHandleableException(illae);
1346:                    } catch (IllegalArgumentException iae) {
1347:                        log.error("Illegal Argument Exception", iae);
1348:                        throw new NonHandleableException(iae);
1349:                    } catch (InvocationTargetException ite) {
1350:                        Throwable e = ite.getTargetException();
1351:                        log.error("Error in substate", e);
1352:                        e.printStackTrace();
1353:
1354:                        if (e instanceof  NonHandleableException) {
1355:                            throw new NonHandleableException(e); //BUG BUG Ok to not create a new instance??
1356:                        } else if (e instanceof  SecurityException) {
1357:                            throw new SecurityException(e.getMessage());
1358:                        } else {
1359:                            throw new ControllerException(e);
1360:                        }
1361:                    } catch (NoSuchMethodException nsme) {
1362:                        try {
1363:
1364:                            // test to see if this method exists in thisClass
1365:                            this Class.getDeclaredMethod("newState",
1366:                                    newStateParams);
1367:
1368:                            // it does exist, since no exception thrown.  give feedback
1369:                            if (log.isDebugEnabled()) {
1370:                                log
1371:                                        .debug("Method '"
1372:                                                + nextState.getHandlerName()
1373:                                                + "' does not exist in controller class '"
1374:                                                + getClass().getName()
1375:                                                + "'. State must be handled by newState method.");
1376:                            }
1377:                        } catch (NoSuchMethodException nsme2) {
1378:
1379:                            // If the controller doesn't have a newState method, then
1380:                            // we have a problem....
1381:                            String errMsg = ("Method '"
1382:                                    + nextState.getHandlerName()
1383:                                    + "' does not exist in '"
1384:                                    + getClass().getName()
1385:                                    + "' and there is no 'newState' method to handle " + "transitions. Unable to transition");
1386:                            log.error(errMsg, nsme);
1387:                            throw new ControllerException(errMsg, nsme);
1388:                        }
1389:                    }
1390:                }
1391:
1392:                //This is the old error handling transition logic for backward compatability.
1393:                ErrorCollection finalErrors = cr.getErrors();
1394:                if (finalErrors != null) {
1395:                    if (finalErrors.getErrorCount() > 0) {
1396:                        String errorState = nextState.getErrorState();
1397:                        if (errorState != null) {
1398:                            cr.setFormCache(); //Is this really needed?
1399:                            transition(errorState, myRequest, cr);
1400:                            return cr;
1401:                        }
1402:                    }
1403:                }
1404:
1405:                return cr;
1406:            } /* newState(String) */
1407:
1408:            /**
1409:             * Template Method, allowing a subclass to do an action after
1410:             * any state in this controller is performed.
1411:             * For example, a common header for the web pages
1412:             * could be created here, so long as the web pages in question,
1413:             * with the common header, were all in the same controller which overrides
1414:             * this method.
1415:             *
1416:             * @param nextState the state to be performed
1417:             * @param request   the request object
1418:             * @param response  the response object
1419:             */
1420:            protected void prePerform(State nextState,
1421:                    ControllerRequest request, ControllerResponse response)
1422:                    throws ControllerException {
1423:            }
1424:
1425:            /**
1426:             * Template Method, allowing a subclass to into actions after the invocation of
1427:             * any state in this controller.
1428:             * For example, a common footer for web pages
1429:             * could be created here, so long as the web pages in question,
1430:             * with the common footer, were all in the same controller which overrides
1431:             * this method.  (Multiple controllers which need common pre/post actions
1432:             * could share a common superclass.)
1433:             *
1434:             * @param nextState the state to be performed
1435:             * @param request   the request object
1436:             * @param response  the response object
1437:             */
1438:            protected void postPerform(State nextState,
1439:                    ControllerRequest request, ControllerResponse response)
1440:                    throws ControllerException {
1441:            }
1442:
1443:            /**
1444:             * Return the name of the handle state that is associated with the
1445:             * passed in prompt state.  Null will be returned if the passed in
1446:             * state is not a prompt state.
1447:             *
1448:             * @param nextState the next state to check against
1449:             * @return the name of the 'handle' state paired with the nextState parameter
1450:             */
1451:            protected String nextHandleState(State nextState) {
1452:                String nextHandle = null;
1453:                int i = promptStates.indexOf(nextState);
1454:
1455:                if (i != -1) { //Valid prompt newState name passed in
1456:                    State handleState = (State) handleStates.get(i);
1457:                    nextHandle = handleState.getName();
1458:                }
1459:
1460:                return nextHandle;
1461:            }
1462:
1463:            /**
1464:             * Return the name of the prompt state that is 'next' to the passed
1465:             * in prompt state in the sequence for this controller.  If the
1466:             * passed in state is the last prompt state in this controller then
1467:             * null will be returned.
1468:             *
1469:             * @param nextState the next state to check against
1470:             * @return the name of the 'prompt' state paired with the nextState parameter
1471:             */
1472:            protected String nextPromptState(State nextState) {
1473:                String nextPrompt = null;
1474:                int i = promptStates.indexOf(nextState);
1475:                i++;
1476:
1477:                if ((i > 0) && (i < promptStates.size())) { //Next prompt(s) exist
1478:                    State promptState = (State) promptStates.get(i);
1479:                    nextPrompt = promptState.getName();
1480:                }
1481:
1482:                return nextPrompt;
1483:            }
1484:
1485:            /**
1486:             * Used for logging time of requests.
1487:             *
1488:             * @param beginTimer The start execution time
1489:             * @param request    The HTTPServletRequest to instrument
1490:             */
1491:            protected void endTimer(long beginTimer, HttpServletRequest request) {
1492:                if (log.isInfoEnabled()) {
1493:                    log.info("Request '" + getRequestURL(request)
1494:                            + "', total time "
1495:                            + (System.currentTimeMillis() - beginTimer)
1496:                            + " milliseconds");
1497:                }
1498:            }
1499:
1500:            /**
1501:             * Process the specified HTTP request, and create the corresponding HTTP
1502:             * response (or forward to another web component that will create it).
1503:             * Return an <code>ActionForward</code> instance describing where and how
1504:             * control should be forwarded, or <code>null</code> if the response has
1505:             * already been completed.  Note, that if you wish to run a controller within
1506:             * something other than a HTTP session, then call newState directly.
1507:             *
1508:             * @param mapping  The ActionMapping used to select this instance
1509:             * @param form     The optional ActionForm bean for this request (if any)
1510:             * @param request  The HTTP request we are processing
1511:             * @param response The HTTP response we are creating
1512:             * @return The ActionForward or null
1513:             * @throws IOException      if an input/output error occurs
1514:             * @throws ServletException if a servlet exception occurs
1515:             */
1516:            public ActionForward execute(ActionMapping mapping,
1517:                    ActionForm form, HttpServletRequest request,
1518:                    HttpServletResponse response) throws IOException,
1519:                    ServletException {
1520:                long beginTimer = System.currentTimeMillis();
1521:
1522:                /** to avoid nullPointerExceptions we initialize here the error collection  *RD* Mon Jul 27 2004 */
1523:                ErrorCollection actionErrors = new ErrorCollection();
1524:
1525:                // Call newState directly if we were called from a dispatch in Transition.
1526:                ControllerRequest queuedRequest = (ControllerRequest) request
1527:                        .getAttribute(ExpressoConstants.CONTROLLER_REQUEST_KEY);
1528:
1529:                // TODO: Please document what is the purpose of this QUEUED REQUEST code. *PP* Tue Jan 27 11:18:40 GMT 2004
1530:                if (queuedRequest != null) {
1531:                    request
1532:                            .removeAttribute(ExpressoConstants.CONTROLLER_REQUEST_KEY);
1533:                    String queuedState = StringUtil.notNull(request
1534:                            .getParameter(STATE_PARAM_KEY));
1535:
1536:                    // Only reset the controller form when the controller is
1537:                    // invoked!  If state is specified then the form is not
1538:                    // reset (even if the state specified is the controller's
1539:                    // initial state).
1540:                    if (queuedState.equals("")) {
1541:                        //Reset the ControllerForm and populate from request
1542:                        if (form instanceof  ControllerForm) {
1543:                            ((ControllerForm) form).resetController();
1544:                        }
1545:                    }
1546:
1547:                    // TODO: Why are we repopulating the bean? *PP* Tue Jan 27 11:19:15 GMT 2004
1548:                    /** I commented out the code and nothing seems broken. The form is already populated *RD* Mon Jul 27 2004 */
1549:                    /*try {
1550:                        BeanUtils.populate(form, queuedRequest.getParameters());
1551:                    } catch (Exception e) {
1552:                        throw new ServletException(e);
1553:                    }*/
1554:
1555:                    ControllerResponse queuedResponse = null;
1556:
1557:                    try {
1558:                        queuedRequest.setFormAttribute(mapping.getAttribute());
1559:                        /** test if this action must be automatically validated.
1560:                         * If it's the case validate the form.  *RD* Mon Jul 27 2004 */
1561:                        /** replaced
1562:                         * queuedResponse = newState(queuedState, queuedRequest);
1563:                         * with all this  *RD* Mon Jul 27 2004 */
1564:                        if (mapping.getValidate()) {
1565:                            actionErrors = (ErrorCollection) form.validate(
1566:                                    mapping, request);
1567:                        }
1568:                        /** test if there are no validation errors  *RD* Mon Jul 27 2004 */
1569:                        if (actionErrors.size() == 0) {
1570:                            /**no errors: forward to the handle state  *RD* Mon Jul 27 2004 */
1571:                            queuedResponse = newState(queuedState,
1572:                                    queuedRequest);
1573:                        } else {
1574:                            /** errors: forward control to the prompt state  *RD* Mon Jul 27 2004 */
1575:                            /** retrieve the previous controller and states parameters from the session  *RD* Mon Jul 27 2004 */
1576:                            String previousController = request.getSession()
1577:                                    .getAttribute("previousController")
1578:                                    .toString();
1579:                            String previousState = request.getSession()
1580:                                    .getAttribute("previousState").toString();
1581:                            /** test if the prompt state belongs to this same controller  *RD* Mon Jul 27 2004 */
1582:                            if (previousController.equals(this .getClass()
1583:                                    .getName())) {
1584:                                queuedResponse = newState(StringUtil
1585:                                        .notNull(previousState), queuedRequest);
1586:                                queuedResponse.saveErrors(actionErrors);
1587:                            } else {
1588:                                /** if not transition to the new controller  *RD* Mon Jul 27 2004 */
1589:                                transition(StringUtil.notNull(previousState),
1590:                                        Class.forName(StringUtil
1591:                                                .notNull(previousController)),
1592:                                        queuedRequest, new ControllerResponse());
1593:                            }
1594:
1595:                        }
1596:                    } catch (Exception e) {
1597:                        request.setAttribute(
1598:                                ExpressoConstants.NEWSTATE_EXCEPTION_KEY, e);
1599:                        //push back the exception
1600:                        return (null);
1601:                    }
1602:
1603:                    request.setAttribute(
1604:                            ExpressoConstants.CONTROLLER_REQUEST_KEY,
1605:                            queuedRequest);
1606:                    request.setAttribute(
1607:                            ExpressoConstants.CONTROLLER_RESPONSE_KEY,
1608:                            queuedResponse);
1609:
1610:                    return (null);
1611:                }
1612:
1613:                /* User for error handling */
1614:                String dbName = null;
1615:                String userName = null;
1616:                ServletControllerRequest req = null;
1617:
1618:                try {
1619:                    String requestDB = request.getParameter("db");
1620:                    // STRUTS 11
1621:                    log.debug("request.getParameter(\"db\") = `"
1622:                            + request.getParameter("db") + "'");
1623:                    CheckLogin.getInstance().checkLogin(request, requestDB);
1624:
1625:                    /* Get any, if they exist, parameters from the ActionForm bean */
1626:                    boolean multiPart = false;
1627:
1628:                    if (form != null) {
1629:                        // Call the Struts API to figure if we are dealing
1630:                        // with a multipart form bean, which are typical of
1631:                        // uploading file attachments.
1632:                        //
1633:                        // See Later: If the form is "session" scoped, we need
1634:                        // to reset this handler
1635:                        MultipartRequestHandler mp = form
1636:                                .getMultipartRequestHandler();
1637:
1638:                        if (mp != null) {
1639:                            // The form bean is multipart HTTP request so we
1640:                            // need to handle it as such. Certain parameters
1641:                            // in the `HttpServletRequest' may be multipart
1642:                            // file types.
1643:                            if (log.isDebugEnabled()) {
1644:                                log.debug("Multipart request");
1645:                            }
1646:
1647:                            multiPart = true;
1648:                            req = ServletControllerRequest
1649:                                    .parseParamsMultiPart(mp, mapping, form,
1650:                                            request, response, this );
1651:                            // STRUTS 1.1
1652:                            req.setCallingServlet(this .getServlet());
1653:                        }
1654:                    }
1655:                    if (!multiPart) {
1656:                        // The form bean is NOT multipart HTTP request so we
1657:                        // process as normal.
1658:                        if (log.isDebugEnabled()) {
1659:                            log.debug("Non-multipart request");
1660:                        }
1661:                        req = ServletControllerRequest.parseParams(mapping,
1662:                                form, request, response, this );
1663:                        // STRUTS 1.1
1664:                        req.setCallingServlet(this .getServlet());
1665:                    }
1666:
1667:                    // Check the session for an error collection.... if the error collection exists there,
1668:                    //
1669:                    // then we MOVE it to the request context This is used by
1670:                    // Controller when it needs to do a redirectRequest, but
1671:                    // cannot be kept in the session otherwise it will show up
1672:                    // as an error for every page which doesn't have an error
1673:                    // in the response.
1674:                    //
1675:                    // NOTE: Legacy Expresso Controllers, I think, stored error
1676:                    // collection in the session scope. *PP*
1677:                    ErrorCollection errors = (ErrorCollection) req.getSession()
1678:                            .getAttribute(Globals.ERROR_KEY);
1679:                    if (errors == null) {
1680:                        // retrieve errors from persistent attributes, if any
1681:                        errors = (ErrorCollection) req.getSession()
1682:                                .getPersistentAttribute(Globals.ERROR_KEY);
1683:                        // move to request
1684:                        if (errors != null) {
1685:                            req.getSession().removePersistentAttribute(
1686:                                    Globals.ERROR_KEY);
1687:                            req.getSession().setAttribute(Globals.ERROR_KEY,
1688:                                    errors);
1689:                        }
1690:                    }
1691:
1692:                    /*
1693:                     * If we were called as part of a transition request to
1694:                     * another controller, the parameters will contain a
1695:                     * 'controller' parameter with a value that indicates a
1696:                     * controller other than this one.  If this happens, then
1697:                     * we do a lookup to find the ActionMapping for that
1698:                     * controller/state (or just the controller if there's no
1699:                     * mapping directly to the specified state) and forward to
1700:                     * that mapping
1701:                     */
1702:                    String controllerRequested = StringUtil.notNull(req
1703:                            .getParameter(ExpressoConstants.CONTROLLER_KEY));
1704:
1705:                    // Find out if there is a request state from the
1706:                    // abstracted "ControllerRequest" parameters. Note this
1707:                    // different from the "HttpServletRequest"
1708:                    // parameters. By the time we get here. A "state" set by a
1709:                    // button (Transition) will have been picked up and
1710:                    // set. Likewise a "state" parameter from the
1711:                    // "HttpServletRequest", if any.  So we are checking for
1712:                    // missing controller state definition here.
1713:                    String requestedState = StringUtil.notNull(req
1714:                            .getParameter(STATE_PARAM_KEY));
1715:
1716:                    log.debug("requestedState = `" + requestedState + "'");
1717:                    if (!controllerRequested.equals("")) {
1718:                        if (!controllerRequested.equals(getClass().getName())) {
1719:
1720:                            // If we get here, then we have been asked to
1721:                            // transition to a state in a different
1722:                            // controller.
1723:                            ActionConfig mm = ConfigManager.getActionConfig("",
1724:                                    controllerRequested, requestedState);
1725:                            if (mm == null) {
1726:                                throw new ServletException(
1727:                                        "The controller requested: "
1728:                                                + controllerRequested
1729:                                                        .toString()
1730:                                                + " and/or state within that controller: "
1731:                                                + requestedState.toString()
1732:                                                + " are not available in configuration mapping; if you expected this to be "
1733:                                                + "available, double-check the /config/*-config.xml files.");
1734:                            }
1735:
1736:                            // Build up dispatch URL from all the required
1737:                            // parameters for the external controller and its
1738:                            // target state method
1739:                            FastStringBuffer newURL = FastStringBuffer
1740:                                    .getInstance();
1741:                            String urlString = null;
1742:                            try {
1743:                                newURL.append(mm.getPath());
1744:                                newURL.append(".do");
1745:                                newURL.append("?state=");
1746:                                newURL.append(requestedState);
1747:
1748:                                String oneParamName = null;
1749:                                String oneParamValue = null;
1750:
1751:                                // TODO: Is this a bug or not core developers? *PP*
1752:                                // BUG BUG - Should parameter names and values be URLEncoded?
1753:                                for (Enumeration ep = req.getParameters()
1754:                                        .keys(); ep.hasMoreElements();) {
1755:                                    oneParamName = (String) ep.nextElement();
1756:                                    oneParamValue = req
1757:                                            .getParameter(oneParamName);
1758:                                    newURL.append("&");
1759:                                    newURL.append(oneParamName);
1760:                                    newURL.append("=");
1761:                                    newURL.append(oneParamValue);
1762:                                }
1763:
1764:                                if (log.isDebugEnabled()) {
1765:                                    log.debug("Request to controller '"
1766:                                            + getClass().getName()
1767:                                            + "' was for a transition "
1768:                                            + "to class '"
1769:                                            + controllerRequested
1770:                                            + "', so forwarding to URL '"
1771:                                            + newURL.toString() + "'");
1772:                                }
1773:                                if (log.isInfoEnabled()) {
1774:                                    endTimer(beginTimer, request);
1775:                                }
1776:
1777:                            } finally {
1778:                                urlString = newURL.toString();
1779:                                newURL.release();
1780:                                newURL = null;
1781:                            }
1782:
1783:                            // Request dispatch forward to the target controller and state method
1784:                            GenericDispatcher.forward(request, response,
1785:                                    urlString);
1786:                            request
1787:                                    .removeAttribute(ExpressoConstants.USED_ROUTING_KEY);
1788:                            return null;
1789:                        }
1790:                    }
1791:
1792:                    // Add flag 'usedRouting' to request attribute to indicate
1793:                    // routing params have been consumed already.  This will
1794:                    // prevent any other controllers that this controller may
1795:                    // dispatch to from reusing these parameters (ie the
1796:                    // controller and state parameters).
1797:                    request.setAttribute(ExpressoConstants.USED_ROUTING_KEY,
1798:                            "inuse");
1799:
1800:                    //
1801:                    // If we are configured to use SSL, then we must possibly
1802:                    // issue a redirect to get to the right place.
1803:                    //
1804:                    if (ConfigManager.getContext(req.getDataContext())
1805:                            .isUseSSL()) {
1806:
1807:                        if (log.isDebugEnabled()) {
1808:                            log
1809:                                    .debug("Checking if we need to redirect to different protocol");
1810:                        }
1811:                        Hashtable myStateList = (Hashtable) states
1812:                                .get(getClass().getName());
1813:                        String stateName = req.getParameter(STATE_PARAM_KEY);
1814:                        if (stateName == null || stateName.length() == 0) {
1815:                            stateName = this .getInitialState();
1816:                        }
1817:
1818:                        if (this 
1819:                                .checkSsl(request, response,
1820:                                        ((State) myStateList.get(stateName))
1821:                                                .isSecure())) {
1822:                            return null;
1823:                        }
1824:
1825:                        if (log.isDebugEnabled()) {
1826:                            log.debug("No more redirection necessary");
1827:                        }
1828:                    }
1829:
1830:                    if (log.isDebugEnabled()) {
1831:                        log.debug("Controller '"
1832:                                + getClass().getName()
1833:                                + "' to state '"
1834:                                + StringUtil.notNull(req
1835:                                        .getParameter(STATE_PARAM_KEY)) + "'");
1836:                    }
1837:
1838:                    req.setFormAttribute(mapping.getAttribute());
1839:
1840:                    // Only reset the controller form when the controller is
1841:                    // invoked!  If state is specified then the form is not
1842:                    // reset (even if the state specified is the controller's
1843:                    // initial state).  This avoids an unwanted reset when
1844:                    // user clicks on 'previous' in the 2nd screen of a
1845:                    // wizard.
1846:                    if (requestedState.equals("")) {
1847:                        //Reset the ControllerForm and populate from request
1848:                        if (form instanceof  ControllerForm) {
1849:                            ((ControllerForm) form).resetController();
1850:                        }
1851:                    }
1852:
1853:                    // TODO: Why are we setting the form bean again here? What are doing here in this code? *PP* Tue Jan 27 11:35:22 GMT 2004
1854:                    /* BUG BUG
1855:                            the test if form instanceof DefaultForm should be done before
1856:                            BeanUtils.populate() otherwise the DefaultForm never gets populated
1857:                            This also fixes Input.setDefaultValue(ControllerResponse) which wasn't working
1858:                     *RD* Mon Jul 27 2004
1859:
1860:                    try {
1861:                        BeanUtils.populate(form, req.getParameters());
1862:                    } catch (Exception e) {
1863:                        if (form instanceof DefaultForm) {
1864:                            try {
1865:                                ((DefaultForm) form).setUsingHashtableParameters(req.getParameters());
1866:                            } catch (Exception ex) {
1867:                                ex.printStackTrace();
1868:                                throw new ServletException(ex);
1869:                            }
1870:                        } else {
1871:                            log.error("Error populating form", e);
1872:                            throw new ServletException(e);
1873:                        }
1874:                                 }*/
1875:                    /** corrected this  *RD* Mon Jul 27 2004 */
1876:                    /** we populate the DefaultForm with the contents of the HTML form  *RD* Mon Jul 27 2004 */
1877:                    if (form instanceof  DefaultForm) {
1878:                        try {
1879:                            ((DefaultForm) form)
1880:                                    .setUsingHashtableParameters(req
1881:                                            .getParameters());
1882:                        } catch (Exception ex) {
1883:                            ex.printStackTrace();
1884:                            throw new ServletException(ex);
1885:                        }
1886:                    }
1887:                    /** I commented out the code and nothing seems broken. The form is already populated *RD* Mon Jul 27 2004 */
1888:                    /*else {
1889:                             try {
1890:                               BeanUtils.populate(form, req.getParameters());
1891:                             }
1892:                             catch (Exception e) {
1893:                               log.error("Error populating form", e);
1894:                               throw new ServletException(e);
1895:                             }
1896:                    }*/
1897:
1898:                    // Remove the last controller response from the request
1899:                    // scope in preparation for invoking the new state method.
1900:                    request
1901:                            .removeAttribute(ExpressoConstants.CONTROLLER_RESPONSE_KEY);
1902:                    dbName = req.getDataContext();
1903:                    userName = req.getUser();
1904:                    if (log.isDebugEnabled()) {
1905:                        log.debug("Before newstate in '" + getClass().getName()
1906:                                + "'");
1907:                    }
1908:
1909:                    // ============================================================
1910:                    // ============================================================
1911:                    // Call the target controller's new "state method" as required
1912:                    // ============================================================
1913:                    // ============================================================
1914:                    ControllerResponse res = null;
1915:                    try {
1916:                        /** test if this action must be automatically validated.
1917:                         * If it's the case validate the form.  *RD* Mon Jul 27 2004
1918:                         * replaced
1919:                         * res = newState(StringUtil.notNull(previousState), req);
1920:                         * with all this  *RD* Mon Jul 27 2004 */
1921:
1922:                        if (mapping.getValidate()) {
1923:                            actionErrors = (ErrorCollection) form.validate(
1924:                                    mapping, request);
1925:                        }
1926:                        /** test if there are no validation errors  *RD* Mon Jul 27 2004 */
1927:                        if (actionErrors.size() == 0) {
1928:                            /** no errors: forward to the handle state  *RD* Mon Jul 27 2004 */
1929:                            res = newState(StringUtil.notNull(requestedState),
1930:                                    req);
1931:                        } else {
1932:                            /** errors: forward control to the prompt state  *RD* Mon Jul 27 2004 */
1933:                            /** etrieve the previous controller and states parameters from the session  *RD* Mon Jul 27 2004 */
1934:                            String previousController = request.getSession()
1935:                                    .getAttribute("previousController")
1936:                                    .toString();
1937:                            String previousState = request.getSession()
1938:                                    .getAttribute("previousState").toString();
1939:                            /** test if the prompt state belongs to this same controller  *RD* Mon Jul 27 2004 */
1940:                            if (previousController.equals(this .getClass()
1941:                                    .getName())) {
1942:                                res = newState(StringUtil
1943:                                        .notNull(previousState), req);
1944:                                res.saveErrors(actionErrors);
1945:                            } else {
1946:                                /** if not transition to the new controller  *RD* Mon Jul 27 2004 */
1947:                                transition(StringUtil.notNull(previousState),
1948:                                        Class.forName(StringUtil
1949:                                                .notNull(previousController)),
1950:                                        req, new ControllerResponse());
1951:                            }
1952:                        }
1953:
1954:                    } finally {
1955:                        if (form != null
1956:                                && "session".equals(mapping.getScope())) {
1957:                            // Here is a fix for multipart action form beans that
1958:                            // are "session" scoped.  We need to reset the
1959:                            // multipart request handler for these beans in order
1960:                            // to prevent infinite looping in the Controller's
1961:                            // transition mechanism.
1962:                            form
1963:                                    .setMultipartRequestHandler(/*MultipartRequestHandler*/null);
1964:                        }
1965:                    }
1966:
1967:                    if (log.isDebugEnabled()) {
1968:                        log.debug("After newstate in '" + getClass().getName()
1969:                                + "' controller is '"
1970:                                + res.getControllerClass() + "'");
1971:                    }
1972:
1973:                    // Store the controller response now
1974:                    res.setRequestPath(mapping.getPath());
1975:                    request.setAttribute(
1976:                            ExpressoConstants.CONTROLLER_RESPONSE_KEY, res);
1977:
1978:                    // Has the controller state method declared a custom
1979:                    // response? For example if the controller is sending down
1980:                    // a binary stream of a multimedia file stream its own
1981:                    // accord.
1982:                    if (res.isCustomResponse()) {
1983:                        // Custom response it is, then. End the timing and
1984:                        // return `null' to also flag this condition to the
1985:                        // Struts MVC framework
1986:                        if (log.isInfoEnabled()) {
1987:                            endTimer(beginTimer, request);
1988:                        }
1989:                        request
1990:                                .removeAttribute(ExpressoConstants.USED_ROUTING_KEY);
1991:                        return null;
1992:                    }
1993:
1994:                    ActionConfig finalConfig = mapping;
1995:
1996:                    // Now get the mapping again if needed, this time for the controller
1997:                    // specified by the ControllerResponse.getControllerClass(), which
1998:                    // may or may not be the controller we started out with ...
1999:                    if (!res.getControllerClass().equals(mapping.getType())) {
2000:                        if (log.isDebugEnabled()) {
2001:                            log
2002:                                    .debug("Controller '"
2003:                                            + getClass().getName()
2004:                                            + "' transitioned internally to controller '"
2005:                                            + res.getControllerClass()
2006:                                            + "', state '"
2007:                                            + res.getCurrentState()
2008:                                            + "'. Getting alternate mapping...");
2009:                        }
2010:
2011:                        // mapping = ConfigManager.getMapping(res.getControllerClass(),
2012:                        //                    res.getCurrentState().getName());
2013:
2014:                        ActionConfig config = ConfigManager.getActionConfig("",
2015:                                res.getControllerClass(), res.getCurrentState()
2016:                                        .getName());
2017:
2018:                        if (config == null) {
2019:                            throw new ControllerException(
2020:                                    "Unable to find ActionConfig for: "
2021:                                            + res.getControllerClass() + ":"
2022:                                            + res.getCurrentState().getName());
2023:                        }
2024:                        finalConfig = config;
2025:
2026:                        if (log.isDebugEnabled()) {
2027:                            log.debug("Got mapping for '"
2028:                                    + finalConfig.getPath() + "'");
2029:                        }
2030:                    } else {
2031:                        if (log.isDebugEnabled()) {
2032:                            log.debug("Controller '" + getClass().getName()
2033:                                    + "' using type '" + finalConfig.getType()
2034:                                    + "', transitioning to state '"
2035:                                    + res.getCurrentState()
2036:                                    + "' within the same controller.");
2037:                        }
2038:                    }
2039:
2040:                    // Retrieve the final action forward derived from the
2041:                    // controller state method
2042:                    ActionForward fwd = getActionForward(req, finalConfig, res);
2043:
2044:                    if (log.isInfoEnabled()) {
2045:                        endTimer(beginTimer, request);
2046:                    }
2047:
2048:                    // Remove the used routing key if it was set to avoid looping.
2049:                    request.removeAttribute(ExpressoConstants.USED_ROUTING_KEY);
2050:                    // Return the action forward as normal for Struts Action controller
2051:                    return fwd;
2052:                } catch (NonHandleableException ne) {
2053:                    throw new ServletException(ne);
2054:                    /**
2055:                     * special case: when there is no login, redirect to login screen
2056:                     */
2057:                } catch (SecurityException securExcep) {
2058:                    // Has this current user logged in?
2059:                    if (userName.equals(User.UNKNOWN_USER)) {
2060:                        // If not redirect user to login screen using the
2061:                        // global action forward
2062:                        ActionForward loginForward = mapping
2063:                                .findForward(ExpressoConstants.APPLICATION_LOGON_FORWARD);
2064:                        if (loginForward == null) {
2065:                            // do try/catch to capture stack trace
2066:                            try {
2067:                                throw new Exception(
2068:                                        "cannot find forward for 'logon'; one should be in <application>-config.xml");
2069:                            } catch (Exception e) {
2070:                                e.printStackTrace(System.err);
2071:                                handleException(request, req, dbName, userName,
2072:                                        e);
2073:                                return (mapping
2074:                                        .findForward(ExpressoConstants.ERROR_FORWARD));
2075:                            }
2076:                        }
2077:
2078:                        try {
2079:                            addRequestedURLtoSession(request, req);
2080:                        } catch (Exception e) {
2081:                            // do not abort here; we just had problem adding an
2082:                            // item to session; we will live without it.
2083:                            log
2084:                                    .error(
2085:                                            "unexpected problem adding item to session: ",
2086:                                            e);
2087:                        }
2088:
2089:                        // Do not return an action forward since the URL will
2090:                        // say the wrong thing.  Instead, do a redirect so
2091:                        // that browser will show the correct login URL
2092:                        redirectRequest(response, ConfigManager
2093:                                .getContextPath()
2094:                                + loginForward.getPath());
2095:                        return null;
2096:                    } else {
2097:                        // If we get here, then we have a recognised user with
2098:                        // a genuine login account.
2099:
2100:                        // See if there is a regDomain out there assigned to
2101:                        try {
2102:                            ControllerSecurity cs = new ControllerSecurity();
2103:                            RegistrationDomain rd = new RegistrationDomain();
2104:                            ControllerSecurity oneSecurityEntry = null;
2105:                            String groupName = null;
2106:                            cs.setDataContext(dbName);
2107:
2108:                            // Search for the Controller which extended from
2109:                            // this class (the calling controller)
2110:                            cs
2111:                                    .setField("ControllerClass", getClass()
2112:                                            .getName());
2113:                            for (Iterator cse = cs.searchAndRetrieveList()
2114:                                    .iterator(); cse.hasNext();) {
2115:                                cs.clear();
2116:                                oneSecurityEntry = (ControllerSecurity) cse
2117:                                        .next();
2118:                                groupName = oneSecurityEntry
2119:                                        .getField("GroupName");
2120:                                // Now see if there is a registration domain for that group
2121:                                rd.clear();
2122:                                rd.setField("GroupName", groupName);
2123:                                if (rd.find()) {
2124:                                    // Find the action forward on the registration mapping
2125:                                    ActionForward registrationForward = mapping
2126:                                            .findForward(ExpressoConstants.REGISTER_FORWARD);
2127:
2128:                                    if (registrationForward == null) {
2129:                                        // do try/catch to capture stack trace
2130:                                        try {
2131:                                            throw new Exception(
2132:                                                    "cannot find forward for '"
2133:                                                            + ExpressoConstants.REGISTER_FORWARD
2134:                                                            + "'; One should be defined in <application>-config.xml");
2135:                                        } catch (Exception e) {
2136:                                            e.printStackTrace(System.err);
2137:                                            handleException(request, req,
2138:                                                    dbName, userName, e);
2139:
2140:                                            return (mapping
2141:                                                    .findForward(ExpressoConstants.ERROR_FORWARD));
2142:                                        }
2143:                                    }
2144:
2145:                                    try {
2146:                                        addRegDomainParamtoSession(request,
2147:                                                req, rd.getField("Name"));
2148:
2149:                                    } catch (Exception e) {
2150:                                        // do not abort here; we just had problem adding an
2151:                                        // item to session; we will live without it.
2152:                                        log
2153:                                                .error(
2154:                                                        "unexpected problem adding item to session: ",
2155:                                                        e);
2156:                                    }
2157:
2158:                                    // Do not return an action forward since the URL will say the wrong
2159:                                    // thing. Instead, do a redirect so that browser will
2160:                                    // show the login URL
2161:                                    try {
2162:                                        ErrorCollection ec = req
2163:                                                .getErrorCollection();
2164:                                        if (ec == null) {
2165:                                            ec = new ErrorCollection();
2166:                                        }
2167:                                        ec.addError(securExcep.getMessage());
2168:                                        req.getSession()
2169:                                                .setPersistentAttribute(
2170:                                                        Globals.ERROR_KEY, ec);
2171:                                    } catch (ControllerException ex) {
2172:                                        log
2173:                                                .error(
2174:                                                        "Unable to save error for a permission denied message",
2175:                                                        ex);
2176:                                    }
2177:                                    redirectRequest(response, ConfigManager
2178:                                            .getContextPath()
2179:                                            + registrationForward.getPath());
2180:                                    return null;
2181:
2182:                                } else {
2183:                                    log.warn("Registration Domain for "
2184:                                            + groupName + " and class "
2185:                                            + getClass().getName()
2186:                                            + " not found");
2187:                                }
2188:                            }
2189:                        } catch (DBException dbe) {
2190:                            handleException(request, req, dbName, userName, dbe);
2191:                        }
2192:
2193:                        // standard handling--user has logged in, but tried to
2194:                        // do something not allowed.
2195:                        System.err.println(securExcep.getMessage());
2196:                        handleException(request, req, dbName, userName,
2197:                                securExcep);
2198:
2199:                        return (mapping
2200:                                .findForward(ExpressoConstants.ERROR_FORWARD));
2201:                    }
2202:                } catch (NullPointerException npe) {
2203:                    npe.printStackTrace(System.err);
2204:                    log.error("Null Pointer Exception", npe);
2205:                    handleException(request, req, dbName, userName, npe);
2206:                    return (mapping.findForward("error"));
2207:                } catch (Exception ee) {
2208:                    ee.printStackTrace(System.err);
2209:                    handleException(request, req, dbName, userName, ee);
2210:                    return (mapping.findForward("error"));
2211:                }
2212:            }
2213:
2214:            /**
2215:             * Determine the forward appropriate for this controller/state,
2216:             * either from parameters or from configuration files, or from
2217:             * remapping based on past extensions like .xsl
2218:             *
2219:             * @param req     the ServletControllerRequest object
2220:             * @param mapping the ActionConfig that defines the mapping
2221:             * @param res     the ControllerResponse object that has been handed back to
2222:             *                us by Controller.newState()
2223:             * @return an ActionForward instance.
2224:             * @throws NonHandleableException upon fatal error
2225:             * @throws ControllerException    upon error
2226:             */
2227:            protected ActionForward getActionForward(
2228:                    ServletControllerRequest req, ActionConfig mapping,
2229:                    ControllerResponse res) throws NonHandleableException,
2230:                    ControllerException {
2231:
2232:                ForwardConfig fwd = null;
2233:
2234:                /* If we were overridden and told to go to a specific style */
2235:                if (!StringUtil.notNull(req.getParameter("style")).equals("")) {
2236:                    String style = req.getParameter("style");
2237:                    fwd = mapping.findForwardConfig(style);
2238:
2239:                    if (fwd == null) {
2240:                        fwd = mapping.getModuleConfig()
2241:                                .findForwardConfig(style);
2242:                        if (fwd == null) {
2243:                            throw new NonHandleableException("Style '"
2244:                                    + req.getParameter("style")
2245:                                    + "' was not found for controller '"
2246:                                    + res.getControllerClass() + "'");
2247:                        }
2248:                    }
2249:                } else if (res instanceof  ServletControllerResponse) {
2250:                    /* If the response is actually an servlet controller response
2251:                     * see if there was an action forward defined.
2252:                     */
2253:                    ServletControllerResponse resServ = (ServletControllerResponse) res;
2254:                    if (resServ.getActionForward() != null) {
2255:                        fwd = resServ.getActionForward();
2256:                    }
2257:                }
2258:
2259:                /* If this controller returned a specific "style", then try to find the
2260:                 * ActionForward for this style.
2261:                 */
2262:                if ((fwd == null) && (res.getStyle() != null)) {
2263:                    fwd = mapping.findForwardConfig(res.getStyle());
2264:                    if (fwd == null) {
2265:                        fwd = mapping.getModuleConfig().findForwardConfig(
2266:                                res.getStyle());
2267:                    }
2268:                }
2269:
2270:                /* If we didn't specify a style, or the style was not found, then
2271:                 * use the name of the current state to determine the forward to use
2272:                 */
2273:                if (fwd == null) {
2274:                    fwd = ConfigManager.findForwardConfig(mapping, res
2275:                            .getCurrentState().getName());
2276:
2277:                    //Config Manager has it's own implementation because it seems that
2278:                    //mapping.findForwardConfig does NOT return the same results as
2279:                    //iterating through the forward array and returning the match :(
2280:                    //            fwd = mapping.findForwardConfig(res.getCurrentState().getName());
2281:                }
2282:                /* If nothing yet (e.g. no error and no forward), then use default
2283:                 */
2284:                if (fwd == null) {
2285:                    if (log.isDebugEnabled()) {
2286:                        log.debug("No forward for '"
2287:                                + res.getCurrentState().getName()
2288:                                + "' in controller '"
2289:                                + res.getControllerClass()
2290:                                + "' using mapping for '" + mapping.getPath()
2291:                                + "', which is for class '" + mapping.getType()
2292:                                + "'. Using default view.");
2293:                    }
2294:
2295:                    fwd = mapping.getModuleConfig()
2296:                            .findForwardConfig("default");
2297:                }
2298:
2299:                fwd = remapFromExtension(fwd, mapping, req);
2300:
2301:                if (log.isDebugEnabled()) {
2302:                    if (fwd == null) {
2303:                        log.debug("Controller returning a null fwd object");
2304:                    } else {
2305:                        log.debug("Controller '" + res.getControllerClass()
2306:                                + "', state '"
2307:                                + res.getCurrentState().getName()
2308:                                + "' forwarding to view '" + fwd.getPath()
2309:                                + "'");
2310:                    }
2311:                }
2312:
2313:                ActionForward forward = new ActionForward(fwd.getPath(), fwd
2314:                        .getPath(), fwd.getRedirect(), fwd.getContextRelative());
2315:
2316:                return forward;
2317:            }
2318:
2319:            /**
2320:             * if the extension in the current forward is ".xsl" or ".xslt",
2321:             * remap the forward to "xml", and set a parameter for the xsl style sheet.
2322:             * author: Larry Hamel, CodeGuild, Inc.
2323:             *
2324:             * @param fwd     The ForwardConfig object
2325:             * @param mapping the ActionConfig for the particular controller instance
2326:             * @param req     the ServletControllerRequest for the request.
2327:             * @return ForwardConfig instance.
2328:             * @throws ControllerException upon error
2329:             */
2330:            protected ForwardConfig remapFromExtension(ForwardConfig fwd,
2331:                    ActionConfig mapping, ServletControllerRequest req)
2332:                    throws ControllerException {
2333:
2334:                if (fwd != null) {
2335:                    String path = fwd.getPath();
2336:                    if (path != null) {
2337:                        int lastDot = path.lastIndexOf('.');
2338:                        if (lastDot != -1) {
2339:                            String ext = path.substring(lastDot);
2340:                            if (ext.equalsIgnoreCase(".xsl")
2341:                                    || ext.equalsIgnoreCase(".xslt")) {
2342:                                fwd = mapping.getModuleConfig()
2343:                                        .findForwardConfig("xml");
2344:                                if (fwd == null) {
2345:                                    log
2346:                                            .warn("cannot find action forward 'xml' which must be defined when using XSL forwards");
2347:                                }
2348:                                req.setParameter("xsl", path);
2349:                            }
2350:                        }
2351:                    }
2352:                }
2353:                return fwd;
2354:            }
2355:
2356:            /**
2357:             * redirect response so that URL changes in client browser
2358:             *
2359:             * @param response    The Servlet Response
2360:             * @param redirectURL The URL to redirect the browser to.
2361:             * @throws IOException upon browser error.
2362:             */
2363:            protected void redirectRequest(HttpServletResponse response,
2364:                    String redirectURL) throws IOException {
2365:
2366:                try {
2367:                    if (log.isDebugEnabled()) {
2368:                        log.debug("redirecting to: " + redirectURL);
2369:                    }
2370:
2371:                    response.sendRedirect(redirectURL);
2372:                } catch (java.lang.IllegalStateException e) {
2373:                    log.error("Error performing redirect.", e);
2374:                }
2375:
2376:                // don't flush so that subclasses can make use of this too;
2377:                // sendRedirect() just sets headers to 301
2378:            }
2379:
2380:            /**
2381:             * Populate the state form with any matching request parameters.
2382:             *
2383:             * @param stateForm The name of the state form to populate
2384:             * @param request   The source of the variables for the state form.
2385:             * @throws ControllerException upon <code>BeanUtils.populate()</code> error
2386:             */
2387:            protected void populateStateForm(StateForm stateForm,
2388:                    ControllerRequest request) throws ControllerException {
2389:                try {
2390:                    BeanUtils.populate(stateForm, request.getParameters());
2391:                } catch (Exception e) {
2392:                    throw new ControllerException(e);
2393:                }
2394:            }
2395:
2396:            /**
2397:             * Return the name of the prompt state that is 'previous' to the passed
2398:             * in prompt state in the sequence for this controller.  If the
2399:             * passed in state is the first prompt state in this controller then
2400:             * null will be returned.
2401:             *
2402:             * @param nextState The state to check against
2403:             * @return the previous prompt state
2404:             */
2405:            protected String previousPromptState(State nextState) {
2406:                String previousPrompt = null;
2407:                int i = promptStates.indexOf(nextState);
2408:
2409:                if (i > 0) { //Previous prompt(s) exist
2410:                    State previousState = (State) promptStates.get(i - 1);
2411:                    previousPrompt = previousState.getName();
2412:                }
2413:
2414:                return previousPrompt;
2415:            }
2416:
2417:            /**
2418:             * <p/>
2419:             * This method picks up the following routing parameters from the current request
2420:             * and builds transition objects from them before the state is invoked.
2421:             * </p>
2422:             * <p/>
2423:             * 1. "Controller Success"
2424:             * These parameters identify the state that should be run once this
2425:             * controller completes successfully (ie the'final' state has completed without errors).
2426:             * Any controller success parameters will cause this method to put a
2427:             * serialized transition object specific to this controller in session scope.
2428:             * </p>
2429:             * <p/>
2430:             * <p/>
2431:             * 2. "State Success"
2432:             * These parameters identify the state that should be run if this state
2433:             * completes without errors.
2434:             * Any state success parameters will cause this method to assign a
2435:             * transition object to this currently running state.
2436:             * </p>
2437:             * <p/>
2438:             * <p/>
2439:             * 3. "State Error"
2440:             * These parameters identify the state that should be run if this state
2441:             * completes with errors.
2442:             * Any state error parameters will cause this method to assign a
2443:             * transition object to this currently running state.
2444:             * </p>
2445:             * <p/>
2446:             * <b>Note</b>, the transition specified at this time can be overridden by
2447:             * the state when it executes.
2448:             *
2449:             * @param nextState the next state to check process
2450:             * @param request   The controllerRequest object
2451:             * @throws ControllerException upon error.
2452:             */
2453:            protected void processRequestTransitions(State nextState,
2454:                    ControllerRequest request) throws ControllerException {
2455:                PersistentSession session = request.getSession();
2456:                String sessionKey = CTL_SUCC_TRAN + getClass().getName();
2457:
2458:                //process any CONTROLLER SUCCESS routing
2459:                String controllerSuccessReturn = request
2460:                        .getParameter(CTL_SUCC_TRAN);
2461:
2462:                if (controllerSuccessReturn != null) {
2463:                    request.removeParameter(CTL_SUCC_TRAN);
2464:                    session.setPersistentAttribute(sessionKey,
2465:                            controllerSuccessReturn);
2466:                } else {
2467:                    String controllerSuccessReturnController = request
2468:                            .getParameter(CTL_SUCC_CTL);
2469:
2470:                    if (controllerSuccessReturnController != null) {
2471:                        String controllerSuccessReturnState = request
2472:                                .getParameter(CTL_SUCC_STATE);
2473:                        Transition t = new Transition();
2474:                        t.setState(controllerSuccessReturnState);
2475:                        t
2476:                                .setControllerObject(controllerSuccessReturnController);
2477:                        FastStringBuffer fsb = FastStringBuffer.getInstance();
2478:                        try {
2479:                            controllerSuccessReturn = t.toXML(fsb).toString();
2480:                        } finally {
2481:                            fsb.release();
2482:                            fsb = null;
2483:                        }
2484:                        session.setPersistentAttribute(sessionKey,
2485:                                controllerSuccessReturn);
2486:                        request.removeParameter(CTL_SUCC_CTL);
2487:                        request.removeParameter(CTL_SUCC_STATE);
2488:                    }
2489:                }
2490:
2491:                //process any STATE SUCCESS routing
2492:                Transition successTransition = null;
2493:                String successTran = request.getParameter(STATE_SUCC_TRAN);
2494:
2495:                if (successTran != null) {
2496:                    request.removeParameter(STATE_SUCC_TRAN);
2497:
2498:                    try {
2499:                        successTransition = Transition.fromXML(successTran);
2500:                    } catch (Exception e) {
2501:                        throw new ControllerException(e);
2502:                    }
2503:                }
2504:
2505:                String stateSuccessReturnController = request
2506:                        .getParameter(STATE_SUCC_CTL);
2507:
2508:                if (stateSuccessReturnController != null) {
2509:                    if (successTransition != null) {
2510:                        throw new ControllerException(
2511:                                "State cannot handle stateSuccessReturn Transition object "
2512:                                        + "AND stateSuccessXXX parameters in the same call.");
2513:                    }
2514:
2515:                    String stateSuccessReturnState = request
2516:                            .getParameter(STATE_SUCC_STATE);
2517:                    successTransition = new Transition();
2518:                    successTransition.setState(stateSuccessReturnState);
2519:                    successTransition
2520:                            .setControllerObject(stateSuccessReturnController);
2521:                    request.removeParameter(STATE_SUCC_CTL);
2522:                    request.removeParameter(STATE_SUCC_STATE);
2523:                }
2524:                //Only set if not null.  This allows design-time defaults if no runtime routing overrides it.
2525:                if (successTransition != null) {
2526:                    nextState.setSuccessTransition(successTransition);
2527:                }
2528:
2529:                //process any STATE ERROR routing
2530:                Transition errorTransition = null;
2531:                String errorTran = request.getParameter(STATE_ERR_TRAN);
2532:
2533:                if (errorTran != null) {
2534:                    request.removeParameter(STATE_ERR_TRAN);
2535:
2536:                    try {
2537:                        errorTransition = Transition.fromXML(errorTran);
2538:                    } catch (Exception e) {
2539:                        throw new ControllerException(e);
2540:                    }
2541:                }
2542:
2543:                String stateErrorReturnController = request
2544:                        .getParameter(STATE_ERR_CTL);
2545:
2546:                if (stateErrorReturnController != null) {
2547:                    if (errorTransition != null) {
2548:                        throw new ControllerException(
2549:                                "State cannot handle stateErrorReturn Transition object "
2550:                                        + "AND stateErrorXXX parameters in the same call.");
2551:                    }
2552:
2553:                    String stateErrorReturnState = request
2554:                            .getParameter(STATE_ERR_STATE);
2555:                    errorTransition = new Transition();
2556:                    errorTransition.setState(stateErrorReturnState);
2557:                    errorTransition
2558:                            .setControllerObject(stateErrorReturnController);
2559:                    request.removeParameter(STATE_ERR_CTL);
2560:                    request.removeParameter(STATE_ERR_STATE);
2561:                }
2562:                //Only set if not null.  This allows design-time defaults if no runtime routing overrides it.
2563:                if (errorTransition != null) {
2564:                    nextState.setErrorTransition(errorTransition);
2565:                }
2566:            }
2567:
2568:            /**
2569:             * This method is the traffic cop that determines which transition to execute
2570:             * after a state completes.
2571:             * <p/>
2572:             * 1. "State Error"
2573:             * The state returned with errors in the error collection.  The 'error transition'
2574:             * associated with the state is executed.  This transition could have been set
2575:             * either in processRequestTransitions() prior to state execution or in the
2576:             * state itself during execution.
2577:             * </p>
2578:             * <p/>
2579:             * <p/>
2580:             * 2. "State Success"
2581:             * The state returned without errors in the error collection.  The following
2582:             * priority is followed:
2583:             * - If the 'success transition' is not null for this state then it is executed.
2584:             * - If the state that just completed is a final state then:
2585:             * - If the 'chaining transition' is not null for this controller then it is executed.
2586:             * - If the 'controller success transition' is not null for this controller then
2587:             * it is executed.
2588:             * </p>
2589:             *
2590:             * @param request   The ControllerRequest Object
2591:             * @param response  The ControllerResponse Object
2592:             * @param nextState the state to transition to.
2593:             * @return An instantiated Transition Object
2594:             * @throws NonHandleableException upon a fatal error.
2595:             */
2596:            protected Transition processTransitions(ControllerRequest request,
2597:                    ControllerResponse response, State nextState)
2598:                    throws ControllerException, NonHandleableException {
2599:                Transition successTransition = nextState.getSuccessTransition();
2600:                Transition errorTransition = nextState.getErrorTransition();
2601:                Transition chainingTransition = null;
2602:                PersistentSession session = request.getSession();
2603:                String sessionKey = CTL_SUCC_TRAN + getClass().getName();
2604:
2605:                //Determine where we will transition to!!
2606:                Transition nextTransition = null;
2607:
2608:                if (response.hasErrors()) {
2609:                    nextTransition = errorTransition; //could execute this on final state.
2610:                } else {
2611:                    nextTransition = successTransition;
2612:
2613:                    if ((nextTransition == null)
2614:                            && isFinalState(nextState.getName())) {
2615:                        if (getControllerChainingTransition() != null) {
2616:
2617:                            //Make it thread-safe
2618:                            try {
2619:                                chainingTransition = (Transition) getControllerChainingTransition()
2620:                                        .clone();
2621:                            } catch (CloneNotSupportedException cne) {
2622:                                throw new ControllerException(
2623:                                        "Cannot clone the chainingTransition class");
2624:                            }
2625:
2626:                            nextTransition = chainingTransition;
2627:                        } else {
2628:                            Object successObject = null;
2629:
2630:                            try {
2631:                                successObject = session
2632:                                        .getPersistentAttribute(sessionKey);
2633:                            } //Can occur if user invalidated the session! (ugly)
2634:                            catch (NullPointerException npe) {
2635:                                log.debug("Invalidated Session", npe);
2636:                            }
2637:                            if (successObject != null) {
2638:                                String controllerSuccess = successObject
2639:                                        .toString();
2640:
2641:                                try {
2642:                                    nextTransition = Transition
2643:                                            .fromXML(controllerSuccess);
2644:                                } catch (Exception e) {
2645:                                    throw new ControllerException(e);
2646:                                }
2647:                            }
2648:                        }
2649:                    }
2650:                }
2651:                // Now setup context (if chaining) and then transition.  Context includes any
2652:                // parameters required for the destination controller as well as any return
2653:                // address that the source controller delegates to the destination controller.
2654:                if (nextTransition != null) {
2655:                    if (nextTransition == chainingTransition) {
2656:
2657:                        String oneParamKey = "";
2658:                        String oneParamValue = "";
2659:                        Hashtable transitionParams = nextTransition.getParams();
2660:                        for (Enumeration ep = transitionParams.keys(); ep
2661:                                .hasMoreElements();) {
2662:                            oneParamKey = (String) ep.nextElement();
2663:                            oneParamValue = (String) transitionParams
2664:                                    .get(oneParamKey);
2665:
2666:                            //Assign the 'required' parameters from the calling controller.
2667:                            if (oneParamValue.equals("")) {
2668:                                oneParamValue = request
2669:                                        .getParameter(oneParamKey);
2670:                                if (oneParamValue == null) {
2671:                                    throw new ControllerException(
2672:                                            "Required chaining parameter missing"
2673:                                                    + oneParamKey);
2674:                                } else { //Update the blank param with its value from the calling state's request
2675:                                    nextTransition.addParam(oneParamKey,
2676:                                            oneParamValue);
2677:                                }
2678:                            }
2679:                        }
2680:
2681:                        Object successObject = null;
2682:                        try {
2683:                            successObject = session
2684:                                    .getPersistentAttribute(sessionKey);
2685:                        } //Can occur if user invalidated the session! (ugly)
2686:                        catch (NullPointerException npe) {
2687:                            log.debug("Invalidated Session", npe);
2688:                        }
2689:                        if (successObject != null) {
2690:                            String controllerSuccessReturn = successObject
2691:                                    .toString();
2692:
2693:                            //pass the ctler's return address so the next controller will inherit it.
2694:                            nextTransition.addParam(CTL_SUCC_TRAN,
2695:                                    controllerSuccessReturn);
2696:                        }
2697:                    }
2698:
2699:                    nextTransition.transition(request, response);
2700:
2701:                    return nextTransition;
2702:                }
2703:
2704:                return null; //No transition was handled here.
2705:            }
2706:
2707:            /**
2708:             * Set the transition that will be executed when this controller completes
2709:             * successfully.  This will not likely be used as often as the runtime
2710:             * 'controller success' routing parameters.  However when used, it will
2711:             * relay any 'controller success' parameters onto the next controller
2712:             * so that the return path is not lost.
2713:             *
2714:             * @param newControllerChainingTransition
2715:             *         The new transition for when the
2716:             *         controller completes successfully.
2717:             * @throws NonHandleableException upon incorrect parameters.
2718:             */
2719:            protected void setControllerChainingTransition(
2720:                    Transition newControllerChainingTransition)
2721:                    throws NonHandleableException {
2722:                if (!newControllerChainingTransition
2723:                        .isExternalTransition(getClass().getName())) {
2724:                    throw new NonHandleableException(
2725:                            "Chained Transition must go to another controller.");
2726:                }
2727:                if (newControllerChainingTransition.isReturnToSenderEnabled()) {
2728:                    throw new NonHandleableException(
2729:                            "Chained Transition cannot return to sender.");
2730:                }
2731:
2732:                controllerChainingTransition = newControllerChainingTransition;
2733:            }
2734:
2735:            /**
2736:             * Set the transition that will be executed when a user attempts to run
2737:             * a state he doesn't have authorization on.  As always, this transition
2738:             * can have return-to-sender enabled.  This could allow a login screen
2739:             * to be called and then control would automatically return to the
2740:             * state whose authorization failed.
2741:             *
2742:             * @param newControllerSecurityTransition
2743:             *         To execute.
2744:             */
2745:            protected void setControllerSecurityTransition(
2746:                    Transition newControllerSecurityTransition) {
2747:                controllerSecurityTransition = newControllerSecurityTransition;
2748:            }
2749:
2750:            /**
2751:             * Convenience method to be able to access the state
2752:             * as a property from a JSP.
2753:             *
2754:             * @param newState The newState to set to.
2755:             * @param params   The ControllerRequest object
2756:             * @return a newly instantiated ControllerResponse
2757:             * @throws ControllerException    upon error
2758:             * @throws NonHandleableException upon fatal error
2759:             */
2760:            public ControllerResponse setCurrentState(String newState,
2761:                    ControllerRequest params) throws ControllerException,
2762:                    NonHandleableException {
2763:                return newState(newState, params);
2764:            } /* setCurrentState(String) */
2765:
2766:            /**
2767:             * Set what state to invoke if no state parameter is set.
2768:             *
2769:             * @param newInitialState The state to use as the initial state.
2770:             */
2771:            public void setInitialState(String newInitialState) {
2772:                if (!StringUtil.notNull(newInitialState).equals("")) {
2773:                    if (getState(newInitialState) != null) {
2774:                        initialStates
2775:                                .put(getClass().getName(), newInitialState);
2776:                    } else {
2777:                        throw new IllegalArgumentException(
2778:                                "Unable to set initial state " + " to '"
2779:                                        + newInitialState
2780:                                        + "', this is not a valid "
2781:                                        + "state for this controller.");
2782:                    }
2783:                }
2784:            } /* setInitialState(String) */
2785:
2786:            /**
2787:             * Tell this Controller object what Schema it belongs to. This is used
2788:             * when the Controller tries to use it's "getString(String, Object[])"
2789:             * method to prepare internationalized messages - it passes the call
2790:             * along to the appropriate schema which knows how to locate the
2791:             * proper message file.
2792:             *
2793:             * @param schemaClass The classname of the Schema to associate with.
2794:             */
2795:            protected void setSchema(String schemaClass) {
2796:                StringUtil.assertNotBlank(schemaClass,
2797:                        "Must specify a non-blank schema");
2798:                Stack stack = (Stack) schemas.get(getClass().getName());
2799:                if (stack == null) {
2800:                    stack = new Stack();
2801:                    //We have to push Expresso on because of items such as Must Login First
2802:                    stack
2803:                            .push(com.jcorporate.expresso.core.ExpressoSchema.class
2804:                                    .getName());
2805:                }
2806:
2807:                if (!stack.contains(schemaClass)) {
2808:                    stack.push(schemaClass);
2809:                }
2810:
2811:                schemas.put(getClass().getName(), stack);
2812:            } /* setSchema(String) */
2813:
2814:            /**
2815:             * Identical to setSchema(String) but provides a typesafe way of passing
2816:             * parameters.  Example: <br />
2817:             * <code> setSchema(com.jcorporate.expresso.core.ExpressoSchema
2818:             * .<b>class</b>);</code> <br />
2819:             *
2820:             * @param schemaClass The Class of the schema to set
2821:             */
2822:            protected void setSchema(Class schemaClass) {
2823:                if (schemaClass == null) {
2824:                    throw new IllegalArgumentException(
2825:                            "Parameter schemaClass must not be null");
2826:                }
2827:
2828:                setSchema(schemaClass.getName());
2829:            }
2830:
2831:            /**
2832:             * Allows for DBCreate to set up proper default
2833:             * values for views, etc.
2834:             *
2835:             * @param dbName the name of the db to add these values to.
2836:             * @throws DBException upon error
2837:             */
2838:            public void setupDefaultValues(String dbName) throws DBException {
2839:            }
2840:
2841:            /**
2842:             * This method is called before a state executes.  It will assign a
2843:             * return-to-sender transition to the state.  This transition will
2844:             * include the parameters that this state is being called with.
2845:             * <p/>
2846:             * If this state causes a transition (with return-to-sender enabled) to
2847:             * be executed, then this state's return-to-sender transition will be
2848:             * serialized and passed to the next controller.  This controller will
2849:             * then use this transition (once the controller completes successfull)
2850:             * to return to this state with the same parameters that this state was
2851:             * initally called with.
2852:             * <p/>
2853:             * This method will also check for a request parameter that overrides the
2854:             * return-to-sender transition that would normally be associated with this
2855:             * state.  This is useful when the final state reruns all of the controller's
2856:             * handle states.  In that case, any transitions should return to the final
2857:             * state and not the handle state that caused the transition.
2858:             *
2859:             * @param nextState = The state that is about to be executed
2860:             * @param request   The parsed ControllerRequest object
2861:             * @throws ControllerException upon error.
2862:             */
2863:            protected void setupReturnToSender(State nextState,
2864:                    ControllerRequest request) throws ControllerException {
2865:                Transition returnToSender = null;
2866:                String tran = request.getParameter(RETURN_TO_SENDER_TRAN);
2867:
2868:                if (tran != null) {
2869:                    request.removeParameter(RETURN_TO_SENDER_TRAN);
2870:
2871:                    try {
2872:                        returnToSender = Transition.fromXML(tran);
2873:                    } catch (Exception e) {
2874:                        throw new ControllerException(e);
2875:                    }
2876:                }
2877:                //This is the transition that will be executed from another state/controller to return to
2878:                //this state.  So don't call enableReturnToSender() otherwise we will run into a little
2879:                //ping pong action.
2880:                if (returnToSender == null) { //don't override if passed in (eg final mode)
2881:                    returnToSender = new Transition();
2882:                    returnToSender.setState(nextState.getName());
2883:                    returnToSender.setControllerObject(getClass().getName()); //back to here
2884:
2885:                    //Cache the parameters so that when/if this Transition is executed by some other state, our
2886:                    //input parameters to this state will be available.
2887:                    returnToSender.setReturnToSenderParms(request);
2888:                }
2889:
2890:                nextState.setReturnToSender(returnToSender);
2891:            }
2892:
2893:            /**
2894:             * Is this state allowed for the current user? The generic controller
2895:             * object can't determine this, but the DBController child of this
2896:             * object checks the database to determine which users can access which
2897:             * states.
2898:             *
2899:             * @param newState The name of the state being checked
2900:             * @param params   The ControllerRequestObject
2901:             * @return True if the state is allowed, else false if it is not
2902:             * @throws ControllerException upon error
2903:             */
2904:            public boolean stateAllowed(String newState,
2905:                    ControllerRequest params) throws ControllerException {
2906:                return true;
2907:            } /* stateAllowed(String) */
2908:
2909:            protected void transition(String newState, ControllerRequest req,
2910:                    ControllerResponse res) throws ControllerException,
2911:                    NonHandleableException {
2912:                transition(newState, req, res, true);
2913:            } /* transition(String, ControllerRequest, ControllerResponse) */
2914:
2915:            /**
2916:             * convenience method for transition to other controller
2917:             *
2918:             * @param newState           the new state to transition to
2919:             * @param externalController the class of the external controller
2920:             * @param req                the ControllerRequest parameter that the state handler has
2921:             * @param res                the ControllerResponse object that was passed to your state method
2922:             * @throws ControllerException    upon error
2923:             * @throws NonHandleableException upon fatal error
2924:             */
2925:            protected void transition(String newState,
2926:                    Class externalController, ControllerRequest req,
2927:                    ControllerResponse res) throws ControllerException,
2928:                    NonHandleableException {
2929:
2930:                Transition trans = new Transition("", "", externalController,
2931:                        newState);
2932:                trans.transition(req, res);
2933:            }
2934:
2935:            /**
2936:             * Transition to an internal state.  By internal state we mean that this method
2937:             * is used for transitioning to another 'state' inside the same controller class
2938:             * [inherited states not withstanding].  You cannot, however use this method
2939:             * to transfer control between controllers
2940:             *
2941:             * @param newState the state to transition to
2942:             * @param req      The ControllerRequest object that has been given your state
2943:             *                 handler
2944:             * @param res      The ControllerResponse object that has been given to your
2945:             *                 state handler
2946:             * @param clear    Should existing ControllerElements (Input/Output/Block/Transition)
2947:             *                 be removed from the resulting ControllerResponse (set to true if that is the
2948:             *                 desired behavior)
2949:             * @throws ControllerException    upon error
2950:             * @throws NonHandleableException upon fatal error
2951:             */
2952:            protected void transition(String newState, ControllerRequest req,
2953:                    ControllerResponse res, boolean clear)
2954:                    throws ControllerException, NonHandleableException {
2955:                if (log.isDebugEnabled()) {
2956:                    log.debug("Transitioning to state '" + newState
2957:                            + "' in controller '" + getClass().getName() + "'");
2958:                }
2959:
2960:                ControllerResponse newResponse = newState(newState, req);
2961:
2962:                if (clear) {
2963:                    res.clearOutputCache();
2964:                    res.clearInputCache();
2965:                    res.clearTransitionCache();
2966:                    res.clearBlockCache();
2967:                }
2968:
2969:                res.setDBName(newResponse.getDBName());
2970:                res.setCustomResponse(newResponse.isCustomResponse());
2971:                res.setCurrentState(newResponse.getCurrentState());
2972:                res.setStyle(newResponse.getStyle());
2973:                res.setTitle(newResponse.getTitle());
2974:
2975:                Block oneBlock = null;
2976:                Vector newBlocks = newResponse.getBlocks();
2977:
2978:                if (newBlocks != null) {
2979:                    for (Enumeration eb = newBlocks.elements(); eb
2980:                            .hasMoreElements();) {
2981:                        oneBlock = (Block) eb.nextElement();
2982:                        oneBlock.setControllerResponse(res);
2983:                        res.addBlock(oneBlock);
2984:                    }
2985:                }
2986:
2987:                Output oneOutput = null;
2988:                Vector newOutputs = newResponse.getOutputs();
2989:
2990:                if (newOutputs != null) {
2991:                    for (Enumeration eo = newOutputs.elements(); eo
2992:                            .hasMoreElements();) {
2993:                        oneOutput = (Output) eo.nextElement();
2994:                        oneOutput.setControllerResponse(res);
2995:                        res.addOutput(oneOutput);
2996:                    }
2997:                }
2998:
2999:                Vector newInputs = newResponse.getInputs();
3000:                Input oneInput = null;
3001:
3002:                if (newInputs != null) {
3003:                    for (Enumeration ei = newInputs.elements(); ei
3004:                            .hasMoreElements();) {
3005:                        oneInput = (Input) ei.nextElement();
3006:                        oneInput.setControllerResponse(res);
3007:                        res.addInput(oneInput);
3008:                    }
3009:                }
3010:
3011:                Vector newTransitions = newResponse.getTransitions();
3012:
3013:                if (newTransitions != null) {
3014:                    Transition oneTransition = null;
3015:
3016:                    for (Enumeration et = newResponse.getTransitions()
3017:                            .elements(); et.hasMoreElements();) {
3018:                        oneTransition = (Transition) et.nextElement();
3019:                        oneTransition.setControllerResponse(res);
3020:                        res.addTransition(oneTransition);
3021:                    }
3022:                }
3023:
3024:                res.setControllerClass(newResponse.getControllerClass());
3025:            } /* transition(String, ControllerRequest, ControllerResponse) */
3026:
3027:            /**
3028:             * Move the state's form data back into the controller's form.
3029:             * The controller's form is specified in the struts config file.  The state's
3030:             * form is specified in the state's stateFormClass attribute.
3031:             *
3032:             * @param stateForm      The stateForm to unload
3033:             * @param controllerForm The associated controllerForm
3034:             * @throws ControllerException upon error transferring the data between
3035:             *                             the forms.
3036:             */
3037:            protected void unloadStateForm(StateForm stateForm,
3038:                    ActionForm controllerForm) throws ControllerException {
3039:                if (stateForm != controllerForm) {
3040:                    try { //stateForm could be null here.
3041:                        BeanUtils.populate(controllerForm, BeanUtils
3042:                                .describe(stateForm));
3043:                    } catch (Exception e) {
3044:                        if (com.jcorporate.expresso.core.controller.DefaultForm.class
3045:                                .getName().equals(
3046:                                        controllerForm.getClass().getName())) {
3047:                            return;
3048:                        }
3049:                        throw new ControllerException(e);
3050:                    }
3051:                }
3052:            }
3053:
3054:            /**
3055:             * redirect response so that URL changes in client browser
3056:             *
3057:             * @param request     The ControllerRquest object.
3058:             * @param response    The ControllerResponse object
3059:             * @param redirectURL The URL to redirect the browser to.
3060:             * @throws IOException upon redirect error.
3061:             */
3062:            public void redirectRequest(ControllerRequest request,
3063:                    ControllerResponse response, String redirectURL)
3064:                    throws IOException {
3065:                response.setCustomResponse(true); // tell expresso not to forward to jsp after finishing controller method
3066:                ServletControllerRequest sr = (ServletControllerRequest) request;
3067:                HttpServletResponse httpResponse = (HttpServletResponse) sr
3068:                        .getServletResponse();
3069:                this .redirectRequest(httpResponse, redirectURL);
3070:            }
3071:
3072:            /**
3073:             * Checks to see if SSL should be toggled for this
3074:             * action
3075:             *
3076:             * @param aRequest  The current request object
3077:             * @param aResponse The current response object
3078:             * @param isSecure  should the request be secure.
3079:             * @return true if this state should be toggled for protocol
3080:             */
3081:            private boolean checkSsl(HttpServletRequest aRequest,
3082:                    HttpServletResponse aResponse, boolean isSecure) {
3083:
3084:                String redirectString = null;
3085:                com.jcorporate.expresso.core.misc.ConfigExpresso config = ConfigManager
3086:                        .getConfig();
3087:                redirectString = SecureRequestUtils.getRedirectString(aRequest,
3088:                        config.getHttpPort(), config.getSslPort(), isSecure);
3089:
3090:                if (redirectString != null) {
3091:                    try {
3092:                        // Redirect the page to the desired URL
3093:                        this .redirectRequest(aResponse, redirectString);
3094:                        return true;
3095:                    } catch (java.io.IOException ioe) {
3096:                        log.warn("IOException in redirect: ", ioe);
3097:                        //                System.out.println("IOException in redirect" + ioe.getMessage());
3098:                    }
3099:                }
3100:
3101:                return false;
3102:            }
3103:
3104:            /**
3105:             * Call from subclass to log into Category with subclass name
3106:             * will create logger with subclass name as necessary.
3107:             * @return org.apache.logj.Logger
3108:             */
3109:            public synchronized Logger getLogger() {
3110:                if (mLog == null) {
3111:                    setupSubclassLog();
3112:                }
3113:
3114:                return mLog;
3115:            }
3116:
3117:            /**
3118:             * setup a subclass logger separately from the base controller logger.
3119:             * Is this right? *PP*
3120:             */
3121:            protected synchronized void setupSubclassLog() {
3122:                if (mLog == null) {
3123:                    mLog = Logger.getLogger(getClass());
3124:                }
3125:            }
3126:
3127:            /**
3128:             * Generate a new transaction token, to be used for enforcing a single
3129:             * request for a particular transaction.
3130:             * <p/>
3131:             * <p/>
3132:             * Thanks to "Raul DAVIDOVICH" (R.DAVIDOVICH@caconcology.com)
3133:             * </p>
3134:             *
3135:             * @param request The request we are processing
3136:             * @return transaction token usually cryptographically created
3137:             */
3138:            protected String generateToken(ControllerRequest request) {
3139:                if (request instanceof  ServletControllerRequest) {
3140:                    ServletControllerRequest scr = (ServletControllerRequest) request;
3141:                    return super .generateToken((HttpServletRequest) scr
3142:                            .getServletRequest());
3143:                } else {
3144:                    return "no-web-environment.transaction.token";
3145:                }
3146:            }
3147:
3148:            /**
3149:             * Return <code>true</code> if there is a transaction token stored in
3150:             * the user's current session, and the value submitted as a request
3151:             * parameter with this action matches it.  Returns <code>false</code>
3152:             * under any of the following circumstances:
3153:             * <ul>
3154:             * <li>No session associated with this request</li>
3155:             * <li>No transaction token saved in the session</li>
3156:             * <li>No transaction token included as a request parameter</li>
3157:             * <li>The included transaction token value does not match the
3158:             * transaction token in the user's session</li>
3159:             * </ul>
3160:             *
3161:             * @param request The servlet request we are processing
3162:             * @return boolean value if the request transaction token matched
3163:             *         the stored transaction token.
3164:             * @see #generateToken
3165:             * @see #resetToken
3166:             * @see #saveToken
3167:             */
3168:            protected boolean isTokenValid(ControllerRequest request) {
3169:                if (request instanceof  ServletControllerRequest) {
3170:                    ServletControllerRequest scr = (ServletControllerRequest) request;
3171:                    return super .isTokenValid((HttpServletRequest) scr
3172:                            .getServletRequest());
3173:                } else {
3174:                    // Also true in a new app web environment e.g command line	interface
3175:                    return true;
3176:                }
3177:            }
3178:
3179:            /**
3180:             * Reset the saved transaction token in the user's session.  This
3181:             * indicates that transactional token checking will not be needed
3182:             * on the next request that is submitted.
3183:             *
3184:             * @param request The servlet request we are processing
3185:             * @see #saveToken
3186:             * @see #isTokenValid
3187:             */
3188:            protected void resetToken(ControllerRequest request) {
3189:                if (request instanceof  ServletControllerRequest) {
3190:                    ServletControllerRequest scr = (ServletControllerRequest) request;
3191:                    super .resetToken(scr.getHttpServletRequest());
3192:                }
3193:            }
3194:
3195:            /**
3196:             * Save a new transaction token in the user's current session,
3197:             * creating a new session if necessary.
3198:             *
3199:             * @param request The servlet request we are processing
3200:             * @see #resetToken
3201:             * @see #isTokenValid
3202:             */
3203:            protected void saveToken(ControllerRequest request) {
3204:                if (request instanceof  ServletControllerRequest) {
3205:                    ServletControllerRequest scr = (ServletControllerRequest) request;
3206:                    super .saveToken(scr.getHttpServletRequest());
3207:                }
3208:            }
3209:
3210:            /**
3211:             * Fetches array of parameter values from underlying HTTP request; use this in a web app to access
3212:             * the underlying parameters in the HTTP request which have the same name; parameters with the same name are not
3213:             * reflected in the hashtable maintained by ControllerRequest;
3214:             *
3215:             * @param request   cast ControllerRequest to get required type
3216:             * @param paramName key to look for among all parameters
3217:             * @return an array of String objects containing all of the values the given request parameter has, or null if the parameter does not exist.
3218:             */
3219:            public static String[] getParamValues(
3220:                    ServletControllerRequest request, String paramName) {
3221:                return request.getParamValues(paramName);
3222:            }
3223:        } /* Controller */
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.