Source Code Cross Referenced for PageFlowRequestProcessor.java in  » Library » Apache-beehive-1.0.2-src » org » apache » beehive » netui » pageflow » 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 » Library » Apache beehive 1.0.2 src » org.apache.beehive.netui.pageflow 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Licensed to the Apache Software Foundation (ASF) under one or more
0003:         * contributor license agreements.  See the NOTICE file distributed with
0004:         * this work for additional information regarding copyright ownership.
0005:         * The ASF licenses this file to You under the Apache License, Version 2.0
0006:         * (the "License"); you may not use this file except in compliance with
0007:         * the License.  You may obtain a copy of the License at
0008:         * 
0009:         *     http://www.apache.org/licenses/LICENSE-2.0
0010:         * 
0011:         * Unless required by applicable law or agreed to in writing, software
0012:         * distributed under the License is distributed on an "AS IS" BASIS,
0013:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014:         * See the License for the specific language governing permissions and
0015:         * limitations under the License.
0016:         *
0017:         * $Header:$
0018:         */
0019:        package org.apache.beehive.netui.pageflow;
0020:
0021:        import org.apache.beehive.netui.core.urls.URLRewriterService;
0022:        import org.apache.beehive.netui.core.urls.TemplatedURLFormatter;
0023:        import org.apache.beehive.netui.core.urltemplates.URLTemplatesFactory;
0024:        import org.apache.beehive.netui.pageflow.config.PageFlowActionForward;
0025:        import org.apache.beehive.netui.pageflow.config.PageFlowActionMapping;
0026:        import org.apache.beehive.netui.pageflow.handler.ActionForwardHandler;
0027:        import org.apache.beehive.netui.pageflow.handler.FlowControllerHandlerContext;
0028:        import org.apache.beehive.netui.pageflow.handler.ForwardRedirectHandler;
0029:        import org.apache.beehive.netui.pageflow.handler.Handlers;
0030:        import org.apache.beehive.netui.pageflow.handler.LoginHandler;
0031:        import org.apache.beehive.netui.pageflow.handler.ReloadableClassHandler;
0032:        import org.apache.beehive.netui.pageflow.interceptor.InterceptorException;
0033:        import org.apache.beehive.netui.pageflow.interceptor.Interceptors;
0034:        import org.apache.beehive.netui.pageflow.interceptor.Interceptor;
0035:        import org.apache.beehive.netui.pageflow.interceptor.action.ActionInterceptorContext;
0036:        import org.apache.beehive.netui.pageflow.interceptor.action.InterceptorForward;
0037:        import org.apache.beehive.netui.pageflow.interceptor.action.internal.ActionInterceptors;
0038:        import org.apache.beehive.netui.pageflow.interceptor.request.RequestInterceptorContext;
0039:        import org.apache.beehive.netui.pageflow.internal.*;
0040:        import org.apache.beehive.netui.pageflow.scoping.ScopedRequest;
0041:        import org.apache.beehive.netui.pageflow.scoping.ScopedServletUtils;
0042:        import org.apache.beehive.netui.script.common.ImplicitObjectUtil;
0043:        import org.apache.beehive.netui.util.internal.concurrent.InternalConcurrentHashMap;
0044:        import org.apache.beehive.netui.util.internal.DiscoveryUtils;
0045:        import org.apache.beehive.netui.util.internal.FileUtils;
0046:        import org.apache.beehive.netui.util.internal.InternalStringBuilder;
0047:        import org.apache.beehive.netui.util.internal.ServletUtils;
0048:        import org.apache.beehive.netui.util.config.ConfigUtil;
0049:        import org.apache.beehive.netui.util.config.bean.PageFlowConfig;
0050:        import org.apache.beehive.netui.util.config.bean.PreventCache;
0051:        import org.apache.beehive.netui.util.logging.Logger;
0052:        import org.apache.struts.Globals;
0053:        import org.apache.struts.action.Action;
0054:        import org.apache.struts.action.ActionForm;
0055:        import org.apache.struts.action.ActionForward;
0056:        import org.apache.struts.action.ActionMapping;
0057:        import org.apache.struts.action.ActionServlet;
0058:        import org.apache.struts.action.ActionErrors;
0059:        import org.apache.struts.action.InvalidCancelException;
0060:        import org.apache.struts.config.ActionConfig;
0061:        import org.apache.struts.config.FormBeanConfig;
0062:        import org.apache.struts.config.ForwardConfig;
0063:        import org.apache.struts.config.ModuleConfig;
0064:        import org.apache.struts.tiles.TilesRequestProcessor;
0065:        import org.apache.struts.tiles.TilesUtil;
0066:        import org.apache.struts.tiles.TilesUtilImpl;
0067:        import org.apache.struts.tiles.TilesUtilStrutsImpl;
0068:        import org.apache.struts.upload.MultipartRequestHandler;
0069:        import org.apache.struts.upload.MultipartRequestWrapper;
0070:        import org.apache.struts.util.RequestUtils;
0071:        import org.apache.struts.util.TokenProcessor;
0072:
0073:        import javax.servlet.FilterChain;
0074:        import javax.servlet.Servlet;
0075:        import javax.servlet.ServletConfig;
0076:        import javax.servlet.ServletContext;
0077:        import javax.servlet.ServletException;
0078:        import javax.servlet.ServletRequest;
0079:        import javax.servlet.ServletResponse;
0080:        import javax.servlet.http.HttpServletRequest;
0081:        import javax.servlet.http.HttpServletResponse;
0082:        import javax.servlet.http.HttpSession;
0083:        import java.io.IOException;
0084:        import java.io.InputStream;
0085:        import java.io.Serializable;
0086:        import java.lang.reflect.Field;
0087:        import java.lang.reflect.Modifier;
0088:        import java.net.URI;
0089:        import java.net.URISyntaxException;
0090:        import java.util.*;
0091:
0092:        /**
0093:         * The Page Flow extension of the Struts RequestProcessor, which contains callbacks that are invoked
0094:         * during processing of a request to the Struts action servlet.  This class is registered as the
0095:         * <strong>controller</strong> for all Struts modules derived from page flows.
0096:         */
0097:        public class PageFlowRequestProcessor extends TilesRequestProcessor
0098:                implements  Serializable, InternalConstants, PageFlowConstants {
0099:            private static int requestNumber = 0;
0100:
0101:            private static final Logger LOG = Logger
0102:                    .getInstance(PageFlowRequestProcessor.class);
0103:            private static final String ACTION_OVERRIDE_PARAM_PREFIX = "actionOverride:";
0104:            private static final int ACTION_OVERRIDE_PARAM_PREFIX_LEN = ACTION_OVERRIDE_PARAM_PREFIX
0105:                    .length();
0106:            private static final String SCHEME_UNSECURE = "http";
0107:            private static final String SCHEME_SECURE = "https";
0108:            private static final String REDIRECT_REQUEST_ATTRS_PREFIX = InternalConstants.ATTR_PREFIX
0109:                    + "requestAttrs:";
0110:            private static final String REDIRECT_REQUEST_ATTRS_PARAM = "forceRedirect";
0111:            private static final String FLOW_CONTROLLER_ACTION_CLASSNAME = FlowControllerAction.class
0112:                    .getName();
0113:
0114:            private Map/*< String, Class >*/_formBeanClasses = new HashMap/*< String, Class >*/();
0115:            private Map/*< String, List< ActionMapping > >*/_overloadedActions = new HashMap/*< String, List< ActionMapping > >*/();
0116:            private Handlers _handlers;
0117:            private FlowControllerFactory _flowControllerFactory;
0118:            private LegacySettings _legacySettings;
0119:            private InternalConcurrentHashMap/*< String, Class >*/_pageServletClasses = new InternalConcurrentHashMap/*< String, Class >*/();
0120:            private transient ServletContainerAdapter _servletContainerAdapter;
0121:            private transient PageFlowPageFilter _pageServletFilter;
0122:
0123:            protected Action processActionCreate(HttpServletRequest request,
0124:                    HttpServletResponse response, ActionMapping actionMapping)
0125:                    throws IOException {
0126:                String className = actionMapping.getType();
0127:
0128:                if (className != null
0129:                        && className.equals(FLOW_CONTROLLER_ACTION_CLASSNAME)) {
0130:                    FlowController fc = PageFlowRequestWrapper.get(request)
0131:                            .getCurrentFlowController();
0132:                    assert fc != null : "no FlowController for request "
0133:                            + request.getRequestURI();
0134:                    assert fc.getClass().getName().equals(
0135:                            actionMapping.getParameter()) : "current page flow  type "
0136:                            + fc.getClass().getName()
0137:                            + " does not match type specified in "
0138:                            + FLOW_CONTROLLER_ACTION_CLASSNAME
0139:                            + ": "
0140:                            + actionMapping.getParameter();
0141:
0142:                    Action action = new FlowControllerAction(fc);
0143:                    action.setServlet(servlet);
0144:                    return action;
0145:                }
0146:
0147:                return super .processActionCreate(request, response,
0148:                        actionMapping);
0149:            }
0150:
0151:            /**
0152:             * See if this action mapping is our custom config type, and if so, see if the action should use a member variable
0153:             * in the page flow controller as its form bean (the <code>useFormBean</code> attribute on
0154:             * <code>&#64;Jpf.Action</code>).  If so, return the appropriate Field in the controller class.
0155:             */
0156:            private Field getPageFlowScopedFormMember(ActionMapping mapping,
0157:                    HttpServletRequest request) {
0158:                if (mapping instanceof  PageFlowActionMapping) {
0159:                    PageFlowActionMapping pfam = (PageFlowActionMapping) mapping;
0160:                    String formMember = pfam.getFormMember();
0161:                    if (formMember == null)
0162:                        return null;
0163:
0164:                    Field field = null;
0165:                    FlowController fc = PageFlowRequestWrapper.get(request)
0166:                            .getCurrentFlowController();
0167:                    try {
0168:                        field = fc.getClass().getDeclaredField(formMember);
0169:                    } catch (NoSuchFieldException e) {
0170:                        // try finding a non-private field from the class hierarchy
0171:                        field = InternalUtils.lookupField(fc.getClass(),
0172:                                formMember);
0173:                        if (field == null
0174:                                || Modifier.isPrivate(field.getModifiers())) {
0175:                            LOG.error("Could not find page flow member "
0176:                                    + formMember + " as the form bean.");
0177:                            return null;
0178:                        }
0179:                    }
0180:
0181:                    if (!Modifier.isPublic(field.getModifiers()))
0182:                        field.setAccessible(true);
0183:                    return field;
0184:                }
0185:
0186:                return null;
0187:            }
0188:
0189:            protected ActionForm processActionForm(HttpServletRequest request,
0190:                    HttpServletResponse response, ActionMapping mapping) {
0191:                //
0192:                // See if we're using a pageflow-scoped form (a member variable in the current pageflow).
0193:                //
0194:                Field formMemberField = getPageFlowScopedFormMember(mapping,
0195:                        request);
0196:
0197:                //
0198:                // First look to see whether the input form was overridden in the request.
0199:                // This happens when a pageflow action forwards to another pageflow,
0200:                // whose begin action expects a form.  In this case, the form is already
0201:                // constructed, and shouldn't be instantiated anew or populated from request
0202:                // parameters.
0203:                //
0204:                ActionForm previousForm = InternalUtils.getForwardedFormBean(
0205:                        request, false);
0206:
0207:                if (previousForm != null) {
0208:                    //
0209:                    // If there was a forwarded form, and if this action specifies a pageflow-scoped form member,
0210:                    // set the member with this form.
0211:                    //
0212:                    if (formMemberField != null) {
0213:                        try {
0214:                            FlowController fc = PageFlowRequestWrapper.get(
0215:                                    request).getCurrentFlowController();
0216:                            assert fc != null : "no FlowController in request "
0217:                                    + request.getRequestURI();
0218:                            formMemberField.set(fc, InternalUtils
0219:                                    .unwrapFormBean(previousForm));
0220:                        } catch (IllegalAccessException e) {
0221:                            LOG.error("Could not access page flow member "
0222:                                    + formMemberField.getName()
0223:                                    + " as the form bean.", e);
0224:                        }
0225:                    }
0226:
0227:                    //
0228:                    // Return the forwarded form.
0229:                    //
0230:                    previousForm.setServlet(servlet);
0231:                    return previousForm;
0232:                }
0233:
0234:                //
0235:                // First see if the previous action put a pageflow-scoped form in the request.  If so, remove it;
0236:                // we don't want a normal request-scoped action to use this pageflow-scoped form.
0237:                //
0238:                String pageFlowScopedFormName = PageFlowRequestWrapper.get(
0239:                        request).getPageFlowScopedFormName();
0240:                if (pageFlowScopedFormName != null) {
0241:                    request.removeAttribute(pageFlowScopedFormName);
0242:                    PageFlowRequestWrapper.get(request)
0243:                            .setPageFlowScopedFormName(null);
0244:                }
0245:
0246:                //
0247:                // If this action specifies a pageflow-scoped form member variable, use it.
0248:                //
0249:                if (formMemberField != null) {
0250:                    try {
0251:                        FlowController fc = PageFlowRequestWrapper.get(request)
0252:                                .getCurrentFlowController();
0253:                        ActionForm form = InternalUtils
0254:                                .wrapFormBean(formMemberField.get(fc));
0255:
0256:                        if (form == null) // the pageflow hasn't filled the value yet
0257:                        {
0258:                            form = InternalUtils.createActionForm(mapping,
0259:                                    moduleConfig, servlet, getServletContext());
0260:                            form.reset(mapping, request);
0261:                            formMemberField.set(fc, InternalUtils
0262:                                    .unwrapFormBean(form));
0263:                        }
0264:
0265:                        //
0266:                        // Store the form in the right place in the request, so Struts can see it.
0267:                        // But, mark a flag so we know to remove this on the next action request -- we don't
0268:                        // want this form used by another action unless that action uses the pageflow-scoped
0269:                        // form.
0270:                        //
0271:                        String formAttrName = mapping.getAttribute();
0272:                        request.setAttribute(formAttrName, form);
0273:                        PageFlowRequestWrapper.get(request)
0274:                                .setPageFlowScopedFormName(formAttrName);
0275:                        return form;
0276:                    } catch (IllegalAccessException e) {
0277:                        LOG.error("Could not access page flow member "
0278:                                + formMemberField.getName()
0279:                                + " as the form bean.", e);
0280:                    }
0281:                }
0282:
0283:                ActionForm bean = super .processActionForm(request, response,
0284:                        mapping);
0285:                if (bean == null) {
0286:                    bean = InternalUtils.createActionForm(mapping,
0287:                            moduleConfig, servlet, getServletContext());
0288:                }
0289:
0290:                return bean;
0291:            }
0292:
0293:            protected void processPopulate(HttpServletRequest request,
0294:                    HttpServletResponse response, ActionForm form,
0295:                    ActionMapping mapping) throws ServletException {
0296:                //
0297:                // If a previous action forwarded us a form, use that -- don't populate it from request parameters.
0298:                //
0299:                ActionForm previousForm = InternalUtils.getForwardedFormBean(
0300:                        request, true);
0301:
0302:                if (previousForm != null) {
0303:                    return;
0304:                }
0305:
0306:                if (LOG.isDebugEnabled()) {
0307:                    LOG.debug("Populating bean properties from this request");
0308:                }
0309:
0310:                // struts does this
0311:                if (form != null) {
0312:                    form.setServlet(servlet);
0313:                    form.reset(mapping, request);
0314:                }
0315:
0316:                if (mapping.getMultipartClass() != null) {
0317:                    request.setAttribute(Globals.MULTIPART_KEY, mapping
0318:                            .getMultipartClass());
0319:                }
0320:
0321:                PageFlowRequestWrapper requestWrapper = PageFlowRequestWrapper
0322:                        .get(request);
0323:                boolean alreadyCalledInRequest = requestWrapper
0324:                        .isProcessPopulateAlreadyCalled();
0325:                if (!alreadyCalledInRequest)
0326:                    requestWrapper.setProcessPopulateAlreadyCalled(true);
0327:
0328:                //
0329:                // If this is a forwarded request and the form-bean is null, don't call to ProcessPopulate.
0330:                // We don't want to expose errors due to parameters from the original request, which won't
0331:                // apply to a forwarded action that doesn't take a form.
0332:                //
0333:                if (!alreadyCalledInRequest || form != null) {
0334:                    // If this request was forwarded by a button-override of the main form action, then ensure that there are
0335:                    // no databinding errors when the override action does not use a form bean.
0336:                    if (form == null && requestWrapper.isForwardedByButton()) {
0337:                        // This is currently TODO; I removed the use of NullActionForm.
0338:                        // See http://issues.apache.org/jira/browse/BEEHIVE-947 .
0339:                    }
0340:
0341:                    ProcessPopulate.populate(request, response, form,
0342:                            alreadyCalledInRequest);
0343:                }
0344:            }
0345:
0346:            /**
0347:             * The requested action can be overridden by a request parameter.  In this case, we parse the action from
0348:             * the request parameter and forward to a URI constructed from it.
0349:             *
0350:             * @param request the current HttpServletRequest
0351:             * @param response the current HttpServletResponse
0352:             * @return <code>true</code> if the action was overridden by a request parameter, in which case the request
0353:             *         was forwarded.
0354:             * @throws IOException
0355:             * @throws ServletException
0356:             */
0357:            protected boolean processActionOverride(HttpServletRequest request,
0358:                    HttpServletResponse response) throws IOException,
0359:                    ServletException {
0360:                // Only make this check if this is an initial (non-forwarded) request.
0361:                //
0362:                // TODO: performance?
0363:                //
0364:                PageFlowRequestWrapper wrapper = PageFlowRequestWrapper
0365:                        .get(request);
0366:                if (!wrapper.isForwardedByButton()
0367:                        && !wrapper.isForwardedRequest()) {
0368:                    //
0369:                    // First, since we need access to request parameters here, process a multipart request
0370:                    // if that's what we have.  This puts the parameters (each in a MIME part) behind an
0371:                    // interface that makes them look like normal request parameters.
0372:                    //
0373:                    HttpServletRequest multipartAwareRequest = processMultipart(request);
0374:
0375:                    for (Enumeration e = multipartAwareRequest
0376:                            .getParameterNames(); e.hasMoreElements();) {
0377:                        String paramName = (String) e.nextElement();
0378:
0379:                        if (paramName.startsWith(ACTION_OVERRIDE_PARAM_PREFIX)) {
0380:                            String actionPath = paramName
0381:                                    .substring(ACTION_OVERRIDE_PARAM_PREFIX_LEN);
0382:                            ServletContext servletContext = getServletContext();
0383:
0384:                            String qualifiedAction = InternalUtils
0385:                                    .qualifyAction(servletContext, actionPath);
0386:                            actionPath = InternalUtils.createActionPath(
0387:                                    request, qualifiedAction);
0388:
0389:                            if (LOG.isDebugEnabled()) {
0390:                                LOG
0391:                                        .debug("A request parameter overrode the action.  Forwarding to: "
0392:                                                + actionPath);
0393:                            }
0394:
0395:                            wrapper.setForwardedByButton(true);
0396:                            doForward(actionPath, request, response);
0397:                            return true;
0398:                        }
0399:                    }
0400:                }
0401:
0402:                return false;
0403:            }
0404:
0405:            /**
0406:             * Internal method used to process an action.
0407:             *
0408:             * @param request the current request
0409:             * @param response the current response
0410:             * @throws IOException
0411:             * @throws ServletException
0412:             */
0413:            private void processInternal(HttpServletRequest request,
0414:                    HttpServletResponse response) throws IOException,
0415:                    ServletException {
0416:                //
0417:                // First wrap the request with an object that contains request-scoped values that our runtime uses.  This
0418:                // is faster than sticking everything into attributes on the request (then basically reading from a HashMap).
0419:                //
0420:                request = PageFlowRequestWrapper.wrapRequest(request);
0421:
0422:                String uri = InternalUtils.getDecodedServletPath(request);
0423:                ServletContext servletContext = getServletContext();
0424:
0425:                // The ServletContainerAdapter reference may have been lost during serialization/deserialization.
0426:                if (_servletContainerAdapter == null) {
0427:                    _servletContainerAdapter = AdapterManager
0428:                            .getServletContainerAdapter(servletContext);
0429:                }
0430:
0431:                //
0432:                // Allow the container to do a security check on forwarded requests, if that feature is enabled.
0433:                //
0434:                if (LegacySettings.get(servletContext).shouldDoSecureForwards()
0435:                        && PageFlowRequestWrapper.get(request)
0436:                                .isForwardedRequest()) {
0437:                    //
0438:                    // In some situations (namely, in scoped requests under portal), the initial
0439:                    // security check may not have been done for the request URI.  In this case, a redirect
0440:                    // to https may happen during checkSecurity().
0441:                    //
0442:                    if (_servletContainerAdapter.doSecurityRedirect(uri,
0443:                            request, response)) {
0444:                        if (LOG.isDebugEnabled())
0445:                            LOG
0446:                                    .debug("checkSecurity() caused a redirect.  Ending processing for this request "
0447:                                            + '(' + uri + ')');
0448:
0449:                        return;
0450:                    }
0451:                }
0452:
0453:                //
0454:                // If we've come in on a forced redirect due to security constraints, look for request attrs
0455:                // that we put into the session.
0456:                //
0457:                String hash = request
0458:                        .getParameter(REDIRECT_REQUEST_ATTRS_PARAM);
0459:                if (hash != null) {
0460:                    HttpSession session = request.getSession(false);
0461:
0462:                    if (session != null) {
0463:                        String carryoverAttrName = makeRedirectedRequestAttrsKey(
0464:                                uri, hash);
0465:                        Map attrs = (Map) session
0466:                                .getAttribute(carryoverAttrName);
0467:                        session.removeAttribute(carryoverAttrName);
0468:
0469:                        if (attrs != null) {
0470:                            for (Iterator i = attrs.entrySet().iterator(); i
0471:                                    .hasNext();) {
0472:                                Map.Entry entry = (Map.Entry) i.next();
0473:
0474:                                String attrName = (String) entry.getKey();
0475:                                if (request.getAttribute(attrName) == null) {
0476:                                    request.setAttribute(attrName, entry
0477:                                            .getValue());
0478:                                }
0479:                            }
0480:                        }
0481:                    }
0482:                }
0483:
0484:                //
0485:                // The requested action can be overridden by a request parameter.  In this case, we parse the action from
0486:                // the request parameter and forward to a URI constructed from it.  If this happens, just return.
0487:                //
0488:                if (processActionOverride(request, response))
0489:                    return;
0490:
0491:                //
0492:                // Process any direct request for a page flow by forwarding to its "begin" action.
0493:                //
0494:                if (processPageFlowRequest(request, response, uri))
0495:                    return;
0496:
0497:                //
0498:                // Get the FlowController for this request (page flow or shared flow), and cache it in the request.
0499:                //
0500:                String flowControllerClassName = InternalUtils
0501:                        .getFlowControllerClassName(moduleConfig);
0502:
0503:                if (flowControllerClassName == null
0504:                        && !(moduleConfig instanceof  AutoRegisterActionServlet.MissingRootModuleControllerConfig)) {
0505:                    //
0506:                    // If this isn't a blank module initialized in place of a missing root PageFlowController, emit a warning
0507:                    // about the missing controllerClass property.
0508:                    //
0509:                    if (LOG.isWarnEnabled())
0510:                        LOG
0511:                                .warn("Struts module "
0512:                                        + moduleConfig.getPrefix()
0513:                                        + " is configured to use "
0514:                                        + getClass().getName()
0515:                                        + " as the request processor, but the <controller> element does not contain a <set-property>"
0516:                                        + " for \"controllerClass\".  Page Flow actions in this module may not be handled correctly.");
0517:                }
0518:
0519:                //
0520:                // Look up or create the appropriate SharedFlowControllers if they don't exist.
0521:                //
0522:                if (LOG.isInfoEnabled())
0523:                    LOG
0524:                            .info("Attempting to instantiate SharedFlowControllers for request "
0525:                                    + request.getRequestURI());
0526:
0527:                FlowController currentFlowController = null;
0528:
0529:                try {
0530:                    RequestContext requestContext = new RequestContext(request,
0531:                            response);
0532:                    Map/*< String, SharedFlowController >*/sharedFlows = _flowControllerFactory
0533:                            .getSharedFlowsForRequest(requestContext);
0534:
0535:                    /* todo: why are the shared flow / global app objects loaded for data binding here? */
0536:                    ImplicitObjectUtil.loadSharedFlow(request, sharedFlows);
0537:                    ImplicitObjectUtil.loadGlobalApp(request, PageFlowUtils
0538:                            .getGlobalApp(request));
0539:
0540:                    if (flowControllerClassName != null) {
0541:                        currentFlowController = getFlowController(
0542:                                requestContext, flowControllerClassName);
0543:                        PageFlowRequestWrapper
0544:                                .get(request)
0545:                                .setCurrentFlowController(currentFlowController);
0546:                    } else {
0547:                        PageFlowRequestWrapper.get(request)
0548:                                .setCurrentFlowController(null);
0549:                    }
0550:                } catch (ClassNotFoundException e) {
0551:                    LOG.error("Could not find FlowController class "
0552:                            + flowControllerClassName, e);
0553:                    ServletUtils.throwServletException(e);
0554:                } catch (InstantiationException e) {
0555:                    LOG.error("Could not instantiate FlowController of type "
0556:                            + flowControllerClassName, e);
0557:                    ServletUtils.throwServletException(e);
0558:                } catch (IllegalAccessException e) {
0559:                    LOG.error("Could not instantiate FlowController of type "
0560:                            + flowControllerClassName, e);
0561:                    ServletUtils.throwServletException(e);
0562:                }
0563:
0564:                //
0565:                // Get the page flow for this request.
0566:                //
0567:                PageFlowController jpf = PageFlowUtils.getCurrentPageFlow(
0568:                        request, getServletContext());
0569:
0570:                //
0571:                // Remove any current JavaServer Faces backing bean.  We have "left" any JSF page and are now processing a
0572:                // Page Flow action.
0573:                //
0574:                InternalUtils.removeCurrentFacesBackingBean(request,
0575:                        servletContext);
0576:
0577:                //
0578:                // Set up implicit objects used by the expression language in simple actions and in declarative validation.
0579:                //
0580:                ImplicitObjectUtil.loadImplicitObjects(request, response,
0581:                        servletContext, jpf);
0582:
0583:                try {
0584:                    super .process(request, response);
0585:                } catch (UnhandledException unhandledException) {
0586:                    // If we get here, then we've already tried to find an exception handler.  Just throw.
0587:                    rethrowUnhandledException(unhandledException);
0588:                } catch (ServletException servletEx) {
0589:                    // If a ServletException escapes out of any of the processing methods, let the current FlowController handle it.
0590:                    if (!handleException(servletEx, currentFlowController,
0591:                            request, response))
0592:                        throw servletEx;
0593:                } catch (IOException ioe) {
0594:                    // If an IOException escapes out of any of the processing methods, let the current FlowController handle it.
0595:                    if (!handleException(ioe, currentFlowController, request,
0596:                            response))
0597:                        throw ioe;
0598:                } catch (Throwable th) {
0599:                    // If a Throwable escapes out of any of the processing methods, let the current FlowController handle it.
0600:                    if (!handleException(th, currentFlowController, request,
0601:                            response)) {
0602:                        if (th instanceof  Error)
0603:                            throw (Error) th;
0604:                        ServletUtils.throwServletException(th);
0605:                    }
0606:                }
0607:            }
0608:
0609:            private FlowController getFlowController(
0610:                    RequestContext requestContext, String fcClassName)
0611:                    throws ClassNotFoundException, InstantiationException,
0612:                    IllegalAccessException {
0613:                Class fcClass = _flowControllerFactory
0614:                        .getFlowControllerClass(fcClassName);
0615:                HttpServletRequest request = requestContext.getHttpRequest();
0616:                HttpServletResponse response = requestContext.getHttpResponse();
0617:
0618:                if (PageFlowController.class.isAssignableFrom(fcClass)) {
0619:                    PageFlowController current = PageFlowUtils
0620:                            .getCurrentPageFlow(request, getServletContext());
0621:
0622:                    if (current != null && current.getClass().equals(fcClass)) {
0623:                        if (LOG.isDebugEnabled()) {
0624:                            LOG.debug("Using current page flow: " + current);
0625:                        }
0626:
0627:                        //
0628:                        // Reinitialize transient data that may have been lost on session failover.
0629:                        //
0630:                        current.reinitialize(request, response,
0631:                                getServletContext());
0632:                        return current;
0633:                    }
0634:
0635:                    return _flowControllerFactory.createPageFlow(
0636:                            new RequestContext(request, response), fcClass);
0637:                } else {
0638:                    assert SharedFlowController.class.isAssignableFrom(fcClass) : fcClass
0639:                            .getName();
0640:
0641:                    SharedFlowController current = PageFlowUtils.getSharedFlow(
0642:                            fcClass.getName(), request);
0643:
0644:                    if (current != null) {
0645:                        current.reinitialize(request, response,
0646:                                getServletContext());
0647:                        return current;
0648:                    }
0649:
0650:                    return _flowControllerFactory.createSharedFlow(
0651:                            new RequestContext(request, response), fcClass);
0652:                }
0653:            }
0654:
0655:            private boolean handleException(Throwable th, FlowController fc,
0656:                    HttpServletRequest request, HttpServletResponse response) {
0657:                if (fc != null) {
0658:                    try {
0659:                        ActionMapping mapping = InternalUtils
0660:                                .getCurrentActionMapping(request);
0661:                        ActionForm form = InternalUtils
0662:                                .getCurrentActionForm(request);
0663:                        ActionForward fwd = fc.handleException(th, mapping,
0664:                                form, request, response);
0665:                        processForwardConfig(request, response, fwd);
0666:                        return true;
0667:                    } catch (UnhandledException unhandledException) {
0668:                        if (LOG.isInfoEnabled()) {
0669:                            LOG
0670:                                    .info(
0671:                                            "This exception was unhandled by any exception handler.",
0672:                                            unhandledException);
0673:                        }
0674:
0675:                        return false;
0676:                    } catch (Throwable t) {
0677:                        LOG.error("Exception while handling exception "
0678:                                + th.getClass().getName()
0679:                                + ".  The original exception will be thrown.",
0680:                                t);
0681:                        return false;
0682:                    }
0683:                }
0684:
0685:                return false;
0686:            }
0687:
0688:            /**
0689:             * Process any direct request for a page flow by forwarding to its "begin" action.
0690:             *
0691:             * @param request the current HttpServletRequest
0692:             * @param response the current HttpServletResponse
0693:             * @param uri the decoded request URI
0694:             * @return <code>true</code> if the request was for a page flow, in which case it was forwarded.
0695:             * @throws IOException
0696:             * @throws ServletException
0697:             */
0698:            protected boolean processPageFlowRequest(
0699:                    HttpServletRequest request, HttpServletResponse response,
0700:                    String uri) throws IOException, ServletException {
0701:                //
0702:                // Forward requests for *.jpf to the "begin" action within the appropriate Struts module.
0703:                //
0704:                if (FileUtils.osSensitiveEndsWith(uri,
0705:                        PageFlowConstants.PAGEFLOW_EXTENSION)) {
0706:                    //
0707:                    // Make sure the current module config matches the request URI.  If not, this could be an
0708:                    // EAR where the struts-config.xml wasn't included because of a compilation error.
0709:                    //
0710:                    String modulePath = PageFlowUtils.getModulePath(request);
0711:                    if (!moduleConfig.getPrefix().equals(modulePath)) {
0712:                        if (LOG.isErrorEnabled()) {
0713:                            InternalStringBuilder msg = new InternalStringBuilder(
0714:                                    "No module configuration registered for ");
0715:                            msg.append(uri).append(" (module path ").append(
0716:                                    modulePath).append(").");
0717:                            LOG.error(msg.toString());
0718:                        }
0719:
0720:                        if (modulePath.length() == 0)
0721:                            modulePath = "/";
0722:                        InternalUtils.sendDevTimeError("PageFlow_NoModuleConf",
0723:                                null,
0724:                                HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
0725:                                request, response, getServletContext(),
0726:                                new Object[] { uri, modulePath });
0727:                        return true;
0728:                    }
0729:
0730:                    // Make sure that the requested pageflow matches the pageflow for the directory.
0731:                    ActionMapping beginMapping = getBeginMapping();
0732:                    if (beginMapping != null) {
0733:                        String desiredType = beginMapping.getParameter();
0734:                        desiredType = desiredType.substring(desiredType
0735:                                .lastIndexOf('.') + 1)
0736:                                + PAGEFLOW_EXTENSION;
0737:                        String requestedType = InternalUtils
0738:                                .getDecodedServletPath(request);
0739:                        requestedType = requestedType.substring(requestedType
0740:                                .lastIndexOf('/') + 1);
0741:
0742:                        if (!requestedType.equals(desiredType)) {
0743:                            if (LOG.isDebugEnabled()) {
0744:                                LOG
0745:                                        .debug("Wrong .jpf requested for this directory: got "
0746:                                                + requestedType
0747:                                                + ", expected "
0748:                                                + desiredType);
0749:                            }
0750:
0751:                            if (LOG.isErrorEnabled()) {
0752:                                InternalStringBuilder msg = new InternalStringBuilder(
0753:                                        "Wrong .jpf requested for this directory: got ");
0754:                                msg.append(requestedType).append(", expected ")
0755:                                        .append(desiredType).append('.');
0756:                                LOG.error(msg.toString());
0757:                            }
0758:
0759:                            InternalUtils
0760:                                    .sendDevTimeError(
0761:                                            "PageFlow_WrongPath",
0762:                                            null,
0763:                                            HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
0764:                                            request, response,
0765:                                            getServletContext(),
0766:                                            new Object[] { requestedType,
0767:                                                    desiredType });
0768:
0769:                            return true;
0770:                        }
0771:                    }
0772:
0773:                    uri = PageFlowUtils.getBeginActionURI(uri);
0774:
0775:                    if (LOG.isDebugEnabled()) {
0776:                        LOG.debug("Got request for " + request.getRequestURI()
0777:                                + ", forwarding to " + uri);
0778:                    }
0779:
0780:                    doForward(uri, request, response);
0781:                    return true;
0782:                }
0783:
0784:                return false;
0785:            }
0786:
0787:            /**
0788:             * A MultipartRequestWrapper that we cache in the outer request once we've handled the multipart request once.
0789:             * It extends the base Struts MultipartRequestWrapper by being aware of ScopedRequests; for ScopedRequests, it
0790:             * filters the parameter names accordingly.
0791:             */
0792:            private static class RehydratedMultipartRequestWrapper extends
0793:                    MultipartRequestWrapper {
0794:                public RehydratedMultipartRequestWrapper(HttpServletRequest req) {
0795:                    super (req);
0796:
0797:                    MultipartRequestHandler handler = MultipartRequestUtils
0798:                            .getCachedMultipartHandler(req);
0799:
0800:                    if (handler != null) {
0801:                        ScopedRequest scopedRequest = ScopedServletUtils
0802:                                .unwrapRequest(req);
0803:                        Map textElements = handler.getTextElements();
0804:                        parameters = scopedRequest != null ? scopedRequest
0805:                                .filterParameterMap(textElements)
0806:                                : textElements;
0807:                    }
0808:                }
0809:            }
0810:
0811:            public void process(HttpServletRequest request,
0812:                    HttpServletResponse response) throws IOException,
0813:                    ServletException {
0814:                int localRequestCount = -1;
0815:
0816:                if (LOG.isTraceEnabled()) {
0817:                    localRequestCount = ++requestNumber;
0818:                    LOG.trace("------------------------------- Start Request #"
0819:                            + localRequestCount
0820:                            + " -----------------------------------");
0821:                }
0822:
0823:                //
0824:                // First reinitialize the reloadable class handler.  This will bounce a classloader if necessary.
0825:                //
0826:                ServletContext servletContext = getServletContext();
0827:                _handlers.getReloadableClassHandler().reloadClasses(
0828:                        new RequestContext(request, response));
0829:
0830:                //
0831:                // Get the chain of pre-request interceptors.
0832:                //
0833:                RequestInterceptorContext context = new RequestInterceptorContext(
0834:                        request, response, getServletContext());
0835:                List/*< Interceptor >*/interceptors = context
0836:                        .getRequestInterceptors();
0837:
0838:                //
0839:                // Execute pre-request interceptors
0840:                //
0841:                try {
0842:                    Interceptors.doPreIntercept(context, interceptors);
0843:
0844:                    if (context.requestWasCancelled()) {
0845:                        if (LOG.isDebugEnabled()) {
0846:                            LOG.debug("Interceptor "
0847:                                    + context.getOverridingInterceptor()
0848:                                    + " cancelled the request.");
0849:                        }
0850:
0851:                        return;
0852:                    }
0853:                } catch (InterceptorException e) {
0854:                    ServletUtils.throwServletException(e);
0855:                }
0856:
0857:                //
0858:                // Initialize the ServletContext in the request.  Often, we need access to the ServletContext when we only
0859:                // have a ServletRequest.
0860:                //
0861:                InternalUtils.setServletContext(request, servletContext);
0862:
0863:                //
0864:                // Callback to the servlet container adapter.
0865:                //
0866:                PageFlowEventReporter er = _servletContainerAdapter
0867:                        .getEventReporter();
0868:                _servletContainerAdapter.beginRequest(request, response);
0869:                RequestContext requestContext = new RequestContext(request,
0870:                        response);
0871:                er.beginActionRequest(requestContext);
0872:                long startTime = System.currentTimeMillis();
0873:
0874:                // Register the default URLRewriter
0875:                URLRewriterService.registerURLRewriter(0, request,
0876:                        new DefaultURLRewriter());
0877:
0878:                //
0879:                // A ServletContext may have synchronization associated with getting attributes.
0880:                // This could be a bottleneck under load for an app with pages that require lots
0881:                // of URL rewriting. To improve performance add the template factory and formatter
0882:                // to the request.
0883:                //
0884:                if (URLTemplatesFactory.getURLTemplatesFactory(request) == null) {
0885:                    URLTemplatesFactory.initServletRequest(request,
0886:                            URLTemplatesFactory
0887:                                    .getURLTemplatesFactory(servletContext));
0888:                }
0889:                if (TemplatedURLFormatter.getTemplatedURLFormatter(request) == null) {
0890:                    TemplatedURLFormatter.initServletRequest(request,
0891:                            TemplatedURLFormatter
0892:                                    .getTemplatedURLFormatter(servletContext));
0893:                }
0894:
0895:                PageFlowRequestWrapper rw = PageFlowRequestWrapper
0896:                        .unwrap(request);
0897:                boolean isForwardedRequest = rw != null
0898:                        && rw.isForwardedRequest();
0899:
0900:                try {
0901:                    processInternal(request, response);
0902:                } finally {
0903:                    //
0904:                    // If this is not a forwarded request, then commit any session-scoped changes that were stored in the
0905:                    // request.
0906:                    //
0907:                    if (!isForwardedRequest) {
0908:                        Handlers.get(getServletContext()).getStorageHandler()
0909:                                .applyChanges(requestContext);
0910:                    }
0911:
0912:                    //
0913:                    // Callback to the server adapter.
0914:                    //
0915:                    _servletContainerAdapter.endRequest(request, response);
0916:                    long timeTaken = System.currentTimeMillis() - startTime;
0917:                    er.endActionRequest(requestContext, timeTaken);
0918:                }
0919:
0920:                //
0921:                // Execute post-request interceptors
0922:                //
0923:                try {
0924:                    Interceptors.doPostIntercept(context, interceptors);
0925:                } catch (InterceptorException e) {
0926:                    ServletUtils.throwServletException(e);
0927:                }
0928:
0929:                if (LOG.isTraceEnabled()) {
0930:                    LOG.trace("-------------------------------- End Request #"
0931:                            + localRequestCount
0932:                            + " ------------------------------------");
0933:                }
0934:            }
0935:
0936:            /**
0937:             * If this is a multipart request, wrap it with a special wrapper.  Otherwise, return the request unchanged.
0938:             *
0939:             * @param request The HttpServletRequest we are processing
0940:             */
0941:            protected HttpServletRequest processMultipart(
0942:                    HttpServletRequest request) {
0943:                if (!"POST".equalsIgnoreCase(request.getMethod()))
0944:                    return request;
0945:
0946:                String contentType = request.getContentType();
0947:                if (contentType != null
0948:                        && contentType.startsWith("multipart/form-data")) {
0949:                    PageFlowRequestWrapper pageFlowRequestWrapper = PageFlowRequestWrapper
0950:                            .get(request);
0951:
0952:                    //
0953:                    // We may have already gotten a multipart wrapper during process().  If so, use that.
0954:                    //
0955:                    MultipartRequestWrapper cachedWrapper = pageFlowRequestWrapper
0956:                            .getMultipartRequestWrapper();
0957:
0958:                    if (cachedWrapper != null
0959:                            && cachedWrapper.getRequest() == request)
0960:                        return cachedWrapper;
0961:
0962:                    try {
0963:                        //
0964:                        // First, pre-handle the multipart request.  This parses the stream and caches a single
0965:                        // MultipartRequestHandler in the outer request, so we can create new wrappers around it at will.
0966:                        //
0967:                        MultipartRequestUtils
0968:                                .preHandleMultipartRequest(request);
0969:                    } catch (ServletException e) {
0970:                        LOG.error("Could not parse multipart request.", e
0971:                                .getRootCause());
0972:                        return request;
0973:                    }
0974:
0975:                    MultipartRequestWrapper ret = new RehydratedMultipartRequestWrapper(
0976:                            request);
0977:                    pageFlowRequestWrapper.setMultipartRequestWrapper(ret);
0978:                    return ret;
0979:                } else {
0980:                    return request;
0981:                }
0982:
0983:            }
0984:
0985:            protected ActionMapping getBeginMapping() {
0986:                return (ActionMapping) moduleConfig
0987:                        .findActionConfig(BEGIN_ACTION_PATH);
0988:            }
0989:
0990:            private static String makeRedirectedRequestAttrsKey(
0991:                    String webappRelativeURI, String hash) {
0992:                return REDIRECT_REQUEST_ATTRS_PREFIX + hash + webappRelativeURI;
0993:            }
0994:
0995:            private static void rethrowUnhandledException(UnhandledException ex)
0996:                    throws ServletException {
0997:                Throwable rootCause = ex.getRootCause();
0998:
0999:                //
1000:                // We shouldn't (and don't need to) wrap Errors or RuntimeExceptions.
1001:                //
1002:                if (rootCause instanceof  Error) {
1003:                    throw (Error) rootCause;
1004:                } else if (rootCause instanceof  RuntimeException) {
1005:                    throw (RuntimeException) rootCause;
1006:                }
1007:
1008:                throw ex;
1009:            }
1010:
1011:            public ActionForward processException(HttpServletRequest request,
1012:                    HttpServletResponse response, Exception ex,
1013:                    ActionForm form, ActionMapping mapping) throws IOException,
1014:                    ServletException {
1015:                //
1016:                // Note: we should only get here if FlowController.handleException itself throws an exception, or if the user
1017:                // has merged in Struts code that delegates to an action/exception-handler outside of the pageflow.
1018:                //
1019:                // If this is an UnhandledException thrown from FlowController.handleException, don't try to re-handle it here.
1020:                //
1021:
1022:                if (ex instanceof  UnhandledException) {
1023:                    rethrowUnhandledException((UnhandledException) ex);
1024:                    assert false; // rethrowUnhandledException always throws something.
1025:                    return null;
1026:                } else {
1027:                    return super .processException(request, response, ex, form,
1028:                            mapping);
1029:                }
1030:            }
1031:
1032:            /**
1033:             * Used by {@link PageFlowRequestProcessor#processMapping}.  Its main job is to return
1034:             * {@link ExceptionHandledAction} as the type.
1035:             */
1036:            protected static class ExceptionHandledActionMapping extends
1037:                    ActionMapping {
1038:                private ActionForward _fwd;
1039:
1040:                public ExceptionHandledActionMapping(String actionPath,
1041:                        ActionForward fwd) {
1042:                    setPath(actionPath);
1043:                    _fwd = fwd;
1044:                }
1045:
1046:                public String getType() {
1047:                    return ExceptionHandledAction.class.getName();
1048:                }
1049:
1050:                public ActionForward getActionForward() {
1051:                    return _fwd;
1052:                }
1053:
1054:                public boolean getValidate() {
1055:                    return false;
1056:                }
1057:            }
1058:
1059:            /**
1060:             * Used by {@link PageFlowRequestProcessor#processMapping}.  This action simply returns the ActionForward stored in the
1061:             * ExceptionHandledActionMapping that's passed in.
1062:             */
1063:            public static class ExceptionHandledAction extends Action {
1064:                public ActionForward execute(ActionMapping mapping,
1065:                        ActionForm form, HttpServletRequest request,
1066:                        HttpServletResponse response) {
1067:                    assert mapping instanceof  ExceptionHandledActionMapping : mapping
1068:                            .getClass().getName();
1069:
1070:                    return ((ExceptionHandledActionMapping) mapping)
1071:                            .getActionForward();
1072:                }
1073:            }
1074:
1075:            private boolean isCorrectFormType(Class formBeanClass,
1076:                    ActionMapping mapping) {
1077:                assert mapping.getName() != null : "cannot pass an ActionMapping that has no form bean";
1078:                Class cachedFormBeanClass = (Class) _formBeanClasses
1079:                        .get(mapping.getName());
1080:                return isCorrectFormType(formBeanClass, cachedFormBeanClass,
1081:                        mapping);
1082:            }
1083:
1084:            private boolean isCorrectFormType(Class formBeanClass,
1085:                    Class actionMappingFormBeanClass, ActionMapping mapping) {
1086:                if (actionMappingFormBeanClass != null) {
1087:                    return actionMappingFormBeanClass
1088:                            .isAssignableFrom(formBeanClass);
1089:                } else {
1090:                    //
1091:                    // The form bean class couldn't be loaded at init time -- just check against the class name.
1092:                    //
1093:                    FormBeanConfig mappingFormBean = moduleConfig
1094:                            .findFormBeanConfig(mapping.getName());
1095:                    String formClassName = formBeanClass.getName();
1096:
1097:                    if (mappingFormBean != null
1098:                            && mappingFormBean.getType().equals(formClassName))
1099:                        return true;
1100:
1101:                    if (mapping instanceof  PageFlowActionMapping) {
1102:                        String desiredType = ((PageFlowActionMapping) mapping)
1103:                                .getFormClass();
1104:                        if (formClassName.equals(desiredType))
1105:                            return true;
1106:                    }
1107:                }
1108:
1109:                return false;
1110:            }
1111:
1112:            private ActionMapping checkTransaction(HttpServletRequest request,
1113:                    HttpServletResponse response, ActionMapping mapping,
1114:                    String actionPath) throws IOException {
1115:                if (mapping instanceof  PageFlowActionMapping
1116:                        && ((PageFlowActionMapping) mapping)
1117:                                .isPreventDoubleSubmit()) {
1118:                    if (!TokenProcessor.getInstance().isTokenValid(request,
1119:                            true)) {
1120:                        FlowController currentFC = PageFlowRequestWrapper.get(
1121:                                request).getCurrentFlowController();
1122:                        String actionName = InternalUtils
1123:                                .getActionName(mapping);
1124:                        DoubleSubmitException ex = new DoubleSubmitException(
1125:                                actionName, currentFC);
1126:
1127:                        if (currentFC != null) {
1128:                            try {
1129:                                ActionForward fwd = currentFC.handleException(
1130:                                        ex, mapping, null, request, response);
1131:                                return new ExceptionHandledActionMapping(
1132:                                        actionPath, fwd);
1133:                            } catch (ServletException servletException) {
1134:                                LOG.error("Exception occurred while handling "
1135:                                        + ex.getClass().getName(),
1136:                                        servletException);
1137:                            }
1138:                        }
1139:
1140:                        ex.sendResponseErrorCode(response);
1141:                        return null;
1142:                    }
1143:                }
1144:
1145:                return mapping;
1146:            }
1147:
1148:            public void init(ActionServlet actionServlet, ModuleConfig mc)
1149:                    throws ServletException {
1150:                super .init(actionServlet, mc);
1151:
1152:                ServletContext servletContext = getServletContext();
1153:
1154:                //
1155:                // Cache a reference to the ServletContainerAdapter, the Handlers, and the LegacySettings.
1156:                //
1157:                _servletContainerAdapter = AdapterManager
1158:                        .getServletContainerAdapter(servletContext);
1159:                _legacySettings = LegacySettings.get(servletContext);
1160:                _handlers = Handlers.get(servletContext);
1161:                _flowControllerFactory = FlowControllerFactory
1162:                        .get(servletContext);
1163:
1164:                // Initialize delegating action mappings and exception configs.
1165:                InternalUtils.initDelegatingConfigs(mc, servletContext);
1166:
1167:                // Cache a list of overloaded actions for each overloaded action path (actions are overloaded by form bean type).
1168:                cacheOverloadedActionMappings();
1169:
1170:                // Cache the form bean Classes by form bean name.
1171:                cacheFormClasses();
1172:
1173:                // Initialize the request interceptors and action interceptors.
1174:                ActionInterceptorContext.init(servletContext);
1175:                RequestInterceptorContext.init(servletContext);
1176:
1177:                ensurePageServletFilter();
1178:                assert _pageServletFilter != null;
1179:            }
1180:
1181:            private void cacheOverloadedActionMappings() {
1182:                ActionConfig[] actionConfigs = moduleConfig.findActionConfigs();
1183:
1184:                for (int i = 0; i < actionConfigs.length; i++) {
1185:                    ActionConfig actionConfig = actionConfigs[i];
1186:
1187:                    if (actionConfig instanceof  PageFlowActionMapping) {
1188:                        PageFlowActionMapping mapping = (PageFlowActionMapping) actionConfig;
1189:                        String unqualifiedActionPath = ((PageFlowActionMapping) actionConfig)
1190:                                .getUnqualifiedActionPath();
1191:
1192:                        if (unqualifiedActionPath != null) {
1193:                            List/*< ActionMapping >*/overloaded = (List) _overloadedActions
1194:                                    .get(unqualifiedActionPath);
1195:
1196:                            if (overloaded == null) {
1197:                                overloaded = new ArrayList/*< ActionMapping >*/();
1198:                                _overloadedActions.put(unqualifiedActionPath,
1199:                                        overloaded);
1200:                            }
1201:
1202:                            overloaded.add(mapping);
1203:                        }
1204:                    }
1205:                }
1206:            }
1207:
1208:            private void cacheFormClasses() {
1209:                FormBeanConfig[] formBeans = moduleConfig.findFormBeanConfigs();
1210:                ReloadableClassHandler rch = _handlers
1211:                        .getReloadableClassHandler();
1212:
1213:                for (int i = 0; i < formBeans.length; i++) {
1214:                    FormBeanConfig formBeanConfig = formBeans[i];
1215:                    String formType = InternalUtils
1216:                            .getFormBeanType(formBeanConfig);
1217:
1218:                    try {
1219:                        Class formBeanClass = rch.loadClass(formType);
1220:                        _formBeanClasses.put(formBeanConfig.getName(),
1221:                                formBeanClass);
1222:                    } catch (ClassNotFoundException e) {
1223:                        LOG.error("Could not load class " + formType
1224:                                + " referenced from form bean config "
1225:                                + formBeanConfig.getName()
1226:                                + " in Struts module " + moduleConfig);
1227:                    }
1228:                }
1229:            }
1230:
1231:            /**
1232:             * Read component instance mapping configuration file.
1233:             * This is where we read files properties.
1234:             */
1235:
1236:            protected void initDefinitionsMapping() throws ServletException {
1237:                definitionsFactory = null;
1238:                TilesUtilImpl tilesUtil = TilesUtil.getTilesUtil();
1239:
1240:                if (tilesUtil instanceof  TilesUtilStrutsImpl) {
1241:                    // Retrieve and set factory for this modules
1242:                    definitionsFactory = ((TilesUtilStrutsImpl) tilesUtil)
1243:                            .getDefinitionsFactory(getServletContext(),
1244:                                    moduleConfig);
1245:
1246:                    if (definitionsFactory == null && log.isDebugEnabled()) {
1247:                        log.debug("Definition Factory not found for module: '"
1248:                                + moduleConfig.getPrefix());
1249:                    }
1250:                }
1251:            }
1252:
1253:            public ActionMapping processMapping(HttpServletRequest request,
1254:                    HttpServletResponse response, String path)
1255:                    throws IOException {
1256:                PageFlowRequestWrapper rw = PageFlowRequestWrapper.get(request);
1257:                FlowController fc = rw.getCurrentFlowController();
1258:                Object forwardedForm = InternalUtils
1259:                        .unwrapFormBean(InternalUtils.getForwardedFormBean(
1260:                                request, false));
1261:
1262:                //
1263:                // First, see if this is a request for a shared flow action.  The shared flow's name (as declared by the
1264:                // current page flow) will precede the dot.
1265:                //
1266:                if (fc != null
1267:                        && !processSharedFlowMapping(request, response, path,
1268:                                fc))
1269:                    return null;
1270:
1271:                //
1272:                // Look for a form-specific action path.  This is used when there are two actions with the same
1273:                // name, but different forms (in nesting).
1274:                //
1275:                Class forwardedFormClass = null;
1276:
1277:                if (forwardedForm != null) {
1278:                    forwardedFormClass = forwardedForm.getClass();
1279:                    List/*< ActionMapping >*/possibleMatches = (List) _overloadedActions
1280:                            .get(path);
1281:                    ActionMapping bestMatch = null;
1282:
1283:                    //
1284:                    // Troll through the overloaded actions for the given path.  Look for the one whose form bean class is
1285:                    // exactly the class of the forwarded form; failing that, look for one that's assignable from the class
1286:                    // of the forwarded form.
1287:                    //
1288:                    for (int i = 0; possibleMatches != null
1289:                            && i < possibleMatches.size(); ++i) {
1290:                        ActionMapping possibleMatch = (ActionMapping) possibleMatches
1291:                                .get(i);
1292:                        assert possibleMatch instanceof  PageFlowActionMapping : possibleMatch
1293:                                .getClass();
1294:                        Class cachedFormBeanClass = (Class) _formBeanClasses
1295:                                .get(possibleMatch.getName());
1296:
1297:                        if (forwardedFormClass.equals(cachedFormBeanClass)) {
1298:                            bestMatch = possibleMatch;
1299:                            break;
1300:                        }
1301:                        if (bestMatch == null
1302:                                && isCorrectFormType(forwardedFormClass,
1303:                                        possibleMatch)) {
1304:                            bestMatch = possibleMatch;
1305:                        }
1306:                    }
1307:
1308:                    if (bestMatch != null) {
1309:                        request.setAttribute(Globals.MAPPING_KEY, bestMatch);
1310:
1311:                        if (LOG.isDebugEnabled()) {
1312:                            LOG.debug("Found form-specific action mapping "
1313:                                    + bestMatch.getPath() + " for " + path
1314:                                    + ", form " + forwardedFormClass.getName());
1315:                        }
1316:
1317:                        return checkTransaction(request, response, bestMatch,
1318:                                path);
1319:                    }
1320:                }
1321:
1322:                //
1323:                // Look for a directly-defined mapping for this path.
1324:                //
1325:                ActionMapping mapping = (ActionMapping) moduleConfig
1326:                        .findActionConfig(path);
1327:
1328:                if (mapping != null) {
1329:                    boolean wrongForm = false;
1330:
1331:                    //
1332:                    // We're going to bail out if there is a forwarded form and this mapping requires a different form type.
1333:                    //
1334:                    if (forwardedForm != null) {
1335:                        boolean mappingHasNoFormBean = mapping.getName() == null;
1336:                        wrongForm = mappingHasNoFormBean
1337:                                || !isCorrectFormType(forwardedFormClass,
1338:                                        mapping);
1339:                    }
1340:
1341:                    if (!wrongForm) {
1342:                        request.setAttribute(Globals.MAPPING_KEY, mapping);
1343:                        return checkTransaction(request, response, mapping,
1344:                                path);
1345:                    }
1346:                }
1347:
1348:                //
1349:                // Look for a mapping for "unknown" paths
1350:                //
1351:                ActionMapping unknown = getUnknownActionFromConfig(moduleConfig);
1352:                if (unknown != null) {
1353:                    request.setAttribute(Globals.MAPPING_KEY, unknown);
1354:                    return checkTransaction(request, response, unknown, path);
1355:                }
1356:
1357:                // If we haven't already tried this action on a shared flow or on Global.app, see if it's in the Global.app
1358:                // module.  If it is, forward to it.  (Global.app is a deprecated fallback for unhandled actions.)
1359:                String errorServletPath = rw.getOriginalServletPath();
1360:                ModuleConfig globalApp = null;
1361:
1362:                if (errorServletPath == null
1363:                        && (globalApp = InternalUtils.ensureModuleConfig(
1364:                                GLOBALAPP_MODULE_CONTEXT_PATH,
1365:                                getServletContext())) != null
1366:                        && (globalApp.findActionConfig(path) != null || getUnknownActionFromConfig(globalApp) != null)) {
1367:
1368:                    if (LOG.isDebugEnabled()) {
1369:                        LOG.debug("Trying Global.app for unhandled action "
1370:                                + path);
1371:                    }
1372:
1373:                    errorServletPath = InternalUtils
1374:                            .getDecodedServletPath(request);
1375:                    rw.setOriginalServletPath(errorServletPath);
1376:                    String globalAppURI = GLOBALAPP_MODULE_CONTEXT_PATH + path
1377:                            + ACTION_EXTENSION;
1378:                    try {
1379:                        doForward(globalAppURI, request, response);
1380:                    } catch (ServletException e) {
1381:                        LOG.error("Could not forward to Global.app path "
1382:                                + globalAppURI);
1383:                    }
1384:                    return null;
1385:                } else {
1386:                    // If we are currently returning from nesting, then it is possible that the given action may actually be
1387:                    // found in a page flow that's farther down the nesting stack.  This can happen when the browser back button
1388:                    // is used; see http://issues.apache.org/jira/browse/BEEHIVE-1024 .
1389:                    //
1390:                    // In this case, we simply forward to the action in the page flow in which it is found.  The runtime will
1391:                    // take care of popping page flows until the right instance is made the current page flow.
1392:                    if (rw.isReturningFromNesting()) {
1393:                        ModuleConfig found = PageFlowStack.get(request,
1394:                                getServletContext()).findActionInStack(path);
1395:
1396:                        if (found != null) {
1397:                            String servletPath = found.getPrefix() + path
1398:                                    + ACTION_EXTENSION;
1399:
1400:                            try {
1401:                                doForward(servletPath, request, response);
1402:                            } catch (ServletException e) {
1403:                                LOG.error("Could not forward to path "
1404:                                        + servletPath);
1405:                            }
1406:                            return null;
1407:                        }
1408:                    }
1409:
1410:                    // If the error action path has a slash in it, then it's not local to the current page flow.  Replace
1411:                    // it with the original servlet path.
1412:                    if (errorServletPath != null && path.indexOf('/') > 0)
1413:                        path = errorServletPath;
1414:                    return processUnresolvedAction(path, request, response,
1415:                            forwardedForm);
1416:                }
1417:            }
1418:
1419:            private ActionMapping getUnknownActionFromConfig(ModuleConfig mc) {
1420:                ActionConfig configs[] = mc.findActionConfigs();
1421:                for (int i = 0; i < configs.length; i++) {
1422:                    if (configs[i].getUnknown()) {
1423:                        return (ActionMapping) configs[i];
1424:                    }
1425:                }
1426:                return null;
1427:            }
1428:
1429:            protected boolean processSharedFlowMapping(
1430:                    HttpServletRequest request, HttpServletResponse response,
1431:                    String actionPath, FlowController currentFlowController)
1432:                    throws IOException {
1433:                if (currentFlowController.isPageFlow()) {
1434:                    int dot = actionPath.indexOf('.');
1435:
1436:                    if (dot != -1) {
1437:                        Map/*< String, SharedFlowController >*/sharedFlows = PageFlowUtils
1438:                                .getSharedFlows(request);
1439:                        if (sharedFlows == null)
1440:                            return true;
1441:                        if (dot == actionPath.length() - 1)
1442:                            return true; // empty action name
1443:                        assert actionPath.length() > 0
1444:                                && actionPath.charAt(0) == '/' : actionPath;
1445:                        String sharedFlowName = actionPath.substring(1, dot);
1446:                        SharedFlowController sf = (SharedFlowController) sharedFlows
1447:                                .get(sharedFlowName);
1448:
1449:                        if (sf != null) {
1450:                            if (LOG.isDebugEnabled()) {
1451:                                LOG.debug("Forwarding to shared flow "
1452:                                        + sf.getDisplayName()
1453:                                        + " to handle action \"" + actionPath
1454:                                        + "\".");
1455:                            }
1456:
1457:                            //
1458:                            // Save the original request URI, so if the action fails on the shared flow, too, then we can
1459:                            // give an error message that includes *this* URI, not the shared flow URI.
1460:                            //
1461:                            PageFlowRequestWrapper
1462:                                    .get(request)
1463:                                    .setOriginalServletPath(
1464:                                            InternalUtils
1465:                                                    .getDecodedServletPath(request));
1466:
1467:                            //
1468:                            // Construct a URI that is [shared flow module path] + [base action path] + [action-extension (.do)]
1469:                            //
1470:                            int lastSlash = actionPath.lastIndexOf('/');
1471:                            assert lastSlash != -1 : actionPath;
1472:                            InternalStringBuilder uri = new InternalStringBuilder(
1473:                                    sf.getModulePath());
1474:                            uri.append('/');
1475:                            uri.append(actionPath.substring(dot + 1));
1476:                            uri.append(ACTION_EXTENSION);
1477:
1478:                            try {
1479:                                doForward(uri.toString(), request, response);
1480:                                return false;
1481:                            } catch (ServletException e) {
1482:                                LOG.error(
1483:                                        "Could not forward to shared flow URI "
1484:                                                + uri, e);
1485:                            }
1486:                        }
1487:                    }
1488:                }
1489:
1490:                return true;
1491:            }
1492:
1493:            protected ActionMapping processUnresolvedAction(String actionPath,
1494:                    HttpServletRequest request, HttpServletResponse response,
1495:                    Object returningForm) throws IOException {
1496:                if (LOG.isInfoEnabled()) {
1497:                    InternalStringBuilder msg = new InternalStringBuilder(
1498:                            "Action \"").append(actionPath);
1499:                    LOG.info(msg.append("\" was also unhandled by Global.app.")
1500:                            .toString());
1501:                }
1502:
1503:                //
1504:                // If there's a PageFlowController for this request, try and let it handle an
1505:                // action-not-found exception.  Otherwise, let Struts print out its "invalid path"
1506:                // message.
1507:                //
1508:                FlowController fc = PageFlowUtils.getCurrentPageFlow(request,
1509:                        getServletContext());
1510:
1511:                try {
1512:                    if (fc != null) {
1513:                        Exception ex = new ActionNotFoundException(actionPath,
1514:                                fc, returningForm);
1515:                        InternalUtils.setCurrentModule(fc.getModuleConfig(),
1516:                                request);
1517:                        ActionForward result = fc.handleException(ex, null,
1518:                                null, request, response);
1519:                        return new ExceptionHandledActionMapping(actionPath,
1520:                                result);
1521:                    }
1522:                } catch (ServletException e) {
1523:                    // ignore this -- just let Struts do its thing.
1524:
1525:                    if (LOG.isDebugEnabled()) {
1526:                        LOG.debug(e);
1527:                    }
1528:                }
1529:
1530:                if (LOG.isDebugEnabled()) {
1531:                    LOG
1532:                            .debug("Couldn't handle an ActionNotFoundException -- delegating to Struts");
1533:                }
1534:
1535:                return super .processMapping(request, response, actionPath);
1536:            }
1537:
1538:            protected boolean processRoles(HttpServletRequest request,
1539:                    HttpServletResponse response, ActionMapping mapping)
1540:                    throws IOException, ServletException {
1541:                //
1542:                // If there are no required roles for this action, just return.
1543:                //
1544:                String roles[] = mapping.getRoleNames();
1545:                if (roles == null || roles.length < 1) {
1546:                    return true;
1547:                }
1548:
1549:                // Check the current user against the list of required roles
1550:                FlowController fc = PageFlowRequestWrapper.get(request)
1551:                        .getCurrentFlowController();
1552:                FlowControllerHandlerContext context = new FlowControllerHandlerContext(
1553:                        request, response, fc);
1554:
1555:                for (int i = 0; i < roles.length; i++) {
1556:                    if (_handlers.getLoginHandler().isUserInRole(context,
1557:                            roles[i])) {
1558:                        if (LOG.isDebugEnabled()) {
1559:                            LOG.debug(" User " + request.getRemoteUser()
1560:                                    + " has role '" + roles[i]
1561:                                    + "', granting access");
1562:                        }
1563:
1564:                        return true;
1565:                    }
1566:                }
1567:
1568:                // The current user is not authorized for this action
1569:                if (LOG.isDebugEnabled()) {
1570:                    LOG
1571:                            .debug(" User '"
1572:                                    + request.getRemoteUser()
1573:                                    + "' does not have any required role, denying access");
1574:                }
1575:
1576:                //
1577:                // Here, Struts sends an HTTP error.  We try to let the current page flow handle a relevant exception.
1578:                //
1579:                LoginHandler loginHandler = _handlers.getLoginHandler();
1580:                String actionName = InternalUtils.getActionName(mapping);
1581:                FlowController currentFC = PageFlowRequestWrapper.get(request)
1582:                        .getCurrentFlowController();
1583:                PageFlowException ex;
1584:
1585:                if (loginHandler.getUserPrincipal(context) == null) {
1586:                    ex = currentFC.createNotLoggedInException(actionName,
1587:                            request);
1588:                } else {
1589:                    ex = new UnfulfilledRolesException(mapping.getRoleNames(),
1590:                            mapping.getRoles(), actionName, currentFC);
1591:                }
1592:
1593:                if (currentFC != null) {
1594:                    ActionForward fwd = currentFC.handleException(ex, mapping,
1595:                            null, request, response);
1596:                    processForwardConfig(request, response, fwd);
1597:                } else {
1598:                    ((ResponseErrorCodeSender) ex)
1599:                            .sendResponseErrorCode(response);
1600:                }
1601:
1602:                return false;
1603:            }
1604:
1605:            private static String addScopeParams(String url,
1606:                    HttpServletRequest request) {
1607:                //
1608:                // If the current request is scoped, add the right request parameter to the URL.
1609:                //
1610:                String scopeID = request
1611:                        .getParameter(ScopedServletUtils.SCOPE_ID_PARAM);
1612:                if (scopeID != null) {
1613:                    return InternalUtils.addParam(url,
1614:                            ScopedServletUtils.SCOPE_ID_PARAM, scopeID);
1615:                } else {
1616:                    return url;
1617:                }
1618:            }
1619:
1620:            /**
1621:             * This override of the base method ensures that absolute URIs don't get the context
1622:             * path prepended, and handles forwards to special things like return-to="currentPage".
1623:             */
1624:            protected void processForwardConfig(HttpServletRequest request,
1625:                    HttpServletResponse response, ForwardConfig fwd)
1626:                    throws IOException, ServletException {
1627:                ServletContext servletContext = getServletContext();
1628:                ForwardRedirectHandler fwdRedirectHandler = _handlers
1629:                        .getForwardRedirectHandler();
1630:                FlowController fc = PageFlowRequestWrapper.get(request)
1631:                        .getCurrentFlowController();
1632:                FlowControllerHandlerContext context = new FlowControllerHandlerContext(
1633:                        request, response, fc);
1634:
1635:                // Register this module as the one that's handling the action.
1636:                if (fc != null) {
1637:                    InternalUtils.setForwardingModule(request, fc
1638:                            .getModulePath());
1639:                }
1640:
1641:                //
1642:                // The following is similar to what's in super.processForwardConfig(), but it avoids putting
1643:                // a slash in front of absolute URLs (e.g., ones that start with "http:").
1644:                //
1645:                if (fwd != null) {
1646:                    if (LOG.isDebugEnabled())
1647:                        LOG.debug("processForwardConfig(" + fwd + ')');
1648:
1649:                    //
1650:                    // Try to process a tiles definition. If the forward doesn't contain a
1651:                    // a tiles definition, continue on.
1652:                    //
1653:                    if (processTilesDefinition(fwd.getPath(), fwd
1654:                            .getContextRelative(), request, response)) {
1655:                        if (log.isDebugEnabled()) {
1656:                            log.debug("  '" + fwd.getPath()
1657:                                    + "' - processed as definition");
1658:                        }
1659:                        return;
1660:                    }
1661:
1662:                    //
1663:                    // If this is a "special" page flow forward, create a Forward to handle it and pass
1664:                    // it to the current page flow.  This should only happen when processValidate()
1665:                    // calls this method (or if a plain Struts action forwards to this forward) --
1666:                    // otherwise, the page flow should be using a Forward already.
1667:                    //
1668:                    if (fwd instanceof  PageFlowActionForward) {
1669:                        ActionMapping mapping = (ActionMapping) request
1670:                                .getAttribute(Globals.MAPPING_KEY);
1671:                        assert mapping != null;
1672:                        ActionForm form = InternalUtils.getFormBean(mapping,
1673:                                request);
1674:                        Forward pfFwd = new Forward((ActionForward) fwd,
1675:                                servletContext);
1676:                        ActionForwardHandler handler = _handlers
1677:                                .getActionForwardHandler();
1678:                        fwd = handler.processForward(context, pfFwd, mapping,
1679:                                null, InternalUtils.getActionName(mapping),
1680:                                null, form);
1681:                    }
1682:
1683:                    String path = fwd.getPath();
1684:                    boolean startsWithSlash = path.length() > 0
1685:                            && path.charAt(0) == '/';
1686:
1687:                    //
1688:                    // If the URI is absolute (e.g., starts with "http:"), do a redirect to it no matter what.
1689:                    //
1690:                    if (FileUtils.isAbsoluteURI(path)) {
1691:                        fwdRedirectHandler.redirect(context, addScopeParams(
1692:                                path, request));
1693:                    } else if (fwd.getRedirect()) {
1694:                        String redirectURI;
1695:
1696:                        if (startsWithSlash && fwd instanceof  Forward
1697:                                && ((Forward) fwd).isExplicitPath()) {
1698:                            redirectURI = path;
1699:                        } else if (fwd instanceof  Forward
1700:                                && ((Forward) fwd).isExternalRedirect()) {
1701:                            assert startsWithSlash : path; // compiler should ensure path starts with '/'
1702:                            redirectURI = path;
1703:                        } else {
1704:                            redirectURI = request.getContextPath()
1705:                                    + RequestUtils.forwardURL(request, fwd);
1706:                        }
1707:
1708:                        fwdRedirectHandler.redirect(context, addScopeParams(
1709:                                redirectURI, request));
1710:                    } else {
1711:                        String fwdURI;
1712:
1713:                        if (startsWithSlash && fwd instanceof  Forward
1714:                                && ((Forward) fwd).isExplicitPath()) {
1715:                            fwdURI = path;
1716:                        } else {
1717:                            fwdURI = RequestUtils.forwardURL(request, fwd);
1718:
1719:                            //
1720:                            // First, see if the current module is a Shared Flow module.  If so, unless this is a forward to
1721:                            // another action in the shared flow, we need to translate the local path so it makes sense (strip
1722:                            // off the shared flow module prefix "/-" and replace it with "/").
1723:                            //
1724:                            ModuleConfig mc = (ModuleConfig) request
1725:                                    .getAttribute(Globals.MODULE_KEY);
1726:
1727:                            if (InternalUtils.isSharedFlowModule(mc)
1728:                                    && !fwdURI.endsWith(ACTION_EXTENSION)
1729:                                    && fwdURI
1730:                                            .startsWith(SHARED_FLOW_MODULE_PREFIX)) {
1731:                                fwdURI = '/' + fwdURI
1732:                                        .substring(SHARED_FLOW_MODULE_PREFIX_LEN);
1733:                            }
1734:                        }
1735:
1736:                        doForward(fwdURI, request, response);
1737:                    }
1738:                }
1739:            }
1740:
1741:            protected boolean changeScheme(String webappRelativeURI,
1742:                    String scheme, int port,
1743:                    FlowControllerHandlerContext context)
1744:                    throws URISyntaxException, IOException, ServletException {
1745:                if (port == -1) {
1746:                    if (LOG.isWarnEnabled()) {
1747:                        LOG
1748:                                .warn("Could not change the scheme to "
1749:                                        + scheme
1750:                                        + " because the relevant port was not provided "
1751:                                        + "by the ServletContainerAdapter.");
1752:                        return false;
1753:                    }
1754:                }
1755:
1756:                //
1757:                // First put all request attributes into the session, so they can be added to the
1758:                // redirected request.
1759:                //
1760:                Map attrs = new HashMap();
1761:                String queryString = null;
1762:                ServletContext servletContext = getServletContext();
1763:                HttpServletRequest request = ((RequestContext) context)
1764:                        .getHttpRequest();
1765:
1766:                for (Enumeration e = request.getAttributeNames(); e
1767:                        .hasMoreElements();) {
1768:                    String name = (String) e.nextElement();
1769:                    attrs.put(name, request.getAttribute(name));
1770:                }
1771:
1772:                if (!attrs.isEmpty()) {
1773:                    String hash = Integer.toString(request.hashCode());
1774:                    String key = makeRedirectedRequestAttrsKey(
1775:                            webappRelativeURI, hash);
1776:                    request.getSession().setAttribute(key, attrs);
1777:                    queryString = URLRewriterService.getNamePrefix(
1778:                            servletContext, request,
1779:                            REDIRECT_REQUEST_ATTRS_PARAM)
1780:                            + REDIRECT_REQUEST_ATTRS_PARAM + '=' + hash;
1781:                }
1782:
1783:                //
1784:                // Now do the redirect.
1785:                //
1786:                URI redirectURI = new URI(scheme, null,
1787:                        request.getServerName(), port, request.getContextPath()
1788:                                + webappRelativeURI, queryString, null);
1789:
1790:                ForwardRedirectHandler fwdRedirectHandler = _handlers
1791:                        .getForwardRedirectHandler();
1792:                fwdRedirectHandler.redirect(context, redirectURI.toString());
1793:
1794:                if (LOG.isDebugEnabled()) {
1795:                    LOG.debug("Redirected to " + redirectURI);
1796:                }
1797:
1798:                return true;
1799:            }
1800:
1801:            /**
1802:             * @deprecated Use {@link LegacySettings#shouldDoSecureForwards} instead.
1803:             */
1804:            protected boolean shouldDoSecureForwards() {
1805:                return _legacySettings.shouldDoSecureForwards();
1806:            }
1807:
1808:            protected void doForward(String uri, HttpServletRequest request,
1809:                    HttpServletResponse response) throws IOException,
1810:                    ServletException {
1811:                boolean securityRedirected = false;
1812:                ServletContext servletContext = getServletContext();
1813:                PageFlowRequestWrapper wrappedRequest = PageFlowRequestWrapper
1814:                        .get(request);
1815:
1816:                //
1817:                // As in the TilesRequestProcessor.doForward(), if the response has already been commited,
1818:                // do an include instead.
1819:                //
1820:                if (!wrappedRequest.isScopedLookup() && response.isCommitted()) {
1821:                    doInclude(uri, request, response);
1822:                    return;
1823:                }
1824:
1825:                FlowController fc = wrappedRequest.getCurrentFlowController();
1826:                FlowControllerHandlerContext context = new FlowControllerHandlerContext(
1827:                        request, response, fc);
1828:
1829:                if (_legacySettings.shouldDoSecureForwards()) {
1830:                    SecurityProtocol sp = PageFlowUtils.getSecurityProtocol(
1831:                            uri, servletContext, request);
1832:
1833:                    if (!sp.equals(SecurityProtocol.UNSPECIFIED)) {
1834:                        try {
1835:                            if (request.isSecure()) {
1836:                                if (sp.equals(SecurityProtocol.UNSECURE)) {
1837:                                    int listenPort = _servletContainerAdapter
1838:                                            .getListenPort(request);
1839:                                    securityRedirected = changeScheme(uri,
1840:                                            SCHEME_UNSECURE, listenPort,
1841:                                            context);
1842:                                }
1843:                            } else {
1844:                                if (sp.equals(SecurityProtocol.SECURE)) {
1845:                                    int secureListenPort = _servletContainerAdapter
1846:                                            .getSecureListenPort(request);
1847:                                    securityRedirected = changeScheme(uri,
1848:                                            SCHEME_SECURE, secureListenPort,
1849:                                            context);
1850:                                }
1851:                            }
1852:                        } catch (URISyntaxException e) {
1853:                            LOG.error("Bad forward URI " + uri, e);
1854:                        }
1855:                    }
1856:                }
1857:
1858:                if (!securityRedirected) {
1859:                    if (!processPageForward(uri, request, response)) {
1860:                        ForwardRedirectHandler fwdRedirectHandler = _handlers
1861:                                .getForwardRedirectHandler();
1862:                        fwdRedirectHandler.forward(context, uri);
1863:                    }
1864:                }
1865:            }
1866:
1867:            /**
1868:             * An opportunity to process a page forward in a different way than performing a server forward.  The default
1869:             * implementation looks for a file on classpath called
1870:             * META-INF/pageflow-page-servlets/<i>path-to-page</i>.properties (e.g.,
1871:             * "/META-INF/pageflow-page-servlets/foo/bar/hello.jsp.properties").  This file contains mappings from
1872:             * <i>platform-name</i> (the value returned by {@link ServletContainerAdapter#getPlatformName}) to the name of a Servlet
1873:             * class that will process the page request.  If the current platform name is not found, the value "default" is
1874:             * tried.  An example file might look like this:
1875:             * <pre>
1876:             *     tomcat=org.apache.jsp.foo.bar.hello_jsp
1877:             *     default=my.servlets.foo.bar.hello
1878:             * </pre>
1879:             * @param pagePath the webapp-relative path to the page, e.g., "/foo/bar/hello.jsp"
1880:             * @param request the current HttpServletRequest
1881:             * @param response the current HttpServletResponse
1882:             * @return <code>true</code> if the method handled the request, in which case it should not be forwarded.
1883:             * @throws IOException
1884:             * @throws ServletException
1885:             */
1886:            private boolean processPageForward(String pagePath,
1887:                    HttpServletRequest request, HttpServletResponse response)
1888:                    throws IOException, ServletException {
1889:                Class pageServletClass = (Class) _pageServletClasses
1890:                        .get(pagePath);
1891:
1892:                if (pageServletClass == null) {
1893:                    pageServletClass = Void.class;
1894:                    ClassLoader cl = DiscoveryUtils.getClassLoader();
1895:                    String path = "META-INF/pageflow-page-servlets" + pagePath
1896:                            + ".properties";
1897:                    InputStream in = cl.getResourceAsStream(path);
1898:
1899:                    if (in != null) {
1900:                        String className = null;
1901:
1902:                        try {
1903:                            Properties props = new Properties();
1904:                            props.load(in);
1905:                            className = props
1906:                                    .getProperty(_servletContainerAdapter
1907:                                            .getPlatformName());
1908:                            if (className == null)
1909:                                className = props.getProperty("default");
1910:
1911:                            if (className != null) {
1912:                                pageServletClass = cl.loadClass(className);
1913:
1914:                                if (Servlet.class
1915:                                        .isAssignableFrom(pageServletClass)) {
1916:                                    if (LOG.isInfoEnabled()) {
1917:                                        LOG.info("Loaded page Servlet class "
1918:                                                + className + " for path "
1919:                                                + pagePath);
1920:                                    }
1921:                                } else {
1922:                                    pageServletClass = Void.class;
1923:                                    LOG.error("Page Servlet class " + className
1924:                                            + " for path " + pagePath
1925:                                            + " does not extend "
1926:                                            + Servlet.class.getName());
1927:                                }
1928:                            }
1929:                        } catch (IOException e) {
1930:                            LOG.error("Error while reading " + path, e);
1931:                        } catch (ClassNotFoundException e) {
1932:                            LOG.error("Error while loading page Servlet class "
1933:                                    + className, e);
1934:                        }
1935:                    }
1936:
1937:                    _pageServletClasses.put(pagePath, pageServletClass);
1938:                }
1939:
1940:                if (pageServletClass.equals(Void.class)) {
1941:                    return false;
1942:                }
1943:
1944:                try {
1945:                    Servlet pageServlet = (Servlet) pageServletClass
1946:                            .newInstance();
1947:                    pageServlet.init(new PageServletConfig(pagePath));
1948:
1949:                    ensurePageServletFilter().doFilter(request, response,
1950:                            new PageServletFilterChain(pageServlet));
1951:                    return true;
1952:                } catch (InstantiationException e) {
1953:                    LOG.error("Error while instantiating page Servlet of type "
1954:                            + pageServletClass.getName(), e);
1955:                } catch (IllegalAccessException e) {
1956:                    LOG.error("Error while instantiating page Servlet of type "
1957:                            + pageServletClass.getName(), e);
1958:                }
1959:
1960:                return false;
1961:            }
1962:
1963:            // todo: why does the framework create a subclass of the page flow page filter here?
1964:            private class PageServletFilter extends PageFlowPageFilter {
1965:                public PageServletFilter() {
1966:                    super (getServletContext());
1967:                }
1968:
1969:                /**
1970:                 * Accept all file extensions.
1971:                 * @return the set of acceptable file extensions
1972:                 */
1973:                protected Set getValidFileExtensions() {
1974:                    return null; // accept all
1975:                }
1976:            }
1977:
1978:            /**
1979:             * Used by {@link PageFlowRequestProcessor#processPageForward} to run a page Servlet.
1980:             */
1981:            private static class PageServletFilterChain implements  FilterChain {
1982:                private Servlet _pageServlet;
1983:
1984:                public PageServletFilterChain(Servlet pageServlet) {
1985:                    _pageServlet = pageServlet;
1986:                }
1987:
1988:                public void doFilter(ServletRequest request,
1989:                        ServletResponse response) throws IOException,
1990:                        ServletException {
1991:                    _pageServlet.service(request, response);
1992:                }
1993:            }
1994:
1995:            /**
1996:             * Used by {@link PageFlowRequestProcessor#processPageForward} to initialize a page Servlet.
1997:             */
1998:            private class PageServletConfig implements  ServletConfig {
1999:                private String _pagePath;
2000:
2001:                public PageServletConfig(String pagePath) {
2002:                    _pagePath = pagePath;
2003:                }
2004:
2005:                public String getServletName() {
2006:                    return _pagePath;
2007:                }
2008:
2009:                public ServletContext getServletContext() {
2010:                    return PageFlowRequestProcessor.this .getServletContext();
2011:                }
2012:
2013:                public String getInitParameter(String s) {
2014:                    return null;
2015:                }
2016:
2017:                public Enumeration getInitParameterNames() {
2018:                    return Collections.enumeration(Collections.EMPTY_LIST);
2019:                }
2020:            }
2021:
2022:            /**
2023:             * Set the no-cache headers.  This overrides the base Struts behavior to prevent caching even for the pages.
2024:             */
2025:            protected void processNoCache(HttpServletRequest request,
2026:                    HttpServletResponse response) {
2027:                //
2028:                // Set the no-cache headers if:
2029:                //    1) the module is configured for it, or
2030:                //    2) netui-config.xml has an "always" value for <pageflow-config><prevent-cache>, or
2031:                //    3) netui-config.xml has an "inDevMode" value for <pageflow-config><prevent-cache>, and we're not in
2032:                //       production mode.
2033:                //
2034:                boolean noCache = moduleConfig.getControllerConfig()
2035:                        .getNocache();
2036:
2037:                if (!noCache) {
2038:                    PageFlowConfig pfConfig = ConfigUtil.getConfig()
2039:                            .getPageFlowConfig();
2040:
2041:                    if (pfConfig != null) {
2042:                        PreventCache preventCache = pfConfig.getPreventCache();
2043:
2044:                        if (preventCache != null) {
2045:                            switch (preventCache.getValue()) {
2046:                            case PreventCache.INT_ALWAYS:
2047:                                noCache = true;
2048:                                break;
2049:                            case PreventCache.INT_IN_DEV_MODE:
2050:                                noCache = !_servletContainerAdapter
2051:                                        .isInProductionMode();
2052:                                break;
2053:                            }
2054:                        }
2055:                    }
2056:                }
2057:
2058:                if (noCache) {
2059:                    //
2060:                    // The call to PageFlowPageFilter.preventCache() will cause caching to be prevented
2061:                    // even when we end up forwarding to a page.  Normally, no-cache headers are lost
2062:                    // when a server forward occurs.
2063:                    //
2064:                    ServletUtils.preventCache(response);
2065:                    PageFlowUtils.setPreventCache(request);
2066:                }
2067:            }
2068:
2069:            private class ActionRunner implements 
2070:                    ActionInterceptors.ActionExecutor {
2071:                RequestInterceptorContext _ctxt;
2072:                private Action _action;
2073:                private ActionForm _formBean;
2074:                private ActionMapping _actionMapping;
2075:
2076:                public ActionRunner(RequestInterceptorContext context,
2077:                        Action action, ActionForm formBean,
2078:                        ActionMapping actionMapping) {
2079:                    _ctxt = context;
2080:                    _action = action;
2081:                    _formBean = formBean;
2082:                    _actionMapping = actionMapping;
2083:                }
2084:
2085:                public ActionForward execute() throws InterceptorException,
2086:                        ServletException, IOException {
2087:                    return PageFlowRequestProcessor.super .processActionPerform(
2088:                            _ctxt.getRequest(), _ctxt.getResponse(), _action,
2089:                            _formBean, _actionMapping);
2090:                }
2091:            }
2092:
2093:            protected ActionForward processActionPerform(
2094:                    HttpServletRequest request, HttpServletResponse response,
2095:                    Action action, ActionForm form, ActionMapping mapping)
2096:                    throws IOException, ServletException {
2097:                ServletContext servletContext = getServletContext();
2098:                String actionName = InternalUtils.getActionName(mapping);
2099:                ActionInterceptorContext context = null;
2100:                List/*< Interceptor >*/interceptors = null;
2101:
2102:                if (action instanceof  FlowControllerAction) {
2103:                    FlowController fc = ((FlowControllerAction) action)
2104:                            .getFlowController();
2105:
2106:                    if (fc instanceof  PageFlowController) {
2107:                        PageFlowController pfc = (PageFlowController) fc;
2108:                        context = new ActionInterceptorContext(request,
2109:                                response, servletContext, pfc, null, actionName);
2110:                        interceptors = context.getActionInterceptors();
2111:                    }
2112:                }
2113:
2114:                if (interceptors != null && interceptors.size() == 0)
2115:                    interceptors = null;
2116:
2117:                try {
2118:                    //
2119:                    // Run any pre-action interceptors.
2120:                    //
2121:                    if (interceptors != null
2122:                            && !PageFlowRequestWrapper.get(request)
2123:                                    .isReturningFromActionIntercept()) {
2124:                        Interceptors.doPreIntercept(context, interceptors);
2125:
2126:                        if (context.hasInterceptorForward()) {
2127:                            InterceptorForward fwd = context
2128:                                    .getInterceptorForward();
2129:
2130:                            if (LOG.isDebugEnabled()) {
2131:
2132:                                Interceptor overridingInterceptor = context
2133:                                        .getOverridingInterceptor();
2134:                                StringBuffer msg = new StringBuffer();
2135:                                msg.append("Action interceptor ");
2136:                                msg.append(overridingInterceptor.getClass()
2137:                                        .getName());
2138:                                msg.append(" before action ");
2139:                                msg.append(actionName);
2140:                                msg.append(": forwarding to ");
2141:                                msg.append(fwd != null ? fwd.getPath()
2142:                                        : "null [no forward]");
2143:                                LOG.debug(msg.toString());
2144:                            }
2145:
2146:                            return fwd;
2147:                        }
2148:                    } else {
2149:                        PageFlowRequestWrapper.get(request)
2150:                                .setReturningFromActionIntercept(false);
2151:                    }
2152:
2153:                    //
2154:                    // Execute the action.
2155:                    //
2156:                    RequestInterceptorContext requestContext = context != null ? context
2157:                            : new RequestInterceptorContext(request, response,
2158:                                    getServletContext());
2159:                    ActionRunner actionExecutor = new ActionRunner(
2160:                            requestContext, action, form, mapping);
2161:                    ActionForward ret = ActionInterceptors.wrapAction(context,
2162:                            interceptors, actionExecutor);
2163:
2164:                    //
2165:                    // Run any post-action interceptors.
2166:                    //
2167:                    if (interceptors != null) {
2168:                        context.setOriginalForward(ret);
2169:                        Interceptors.doPostIntercept(context, interceptors);
2170:
2171:                        if (context.hasInterceptorForward()) {
2172:                            InterceptorForward fwd = context
2173:                                    .getInterceptorForward();
2174:
2175:                            if (LOG.isDebugEnabled()) {
2176:                                LOG
2177:                                        .debug("Action interceptor "
2178:                                                + context
2179:                                                        .getOverridingInterceptor()
2180:                                                        .getClass().getName()
2181:                                                + " after action " + actionName
2182:                                                + ": forwarding to " + fwd != null ? fwd
2183:                                                .getPath()
2184:                                                : "null [no forward]");
2185:                            }
2186:
2187:                            return fwd;
2188:                        }
2189:                    }
2190:
2191:                    return ret;
2192:                } catch (InterceptorException e) {
2193:                    ServletUtils.throwServletException(e);
2194:                }
2195:
2196:                // should not get here -- either a value is returned or an exception is thrown.
2197:                assert false;
2198:                return null;
2199:            }
2200:
2201:            void doActionForward(HttpServletRequest request,
2202:                    HttpServletResponse response, ActionForward forward)
2203:                    throws IOException, ServletException {
2204:                request = PageFlowRequestWrapper.wrapRequest(request);
2205:                processForwardConfig(request, response, forward);
2206:            }
2207:
2208:            protected boolean processValidate(HttpServletRequest request,
2209:                    HttpServletResponse response, ActionForm form,
2210:                    ActionMapping mapping) throws IOException,
2211:                    ServletException, InvalidCancelException {
2212:
2213:                //
2214:                // The raw Struts ActionForm doesn't have our logic for enabling declarative validation annotations.
2215:                // If this is what we have, create a wrapper that extends FormData to process validation annotations,
2216:                // but will also invoke the ActionForm's validate().
2217:                //
2218:                if (form != null && !(form instanceof  BaseActionForm)) {
2219:                    ActionForm originalForm = form;
2220:                    form = new ActionFormValidationWrapper(originalForm);
2221:                    form.setServlet(servlet);
2222:                    form.setMultipartRequestHandler(originalForm
2223:                            .getMultipartRequestHandler());
2224:                }
2225:
2226:                return super .processValidate(request, response, form, mapping);
2227:            }
2228:
2229:            /**
2230:             * Internal method used to ensure that the PageServletFilter is available for use by the request processor.
2231:             * If serialization has occurred, this object is transient in this class and may need to be recreated.
2232:             * @return the page servlet filter
2233:             */
2234:            private PageFlowPageFilter ensurePageServletFilter() {
2235:                if (_pageServletFilter == null)
2236:                    _pageServletFilter = new PageServletFilter();
2237:
2238:                return _pageServletFilter;
2239:            }
2240:
2241:            private static class ActionFormValidationWrapper extends
2242:                    BaseActionForm {
2243:                private ActionForm _actionForm;
2244:
2245:                public ActionFormValidationWrapper(ActionForm actionForm) {
2246:                    _actionForm = actionForm;
2247:                }
2248:
2249:                public ActionErrors validate(ActionMapping mapping,
2250:                        HttpServletRequest request) {
2251:                    return validateBean(_actionForm, mapping.getAttribute(),
2252:                            mapping, request);
2253:                }
2254:
2255:                protected ActionErrors getAdditionalActionErrors(
2256:                        ActionMapping mapping, HttpServletRequest request) {
2257:                    return _actionForm.validate(mapping, request);
2258:                }
2259:            }
2260:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.