You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@struts.apache.org by mr...@apache.org on 2005/08/26 07:46:58 UTC

svn commit: r240168 [17/30] - in /struts/sandbox/trunk/ti: ./ core/src/java/org/apache/ti/ core/src/java/org/apache/ti/config/ core/src/java/org/apache/ti/config/mapper/ core/src/java/org/apache/ti/core/ core/src/java/org/apache/ti/core/factory/ core/s...

Added: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/xwork/NavigateToResult.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/xwork/NavigateToResult.java?rev=240168&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/xwork/NavigateToResult.java (added)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/xwork/NavigateToResult.java Thu Aug 25 22:46:03 2005
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * $Header:$
+ */
+package org.apache.ti.pageflow.xwork;
+
+import org.apache.ti.pageflow.Forward;
+import org.apache.ti.pageflow.PreviousInfo;
+
+public abstract class NavigateToResult extends PageFlowResult {
+
+    protected String getQueryString(Forward pageFlowFwd, PreviousInfo previousInfo) {
+        String query = pageFlowFwd.getQueryString();
+        if (query == null) query = "";
+        
+        //
+        // If the restoreQueryString attribute was set, use the query string from the original action URI.
+        //
+        boolean restoreQueryString = isRestoreQueryString();
+        if (restoreQueryString) {
+            String prevQuery = previousInfo.getQueryString();
+            if (prevQuery != null) query += (query.length() > 0 ? "&" : "?") + prevQuery;
+        }
+
+        return query;
+    }
+
+    public abstract String getNavigateToAsString();
+}

Added: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/xwork/PageFlowAction.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/xwork/PageFlowAction.java?rev=240168&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/xwork/PageFlowAction.java (added)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/xwork/PageFlowAction.java Thu Aug 25 22:46:03 2005
@@ -0,0 +1,558 @@
+/*
+ * Copyright 2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * $Header:$
+ */
+package org.apache.ti.pageflow.xwork;
+
+import com.opensymphony.xwork.Action;
+import org.apache.ti.Globals;
+import org.apache.ti.core.urls.URLRewriterService;
+import org.apache.ti.pageflow.ContainerAdapter;
+import org.apache.ti.pageflow.FlowController;
+import org.apache.ti.pageflow.Forward;
+import org.apache.ti.pageflow.ModuleConfig;
+import org.apache.ti.pageflow.PageFlowController;
+import org.apache.ti.pageflow.PageFlowEventReporter;
+import org.apache.ti.pageflow.PageFlowException;
+import org.apache.ti.pageflow.PageFlowUtils;
+import org.apache.ti.pageflow.handler.Handlers;
+import org.apache.ti.pageflow.interceptor.Interceptor;
+import org.apache.ti.pageflow.interceptor.InterceptorException;
+import org.apache.ti.pageflow.interceptor.Interceptors;
+import org.apache.ti.pageflow.interceptor.action.ActionInterceptorContext;
+import org.apache.ti.pageflow.interceptor.action.InterceptorForward;
+import org.apache.ti.pageflow.interceptor.action.internal.ActionInterceptors;
+import org.apache.ti.pageflow.interceptor.request.RequestInterceptorContext;
+import org.apache.ti.pageflow.internal.AdapterManager;
+import org.apache.ti.pageflow.internal.DefaultURLRewriter;
+import org.apache.ti.pageflow.internal.InternalUtils;
+import org.apache.ti.pageflow.internal.UnhandledException;
+import org.apache.ti.script.common.ImplicitObjectUtil;
+import org.apache.ti.util.logging.Logger;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+
+/**
+ * Bean class to handle our extensions to the Struts <action> element.
+ */
+public class PageFlowAction implements Action, Serializable {
+
+    private static final long serialVersionUID = 1;
+    private static final Logger _log = Logger.getInstance(PageFlowAction.class);
+
+    private String _unqualifiedActionPath;
+    private boolean _loginRequired = false;
+    private boolean _preventDoubleSubmit = false;
+    private boolean _simpleAction = false;
+    private boolean _isOverloaded = false;
+    private String _formMember;
+    private String _formBeanType;
+    private String _formBeanAttribute;  // the attribute under which the form bean will be stored
+    private boolean _readonly = false;
+    private Map/*< String, String >*/ _conditionalForwards = new LinkedHashMap/*< String, String >*/();
+    private String _formBeanMessageResourcesKey;
+    private String _defaultForward;
+    private String _validationErrorForward;
+
+    public String getUnqualifiedActionPath() {
+        return _unqualifiedActionPath;
+    }
+
+    public final void setUnqualifiedActionPath(String unqualifiedActionPath) {
+        _unqualifiedActionPath = unqualifiedActionPath;
+    }
+
+    public final boolean isLoginRequired() {
+        return _loginRequired;
+    }
+
+    public void setLoginRequired(boolean loginRequired) {
+        _loginRequired = loginRequired;
+    }
+
+    public boolean isPreventDoubleSubmit() {
+        return _preventDoubleSubmit;
+    }
+
+    public void setPreventDoubleSubmit(boolean preventDoubleSubmit) {
+        _preventDoubleSubmit = preventDoubleSubmit;
+    }
+
+    public boolean isSimpleAction() {
+        return _simpleAction;
+    }
+
+    public void setSimpleAction(boolean simpleAction) {
+        _simpleAction = simpleAction;
+    }
+
+    public boolean isOverloaded() {
+        return _isOverloaded;
+    }
+
+    public void setOverloaded(boolean overloaded) {
+        _isOverloaded = overloaded;
+    }
+
+    public String getFormMember() {
+        return _formMember;
+    }
+
+    public void setFormMember(String formMember) {
+        _formMember = formMember;
+    }
+
+    public String getFormBeanType() {
+        return _formBeanType;
+    }
+
+    public void setFormBeanType(String formBeanType) {
+        _formBeanType = formBeanType;
+    }
+
+    public boolean isReadonly() {
+        return _readonly;
+    }
+
+    public void setReadonly(boolean readonly) {
+        _readonly = readonly;
+    }
+
+    public String getValidationErrorForward() {
+        return _validationErrorForward;
+    }
+
+    public void setValidationErrorForward(String validationErrorForward) {
+        _validationErrorForward = validationErrorForward;
+    }
+
+    public void setConditionalForwards(String conditionalForwards) {
+        String[] pairs = conditionalForwards.split(";");
+
+        for (int i = 0; i < pairs.length; i++) {
+            String pair = pairs[i];
+            int delim = pair.indexOf(':');
+            assert delim != -1 : pair;
+            String forwardName = pair.substring(0, delim);
+            String expression = pair.substring(delim + 1);
+            _conditionalForwards.put(expression, forwardName);
+        }
+    }
+
+    /**
+     * Get a map of expression -> forward-name.  If the expression evaluates to <code>true</code> the forward is used.
+     */
+    public Map/*< String, String >*/ getConditionalForwardsMap() {
+        return _conditionalForwards;
+    }
+
+    public String getFormBeanMessageResourcesKey() {
+        return _formBeanMessageResourcesKey;
+    }
+
+    public void setFormBeanMessageResourcesKey(String formBeanMessageResourcesKey) {
+        _formBeanMessageResourcesKey = formBeanMessageResourcesKey;
+    }
+
+    public String getDefaultForward() {
+        return _defaultForward;
+    }
+
+    public void setDefaultForward(String defaultForward) {
+        _defaultForward = defaultForward;
+    }
+
+    public String getFormBeanAttribute() {
+        return _formBeanAttribute;
+    }
+
+    public void setFormBeanAttribute(String formBeanAttribute) {
+        _formBeanAttribute = formBeanAttribute;
+    }
+
+    private static int requestNumber = 0;
+
+
+    /**
+     * <p>Automatically select a <code>Locale</code> for the current user, if requested.
+     * <strong>NOTE</strong> - configuring Locale selection will trigger
+     * the creation of a new <code>HttpSession</code> if necessary.</p>
+     */
+    protected void processLocale() {
+
+        // Has a Locale already been selected?
+        PageFlowActionContext actionContext = PageFlowActionContext.get();
+        Map sessionScope = actionContext.getSession();
+        if (sessionScope.get(Globals.LOCALE_KEY) != null) {
+            return;
+        }
+        
+        // Use the Locale returned by the servlet container (if any)
+        Locale locale = actionContext.getLocale();
+        if (locale != null) {
+            if (_log.isDebugEnabled()) {
+                _log.debug("Setting user locale '" + locale + '\'');
+            }
+            sessionScope.put(Globals.LOCALE_KEY, locale);
+        }
+
+    }
+
+    private void processInternal()
+            throws IOException, PageFlowException {
+        //
+        // The requested action can be overridden by a request parameter.  In this case, we parse the action from
+        // the request parameter and forward to a URI constructed from it.  If this happens, just return.
+        //
+        // TODO: re-add this, in Chain
+//        if ( processActionOverride() ) return;
+        
+        //
+        // Process any direct request for a page flow by forwarding to its "begin" action.
+        //
+        // TODO: re-add this
+//        if ( processPageFlowRequest( request, response, uri ) ) return;
+        
+        PageFlowActionContext actionContext = PageFlowActionContext.get();        
+        
+        //
+        // Remove any current JavaServer Faces backing bean.  We have "left" any JSF page and are now processing a
+        // Page Flow action.
+        //
+        InternalUtils.removeCurrentFacesBackingBean();
+        
+        //
+        // Set up implicit objects used by the expression language in simple actions and in declarative validation.
+        //
+        ImplicitObjectUtil.loadImplicitObjects(PageFlowUtils.getCurrentPageFlow());
+
+        try {
+            // Select a Locale for the current user if requested
+            // TODO: re-add Locale-choosing, in Chain
+            // processLocale();
+            
+            // Check for any role required to perform this action
+            // TODO: re-add roles, in Chain
+//        if (!processRoles(request, response, mapping)) {
+//            return;
+//        }
+            
+            // TODO: re-add login-required support, in Chain
+            
+            // TODO: re-add action form creation (store in context), population and validation (in Chain)
+            // Process any ActionForm bean related to this request
+//        ActionForm form = processActionForm(request, response, mapping);
+//        processPopulate(request, response, form, mapping);
+//        if (!processValidate(request, response, form, mapping)) {
+//            return;
+//        }
+            
+            // Call the action instance itself
+            Forward forward = processActionPerform();
+            actionContext.setForward(forward);
+        } catch (UnhandledException unhandledException) {
+            // If we get here, then we've already tried to find an exception handler.  Just throw.
+            rethrowUnhandledException(unhandledException);
+        } catch (PageFlowException servletEx) {
+            // If a PageFlowException escapes out of any of the processing methods, let the current FlowController handle it.
+            FlowController currentFlowController = actionContext.getFlowController();
+            if (!handleException(servletEx, currentFlowController)) throw servletEx;
+        } catch (IOException ioe) {
+            // If an IOException escapes out of any of the processing methods, let the current FlowController handle it.
+            FlowController currentFlowController = actionContext.getFlowController();
+            if (!handleException(ioe, currentFlowController)) throw ioe;
+        } catch (Throwable th) {
+            // If a Throwable escapes out of any of the processing methods, let the current FlowController handle it.
+            FlowController currentFlowController = actionContext.getFlowController();
+            if (!handleException(th, currentFlowController)) {
+                if (th instanceof Error) throw (Error) th;
+                throw new PageFlowException(th);
+            }
+        }
+    }
+
+    private boolean handleException(Throwable th, FlowController fc) {
+        if (fc != null) {
+            try {
+                Forward fwd = fc.handleException(th);
+                PageFlowActionContext.get().setForward(fwd);
+                return true;
+            } catch (UnhandledException unhandledException) {
+                if (_log.isInfoEnabled()) {
+                    _log.info("This exception was unhandled by any exception handler.", unhandledException);
+                }
+
+                return false;
+            } catch (Throwable t) {
+                _log.error("Exception while handling exception " + th.getClass().getName()
+                        + ".  The original exception will be thrown.", t);
+                return false;
+            }
+        }
+
+        return false;
+    }
+
+    public String execute() throws Exception {
+        int localRequestCount = -1;
+
+        if (_log.isTraceEnabled()) {
+            localRequestCount = ++requestNumber;
+            _log.trace("------------------------------- Start Request #" + localRequestCount
+                    + " -----------------------------------");
+        }
+        
+        //
+        // First reinitialize the reloadable class handler.  This will bounce a classloader if necessary.
+        //
+        Handlers.get().getReloadableClassHandler().reloadClasses();
+        
+        //
+        // Go through the chain of pre-request interceptors.
+        //
+        RequestInterceptorContext context = new RequestInterceptorContext();
+        List/*< Interceptor >*/ interceptors = context.getRequestInterceptors();
+
+        try {
+            Interceptors.doPreIntercept(context, interceptors);
+
+            if (context.requestWasCancelled()) {
+                if (_log.isDebugEnabled()) {
+                    _log.debug("Interceptor " + context.getOverridingInterceptor() + " cancelled the request.");
+                }
+
+                return null;
+            }
+        } catch (InterceptorException e) {
+            throw new PageFlowException(e);
+        }
+        
+        //
+        // Callback to the server adapter.
+        //
+        ContainerAdapter containerAdapter = AdapterManager.getContainerAdapter();
+        PageFlowEventReporter er = containerAdapter.getEventReporter();
+        containerAdapter.beginRequest();
+        er.beginActionRequest();
+        long startTime = System.currentTimeMillis();
+        
+        //
+        // Initialize the ControlBeanContext in the session.
+        //
+        // TODO: re-add Controls support
+        // JavaControlUtils.initializeControlContext( request, response, servletContext );
+        
+        //
+        // Register the default URLRewriter
+        //
+        URLRewriterService.registerURLRewriter(0, new DefaultURLRewriter());
+
+        try {
+            processInternal();
+        } finally {
+            //
+            // Clean up the ControlBeanContext in the session.
+            //
+            // TODO: re-add Controls support
+            // JavaControlUtils.uninitializeControlContext( request, response, getServletContext() );
+            
+            //
+            // Callback to the server adapter.
+            //
+            containerAdapter.endRequest();
+            long timeTaken = System.currentTimeMillis() - startTime;
+            er.endActionRequest(timeTaken);
+        }
+        
+        //
+        // Go through the chain of pre-request interceptors.
+        //
+        try {
+            Interceptors.doPostIntercept(context, interceptors);
+        } catch (InterceptorException e) {
+            throw new PageFlowException(e);
+        }
+
+        if (_log.isTraceEnabled()) {
+            _log.trace("-------------------------------- End Request #" + localRequestCount
+                    + " ------------------------------------");
+        }
+
+        Forward fwd = PageFlowActionContext.get().getForward();
+        return fwd != null ? fwd.getName() : null;
+    }
+
+    private static final void rethrowUnhandledException(UnhandledException ex)
+            throws PageFlowException {
+        Throwable rootCause = ex.getCause();
+        
+        //
+        // We shouldn't (and don't need to) wrap Errors or RuntimeExceptions.
+        //
+        if (rootCause instanceof Error) {
+            throw (Error) rootCause;
+        } else if (rootCause instanceof RuntimeException) {
+            throw (RuntimeException) rootCause;
+        }
+
+        throw ex;
+    }
+
+    public Forward processException(Exception ex, Object form, PageFlowAction mapping)
+            throws IOException, PageFlowException {
+        //
+        // Note: we should only get here if FlowController.handleException itself throws an exception, or if the user
+        // has merged in Struts code that delegates to an action/exception-handler outside of the pageflow.
+        //
+        // If this is an UnhandledException thrown from FlowController.handleException, don't try to re-handle it here.
+        //
+        
+        if (ex instanceof UnhandledException) {
+            rethrowUnhandledException((UnhandledException) ex);
+            assert false;   // rethrowUnhandledException always throws something.
+            return null;
+        } else {
+            throw new PageFlowException(ex);
+        }
+    }
+
+    public void init()
+            throws PageFlowException {
+        //
+        // Cache a list of overloaded actions for each overloaded action path (actions are overloaded by form bean type).
+        //
+        // TODO: re-add overloaded action support
+//        cacheOverloadedPageFlowActions();
+        
+        //
+        // Cache the form bean Classes by form bean name.
+        //
+        // TODO: re-add class caching?
+//        cacheFormClasses();
+    }
+
+
+    private static class ActionRunner
+            implements ActionInterceptors.ActionExecutor {
+
+        public ActionRunner() {
+        }
+
+        public Forward execute()
+                throws InterceptorException, PageFlowException {
+
+            PageFlowActionContext actionContext = PageFlowActionContext.get();
+            return actionContext.getFlowController().execute();
+        }
+    }
+
+    protected Forward processActionPerform()
+            throws IOException, PageFlowException {
+        PageFlowActionContext actionContext = PageFlowActionContext.get();
+        String actionName = actionContext.getName();
+        ActionInterceptorContext context = null;
+        List/*< Interceptor >*/ interceptors = null;
+
+        FlowController fc = actionContext.getFlowController();
+
+        if (fc instanceof PageFlowController) {
+            PageFlowController pfc = (PageFlowController) fc;
+            context = new ActionInterceptorContext(pfc, null, actionName);
+            interceptors = context.getActionInterceptors();
+        }
+
+        if (interceptors != null && interceptors.size() == 0) interceptors = null;
+
+        try {
+            //
+            // Run any before-action interceptors.
+            //
+            if (interceptors != null && !actionContext.isReturningFromActionIntercept()) {
+                Interceptors.doPreIntercept(context, interceptors);
+
+                if (context.hasInterceptorForward()) {
+                    InterceptorForward fwd = context.getInterceptorForward();
+
+                    if (_log.isDebugEnabled()) {
+
+                        Interceptor overridingInterceptor = context.getOverridingInterceptor();
+                        StringBuffer msg = new StringBuffer();
+                        msg.append("action interceptor ");
+                        msg.append(overridingInterceptor.getClass().getName());
+                        msg.append(" before action ");
+                        msg.append(actionName);
+                        msg.append(": forwarding to ");
+                        msg.append(fwd != null ? fwd.getPath() : "null [no forward]");
+                        _log.debug(msg.toString());
+                    }
+
+                    return fwd;
+                }
+            } else {
+                actionContext.setReturningFromActionIntercept(false);
+            }
+            
+            //
+            // Execute the action.
+            //
+            ActionRunner actionExecutor = new ActionRunner();
+            Forward ret = ActionInterceptors.wrapAction(context, interceptors, actionExecutor);
+            
+            //
+            // Run any after-action interceptors.
+            //
+            if (interceptors != null) {
+                context.setOriginalForward(ret);
+                Interceptors.doPostIntercept(context, interceptors);
+
+                if (context.hasInterceptorForward()) {
+                    InterceptorForward fwd = context.getInterceptorForward();
+
+                    if (_log.isDebugEnabled()) {
+                        _log.debug("action interceptor " + context.getOverridingInterceptor().getClass().getName()
+                                + " after action " + actionName + ": forwarding to "
+                                + fwd != null ? fwd.getPath() : "null [no forward]");
+                    }
+
+                    return fwd;
+                }
+            }
+
+            return ret;
+        } catch (InterceptorException e) {
+            throw new PageFlowException(e);
+        }
+    }
+
+    public String findExceptionHandler(Class exceptionType) {
+        PageFlowActionContext actionContext = PageFlowActionContext.get();
+        ModuleConfig mc = actionContext.getModuleConfig();
+        String actionName = actionContext.getName();
+
+        for (Class i = exceptionType; i != null; i = i.getSuperclass()) {
+            String handlerName = actionName + ':' + i.getName();
+            if (mc.findActionConfig(handlerName) != null) return handlerName;
+        }
+
+        return mc.findExceptionHandler(exceptionType);
+    }
+}

Added: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/xwork/PageFlowActionContext.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/xwork/PageFlowActionContext.java?rev=240168&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/xwork/PageFlowActionContext.java (added)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/xwork/PageFlowActionContext.java Thu Aug 25 22:46:03 2005
@@ -0,0 +1,337 @@
+/*
+ * Copyright 2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * $Header:$
+ */
+package org.apache.ti.pageflow.xwork;
+
+import com.opensymphony.xwork.ActionContext;
+import com.opensymphony.xwork.ActionInvocation;
+import org.apache.commons.chain.web.WebContext;
+import org.apache.ti.config.mapper.ActionMapper;
+import org.apache.ti.config.mapper.ActionMapping;
+import org.apache.ti.pageflow.FlowController;
+import org.apache.ti.pageflow.Forward;
+import org.apache.ti.pageflow.ModuleConfig;
+import org.apache.ti.pageflow.PreviousPageInfo;
+import org.apache.ti.pageflow.internal.InternalConstants;
+import org.apache.ti.pageflow.internal.ViewRenderer;
+import org.apache.ti.util.SourceResolver;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Map;
+
+public class PageFlowActionContext extends ActionContext {
+
+    private static final String STATE_KEY = InternalConstants.ATTR_PREFIX + "contextState";
+    private static final String FLOW_CONTROLLER_KEY = InternalConstants.ATTR_PREFIX + "flowController";
+    private static final String FORWARD_KEY = InternalConstants.ATTR_PREFIX + "forward";
+    private static final String FORM_BEAN_KEY = InternalConstants.ATTR_PREFIX + "formBean";
+
+    /**
+     * This is state that needs to be transferred all the way through a chain of requests.
+     */
+    private static final class State {
+
+        public Integer forwardedRequestCount;
+        public String originalServletPath;
+        public ViewRenderer viewRenderer;
+        public PreviousPageInfo previousPageInfo;
+        public boolean returningFromActionIntercept = false;
+        public String pageFlowScopedFormName;
+        public boolean processPopulateAlreadyCalled = false;
+        //public MultipartRequestWrapper multipartRequestWrapper;
+        public Throwable exceptionBeingHandled = null;
+        public boolean stayInCurrentModule = false;
+        public ModuleConfig moduleConfig;
+    }
+
+    private FlowController _removingFlowController;
+    private WebContext _webContext;
+
+    // TODO: currently these are initialized externally.  Instead we could have specific implementations of this class.
+    private String _requestPath;
+    private String _requestContextPath;
+    private String _requestQueryString;
+    private boolean _requestSecure;
+
+
+    private SourceResolver _sourceResolver;
+
+    public static PageFlowActionContext get() {
+        return (PageFlowActionContext) ActionContext.getContext();
+    }
+
+    public PageFlowActionContext(Map context, WebContext webContext) {
+        super(context);
+        _webContext = webContext;
+
+
+        State state = (State) _webContext.getRequestScope().get(STATE_KEY);
+        if (state == null) {
+            state = new State();
+            _webContext.getRequestScope().put(STATE_KEY, state);
+        }
+    }
+
+    public WebContext getWebContext() {
+        return _webContext;
+    }
+
+    public PageFlowAction getAction() {
+        ActionInvocation actionInvocation = getActionInvocation();
+        return actionInvocation != null ? (PageFlowAction) getActionInvocation().getAction() : null;
+    }
+
+    public boolean isNestedRequest() {
+        return getState().forwardedRequestCount != null;
+    }
+
+    public int getForwardedRequestCount() {
+        return getState().forwardedRequestCount != null ? getState().forwardedRequestCount.intValue() : 0;
+    }
+
+    public void setForwardedRequestCount(int count) {
+        getState().forwardedRequestCount = new Integer(count);
+    }
+
+    public String getOriginalServletPath() {
+        return getState().originalServletPath;
+    }
+
+    public void setOriginalServletPath(String originalServletPath) {
+        getState().originalServletPath = originalServletPath;
+    }
+
+    public FlowController getFlowController() {
+        return (FlowController) get(FLOW_CONTROLLER_KEY);
+    }
+
+    public void setCurrentFlowController(FlowController currentFlowController) {
+        put(FLOW_CONTROLLER_KEY, currentFlowController);
+    }
+
+    public ViewRenderer getViewRenderer() {
+        return getState().viewRenderer;
+    }
+
+    public void setViewRenderer(ViewRenderer viewRenderer) {
+        getState().viewRenderer = viewRenderer;
+    }
+
+    public PreviousPageInfo getPreviousPageInfo(boolean remove) {
+        PreviousPageInfo retVal = getState().previousPageInfo;
+        if (remove) getState().previousPageInfo = null;
+        return retVal;
+    }
+
+    public void setPreviousPageInfo(PreviousPageInfo previousPageInfo) {
+        getState().previousPageInfo = previousPageInfo;
+    }
+
+    public boolean isReturningFromActionIntercept() {
+        return getState().returningFromActionIntercept;
+    }
+
+    public void setReturningFromActionIntercept(boolean returningFromActionIntercept) {
+        getState().returningFromActionIntercept = returningFromActionIntercept;
+    }
+
+    public String getPageFlowScopedFormName() {
+        return getState().pageFlowScopedFormName;
+    }
+
+    public void setPageFlowScopedFormName(String pageFlowScopedFormName) {
+        getState().pageFlowScopedFormName = pageFlowScopedFormName;
+    }
+
+    public boolean isProcessPopulateAlreadyCalled() {
+        return getState().processPopulateAlreadyCalled;
+    }
+
+    public void setProcessPopulateAlreadyCalled(boolean processPopulateAlreadyCalled) {
+        getState().processPopulateAlreadyCalled = processPopulateAlreadyCalled;
+    }
+
+    /*
+    public MultipartRequestWrapper getMultipartRequestWrapper()
+    {
+        return getState().multipartRequestWrapper;
+    }
+    
+    public void setMultipartRequestWrapper( MultipartRequestWrapper multipartRequestWrapper )
+    {
+        getState().multipartRequestWrapper = multipartRequestWrapper;
+    }
+    */
+    
+    public boolean isStayInCurrentModule() {
+        return getState().stayInCurrentModule;
+    }
+
+    public void setStayInCurrentModule(boolean stayInCurrentModule) {
+        getState().stayInCurrentModule = stayInCurrentModule;
+    }
+
+    public Throwable getExceptionBeingHandled() {
+        return getState().exceptionBeingHandled;
+    }
+
+    public void setExceptionBeingHandled(Throwable th) {
+        getState().exceptionBeingHandled = th;
+    }
+
+    private State getState() {
+        return (State) _webContext.getRequestScope().get(STATE_KEY);
+    }
+
+    public URL getResource(String resourcePath)
+            throws IOException, MalformedURLException {
+        return _sourceResolver.resolve(resourcePath, _webContext);
+    }
+
+    public Map getRequestScope() {
+        return _webContext.getRequestScope();
+    }
+
+    public final Map getSession() {
+        return _webContext.getSessionScope();
+    }
+
+    public final Map getApplication() {
+        return _webContext.getApplicationScope();
+    }
+
+    public Map getSessionScope() {
+        return _webContext.getSessionScope();
+    }
+
+    public Map getApplicationScope() {
+        return _webContext.getApplicationScope();
+    }
+
+    /**
+     * Get the namespace for the current request.
+     */
+    public String getNamespace() {
+        ModuleConfig moduleConfig = getState().moduleConfig;
+        return moduleConfig != null ? moduleConfig.getNamespace() : null;
+    }
+
+    public void setModuleConfig(ModuleConfig moduleConfig) {
+        getState().moduleConfig = moduleConfig;
+    }
+
+    public ModuleConfig getModuleConfig() {
+        return getState().moduleConfig;
+    }
+
+    public String getRequestPath() {
+        return _requestPath;
+    }
+
+    public void setRequestPath(String requestPath) {
+        _requestPath = requestPath;
+    }
+
+    public String getRequestContextPath() {
+        return _requestContextPath;
+    }
+
+    public void setRequestContextPath(String requestContextPath) {
+        _requestContextPath = requestContextPath;
+    }
+
+    public String getRequestQueryString() {
+        return _requestQueryString;
+    }
+
+    public void setRequestQueryString(String requestQueryString) {
+        _requestQueryString = requestQueryString;
+    }
+
+    public boolean isRequestSecure() {
+        return _requestSecure;
+    }
+
+    public void setRequestSecure(boolean requestSecure) {
+        _requestSecure = requestSecure;
+    }
+
+    public String getRequestURI() {
+        return getRequestContextPath() + getRequestPath();
+    }
+
+    /**
+     * Get a request scope that is specific to an outer (e.g., outside-of-portlet request).
+     */
+    public Map getOuterRequestScope() {
+        // TODO: implement this differently for portal/portlet support
+        return getRequestScope();
+    }
+
+    /**
+     * Get a request scope that is specific to an inner (e.g., portlet request), and which does not allow outer
+     * request attributes to show through.
+     */
+    public Map getInnerRequestScope() {
+        // TODO: implement this differently for portal/portlet support
+        return getRequestScope();
+    }
+
+    public Forward getForward() {
+        return (Forward) get(FORWARD_KEY);
+    }
+
+    public void setForward(Forward forward) {
+        put(FORWARD_KEY, forward);
+    }
+
+    public Object getFormBean() {
+        return get(FORM_BEAN_KEY);
+    }
+
+    public void setFormBean(Object formBean) {
+        put(FORM_BEAN_KEY, formBean);
+    }
+
+    public SourceResolver getSourceResolver() {
+        return _sourceResolver;
+    }
+
+    public void setSourceResolver(SourceResolver sourceResolver) {
+        _sourceResolver = sourceResolver;
+    }
+
+    public ActionMapping getActionMapping() {
+        return (ActionMapping) get("actionMapping");
+    }
+
+    public ActionMapper getActionMapper() {
+        return (ActionMapper) get("actionMapper");
+    }
+
+    public FlowController getRemovingFlowController() {
+        // Note that this is stored as a member variable because it never gets propagated to another ActionContext.
+        return _removingFlowController;
+    }
+
+    public void setRemovingFlowController(FlowController removingFlowController) {
+        // Note that this is stored as a member variable because it never gets propagated to another ActionContext.
+        _removingFlowController = removingFlowController;
+    }
+}

Added: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/xwork/PageFlowExceptionHandler.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/xwork/PageFlowExceptionHandler.java?rev=240168&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/xwork/PageFlowExceptionHandler.java (added)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/xwork/PageFlowExceptionHandler.java Thu Aug 25 22:46:03 2005
@@ -0,0 +1,222 @@
+/*
+ * Copyright 2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * $Header:$
+ */
+package org.apache.ti.pageflow.xwork;
+
+import com.opensymphony.xwork.Action;
+import org.apache.ti.Globals;
+import org.apache.ti.core.ActionMessage;
+import org.apache.ti.pageflow.ExpressionMessage;
+import org.apache.ti.pageflow.FlowController;
+import org.apache.ti.pageflow.Forward;
+import org.apache.ti.pageflow.PageFlowException;
+import org.apache.ti.pageflow.internal.InternalConstants;
+import org.apache.ti.pageflow.internal.InternalExpressionUtils;
+import org.apache.ti.pageflow.internal.InternalUtils;
+import org.apache.ti.util.Bundle;
+import org.apache.ti.util.MessageResources;
+import org.apache.ti.util.internal.InternalStringBuilder;
+import org.apache.ti.util.internal.cache.ClassLevelCache;
+import org.apache.ti.util.logging.Logger;
+
+import javax.servlet.jsp.el.ELException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Locale;
+
+public class PageFlowExceptionHandler extends PageFlowAction {
+
+    private static final Logger _log = Logger.getInstance(PageFlowExceptionHandler.class);
+
+    private static final String CACHEID_EXCEPTION_HANDLER_METHODS = InternalConstants.ATTR_PREFIX + "exceptionHandlers";
+
+    private String _methodName;
+    private String _defaultMessage;
+    private String _messageKey;
+    private boolean _readOnly;
+
+    public String execute() throws Exception {
+        Forward fwd;
+        if (_methodName != null) {
+            fwd = invokeExceptionHandlerMethod();
+            PageFlowActionContext.get().setForward(fwd);
+        } else {
+            fwd = new Forward(Action.SUCCESS);
+            PageFlowActionContext.get().setForward(fwd);
+        }
+        return fwd != null ? fwd.getName() : null;
+    }
+
+    protected Forward invokeExceptionHandlerMethod()
+            throws PageFlowException {
+        PageFlowActionContext actionContext = PageFlowActionContext.get();
+        Throwable ex = actionContext.getExceptionBeingHandled();
+        FlowController flowController = actionContext.getFlowController();
+        Method method = getExceptionHandlerMethod(getMethodName(), ex);
+        Object formBean = actionContext.getFormBean();
+
+        if (method != null) {
+            // First see if there's a hard-coded message set.
+            String message = getDefaultMessage();
+            ActionMessage error = null;
+
+            if (message != null) {
+                error = new ExpressionMessage(message, new Object[]{ex.getMessage()});
+
+                try {
+                    // The message may be an expression.  Evaluate it.
+                    message = InternalExpressionUtils.evaluateMessage(message);
+                } catch (ELException e) {
+                    _log.error("error while evaluating expression in exception-handler for " + ex.getClass().getName(), e);
+                }
+            }
+
+
+            if (message == null) {
+                // No hard-coded message.  Get the message based on the message key.
+                String messageKey = getMessageKey();
+
+                if (messageKey != null && messageKey.length() > 0) {
+                    message = getMessage(messageKey, null, null);
+                }
+            }
+            
+            //
+            // Expose the exception to the errors tag.
+            //
+            String msgKey = getMessageKey();
+            if (error == null) error = new ActionMessage(msgKey, ex.getMessage());
+            ArrayList errors = new ArrayList();
+            errors.add(error);
+            actionContext.getRequestScope().put(Globals.ERROR_KEY, errors);
+
+            return flowController.invokeExceptionHandler(method, ex, message, formBean, isReadOnly());
+        } else {
+            //
+            // This shouldn't happen except in out-of-date-class situations.  JpfChecker
+            // should prevent this at compilation time.
+            //
+            String err;
+            if (formBean != null) {
+                err = Bundle.getString("PageFlow_MissingExceptionHandlerWithForm",
+                        new Object[]{getMethodName(), formBean.getClass().getName()});
+            } else {
+                err = Bundle.getString("PageFlow_MissingExceptionHandler", getMethodName());
+            }
+
+            InternalUtils.sendError("PageFlow_Custom_Error", null, new Object[]{flowController.getDisplayName(), err});
+            return null;
+        }
+    }
+
+    /**
+     * Get an Exception handler method.
+     *
+     * @param methodName the name of the method to get.
+     * @param ex         the Exception that is to be handled.
+     * @return the Method with the given name that handles the given Exception, or <code>null</code>
+     *         if none matches.
+     */
+    protected Method getExceptionHandlerMethod(String methodName, Throwable ex) {
+        PageFlowActionContext actionContext = PageFlowActionContext.get();
+        FlowController flowController = actionContext.getFlowController();
+        String cacheKey = methodName + '/' + ex.getClass().getName();
+        ClassLevelCache cache = ClassLevelCache.getCache(flowController.getClass());
+        Method method = (Method) cache.get(CACHEID_EXCEPTION_HANDLER_METHODS, cacheKey);
+
+        if (method != null) {
+            return method;
+        }
+
+        Class flowControllerClass = flowController.getClass();
+        for (Class exClass = ex.getClass(); exClass != null; exClass = exClass.getSuperclass()) {
+            Class[] args = new Class[]{exClass, String.class};
+            Method foundMethod = InternalUtils.lookupMethod(flowControllerClass, methodName, args);
+
+            if (foundMethod != null) {
+                if (_log.isDebugEnabled()) {
+                    _log.debug("Found exception handler for " + exClass.getName());
+                }
+
+                if (!Modifier.isPublic(foundMethod.getModifiers())) foundMethod.setAccessible(true);
+                cache.put(CACHEID_EXCEPTION_HANDLER_METHODS, cacheKey, foundMethod);
+                return foundMethod;
+            } else {
+                if (_log.isErrorEnabled()) {
+                    InternalStringBuilder msg = new InternalStringBuilder("Could not find exception handler method ");
+                    msg.append(methodName).append(" for ").append(exClass.getName()).append('.');
+                    _log.error(msg.toString());
+                }
+            }
+        }
+
+        return null;
+    }
+
+    protected String getMessage(String messageKey, String bundle, Object[] args) {
+        if (bundle == null) bundle = Globals.MESSAGES_KEY;
+
+        MessageResources resources = InternalUtils.getMessageResources(bundle);
+
+        if (resources == null) {
+            _log.error("Could not find message-resources for bundle " + bundle);
+            return null;
+        }
+
+        Locale userLocale = PageFlowActionContext.get().getLocale();
+
+        if (args == null) {
+            return resources.getMessage(userLocale, messageKey);
+        } else {
+            return resources.getMessage(userLocale, messageKey, args);
+        }
+    }
+
+
+    public String getDefaultMessage() {
+        return _defaultMessage;
+    }
+
+    public void setDefaultMessage(String defaultMessage) {
+        _defaultMessage = defaultMessage;
+    }
+
+    public String getMessageKey() {
+        return _messageKey;
+    }
+
+    public void setMessageKey(String messageKey) {
+        _messageKey = messageKey;
+    }
+
+    public boolean isReadOnly() {
+        return _readOnly;
+    }
+
+    public void setReadOnly(boolean readOnly) {
+        _readOnly = readOnly;
+    }
+
+    public String getMethodName() {
+        return _methodName;
+    }
+
+    public void setMethodName(String methodName) {
+        _methodName = methodName;
+    }
+}

Added: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/xwork/PageFlowPathResult.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/xwork/PageFlowPathResult.java?rev=240168&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/xwork/PageFlowPathResult.java (added)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/xwork/PageFlowPathResult.java Thu Aug 25 22:46:03 2005
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * $Header:$
+ */
+package org.apache.ti.pageflow.xwork;
+
+import org.apache.ti.pageflow.Forward;
+import org.apache.ti.pageflow.ModuleConfig;
+import org.apache.ti.util.logging.Logger;
+
+public class PageFlowPathResult extends PageFlowResult {
+
+    private static final Logger _log = Logger.getInstance(PageFlowPathResult.class);
+
+    protected Forward applyForward(Forward fwd, ModuleConfig altModuleConfig) {
+
+        //
+        // It's a normal path.  Mark a particular request attribute if it's an inherited local path, which
+        // shouldn't be treated as a transfer to an external page flow (the base class page flow).
+        //
+        if (isInheritedPath()) {
+            PageFlowActionContext actionContext = PageFlowActionContext.get();
+            actionContext.setStayInCurrentModule(true);
+        }
+
+        return fwd;
+    }
+
+    protected boolean shouldSavePreviousPageInfo() {
+        return true;
+    }
+
+    public boolean isPath() {
+        return true;
+    }
+    
+    /* TODO: re-add this sort of support for self-nesting a page flow
+    forward forwardTo( forward fwd, String actionName, ModuleConfig altModuleConfig)
+    {
+        //
+        // Special case: the *only* way for a nested pageflow to nest itself is for it
+        // to forward to itself as a .jpf.  Simply executing an action in the .jpf isn't
+        // enough, obviously, since it's impossible to tell whether it should be executed
+        // in the current pageflow or a new nested one.
+        //
+        if ( fwd != null && getModuleConfig().isNestedFlow())
+        {
+            boolean selfNesting = false;
+            String superFwdPath = superFwd.getPath();
+            
+            if ( superFwdPath.startsWith("/") )
+            {
+                if ( superFwdPath.equals( getPath() ) ) selfNesting = true;
+            }
+            else
+            {
+                String className = getClass().getName();
+                int lastDot = className.lastIndexOf( '.' );
+                String thisPageFlowLocalURI = className.substring( lastDot + 1 ) + PAGEFLOW_EXTENSION;
+                if ( superFwdPath.equals( thisPageFlowLocalURI ) ) selfNesting = true;
+            }
+            
+            if ( selfNesting )
+            {
+                if ( _log.isDebugEnabled() )
+                {
+                    _log.debug( "Self-nesting page flow " + getPath() );
+                }
+                
+                try
+                {
+                    // This will cause the right pageflow stack stuff to happen.
+                    FlowControllerFactory.get().createPageFlow( getClass() );
+                }
+                catch ( IllegalAccessException e )
+                {
+                    // This should never happen -- if we successfully created this page flow once, we can do it again.
+                    assert false : e;
+                    _log.error( e );
+                }
+                catch ( InstantiationException e )
+                {
+                    _log.error( "Could not create PageFlowController instance of type " + getClass().getName(), e );
+                }
+            }
+        }
+        
+        return superFwd;
+    }
+    
+    */
+
+}

Added: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/xwork/PageFlowResult.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/xwork/PageFlowResult.java?rev=240168&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/xwork/PageFlowResult.java (added)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/xwork/PageFlowResult.java Thu Aug 25 22:46:03 2005
@@ -0,0 +1,596 @@
+/*
+ * Copyright 2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * $Header:$
+ */
+package org.apache.ti.pageflow.xwork;
+
+import com.opensymphony.xwork.ActionInvocation;
+import com.opensymphony.xwork.Result;
+import org.apache.ti.pageflow.*;
+import org.apache.ti.pageflow.handler.ForwardRedirectHandler;
+import org.apache.ti.pageflow.handler.Handlers;
+import org.apache.ti.pageflow.internal.AdapterManager;
+import org.apache.ti.pageflow.internal.InternalConstants;
+import org.apache.ti.pageflow.internal.InternalUtils;
+import org.apache.ti.util.internal.FileUtils;
+import org.apache.ti.util.internal.InternalStringBuilder;
+import org.apache.ti.util.logging.Logger;
+
+import java.io.Serializable;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+public abstract class PageFlowResult implements Result {
+
+    private static final Logger _log = Logger.getInstance(PageFlowResult.class);
+
+
+    private static final Map/*< String, Class >*/ PRIMITIVE_TYPES = new HashMap/*< String, Class >*/();
+
+    static {
+        PRIMITIVE_TYPES.put("boolean", boolean.class);
+        PRIMITIVE_TYPES.put("byte", byte.class);
+        PRIMITIVE_TYPES.put("char", char.class);
+        PRIMITIVE_TYPES.put("double", double.class);
+        PRIMITIVE_TYPES.put("float", float.class);
+        PRIMITIVE_TYPES.put("int", int.class);
+        PRIMITIVE_TYPES.put("long", long.class);
+        PRIMITIVE_TYPES.put("short", short.class);
+    }
+
+    private String _name;
+    private String _location;
+    private boolean _isNestedReturn = false;
+    private boolean _isReturnToPage = false;
+    private boolean _isReturnToAction = false;
+    private String _outputFormBeanType;
+    private String _outputFormBeanMember;
+    private boolean _hasExplicitRedirectValue = false;
+    private Map /*<String, ActionOutput>*/ _actionOutputDeclarations;
+    private boolean _restoreQueryString;
+    private boolean _redirect = false;
+    private boolean _externalRedirect = false;
+    private boolean _inheritedPath = false;
+
+    public void execute(ActionInvocation invocation) throws Exception {
+        PageFlowActionContext actionContext = (PageFlowActionContext) invocation.getInvocationContext();
+        Forward fwd = actionContext.getForward();
+        assert fwd != null : "no forward found in context for Result \"" + getName() + '"';
+        if (!preprocess(fwd, actionContext)) {
+            initFrom(fwd, actionContext);
+            applyForward(fwd, actionContext);
+            finishExecution(fwd, actionContext);
+        }
+    }
+
+    protected boolean preprocess(Forward fwd, PageFlowActionContext actionContext) {
+        return false;
+    }
+
+    public String getLocation() {
+        return _location;
+    }
+
+    public void setLocation(String location) {
+        _location = location;
+    }
+
+    public boolean isNestedReturn() {
+        return _isNestedReturn;
+    }
+
+    public void setNestedReturn(boolean nestedReturn) {
+        _isNestedReturn = nestedReturn;
+    }
+
+    public boolean isReturnToPage() {
+        return _isReturnToPage;
+    }
+
+    public void setReturnToPage(boolean returnToPage) {
+        _isReturnToPage = returnToPage;
+    }
+
+    public boolean isReturnToAction() {
+        return _isReturnToAction;
+    }
+
+    public void setReturnToAction(boolean returnToAction) {
+        _isReturnToAction = returnToAction;
+    }
+
+    public String getOutputFormBeanType() {
+        return _outputFormBeanType;
+    }
+
+    public void setOutputFormBeanType(String outputFormBeanType) {
+        _outputFormBeanType = outputFormBeanType;
+    }
+
+    public String getOutputFormBeanMember() {
+        return _outputFormBeanMember;
+    }
+
+    public void setOutputFormBeanMember(String outputFormBeanMember) {
+        _outputFormBeanMember = outputFormBeanMember;
+    }
+
+    public boolean hasExplicitRedirectValue() {
+        return _hasExplicitRedirectValue;
+    }
+
+    public void setHasExplicitRedirectValue(boolean hasExplicitRedirectValue) {
+        _hasExplicitRedirectValue = hasExplicitRedirectValue;
+    }
+
+    /**
+     * Tell whether this forward will restore the original query string on the page restored when a
+     * {@link org.apache.ti.pageflow.annotations.ti.forward &#64;ti.forward},
+     * {@link org.apache.ti.pageflow.annotations.ti.simpleAction &#64;ti.simpleAction},
+     * or {@link org.apache.ti.pageflow.annotations.ti.conditionalForward &#64;ti.conditionalForward}
+     * with <code>navigateTo={@link org.apache.ti.pageflow.annotations.ti.NavigateTo#previousAction ti.NavigateTo.previousAction}
+     * </code> is used.
+     */
+    public boolean isRestoreQueryString() {
+        return _restoreQueryString;
+    }
+
+    /**
+     * Set whether this forward will restore the original query string query string on the page restored when a
+     * {@link org.apache.ti.pageflow.annotations.ti.forward &#64;ti.forward},
+     * {@link org.apache.ti.pageflow.annotations.ti.simpleAction &#64;ti.simpleAction},
+     * or {@link org.apache.ti.pageflow.annotations.ti.conditionalForward &#64;ti.conditionalForward}
+     * with <code>navigateTo={@link org.apache.ti.pageflow.annotations.ti.NavigateTo#previousAction ti.NavigateTo.previousAction}
+     * </code> is used.
+     */
+    public void setRestoreQueryString(boolean restoreQueryString) {
+        _restoreQueryString = restoreQueryString;
+    }
+
+    public boolean isRedirect() {
+        return _redirect;
+    }
+
+    public void setRedirect(boolean redirect) {
+        _redirect = redirect;
+    }
+
+    /**
+     * Tell whether this is a redirect to a URI outside of the current web application.
+     */
+    public boolean isExternalRedirect() {
+        return _externalRedirect;
+    }
+
+    /**
+     * Specify that this is a redirect to a URI outside of the current web application.
+     */
+    public void setExternalRedirect(boolean externalRedirect) {
+        _externalRedirect = externalRedirect;
+    }
+
+    private static class ActionOutput implements Serializable {
+
+        private static final long serialVersionUID = 1;
+
+        private String _actionOutputName;
+        private String _type;
+        private boolean _isNullable;
+
+        public ActionOutput(String name, String type, boolean isNullable) {
+            _actionOutputName = name;
+            _type = type;
+            _isNullable = isNullable;
+        }
+
+        public String getName() {
+            return _actionOutputName;
+        }
+
+        public String getType() {
+            return _type;
+        }
+
+        public boolean getNullable() {
+            return _isNullable;
+        }
+    }
+
+    protected void setActionOutput(int n, String concatenatedVals) {
+        String[] vals = concatenatedVals.split("\\|");
+        assert vals.length == 3 : vals.length;
+        String name = vals[2];
+        String type = vals[0];
+        boolean isNullable = Boolean.valueOf(vals[1]).booleanValue();
+        _actionOutputDeclarations.put(name, new ActionOutput(name, type, isNullable));
+    }
+
+    public void setActionOutput0(String str) {
+        _actionOutputDeclarations = new HashMap();
+        setActionOutput(0, str);
+    }
+
+    public void setActionOutput1(String str) {
+        setActionOutput(1, str);
+    }
+
+    public void setActionOutput2(String str) {
+        setActionOutput(2, str);
+    }
+
+    public void setActionOutput3(String str) {
+        setActionOutput(3, str);
+    }
+
+    public void setActionOutput4(String str) {
+        setActionOutput(4, str);
+    }
+
+    public void setActionOutput5(String str) {
+        setActionOutput(5, str);
+    }
+
+    public void setActionOutput6(String str) {
+        setActionOutput(6, str);
+    }
+
+    public void setActionOutput7(String str) {
+        setActionOutput(7, str);
+    }
+
+    public void setActionOutput8(String str) {
+        setActionOutput(8, str);
+    }
+
+    public void setActionOutput9(String str) {
+        setActionOutput(9, str);
+    }
+
+    public void setActionOutput10(String str) {
+        setActionOutput(10, str);
+    }
+
+    public void setActionOutput11(String str) {
+        setActionOutput(11, str);
+    }
+
+    public void setActionOutput12(String str) {
+        setActionOutput(12, str);
+    }
+
+    public void setActionOutput13(String str) {
+        setActionOutput(13, str);
+    }
+
+    public void setActionOutput14(String str) {
+        setActionOutput(14, str);
+    }
+
+    public void setActionOutput15(String str) {
+        setActionOutput(15, str);
+    }
+
+    public void setActionOutput16(String str) {
+        setActionOutput(16, str);
+    }
+
+    public void setActionOutput17(String str) {
+        setActionOutput(17, str);
+    }
+
+    public void setActionOutput18(String str) {
+        setActionOutput(18, str);
+    }
+
+    public void setActionOutput19(String str) {
+        setActionOutput(19, str);
+    }
+
+    /**
+     * Tell whether the path is inherited from a path in a base class.
+     *
+     * @return <code>true</code> if the path is inherited from a path in a base class.
+     */
+    public boolean isInheritedPath() {
+        return _inheritedPath;
+    }
+
+    public void setInheritedPath(boolean inheritedPath) {
+        _inheritedPath = inheritedPath;
+    }
+
+    protected void initFrom(Forward fwd, PageFlowActionContext actionContext) {
+        // If there was a path specified on the Forward (programmatically), use that.
+        // TODO: enforce an annotation attribute that allows this; otherwise, throw.
+        if (fwd.getPath() != null) setLocation(fwd.getPath());
+        
+        // Add query params to the path.
+        if (fwd.getQueryString() != null) setLocation(getLocation() + fwd.getQueryString());
+
+        Class returnFormClass = null;
+
+        if (_outputFormBeanType != null) {
+            try {
+                returnFormClass = Class.forName(_outputFormBeanType);
+            } catch (ClassNotFoundException e) {
+                // This should never happen -- the JPF compiler ensures that it's a valid class.
+                assert false : e;
+            }
+        }
+
+        FlowController flowController = actionContext.getFlowController();
+
+        if (_outputFormBeanMember != null) {
+            try {
+                assert flowController != null;  // should be set in initialize()
+                Field field = flowController.getClass().getDeclaredField(_outputFormBeanMember);
+                returnFormClass = field.getType();
+                if (!Modifier.isPublic(field.getModifiers())) field.setAccessible(true);
+                Object form = field.get(flowController);
+
+                if (form != null) {
+                    if (_log.isDebugEnabled()) {
+                        _log.debug("using member " + _outputFormBeanMember + " for forward " + getName());
+                    }
+
+                    fwd.addOutputForm(form);
+                } else {
+                    if (_log.isInfoEnabled()) {
+                        _log.info("returnFormMember " + _outputFormBeanMember + " was null.");
+                    }
+                }
+            } catch (NoSuchFieldException e) {
+                assert false : "could not find field " + _outputFormBeanMember; // compiler should catch this
+            } catch (IllegalAccessException e) {
+                assert false;   // should not get here -- field is accessible.
+            }
+        }
+
+        checkOutputFormBeans(fwd, returnFormClass, flowController);
+        checkActionOutputs(fwd, actionContext);
+        
+        
+        //
+        // Throw an exception if this is a redirect, and if there was an output form or an action output added.
+        // Output forms and action outputs are carried in the request, and will be lost on redirects.
+        //
+        if (isRedirect()) {
+            if (_actionOutputDeclarations != null && !_actionOutputDeclarations.isEmpty()) {
+                FlowControllerException ex =
+                        new IllegalActionOutputException(_name, flowController,
+                                (String) _actionOutputDeclarations.keySet().iterator().next());
+                InternalUtils.throwPageFlowException(ex);
+            }
+
+            List outputForms = fwd.getOutputFormBeans();
+            if (outputForms != null && !outputForms.isEmpty()) {
+                FlowControllerException ex =
+                        new IllegalRedirectOutputFormException(_name, flowController,
+                                outputForms.get(0).getClass().getName());
+                InternalUtils.throwPageFlowException(ex);
+            }
+        }
+
+    }
+
+    private void checkOutputFormBeans(Forward fwd, Class returnFormClass, FlowController flowController) {
+        //
+        // Make sure that if there's currently an output form, that it confirms to the return-form-type.
+        //
+        List outputForms = fwd.getOutputFormBeans();
+        if (returnFormClass != null && outputForms != null && outputForms.size() > 0) {
+            Object outputForm = outputForms.get(0);
+
+            if (!returnFormClass.isInstance(outputForm)) {
+                FlowControllerException ex =
+                        new IllegalOutputFormTypeException(getName(), flowController,
+                                outputForm.getClass().getName(),
+                                returnFormClass.getName());
+                InternalUtils.throwPageFlowException(ex);
+            }
+        }
+    }
+
+    /**
+     * Make sure required action outputs are present, and are of the right type (only make the latter check when not
+     * in production mode
+     */
+    private void checkActionOutputs(Forward fwd, PageFlowActionContext actionContext) {
+        if (_actionOutputDeclarations == null) return;
+
+        boolean isInProductionMode = AdapterManager.getContainerAdapter().isInProductionMode();
+        Map fwdActionOutputs = fwd.getActionOutputs();
+
+        for (Iterator i = _actionOutputDeclarations.values().iterator(); i.hasNext();) {
+            ActionOutput actionOutput = (ActionOutput) i.next();
+
+            if (!actionOutput.getNullable()
+                    && (fwdActionOutputs == null || fwdActionOutputs.get(actionOutput.getName()) == null)) {
+                FlowController flowController = actionContext.getFlowController();
+                FlowControllerException ex =
+                        new MissingActionOutputException(flowController, actionOutput.getName(), getName());
+                InternalUtils.throwPageFlowException(ex);
+            }
+                
+            //
+            // If we're *not* in production mode, do some (expensive) checks to ensure that the types for the
+            // action outputs match their declared types.
+            //
+            if (!isInProductionMode && fwdActionOutputs != null) {
+                Object actualActionOutput = fwdActionOutputs.get(actionOutput.getName());
+
+                if (actualActionOutput != null) {
+                    String expectedTypeName = actionOutput.getType();
+                    int expectedArrayDims = 0;
+
+                    while (expectedTypeName.endsWith("[]")) {
+                        ++expectedArrayDims;
+                        expectedTypeName = expectedTypeName.substring(0, expectedTypeName.length() - 2);
+                    }
+
+                    Class expectedType = (Class) PRIMITIVE_TYPES.get(expectedTypeName);
+
+                    if (expectedType == null) {
+                        try {
+                            expectedType = Class.forName(expectedTypeName);
+                        } catch (ClassNotFoundException e) {
+                            _log.error("Could not load expected action output type " + expectedTypeName
+                                    + " for action output '" + actionOutput.getName() + "' on forward '"
+                                    + getName() + "'; skipping type check.");
+                            continue;
+                        }
+                    }
+
+                    Class actualType = actualActionOutput.getClass();
+                    int actualArrayDims = 0;
+                    InternalStringBuilder arraySuffix = new InternalStringBuilder();
+
+                    while (actualType.isArray() && actualArrayDims <= expectedArrayDims) {
+                        ++actualArrayDims;
+                        arraySuffix.append("[]");
+                        actualType = actualType.getComponentType();
+                    }
+
+                    if (actualArrayDims != expectedArrayDims || !expectedType.isAssignableFrom(actualType)) {
+                        FlowController fc = actionContext.getFlowController();
+                        FlowControllerException ex =
+                                new MismatchedActionOutputException(fc, actionOutput.getName(), getName(),
+                                        expectedTypeName,
+                                        actualType.getName() + arraySuffix);
+                        InternalUtils.throwPageFlowException(ex);
+                    }
+                }
+            }
+        }
+    }
+
+    public String getName() {
+        return _name;
+    }
+
+    public void setName(String name) {
+        _name = name;
+    }
+
+    // TODO: re-add an alternative way of displaying pages (rather than server forward)
+    protected boolean processPageForward(String pagePath)
+            throws PageFlowException {
+        return false;
+    }
+
+    protected void doForward(String path)
+            throws PageFlowException {
+        if (!processPageForward(path)) {
+            ForwardRedirectHandler fwdRedirectHandler = Handlers.get().getForwardRedirectHandler();
+            fwdRedirectHandler.forward(path);
+        }
+    }
+
+    protected void applyForward(Forward fwd, PageFlowActionContext actionContext) {
+        //
+        // Set ActionForms specified in the forward.  Note that this overwrites any forms restored
+        // during return-to="page".
+        //
+        PageFlowUtils.setOutputForms(fwd, true);
+        InternalUtils.addActionOutputs(fwd.getActionOutputs(), true);
+
+    }
+
+    /**
+     * This override of the base method ensures that absolute URIs don't get the context
+     * path prepended, and handles forwards to special things like return-to="currentPage".
+     */
+    protected void finishExecution(Forward fwd, PageFlowActionContext actionContext)
+            throws PageFlowException {
+        Handlers handlers = Handlers.get();
+        ForwardRedirectHandler fwdRedirectHandler = handlers.getForwardRedirectHandler();
+        FlowController fc = actionContext.getFlowController();
+        
+        // Register this module as the one that's handling the action.
+        assert fc != null;
+        InternalUtils.setForwardingModule(fc.getNamespace());
+        
+        //
+        // Save info on this forward for return-to="currentPage" or return-to="previousPage".  But, don't save
+        // the info if the current forward is a return-to="currentPage" -- we don't want this to turn into
+        // the page that's seen for *both* return-to="currentPage" and return-to="previousPage".
+        //
+        if (shouldSavePreviousPageInfo()) {
+            Object formBean = actionContext.getFormBean();
+            fc.savePreviousPageInfo(this, fwd, formBean);
+        }
+        
+        // Try to get a resolved path from the forward; otherwise, just use the configured path.
+        String path = getLocation();
+        if (path == null) path = getLocation();
+        boolean startsWithSlash = path.length() > 0 && path.charAt(0) == '/';
+        
+        //
+        // If the URI is absolute (e.g., starts with "http:"), do a redirect to it no matter what.
+        //
+        if (FileUtils.isAbsoluteURI(path)) {
+            fwdRedirectHandler.redirect(addScopeParams(path));
+        } else if (isRedirect()) {
+            String redirectURI = path;
+
+            if (!isExternalRedirect() && startsWithSlash) {
+                redirectURI = actionContext.getRequestContextPath() + path;
+            }
+
+            fwdRedirectHandler.redirect(addScopeParams(redirectURI));
+        } else {
+            String fwdURI = path;
+
+            if (!startsWithSlash) {
+                //
+                // First, see if the current module is a Shared Flow module.  If so, unless this is a forward to
+                // another action in the shared flow, we need to translate the local path so it makes sense (strip
+                // off the shared flow module prefix "/-" and replace it with "/").
+                //
+                ModuleConfig mc = actionContext.getModuleConfig();
+                
+                // TODO: ACTION_EXTENSION can no longer be a constant -- we support arbitrary Servlet mappings
+                if (mc.isSharedFlow() && !fwdURI.endsWith(PageFlowConstants.ACTION_EXTENSION)
+                        && fwdURI.startsWith(InternalConstants.SHARED_FLOW_MODULE_PREFIX)) {
+                    fwdURI = '/' + fwdURI.substring(InternalConstants.SHARED_FLOW_MODULE_PREFIX_LEN);
+                }
+            }
+
+            doForward(fwdURI);
+        }
+    }
+
+    private static String addScopeParams(String path) {
+        // TODO: re-add the previous functionality
+        return path;
+    }
+
+
+    protected abstract boolean shouldSavePreviousPageInfo();
+
+    /**
+     * Tell whether this result was for a straight path, rather than some sort of symbolic navigation (e.g., a
+     * navigateTo=ti.NavigateTo.currentPage).
+     */
+    public abstract boolean isPath();
+
+}
+
+

Added: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/xwork/ReturnActionResult.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/xwork/ReturnActionResult.java?rev=240168&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/xwork/ReturnActionResult.java (added)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/xwork/ReturnActionResult.java Thu Aug 25 22:46:03 2005
@@ -0,0 +1,195 @@
+/*
+ * Copyright 2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * $Header:$
+ */
+package org.apache.ti.pageflow.xwork;
+
+import org.apache.ti.pageflow.EmptyNestingStackException;
+import org.apache.ti.pageflow.FlowController;
+import org.apache.ti.pageflow.FlowControllerException;
+import org.apache.ti.pageflow.Forward;
+import org.apache.ti.pageflow.PageFlowConstants;
+import org.apache.ti.pageflow.PageFlowController;
+import org.apache.ti.pageflow.PageFlowStack;
+import org.apache.ti.pageflow.PageFlowUtils;
+import org.apache.ti.pageflow.interceptor.action.ActionInterceptor;
+import org.apache.ti.pageflow.interceptor.action.AfterNestedInterceptContext;
+import org.apache.ti.pageflow.interceptor.action.InterceptorForward;
+import org.apache.ti.pageflow.internal.InternalUtils;
+import org.apache.ti.script.common.ImplicitObjectUtil;
+import org.apache.ti.util.internal.InternalStringBuilder;
+import org.apache.ti.util.logging.Logger;
+
+public class ReturnActionResult extends PageFlowResult {
+
+    private static final Logger _log = Logger.getInstance(ReturnActionResult.class);
+
+    private String _returnAction;
+
+    protected boolean shouldSavePreviousPageInfo() {
+        return true;
+    }
+
+    public boolean isPath() {
+        return false;
+    }
+
+    public String getReturnAction() {
+        return _returnAction;
+    }
+
+    public void setReturnAction(String returnAction) {
+        _returnAction = returnAction;
+    }
+
+    public boolean preprocess(Forward fwd, PageFlowActionContext actionContext) {
+        PageFlowStack pfStack = PageFlowStack.get();
+
+        assert _returnAction != null : "param returnAction was not set on ReturnActionResult";
+
+        if (pfStack.isEmpty()) {
+            PageFlowController curJpf = PageFlowUtils.getCurrentPageFlow();
+
+            if (_log.isWarnEnabled()) {
+                InternalStringBuilder msg = new InternalStringBuilder("Tried to pop from empty PageFlow stack.");
+                msg.append("  Current page flow is ");
+                msg.append(curJpf != null ? curJpf.getClass().getName() : null);
+                _log.warn(msg.append('.').toString());
+            }
+
+            FlowControllerException ex = new EmptyNestingStackException(curJpf);
+            ex.setActionName(_returnAction);
+            InternalUtils.throwPageFlowException(ex);
+        }
+                
+        // Only nested PageFlowControllers can have return actions.
+        FlowController flowController = actionContext.getFlowController();
+        assert flowController instanceof PageFlowController
+                : flowController.getClass().getName() + " is not a " + PageFlowController.class.getName();
+        Forward exceptionFwd = ((PageFlowController) flowController).exitNesting();
+        if (exceptionFwd != null) return true;
+
+        PageFlowStack.PushedPageFlow pushedPageFlowWrapper = pfStack.pop();
+        PageFlowController poppedPageFlow = pushedPageFlowWrapper.getPageFlow();
+
+        if (_log.isDebugEnabled()) {
+            _log.debug("Popped page flow " + poppedPageFlow + " from the nesting stack");
+        }
+
+        InternalUtils.setCurrentPageFlow(poppedPageFlow);
+
+                
+        //
+        // If an ActionInterceptor forwarded to the nested page flow, give it a chance to change the URI as the nested
+        // flow is returning.  If it doesn't, we'll go to the originally-intended forward.
+        //
+        ActionInterceptor interceptor = pushedPageFlowWrapper.getInterceptor();
+
+        if (interceptor != null) {
+            return handleInterceptorReturn(actionContext, poppedPageFlow, pushedPageFlowWrapper, _returnAction, interceptor);
+        }
+
+        //
+        // Raise the returned action on the popped pageflow.
+        //                    
+        if (_log.isDebugEnabled()) {
+            _log.debug("action on popped page flow is " + _returnAction);
+        }
+
+        InternalStringBuilder returnActionPath = new InternalStringBuilder();
+        returnActionPath.append(poppedPageFlow.getNamespace());
+        returnActionPath.append('/').append(_returnAction).append(PageFlowConstants.ACTION_EXTENSION);
+
+        //
+        // Store the returned form in the request.
+        //
+        Object retForm = fwd.getFirstOutputForm();
+        if (retForm != null) {
+            InternalUtils.setForwardedFormBean(retForm);
+            ImplicitObjectUtil.loadOutputFormBean(retForm);
+        }
+        
+        //
+        // forward to the return-action on the nesting page flow.
+        //
+        setLocation(returnActionPath.toString());
+        return false;
+    }
+
+    private boolean handleInterceptorReturn(PageFlowActionContext actionContext, PageFlowController poppedPageFlow,
+                                            PageFlowStack.PushedPageFlow pushedPageFlowWrapper,
+                                            String returnAction, ActionInterceptor interceptor) {
+        actionContext.setReturningFromActionIntercept(true);
+
+        try {
+            AfterNestedInterceptContext interceptorContext =
+                    new AfterNestedInterceptContext(poppedPageFlow,
+                            pushedPageFlowWrapper.getInterceptedForward(),
+                            pushedPageFlowWrapper.getInterceptedActionName(),
+                            returnAction);
+
+            interceptor.afterNestedIntercept(interceptorContext);
+
+            if (interceptorContext.hasInterceptorForward()) {
+                InterceptorForward fwd = interceptorContext.getInterceptorForward();
+
+                if (_log.isDebugEnabled()) {
+                    InternalStringBuilder message = new InternalStringBuilder();
+                    message.append("Interceptor ");
+                    message.append(interceptor.getClass().getName());
+                    message.append(" after nested page flow: ");
+
+                    if (fwd != null) {
+                        message.append("forwarding to ");
+                        message.append(fwd.getPath());
+                    } else {
+                        message.append("returned InterceptorForward is null.");
+                    }
+
+                    _log.debug(message.toString());
+                }
+
+                if (fwd != null) {
+                    fwd.rehydrateRequest();
+                    setLocation(fwd.getPath());
+                    return false;
+                }
+
+                return true;   // null forward -- cancel processing
+            }
+        } catch (Throwable e) {
+            //
+            // Yes, we *do* mean to catch Throwable here.  It will get re-thrown if the page flow does not handle it.
+            //
+            _log.error("Exception in " + interceptor.getClass().getName() + ".afterNestedIntercept", e);
+
+            try {
+                poppedPageFlow.handleException(e);
+                return true;    // handled exception -- cancel processing
+            } catch (Exception anotherException) {
+                _log.error("Exception thrown while handling exception.", anotherException);
+            }
+        }
+        
+        //
+        // The interceptor declined to forward us anywhere -- just go to the originally-intended forward.
+        //
+        InterceptorForward fwd = pushedPageFlowWrapper.getInterceptedForward();
+        fwd.rehydrateRequest();
+        setLocation(fwd.getPath());
+        return false;
+    }
+}

Modified: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/processor/ControllerActionInvocation.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/processor/ControllerActionInvocation.java?rev=240168&r1=240167&r2=240168&view=diff
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/processor/ControllerActionInvocation.java (original)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/processor/ControllerActionInvocation.java Thu Aug 25 22:46:03 2005
@@ -6,17 +6,17 @@
 
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
-import java.util.Collections;
-import java.util.HashMap;
 import java.util.Map;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.apache.ti.pageflow.xwork.PageFlowActionContext;
 import org.springframework.beans.factory.BeanFactory;
 
-import com.opensymphony.xwork.Action;
 import com.opensymphony.xwork.ActionProxy;
 import com.opensymphony.xwork.DefaultActionInvocation;
+import com.opensymphony.xwork.ActionContext;
+import com.opensymphony.xwork.util.OgnlUtil;
 import com.opensymphony.xwork.config.entities.ActionConfig;
 
 
@@ -45,6 +45,11 @@
 
     protected ControllerActionInvocation(ActionProxy proxy, Map extraContext, boolean pushAction) throws Exception {
         super(proxy, extraContext, pushAction);
+        
+        // TODO: DefaultActionInvocation should make the context-creation (currently in private init()) overridable.
+        PageFlowActionContext actionContext = PageFlowActionContext.get();
+        invocationContext = new PageFlowActionContext(createContextMap(), actionContext.getWebContext());
+        invocationContext.setName(proxy.getActionName());
     }
     
     public void setInvokeAction(InvokeAction inv) {
@@ -149,7 +154,14 @@
         
         return method;
     }
-    
+
+    protected void createAction() {
+        super.createAction();
+        
+        // TODO: have to find out why this is necessary; shouldn't it be part of the base createAction()?
+        OgnlUtil.setProperties(proxy.getConfig().getParams(), action, ActionContext.getContext().getContextMap());
+    }
+
     
     public Object getForm() {
         return form;

Modified: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/processor/chain/CreateActionMapping.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/processor/chain/CreateActionMapping.java?rev=240168&r1=240167&r2=240168&view=diff
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/processor/chain/CreateActionMapping.java (original)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/processor/chain/CreateActionMapping.java Thu Aug 25 22:46:03 2005
@@ -44,6 +44,7 @@
 
         ActionMapping mapping = actionMapper.getMapping(ctx);
         ctx.put("actionMapping", mapping);
+        ctx.put("actionMapper", actionMapper);
         return false;
     }
 

Added: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/processor/chain/PopulateActionContext.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/processor/chain/PopulateActionContext.java?rev=240168&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/processor/chain/PopulateActionContext.java (added)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/processor/chain/PopulateActionContext.java Thu Aug 25 22:46:03 2005
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * $Header:$
+ */
+package org.apache.ti.processor.chain;
+
+import org.apache.commons.chain.Command;
+import org.apache.commons.chain.Context;
+import org.apache.commons.chain.web.WebContext;
+import org.apache.ti.Globals;
+import com.opensymphony.xwork.ActionContext;
+
+public class PopulateActionContext implements Command {
+    
+    public boolean execute(Context context) throws Exception {
+        ActionContext actionContext = ActionContext.getContext();
+        WebContext webContext = (WebContext) context;
+        actionContext.setApplication(webContext.getApplicationScope());
+        actionContext.setSession(webContext.getSessionScope());
+        return false;
+    }
+}

Modified: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/processor/chain/ProcessActionChain.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/processor/chain/ProcessActionChain.java?rev=240168&r1=240167&r2=240168&view=diff
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/processor/chain/ProcessActionChain.java (original)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/processor/chain/ProcessActionChain.java Thu Aug 25 22:46:03 2005
@@ -26,6 +26,8 @@
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.apache.ti.pageflow.xwork.PageFlowActionContext;
+import org.apache.ti.pageflow.handler.Handlers;
 
 /**
  *  Initializes XWork by replacing default factories.
@@ -45,10 +47,18 @@
         ActionContext.setContext(proxy.getInvocation().getInvocationContext());
 
         boolean retCode = false;
+        PageFlowActionContext actionContext = PageFlowActionContext.get();        
+        boolean isNestedRequest = actionContext.isNestedRequest();
+        
 
         try {
             retCode = super.execute(origctx);
         } finally {
+            // If this is not a nested request, then commit any changes made by the storage handler.
+            if ( ! isNestedRequest ) {
+                Handlers.get().getStorageHandler().applyChanges();
+            }
+            
             ActionContext.setContext(nestedContext);
         }
         



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@struts.apache.org
For additional commands, e-mail: dev-help@struts.apache.org