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 [4/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/sr...
Added: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/FlowController.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/FlowController.java?rev=240168&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/FlowController.java (added)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/FlowController.java Thu Aug 25 22:46:03 2005
@@ -0,0 +1,876 @@
+/*
+ * 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;
+
+import com.opensymphony.xwork.Action;
+import org.apache.ti.core.ActionMessage;
+import org.apache.ti.core.urls.MutableURI;
+import org.apache.ti.pageflow.handler.ExceptionsHandler;
+import org.apache.ti.pageflow.handler.Handlers;
+import org.apache.ti.pageflow.handler.LoginHandler;
+import org.apache.ti.pageflow.internal.AdapterManager;
+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.pageflow.xwork.PageFlowAction;
+import org.apache.ti.pageflow.xwork.PageFlowActionContext;
+import org.apache.ti.pageflow.xwork.PageFlowResult;
+import org.apache.ti.util.internal.InternalStringBuilder;
+import org.apache.ti.util.internal.ServletUtils;
+import org.apache.ti.util.internal.cache.ClassLevelCache;
+import org.apache.ti.util.logging.Logger;
+
+import javax.security.auth.login.LoginException;
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.net.URISyntaxException;
+import java.util.Iterator;
+import java.util.Map;
+
+
+/**
+ * Base class for user-written flow controllers - {@link PageFlowController}s and {@link SharedFlowController}s.
+ */
+public abstract class FlowController extends PageFlowManagedObject
+ implements PageFlowConstants, ActionResolver {
+
+ private static final Logger _log = Logger.getInstance(FlowController.class);
+
+ private static final String ONCREATE_EXCEPTION_FORWARD = InternalConstants.ATTR_PREFIX + "onCreateException";
+ private static final String CACHEID_ACTION_METHODS = InternalConstants.ATTR_PREFIX + "actionMethods";
+ private static final int DEFAULT_MAX_CONCURRENT_REQUEST_COUNT = 4;
+ private static final int EXCEEDED_MAX_CONCURRENT_REQUESTS_ERRORCODE = 503;
+ private static final Forward NULL_ACTION_FORWARD = new Forward();
+
+
+ /**
+ * Cached reference to the associated Struts ModuleConfig.
+ */
+ private transient ModuleConfig _moduleConfig = null;
+
+ /**
+ * @see #incrementRequestCount
+ */
+ private transient int _requestCount = 0;
+
+ /**
+ * Default constructor.
+ */
+ protected FlowController() {
+ }
+
+ /**
+ * Reinitialize the object for a new request. Used by the framework; normally should not be called directly.
+ */
+ public void reinitialize() {
+ //
+ // Cache the associated ModuleConfig. This is used throughout the code, in places where the request
+ // isn't available to do a lazy initialization.
+ //
+ super.reinitialize();
+ initModuleConfig();
+ }
+
+ /**
+ * Send a Page Flow error to the browser.
+ *
+ * @param errText the error message to display.
+ */
+ protected void sendError(String errText)
+ throws IOException {
+ InternalUtils.sendError("PageFlow_Custom_Error", null, new Object[]{getDisplayName(), errText});
+ }
+
+ /**
+ * Handle the given exception - invoke user code if appropriate and return a destination URI.
+ *
+ * @param ex the Exception to handle.
+ * @throws PageFlowException if another Exception is thrown during handling of <code>ex</code>.
+ */
+ public synchronized Forward handleException(Throwable ex)
+ throws PageFlowException {
+ ExceptionsHandler eh = Handlers.get().getExceptionsHandler();
+
+ // First, put the exception into the request (or other applicable context).
+ Throwable unwrapped = eh.unwrapException(ex);
+ eh.exposeException(unwrapped);
+ eh.handleException(unwrapped);
+ return new Forward(Action.NONE);
+ }
+
+ /**
+ * Get the name of the current action being executed. This call is only valid
+ * during {@link FlowController#execute} (where any user action method is invoked), and during the lifecycle
+ * methods {@link FlowController#beforeAction} and {@link FlowController#afterAction}.
+ *
+ * @return the name of the current action being executed.
+ * @throws IllegalStateException if this method is invoked outside of action method
+ * execution (i.e., outside of the call to {@link FlowController#execute}, and outside of
+ * {@link FlowController#onCreate}, {@link FlowController#beforeAction}, {@link FlowController#afterAction}.
+ */
+
+ protected static String getCurrentActionName() {
+ return getContext().getName();
+ }
+
+ /**
+ * Perform decision logic to determine the next URI to be displayed.
+ *
+ * @return a Struts forward object that specifies the next URI to be displayed.
+ * @throws PageFlowException if an Exception was thrown during user action-handling code.
+ */
+ public Forward execute()
+ throws PageFlowException {
+ //
+ // Don't actually run the action (and perform the associated synchronization) if there are too many
+ // concurrent requests to this instance.
+ //
+ if (incrementRequestCount()) {
+ try {
+ synchronized (this) {
+ return internalExecute();
+ }
+ } finally {
+ decrementRequestCount();
+ }
+ } else {
+ return null; // error was written to the response by incrementRequestCount()
+ }
+ }
+
+ /**
+ * An internal method for executing an action; should not be invoked directly.
+ */
+ protected Forward internalExecute()
+ throws PageFlowException {
+ ContainerAdapter sca = AdapterManager.getContainerAdapter();
+ PageFlowEventReporter eventReporter = sca.getEventReporter();
+ eventReporter.actionRaised(this);
+ long startTime = System.currentTimeMillis();
+
+ //
+ // If we handled an exception in onCreate, just forward to the result of that.
+ //
+ Forward onCreateFwd = (Forward) getContext().getRequestScope().get(ONCREATE_EXCEPTION_FORWARD);
+
+ if (onCreateFwd != null) {
+ return onCreateFwd == NULL_ACTION_FORWARD ? null : onCreateFwd;
+ }
+
+
+ PageFlowUtils.setActionPath();
+
+ // Store information on this action for use with navigateTo=ti.NavigateTo.previousAction.
+ savePreviousActionInfo();
+
+
+ //
+ // First change the actionPath (path) so that it lines up with our naming convention
+ // for action methods.
+ //
+ boolean gotPastBeforeAction = false;
+
+ try {
+ //
+ // beforeAction callback
+ //
+ beforeAction();
+ gotPastBeforeAction = true;
+
+ PageFlowActionContext actionContext = PageFlowActionContext.get();
+ PageFlowAction pfAction = actionContext.getAction();
+ String actionName = actionContext.getName();
+
+ //
+ // Check whether isLoginRequired=true for this action.
+ //
+ LoginHandler loginHandler = Handlers.get().getLoginHandler();
+
+ if (pfAction.isLoginRequired() && loginHandler.getUserPrincipal() == null) {
+ NotLoggedInException ex = createNotLoggedInException(actionName);
+ return handleException(ex);
+ }
+
+ //
+ // Now delegate to the appropriate action method, or if it's a simple action, handle it that way.
+ //
+ Forward retVal;
+ if (pfAction.isSimpleAction()) {
+ retVal = handleSimpleAction(pfAction);
+ } else {
+ retVal = getActionMethodForward(actionName);
+ }
+
+ long timeTaken = System.currentTimeMillis() - startTime;
+ eventReporter.actionSuccess(this, retVal, timeTaken);
+ return retVal;
+ } catch (Exception e) {
+ //
+ // Even though we handle any Throwable thrown by the user's action method, we don't need
+ // to catch Throwable here, because anything thrown by the action method will be wrapped
+ // in an InvocationTargetException. Any Error (or other Throwable) that appears here
+ // should not be handled by handleException() -- it's probably a framework problem and
+ // should bubble out to the container.
+ //
+ return handleException(e);
+ } finally {
+ Forward overrideReturn = null;
+
+ if (gotPastBeforeAction) {
+ //
+ // afterAction callback
+ //
+ try {
+ afterAction();
+ } catch (Throwable th) {
+ overrideReturn = handleException(th);
+ }
+ }
+
+ if (overrideReturn != null) return overrideReturn;
+ }
+ }
+
+ NotLoggedInException createNotLoggedInException(String actionName) {
+ if (ServletUtils.isSessionExpired(getContext().getWebContext())) {
+ return new LoginExpiredException(this);
+ } else {
+ return new NotLoggedInException(this);
+ }
+ }
+
+ public void login(String username, String password) throws LoginException {
+ Handlers.get().getLoginHandler().login(username, password);
+ }
+
+ public void logout(boolean invalidateSessions) {
+ Handlers.get().getLoginHandler().logout(invalidateSessions);
+ }
+
+ /**
+ * Initialize after object creation. This is a framework-invoked method; it should not normally be called directly.
+ */
+ public synchronized void create() {
+ try {
+ super.create();
+ } catch (Throwable th) {
+ try {
+ _log.info("Handling exception in onCreate(), FlowController " + this, th);
+ Forward fwd = handleException(th);
+ if (fwd == null) fwd = NULL_ACTION_FORWARD;
+ getContext().getRequestScope().put(ONCREATE_EXCEPTION_FORWARD, fwd);
+ } catch (Exception e) {
+ _log.error("Exception thrown while handling exception in onCreate(): " + e.getMessage(), th);
+ }
+ }
+
+ PageFlowEventReporter er = AdapterManager.getContainerAdapter().getEventReporter();
+ er.flowControllerCreated(this);
+ }
+
+ /**
+ * Internal destroy method that is invoked when this object is being removed from the session. This is a
+ * framework-invoked method; it should not normally be called directly.
+ */
+ void destroy() {
+ super.destroy();
+ PageFlowEventReporter er = AdapterManager.getContainerAdapter().getEventReporter();
+ er.flowControllerDestroyed(this, Handlers.get().getStorageHandler().getStorageLocation());
+ }
+
+ /**
+ * Get the namespace for this controller.
+ *
+ * @return a String that is the namespace for this controller.
+ */
+ public abstract String getNamespace();
+
+ /**
+ * Callback that occurs before any user action method is invoked.
+ */
+ protected synchronized void beforeAction()
+ throws Exception {
+ }
+
+ /**
+ * Callback that occurs after any user action method is invoked.
+ */
+ protected synchronized void afterAction()
+ throws Exception {
+ }
+
+ /**
+ * Callback that is invoked when this controller instance is created.
+ */
+ protected void onCreate()
+ throws Exception {
+ }
+
+ /**
+ * Callback that is invoked when this controller instance is "destroyed", i.e., removed from storage.
+ * <br>
+ * Note that this method is <strong>not synchronized</strong>. It is dangerous to synchronize your override of
+ * this method because it may be invoked during a callback from the container. Depending on the container,
+ * synchronization here can cause deadlocks.
+ */
+ protected void onDestroy() {
+ }
+
+ /**
+ * Get an action handler method of the given name/signature.
+ *
+ * @param methodName the name of the action handler method to query.
+ * @param argType the type of the argument to the action handler method; if <code>null</code>,
+ * the method takes no arguments.
+ * @return the desired Method, or <code>null</code> if it doesn't exist.
+ */
+ protected Method getActionMethod(String methodName, Class argType) {
+ String cacheKey = argType != null ? methodName + '/' + argType.getName() : methodName;
+ Class thisClass = getClass();
+ ClassLevelCache cache = ClassLevelCache.getCache(thisClass);
+ Method actionMethod = (Method) cache.get(CACHEID_ACTION_METHODS, cacheKey);
+
+ if (actionMethod != null) {
+ return actionMethod;
+ } else {
+ //
+ // We didn't find it in the cache. Look for it reflectively.
+ //
+ if (argType == null) {
+ //
+ // No form -- look for a method with no arguments.
+ //
+ actionMethod = InternalUtils.lookupMethod(thisClass, methodName, null);
+ } else {
+ //
+ // Has a form. Look for a method with a single argument -- either the given type
+ // or any superclass.
+ //
+ while (argType != null) {
+ actionMethod = InternalUtils.lookupMethod(thisClass, methodName, new Class[]{argType});
+
+ if (actionMethod != null) {
+ break;
+ }
+
+ argType = argType.getSuperclass();
+ }
+ }
+
+ if (actionMethod != null) {
+ Class returnType = actionMethod.getReturnType();
+ if (returnType.equals(Forward.class) || returnType.equals(String.class)) {
+ if (!Modifier.isPublic(actionMethod.getModifiers())) actionMethod.setAccessible(true);
+ cache.put(CACHEID_ACTION_METHODS, cacheKey, actionMethod);
+ return actionMethod;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private Class getFormClass(Object form)
+ throws ClassNotFoundException {
+ String formClassName = getAction().getFormBeanType();
+ if (formClassName != null) return InternalUtils.getReloadableClass(formClassName);
+ return form != null ? form.getClass() : null;
+ }
+
+ /**
+ * Get the forward returned by the action handler method that corresponds to the
+ * given action name and form-bean, or send an error to the browser if there is no
+ * matching method.
+ *
+ * @param actionName the name of the Struts action to handle.
+ * @return the forward returned by the action handler method, or <code>null</code> if
+ * there was no matching method (in which case an error was written to the
+ * browser.
+ * @throws Exception if an Exception was raised in user code.
+ */
+ Forward getActionMethodForward(String actionName)
+ throws Exception {
+ //
+ // Find the method.
+ //
+ Object formBean = getContext().getFormBean();
+ Class formClass = getFormClass(formBean);
+ Method actionMethod = getActionMethod(actionName, formClass);
+
+ //
+ // Invoke the method.
+ //
+ if (actionMethod != null) {
+ return invokeActionMethod(actionMethod, formBean);
+ }
+
+ if (_log.isWarnEnabled()) {
+ InternalStringBuilder msg = new InternalStringBuilder("Could not find matching action method for action=");
+ msg.append(actionName).append(", form=");
+ msg.append(formBean != null ? formBean.getClass().getName() : "[none]");
+ _log.warn(msg.toString());
+ }
+
+ FlowControllerException ex = new NoMatchingActionMethodException(formBean, this);
+ InternalUtils.throwPageFlowException(ex);
+ return null;
+ }
+
+ /**
+ * Invoke the given action handler method, passing it an argument if appropriate.
+ *
+ * @param method the action handler method to invoke.
+ * @param arg the form-bean to pass; may be <code>null</code>.
+ * @return the forward returned by the action handler method.
+ * @throws Exception if an Exception was raised in user code.
+ */
+ Forward invokeActionMethod(Method method, Object arg)
+ throws Exception {
+ Class[] paramTypes = method.getParameterTypes();
+
+ try {
+ if (paramTypes.length > 0 && paramTypes[0].isInstance(arg)) {
+ if (_log.isDebugEnabled()) {
+ _log.debug("Invoking action method " + method.getName() + '(' + paramTypes[0].getName() + ')');
+ }
+
+ return invokeForwardMethod(method, new Object[]{arg});
+ } else if (paramTypes.length == 0) {
+ if (_log.isDebugEnabled()) {
+ _log.debug("Invoking action method " + method.getName() + "()");
+ }
+
+ return invokeForwardMethod(method, null);
+ }
+ } finally {
+ if (!getAction().isReadonly()) {
+ ensureFailover();
+ }
+ }
+
+ if (_log.isWarnEnabled()) {
+ _log.warn("Could not find action method " + method.getName() + " with appropriate signature.");
+ }
+
+ return null;
+ }
+
+ private Forward invokeForwardMethod(Method method, Object[] args)
+ throws IllegalAccessException, InvocationTargetException {
+ Object result = method.invoke(this, args);
+ if (result instanceof String) {
+ result = new Forward((String) result);
+ }
+ return (Forward) result;
+ }
+
+ private void initModuleConfig() {
+ if (_moduleConfig == null) {
+ _moduleConfig = Handlers.get().getModuleRegistrationHandler().getModuleConfig(getNamespace());
+ assert _moduleConfig != null : getNamespace() + "; " + getClass().getName();
+ }
+ }
+
+ /**
+ * Gets the Struts module configuration associated with this controller.
+ *
+ * @return the Struts ModuleConfig for this controller.
+ */
+ public ModuleConfig getModuleConfig() {
+ initModuleConfig();
+ return _moduleConfig;
+ }
+
+ /**
+ * Call an action and return the result URI.
+ *
+ * @param actionName the name of the action to run.
+ * @param form the form bean instance to pass to the action, or <code>null</code> if none should be passed.
+ * @return the result webapp-relative URI, as a String.
+ * @throws ActionNotFoundException when the given action does not exist in this FlowController.
+ * @throws Exception if the action method throws an Exception.
+ */
+ /* TODO: re-enable this method
+ public String resolveAction( String actionName, Object form )
+ throws Exception
+ {
+ ActionConfig mapping = ( ActionConfig ) getModuleConfig().findActionConfig( '/' + actionName );
+
+ if ( mapping == null )
+ {
+ InternalUtils.throwPageFlowException( new ActionNotFoundException( actionName, this, form ) );
+ }
+
+ forward fwd = getActionMethodForward( actionName, form );
+
+ if ( fwd instanceof forward )
+ {
+ ( ( forward ) fwd ).initialize();
+ }
+
+ String path = fwd.getPath();
+ if ( path.startsWith("/") || FileUtils.isAbsoluteURI( path ) )
+ {
+ return path;
+ }
+ else
+ {
+ return '/' + getNamespace() + '/' + path;
+ }
+ }
+ */
+
+ /**
+ * Get a list of the names of actions handled by methods in this PageFlowController.
+ *
+ * @return a String array containing the names of actions handled by methods in this PageFlowController.
+ */
+ public String[] getActions() {
+ Map actionConfigs = getModuleConfig().getActionConfigs();
+ return (String[]) actionConfigs.keySet().toArray(new String[actionConfigs.size()]);
+ }
+
+ /**
+ * Tell whether a given String is the name of an action handled by a method in this PageFlowController.
+ *
+ * @param name the action-name to query.
+ * @return <code>true</code> if <code>name</code> is the name of an action handled by a method in this
+ * PageFlowController.
+ */
+ public boolean isAction(String name) {
+ return getModuleConfig().findActionConfig(name) != null;
+ }
+
+ /**
+ * Called on this object for non-lookup (refresh) requests. This is a framework-invoked method that should not
+ * normally be called directly.
+ */
+ public final synchronized void refresh() {
+ onRefresh();
+ }
+
+ /**
+ * Callback that is invoked when this controller is involved in a refresh request, as can happen in a portal
+ * environment on a request where no action is run in the current page flow, but a previously-displayed page in the
+ * page flow is re-rendered.
+ */
+ protected void onRefresh() {
+ }
+
+ /**
+ * Remove this instance from the user session.
+ */
+ protected void remove() {
+ removeFromSession();
+ }
+
+ /**
+ * Used by derived classes to store information on the most recent action executed.
+ */
+ void savePreviousActionInfo() {
+ }
+
+ /**
+ * Store information about recent pages displayed. This is a framework-invoked method that should not normally be
+ * called directly.
+ */
+ public void savePreviousPageInfo(PageFlowResult result, Forward fwd, Object form) {
+ }
+
+ /**
+ * When this FlowController does not use a {@link org.apache.ti.pageflow.annotations.ti.forward @ti.forward}
+ * annotation with a
+ * <code>navigateTo=</code>{@link org.apache.ti.pageflow.annotations.ti.NavigateTo#previousAction ti.NavigateTo.previousAction}
+ * attribute, the following methods always return <code>null</code> by default.
+ * <ul>
+ * <li>getPreviousActionInfo</li>
+ * <li>getPreviousActionURI</li>
+ * <li>getPreviousForm</li>
+ * </ul>
+ * Override <code>alwaysTrackPreviousAction</code> (which always returns <code>false</code>) to enable these methods
+ * in all cases.
+ *
+ * @return <code>true</code> if the previous action should always be tracked, regardless of whether
+ * <code>return-to="previousAction"</code> is used.
+ * @see PageFlowController#getPreviousActionInfo
+ * @see PageFlowController#getPreviousActionURI
+ * @see PageFlowController#getPreviousFormBean
+ */
+ protected boolean alwaysTrackPreviousAction() {
+ return false;
+ }
+
+ /**
+ * When this FlowController does not use a {@link org.apache.ti.pageflow.annotations.ti.forward @ti.forward}
+ * annotation with either a
+ * <code>navigateTo</code>={@link org.apache.ti.pageflow.annotations.ti.NavigateTo#currentPage ti.NavigateTo.currentPage}
+ * attribute or a
+ * <code>navigateTo</code>={@link org.apache.ti.pageflow.annotations.ti.NavigateTo#previousPage ti.NavigateTo.previousPage}
+ * attribute, the following methods always return <code>null</code> by default.
+ * <ul>
+ * <li>getCurrentPageInfo</li>
+ * <li>getPreviousPageInfo</li>
+ * <li>getCurrentForwardPath</li>
+ * <li>getPreviousForwardPath</li>
+ * </ul>
+ * Override <code>alwaysTrackPreviousPage</code> (which always returns <code>false</code>) to enable these methods
+ * in all cases.
+ *
+ * @return <code>true</code> if the previous page should always be tracked, regardless
+ * of whether <code>return-to="currentPage"</code> or <code>return-to="previousPage"</code>
+ * is used.
+ * @see PageFlowController#getCurrentPageInfo
+ * @see PageFlowController#getPreviousPageInfo
+ * @see PageFlowController#getCurrentForwardPath
+ * @see PageFlowController#getPreviousForwardPath
+ */
+ protected boolean alwaysTrackPreviousPage() {
+ return false;
+ }
+
+ /**
+ * Increment the count of concurrent requests to this FlowController. Note that this method
+ * is not synchronized -- it is used to decide whether to synchronize on this instance,
+ * or to bail out with an error message about too many concurrent requests. This is a framework-invoked
+ * method that should not normally be called directly.
+ */
+ public boolean incrementRequestCount()
+ throws PageFlowException {
+ //
+ // Now, if the current count of concurrent requests to this instance is greater than the max,
+ // send an error on the response.
+ //
+ if (_requestCount >= DEFAULT_MAX_CONCURRENT_REQUEST_COUNT) {
+ if (_log.isDebugEnabled()) {
+ _log.debug("Too many requests to FlowController " + getDisplayName() + " ("
+ + (_requestCount + 1) + '>' + DEFAULT_MAX_CONCURRENT_REQUEST_COUNT
+ + "); returning error code " + EXCEEDED_MAX_CONCURRENT_REQUESTS_ERRORCODE);
+ }
+
+ // TODO: re-add (need an abstraction for this)
+ //response.sendError( EXCEEDED_MAX_CONCURRENT_REQUESTS_ERRORCODE );
+ return false;
+ }
+
+ //
+ // We're ok -- increment the count and continue.
+ //
+ ++_requestCount;
+ return true;
+ }
+
+ /**
+ * Decrement the count of concurrent requests to this FlowController. Note that this method is not synchronized --
+ * it is used in conjunction with {@link #incrementRequestCount} to decide whether to synchronize on this instance,
+ * or to bail out with an error message about too many concurrent requests. This is a framework-invoked
+ * method that should not normally be called directly.
+ */
+ public void decrementRequestCount() {
+ assert _requestCount > 0 : getContext().getRequestPath();
+ --_requestCount;
+ }
+
+ /**
+ * Invoke the given exception handler method. This is a framework-invoked method that should not normally be called
+ * directly
+ *
+ * @param method the action handler method to invoke.
+ * @param ex the Throwable that is to be handled.
+ * @param message the String message that is to be passed to the handler method.
+ * @param formBean the form bean that is associated with the action being processed; may be <code>null</code>.
+ * @param readonly if <code>true</code>, session failover will not be triggered after invoking the method.
+ * @return the forward returned by the exception handler method.
+ */
+ public synchronized Forward invokeExceptionHandler(Method method, Throwable ex, String message,
+ Object formBean, boolean readonly)
+ throws PageFlowException {
+ try {
+ if (_log.isDebugEnabled()) {
+ _log.debug("Invoking exception handler method " + method.getName() + '('
+ + method.getParameterTypes()[0].getName() + ", ...)");
+ }
+
+ try {
+ Forward retVal = null;
+
+ try {
+ Object[] args = new Object[]{ex, message};
+ retVal = invokeForwardMethod(method, args);
+ } finally {
+ if (!readonly) {
+ ensureFailover();
+ }
+ }
+
+ return retVal;
+ } catch (InvocationTargetException e) {
+ Throwable target = e.getTargetException();
+
+ if (target instanceof Exception) {
+ throw (Exception) target;
+ } else {
+ throw e;
+ }
+ }
+ } catch (Throwable e) {
+ _log.error("Exception while handling exception " + ex.getClass().getName()
+ + ". The original exception will be thrown.", e);
+
+ ExceptionsHandler eh = Handlers.get().getExceptionsHandler();
+ Throwable unwrapped = eh.unwrapException(e);
+
+ if (!eh.eatUnhandledException(unwrapped)) {
+ if (ex instanceof PageFlowException) throw (PageFlowException) ex;
+ if (ex instanceof Error) throw (Error) ex;
+ throw new PageFlowException(ex);
+ }
+
+ return null;
+ }
+ }
+
+ /**
+ * Add a property-related message that will be shown with the Errors and Error tags.
+ *
+ * @param propertyName the name of the property with which to associate this error.
+ * @param messageKey the message-resources key for the message.
+ * @param messageArgs zero or more arguments to the message.
+ */
+ protected static void addActionError(String propertyName, String messageKey, Object[] messageArgs) {
+ InternalUtils.addActionError(propertyName, new ActionMessage(messageKey, messageArgs));
+ }
+
+ /**
+ * Add a property-related message as an expression that will be evaluated and shown with the Errors and Error tags.
+ *
+ * @param propertyName the name of the property with which to associate this error.
+ * @param expression the expression that will be evaluated to generate the error message.
+ * @param messageArgs zero or more arguments to the message; may be expressions.
+ */
+ protected static void addActionErrorExpression(String propertyName, String expression, Object[] messageArgs) {
+ PageFlowUtils.addActionErrorExpression(propertyName, expression, messageArgs);
+ }
+
+ private static Forward handleSimpleAction(PageFlowAction action) {
+ Map/*< String, String >*/ conditionalForwards = action.getConditionalForwardsMap();
+
+ if (!conditionalForwards.isEmpty()) {
+ for (Iterator/*< Map.Entry< String, String > >*/ i = conditionalForwards.entrySet().iterator(); i.hasNext();) {
+ Map.Entry/*< String, String >*/ entry = (Map.Entry) i.next();
+ String expression = (String) entry.getKey();
+ String forwardName = (String) entry.getValue();
+
+ try {
+ if (InternalExpressionUtils.evaluateCondition(expression)) {
+ if (_log.isTraceEnabled()) {
+ PageFlowActionContext actionContext = PageFlowActionContext.get();
+ _log.trace("Expression '" + expression + "' evaluated to true on simple action "
+ + actionContext.getName() + "; using forward "
+ + forwardName + '.');
+ }
+
+ return new Forward(forwardName);
+ }
+ } catch (Exception e) // ELException
+ {
+ if (_log.isErrorEnabled()) {
+ _log.error("Exception occurred evaluating navigation expression '" + expression
+ + "'. Cause: " + e.getCause(), e);
+ }
+ }
+ }
+ }
+
+
+ String defaultForwardName = action.getDefaultForward();
+ assert defaultForwardName != null : "defaultForwardName is null on simple action "
+ + PageFlowActionContext.get().getName();
+
+ if (_log.isTraceEnabled()) {
+ PageFlowActionContext actionContext = PageFlowActionContext.get();
+ _log.trace("No expression evaluated to true on simple action " + actionContext.getName()
+ + "; using forward " + defaultForwardName + '.');
+ }
+
+ return new Forward(defaultForwardName);
+ }
+
+
+ /**
+ * Get the flow-scoped form bean member associated with the given ActionConfig. This is a framework-invoked
+ * method that should not normally be called directly.
+ */
+ public Object getFormBean(PageFlowAction action) {
+ String formMember = action.getFormMember();
+
+ try {
+ if (formMember != null) {
+ Field field = getClass().getDeclaredField(formMember);
+ field.setAccessible(true);
+ return field.get(this);
+ }
+ } catch (Exception e) {
+ _log.error("Could not use member field " + formMember + " as the form bean.", e);
+ }
+
+ return null;
+ }
+
+ /**
+ * Create a raw action URI, which can be modified before being sent through the registered URL rewriting chain
+ * using {@link org.apache.ti.core.urls.URLRewriterService#rewriteURL}.
+ *
+ * @param actionName the action name to convert into a MutableURI; may be qualified with a path from the webapp
+ * root, in which case the parent directory from the current request is <i>not</i> used.
+ * @return a MutableURI for the given action, suitable for URL rewriting.
+ * @throws URISyntaxException if there is a problem converting the action URI (derived
+ * from processing the given action name) into a MutableURI.
+ * @throws IllegalStateException if this method is invoked outside of action method
+ * execution (i.e., outside of the call to {@link FlowController#execute},
+ * and outside of {@link FlowController#onCreate},
+ * {@link FlowController#beforeAction}, {@link FlowController#afterAction}.
+ */
+ public MutableURI getActionURI(String actionName)
+ throws URISyntaxException {
+ return PageFlowUtils.getActionURI(actionName);
+ }
+
+ /**
+ * Create a fully-rewritten URI given an action and parameters.
+ *
+ * @param actionName the action name to convert into a fully-rewritten URI; may be qualified with a path from the
+ * webapp root, in which case the parent directory from the current request is <i>not</i> used.
+ * @param parameters the additional parameters to include in the URI query.
+ * @param asValidXml flag indicating that the query of the uri should be written
+ * using the "&amp;" entity, rather than the character, '&'
+ * @return a fully-rewritten URI for the given action.
+ * @throws URISyntaxException if there is a problem converting the action url (derived
+ * from processing the given action name) into a URI.
+ * @throws IllegalStateException if this method is invoked outside of action method
+ * execution (i.e., outside of the call to {@link FlowController#execute},
+ * and outside of {@link FlowController#onCreate},
+ * {@link FlowController#beforeAction}, {@link FlowController#afterAction}.
+ */
+ public String getRewrittenActionURI(String actionName, Map parameters, boolean asValidXml)
+ throws URISyntaxException {
+ return PageFlowUtils.getRewrittenActionURI(actionName, parameters, null, asValidXml);
+ }
+}
Added: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/FlowControllerException.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/FlowControllerException.java?rev=240168&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/FlowControllerException.java (added)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/FlowControllerException.java Thu Aug 25 22:46:03 2005
@@ -0,0 +1,80 @@
+/*
+ * 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;
+
+import org.apache.ti.pageflow.xwork.PageFlowActionContext;
+
+
+/**
+ * Base class for PageFlow-related Exceptions.
+ */
+public abstract class FlowControllerException
+ extends PageFlowManagedObjectException {
+
+ private String _actionName;
+
+
+ protected FlowControllerException(FlowController fc) {
+ super(fc);
+ _actionName = PageFlowActionContext.get().getName();
+ }
+
+ protected FlowControllerException(FlowController fc, Throwable cause) {
+ super(fc, cause);
+ _actionName = PageFlowActionContext.get().getName();
+ }
+
+ /**
+ * Get the related FlowController.
+ *
+ * @return the {@link FlowController} associated with this exception.
+ */
+ public FlowController getFlowController() {
+ return (FlowController) getManagedObject();
+ }
+
+ /**
+ * Get the name of the related FlowController.
+ *
+ * @return the class name of the {@link FlowController} associated with this exception.
+ */
+ public String getFlowControllerURI() {
+ FlowController flowController = getFlowController();
+ return flowController != null ? flowController.getDisplayName() : null;
+ }
+
+ /**
+ * Get the name of the action associated with this exception.
+ *
+ * @return a String that is the name of the action associated with this exception.
+ */
+ public String getActionName() {
+ return _actionName;
+ }
+
+ public void setActionName(String actionName) {
+ _actionName = actionName;
+ }
+
+ /**
+ * Tell whether the root cause may be session expiration in cases where the requested session ID is different than
+ * the actual session ID; if <code>true</code>, then a {@link SessionExpiredException} will be thrown instead of
+ * this one in these situations.
+ */
+ public abstract boolean causeMayBeSessionExpiration();
+}
Added: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/FlowControllerFactory.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/FlowControllerFactory.java?rev=240168&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/FlowControllerFactory.java (added)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/FlowControllerFactory.java Thu Aug 25 22:46:03 2005
@@ -0,0 +1,435 @@
+/*
+ * 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;
+
+import org.apache.ti.core.factory.Factory;
+import org.apache.ti.core.factory.FactoryUtils;
+import org.apache.ti.pageflow.handler.Handlers;
+import org.apache.ti.pageflow.handler.ModuleRegistrationHandler;
+import org.apache.ti.pageflow.internal.InternalConstants;
+import org.apache.ti.pageflow.internal.InternalUtils;
+import org.apache.ti.pageflow.xwork.PageFlowActionContext;
+import org.apache.ti.schema.config.DefaultSharedFlowRefs;
+import org.apache.ti.schema.config.PageflowConfig;
+import org.apache.ti.schema.config.PageflowFactories;
+import org.apache.ti.schema.config.PageflowFactory;
+import org.apache.ti.schema.config.SharedFlowRef;
+import org.apache.ti.util.config.ConfigUtil;
+import org.apache.ti.util.logging.Logger;
+
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+
+/**
+ * Factory for creating {@link FlowController}s - user {@link PageFlowController}s and {@link SharedFlowController}s.
+ */
+public class FlowControllerFactory
+ extends Factory {
+
+ private static final Logger _log = Logger.getInstance(FlowControllerFactory.class);
+
+ private static final String CONTEXT_ATTR = InternalConstants.ATTR_PREFIX + "fcFactory";
+
+ protected FlowControllerFactory() {
+ }
+
+ protected void onCreate() {
+ }
+
+ public static void init(Map appScope) {
+ PageflowFactories factoriesBean = ConfigUtil.getConfig().getPageflowFactories();
+ FlowControllerFactory factory = null;
+
+ if (factoriesBean != null) {
+ PageflowFactory fcFactoryBean = factoriesBean.getFlowcontrollerFactory();
+ factory = (FlowControllerFactory) FactoryUtils.getFactory(fcFactoryBean, FlowControllerFactory.class);
+ }
+
+ if (factory == null) factory = new FlowControllerFactory();
+ factory.reinit();
+
+ appScope.put(CONTEXT_ATTR, factory);
+ }
+
+ /**
+ * Called to reinitialize this instance, most importantly after it has been serialized/deserialized.
+ */
+ protected void reinit() {
+ super.reinit();
+ }
+
+ /**
+ * Get a FlowControllerFactory.
+ *
+ * @return a FlowControllerFactory for the given application. It may or may not be a cached instance.
+ */
+ public static FlowControllerFactory get() {
+ Map appScope = PageFlowActionContext.get().getApplication();
+ FlowControllerFactory factory = (FlowControllerFactory) appScope.get(CONTEXT_ATTR);
+ assert factory != null
+ : FlowControllerFactory.class.getName() + " was not found in application attribute " + CONTEXT_ATTR;
+ factory.reinit();
+ return factory;
+ }
+
+ /**
+ * Get the page flow instance that should be associated with the given request. If it doesn't exist, create it.
+ * If one is created, the page flow stack (for nesting) will be cleared or pushed, and the new instance will be
+ * stored as the current page flow.
+ *
+ * @return the {@link PageFlowController} for the request, or <code>null</code> if none was found.
+ */
+ public PageFlowController getPageFlowForRequest()
+ throws InstantiationException, IllegalAccessException {
+ PageFlowController cur = PageFlowUtils.getCurrentPageFlow();
+
+ //
+ // Reinitialize transient data that may have been lost on session failover.
+ //
+ if (cur != null) cur.reinitialize();
+
+ //
+ // If there's no current PageFlow, or if the current PageFlowController has a namespace that
+ // is incompatible with the current request URI, then create the appropriate PageFlowController.
+ //
+ PageFlowActionContext actionContext = PageFlowActionContext.get();
+ String namespace = actionContext.getNamespace();
+
+ if (namespace != null && (cur == null || !cur.getNamespace().equals(namespace))) {
+ try {
+ String className = InternalUtils.getFlowControllerClassName(namespace);
+ return className != null ? createPageFlow(className) : null;
+ } catch (ClassNotFoundException e) {
+ if (_log.isInfoEnabled()) _log.info("No page flow exists for namespace " + namespace);
+ return null;
+ }
+ }
+
+ return cur;
+ }
+
+ /**
+ * Create a page flow of the given type. The page flow stack (for nesting) will be cleared or pushed, and the new
+ * instance will be stored as the current page flow.
+ *
+ * @param pageFlowClassName the type name of the desired page flow.
+ * @return the newly-created {@link PageFlowController}, or <code>null</code> if none was found.
+ */
+ public PageFlowController createPageFlow(String pageFlowClassName)
+ throws ClassNotFoundException, InstantiationException, IllegalAccessException {
+ Class pageFlowClass = getFlowControllerClass(pageFlowClassName);
+ return createPageFlow(pageFlowClass);
+ }
+
+ /**
+ * Create a {@link PageFlowController} of the given type. The PageFlowController stack (for
+ * nesting) will be cleared or pushed, and the new instance will be stored as the current
+ * PageFlowController.
+ *
+ * @param pageFlowClass the type of the desired PageFlowController.
+ * @return the newly-created PageFlowController, or <code>null</code> if none was found.
+ */
+ public PageFlowController createPageFlow(Class pageFlowClass)
+ throws InstantiationException, IllegalAccessException {
+ if (!PageFlowController.class.isAssignableFrom(pageFlowClass)) return null;
+
+ //
+ // First check if this is a request for a "long lived" page flow. If so, try
+ // PageFlowUtils.getCurrentPageFlow again, with the longLived flag.
+ //
+ PageFlowController retVal = null;
+ String namespace = InternalUtils.inferNamespaceFromClassName(pageFlowClass.getName());
+ ModuleRegistrationHandler mrh = Handlers.get().getModuleRegistrationHandler();
+ ModuleConfig mc = mrh.getModuleConfig(namespace);
+
+ if (mc == null) {
+ _log.error("Struts module " + namespace + " not found for " + pageFlowClass.getName()
+ + "; cannot create page flow.");
+ return null;
+ }
+
+ if (mc.isLongLivedFlow()) {
+ retVal = PageFlowUtils.getLongLivedPageFlow(namespace);
+
+ if (_log.isDebugEnabled()) {
+ if (retVal != null) {
+ _log.debug("Using long lived PageFlowController of type " + pageFlowClass.getName());
+ }
+ }
+ }
+
+ //
+ // First, see if this is a nested page flow that's already on the stack. Unless "renesting" is explicitly
+ // enabled, we don't want to allow another instance of this page flow to be nested. This is a common
+ // browser back-button problem:
+ // 1) request nested page flow A
+ // 2) request nested page flow B
+ // 3) press back button, and execute an action on A.
+ //
+ // This logic does not deal with immediate self-nesting (A->A), which is taken care of in
+ // PageFlowController.forwardTo(). Nested page flows can only self-nest by forwarding to the .jpf URI, not
+ // indirectly by executing actions on themselves (think about it -- that would be a disaster).
+ //
+ boolean createdNew = false;
+ boolean isNestable = mc.isNestedFlow();
+ PageFlowStack pfStack = PageFlowStack.get(false);
+
+ if (isNestable && pfStack != null) {
+ PageflowConfig options = ConfigUtil.getConfig().getPageflowConfig();
+
+ if (options == null || !options.getEnableSelfNesting()) {
+ int lastIndexOfJpfClass = pfStack.lastIndexOf(pageFlowClass);
+
+ if (lastIndexOfJpfClass != -1) {
+ retVal = pfStack.popUntil(lastIndexOfJpfClass);
+ retVal.persistInSession();
+ return retVal;
+ }
+ }
+ }
+
+ //
+ // OK, if it's not an existing long lived page flow, and if this wasn't a nested page flow already on the
+ // stack, then create a new instance.
+ //
+ if (retVal == null) {
+ if (_log.isDebugEnabled()) {
+ _log.debug("Creating PageFlowController of type " + pageFlowClass.getName());
+ }
+
+ retVal = (PageFlowController) getFlowControllerInstance(pageFlowClass);
+ createdNew = true;
+ }
+
+ //
+ // Store the previous PageFlowController on the nesting stack (if this one is nestable),
+ // or destroy the nesting stack.
+ //
+ if (isNestable) {
+ //
+ // Call create() on the newly-created page flow.
+ //
+ if (createdNew) retVal.create();
+ PageFlowController current = PageFlowUtils.getCurrentPageFlow();
+
+ if (current != null) {
+ if (_log.isDebugEnabled()) {
+ _log.debug("Pushing PageFlowController " + current + " onto the nesting stack");
+ }
+
+ if (pfStack == null) pfStack = PageFlowStack.get(true);
+ pfStack.push(current);
+ }
+
+ retVal.reinitialize();
+ retVal.persistInSession();
+ } else {
+ //
+ // Going to a non-nested pageflow. Blow away the pageflow stack.
+ //
+ if (pfStack != null) {
+ if (_log.isDebugEnabled()) {
+ _log.debug("Destroying the PageFlowController stack.");
+ }
+
+ //
+ // Start popping page flows until 1) there are none left on the stack, or 2) we find
+ // one of the type we're returning. If (2), we'll use that one (this means that executing
+ // an action on a nesting page flow while in a nested one will not destroy the nesting
+ // page flow only to create a new instance of it).
+ //
+ PageFlowController onStackAlready = pfStack.popUntil(retVal.getClass());
+
+ if (onStackAlready != null) {
+ if (_log.isDebugEnabled()) {
+ _log.debug("Found a page flow of type " + retVal.getClass() + " in the stack; "
+ + "using that instance and stopping destruction of the nesting stack.");
+ }
+
+ retVal = onStackAlready;
+ retVal.persistInSession();
+ } else {
+ //
+ // We're actually using the newly-created page flow, so call create() on it.
+ // Note that we make the call to persistInSession *before* create, so the previous flow's
+ // onDestroy() gets called before the new one's onCreate().
+ //
+ retVal.reinitialize();
+ retVal.persistInSession();
+ retVal.create();
+ }
+ } else {
+ //
+ // We're actually using the newly-created page flow, so call create() on it (*after* persisting
+ // in the session so the previous page flow's onDestroy() gets called before the new one's
+ // onCreate()).
+ //
+ retVal.reinitialize();
+ retVal.persistInSession();
+ if (createdNew) retVal.create();
+ }
+ }
+
+ return retVal;
+ }
+
+ /**
+ * Create a {@link SharedFlowController} of the given type.
+ *
+ * @param sharedFlowClassName the type name of the desired SharedFlowController.
+ * @return the newly-created SharedFlowController, or <code>null</code> if none was found.
+ */
+ public SharedFlowController createSharedFlow(String sharedFlowClassName)
+ throws ClassNotFoundException, InstantiationException, IllegalAccessException {
+ Class sharedFlowClass = getFlowControllerClass(sharedFlowClassName);
+ return createSharedFlow(sharedFlowClass);
+ }
+
+ /**
+ * Create a {@link SharedFlowController} of the given type.
+ *
+ * @param sharedFlowClass the type of the desired SharedFlowController.
+ * @return the newly-created SharedFlowController, or <code>null</code> if none was found.
+ */
+ public SharedFlowController createSharedFlow(Class sharedFlowClass)
+ throws InstantiationException, IllegalAccessException {
+ assert SharedFlowController.class.isAssignableFrom(sharedFlowClass) : sharedFlowClass.getName();
+
+ if (_log.isDebugEnabled()) {
+ _log.debug("Creating SharedFlowController of type " + sharedFlowClass.getName());
+ }
+
+ SharedFlowController retVal = (SharedFlowController) getFlowControllerInstance(sharedFlowClass);
+ retVal.create();
+
+ if (_log.isDebugEnabled()) {
+ _log.debug("Storing " + retVal + " in the session...");
+ }
+
+ retVal.persistInSession();
+ return retVal;
+ }
+
+ /**
+ * Get the map of shared flows for the given request. The map is derived from the shared flows
+ * that are declared (through the <code>sharedFlowRefs</code> attribute of
+ * {@link org.apache.ti.pageflow.annotations.ti.controller @ti.controller}) in the page flow for the request.
+ *
+ * @return a Map of shared-flow-name (String) to {@link SharedFlowController}.
+ * @throws ClassNotFoundException if a declared shared flow class could not be found.
+ * @throws InstantiationException if a declared shared flow class could not be instantiated.
+ * @throws IllegalAccessException if a declared shared flow class was not accessible.
+ */
+ public Map/*< String, SharedFlowController >*/ getSharedFlowsForRequest()
+ throws ClassNotFoundException, InstantiationException, IllegalAccessException {
+ PageFlowActionContext actionContext = PageFlowActionContext.get();
+ String namespace = actionContext.getNamespace();
+ LinkedHashMap/*< String, SharedFlowController >*/ sharedFlows = getDefaultSharedFlows();
+ if (namespace == null) return null;
+ ModuleRegistrationHandler mrh = Handlers.get().getModuleRegistrationHandler();
+ ModuleConfig mc = mrh.getModuleConfig(namespace);
+
+ if (mc != null) {
+ Map/*< String, String >*/ sharedFlowTypes = mc.getSharedFlowTypes();
+
+ if (sharedFlowTypes != null && sharedFlowTypes.size() > 0) {
+ if (sharedFlows == null) sharedFlows = new LinkedHashMap/*< String, SharedFlowController >*/();
+
+ for (Iterator/*<Map.Entry>*/ i = sharedFlowTypes.entrySet().iterator(); i.hasNext();) {
+ Map.Entry entry = (Map.Entry) i.next();
+ String name = (String) entry.getKey();
+ String type = (String) entry.getValue();
+ addSharedFlow(name, type, sharedFlows);
+ }
+
+ return sharedFlows;
+ }
+ }
+
+ return sharedFlows;
+ }
+
+ LinkedHashMap/*< String, SharedFlowController >*/ getDefaultSharedFlows()
+ throws ClassNotFoundException, InstantiationException, IllegalAccessException {
+ DefaultSharedFlowRefs defaultRefs = ConfigUtil.getConfig().getDefaultSharedFlowRefs();
+
+ if (defaultRefs != null) {
+ SharedFlowRef[] refs = defaultRefs.getSharedFlowRefArray();
+
+ if (refs.length > 0) {
+ LinkedHashMap/*< String, SharedFlowController >*/ sharedFlows = new LinkedHashMap();
+
+ for (int i = 0; i < refs.length; i++) {
+ SharedFlowRef ref = refs[i];
+ if (_log.isInfoEnabled()) {
+ _log.info("Shared flow of type " + ref.getType() + " is a default shared flow reference "
+ + "with name " + ref.getName());
+ }
+ addSharedFlow(ref.getName(), ref.getType(), sharedFlows);
+ }
+
+ return sharedFlows;
+ }
+ }
+
+ return null;
+ }
+
+ private void addSharedFlow(String name, String type, LinkedHashMap sharedFlows)
+ throws ClassNotFoundException, InstantiationException, IllegalAccessException {
+ SharedFlowController sf = PageFlowUtils.getSharedFlow(type);
+
+ //
+ // Reinitialize transient data that may have been lost on session failover.
+ //
+ if (sf != null) {
+ sf.reinitialize();
+ } else {
+ sf = createSharedFlow(type);
+ }
+
+ sharedFlows.put(name, sf);
+ }
+
+ /**
+ * Get a FlowController class. By default, this loads the class using the thread context class loader.
+ *
+ * @param className the name of the {@link FlowController} class to load.
+ * @return the loaded {@link FlowController} class.
+ * @throws ClassNotFoundException if the requested class could not be found.
+ */
+ public Class getFlowControllerClass(String className)
+ throws ClassNotFoundException {
+ return Handlers.get().getReloadableClassHandler().loadClass(className);
+ }
+
+ /**
+ * Get a FlowController instance, given a FlowController class.
+ *
+ * @param flowControllerClass the Class, which must be assignable to {@link FlowController}.
+ * @return a new FlowController instance.
+ */
+ public FlowController getFlowControllerInstance(Class flowControllerClass)
+ throws InstantiationException, IllegalAccessException {
+ assert FlowController.class.isAssignableFrom(flowControllerClass)
+ : "Class " + flowControllerClass.getName() + " does not extend " + FlowController.class.getName();
+ return (FlowController) flowControllerClass.newInstance();
+ }
+}
Added: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/FormData.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/FormData.java?rev=240168&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/FormData.java (added)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/FormData.java Thu Aug 25 22:46:03 2005
@@ -0,0 +1,216 @@
+/*
+ * 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;
+
+
+
+
+/**
+ * Base class for form beans associated with action methods in {@link PageFlowController}s. Note that Page Flow actions
+ * may take form beans of any type.
+ */
+public class FormData {
+
+ /* TODO: re-add the functionality in this class
+
+ private static final Logger _log = Logger.getInstance( FormData.class );
+
+ //
+ // This is used to allow us to run against Validator 1.0 or 1.1. The reflective Method is only used when running
+ // against Validator 1.0 (legacy).
+ //
+ private static Method _legacyInitValidatorMethod = null;
+
+ static
+ {
+ try
+ {
+ _legacyInitValidatorMethod =
+ Resources.class.getMethod( "initValidator",
+ new Class[]{
+ String.class,
+ Object.class,
+ ServletContext.class,
+ HttpServletRequest.class,
+ ActionErrors.class,
+ int.class
+ } );
+ }
+ catch ( NoSuchMethodException e )
+ {
+ // ignore -- we're in Validator 1.1 or later.
+ }
+ }
+
+ public FormData()
+ {
+ super();
+ }
+
+ public ActionErrors validate( ActionMapping mapping, HttpServletRequest request )
+ {
+ return validateBean( this, mapping.getAttribute(), mapping, request );
+ }
+
+ //MessageResources that conglomerates a primary and backup MessageResources.
+ private static class MergedMessageResources
+ extends MessageResources
+ {
+ private MessageResources _primary;
+ private MessageResources _backup;
+
+ public MergedMessageResources( MessageResources primary, MessageResources backup )
+ {
+ super( primary.getFactory(), primary.getConfig(), primary.getReturnNull() );
+ _primary = primary;
+ _backup = backup;
+ }
+
+ public String getMessage( Locale locale, String key )
+ {
+ String message = _primary.getMessage( locale, key );
+ if ( message == null ) message = _backup.getMessage( locale, key );
+ return message;
+ }
+ }
+
+ /**
+ * Run all validation (declarative validation from annotations and the result of {@link Validatable#validate}) on
+ * a given bean.
+ *
+ * @param bean the bean to validate.
+ * @param beanName the name of the bean, to be passed to Validator to look up declarative validation rules.
+ * @param mapping the current ActionMapping.
+ * @param request the current HttpServletRequest.
+ * @return an ActionErrors object containing errors that occurred during bean validation.
+ *
+ protected ActionErrors validateBean( Object bean, String beanName, ActionMapping mapping, HttpServletRequest request )
+ {
+ MessageResources messageResources = ( MessageResources ) request.getAttribute( Globals.MESSAGES_KEY );
+ ExpressionAwareMessageResources.update( messageResources, bean );
+
+ //
+ // See if this action uses a form that defines its own message resources. If so, use those, or combine them
+ // with the message resources from the current module.
+ //
+ if ( mapping instanceof PageFlowAction )
+ {
+ PageFlowAction pfam = ( PageFlowAction ) mapping;
+ String bundle = pfam.getFormBeanMessageResourcesKey();
+
+ if ( bundle != null )
+ {
+ MessageResources formBeanResources = ( MessageResources ) request.getAttribute( bundle );
+ ExpressionAwareMessageResources.update( formBeanResources, bean );
+
+ if ( formBeanResources != null )
+ {
+ if ( messageResources != null )
+ {
+ formBeanResources = new MergedMessageResources( messageResources, formBeanResources );
+ }
+
+ request.setAttribute( Globals.MESSAGES_KEY, formBeanResources );
+ messageResources = formBeanResources;
+ }
+ }
+ }
+
+ //
+ // If there's no MessageResources for this request, create one that can evaluate expressions.
+ //
+ if ( messageResources == null )
+ {
+ messageResources = new ExpressionAwareMessageResources( bean, request, getServlet().getServletContext() );
+ request.setAttribute( Globals.MESSAGES_KEY, messageResources );
+ }
+
+
+ ServletContext servletContext = getServlet().getServletContext();
+ ActionErrors errors = new ActionErrors();
+
+ //
+ // If the ValidatorPlugIn was initialized for this module, run it.
+ //
+ if ( Resources.getValidatorResources( servletContext, request ) != null )
+ {
+ try
+ {
+ //
+ // Run validations associated with the bean.
+ //
+ Validator beanV = initValidator( beanName, bean, servletContext, request, errors, page );
+ validatorResults = beanV.validate();
+
+ //
+ // Run validations associated with the action.
+ //
+ Validator actionV = initValidator( mapping.getPath(), bean, servletContext, request, errors, page );
+ validatorResults.merge( actionV.validate() );
+ }
+ catch ( ValidatorException e )
+ {
+ _log.error( e.getMessage(), e );
+ }
+ }
+
+ //
+ // If this bean implements our Validatable interface, run its validate method.
+ //
+ if ( bean instanceof Validatable )
+ {
+ ( ( Validatable ) bean ).validate( mapping, request, errors );
+ }
+
+ return errors;
+ }
+
+ private static Validator initValidator( String beanName, Object bean, ServletContext context,
+ HttpServletRequest request, ActionErrors errors, int page )
+ {
+ if ( _legacyInitValidatorMethod != null )
+ {
+ try
+ {
+ Object[] args = new Object[]{ beanName, bean, context, request, errors, new Integer( page ) };
+ Validator validator = ( Validator ) _legacyInitValidatorMethod.invoke( Resources.class, args );
+
+ //
+ // The NetUI validator rules work on both 1.1 and 1.2. They take ActionMessages instead of ActionErrors.
+ //
+ validator.addResource( "org.apache.struts.action.ActionMessages", errors );
+ return validator;
+ }
+ catch ( IllegalAccessException e )
+ {
+ assert false : e.getMessage();
+ throw new RuntimeException( e );
+ }
+ catch ( InvocationTargetException e )
+ {
+ assert false : e.getMessage();
+ throw new RuntimeException( e );
+ }
+ }
+ else
+ {
+ return Resources.initValidator( beanName, bean, context, request, errors, page );
+ }
+ }
+ */
+}
Added: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/Forward.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/Forward.java?rev=240168&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/Forward.java (added)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/Forward.java Thu Aug 25 22:46:03 2005
@@ -0,0 +1,333 @@
+/*
+ * 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;
+
+import org.apache.ti.pageflow.handler.Handlers;
+import org.apache.ti.pageflow.handler.ReloadableClassHandler;
+import org.apache.ti.pageflow.xwork.PageFlowActionContext;
+import org.apache.ti.util.internal.InternalStringBuilder;
+import org.apache.ti.util.logging.Logger;
+
+import java.io.Serializable;
+import java.net.URI;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * An object of this type is returned from an action methods in a {@link PageFlowController} to
+ * determine the next URI to be displayed. It is constructed on the name of a forward defined
+ * by the @{@link org.apache.ti.pageflow.annotations.ti.forward @ti.forward} annotation, and resolves to the URI
+ * specified in that forward.
+ */
+public class Forward implements Serializable {
+
+ public static final Forward SUCCESS = new Forward("success");
+
+ private static final long serialVersionUID = 1;
+ private static final Object[] EMPTY_ACTION_FORM_ARRAY = new Object[0];
+
+ private static final Logger _log = Logger.getInstance(Forward.class);
+
+
+ private String _name;
+ private String _path;
+
+ private List _outputFormBeans = null;
+ private boolean _init = false;
+ private InternalStringBuilder _queryString = null;
+ private boolean _explicitPath = false;
+ private String _outputFormBeanType = null;
+ private Map _actionOutputs = null;
+
+ /**
+ * Construct based on an initializer forward. This is a framework-invoked constructor that should not normally
+ * be called directly.
+ */
+ protected Forward(Forward init) {
+ _outputFormBeans = init._outputFormBeans;
+ _init = init._init;
+ _queryString = init._queryString;
+ _explicitPath = init._explicitPath;
+ _outputFormBeanType = init._outputFormBeanType;
+ _actionOutputs = init._actionOutputs;
+ }
+
+ /**
+ * Construct based on a given request. This is a framework-invoked constructor that should not normally
+ * be called directly.
+ */
+ protected Forward() {
+ setPath(PageFlowActionContext.get().getRequestPath());
+ _explicitPath = true;
+ }
+
+ /**
+ * Constructor which accepts the name of a forward defined by the
+ * {@link org.apache.ti.pageflow.annotations.ti.forward @ti.forward}
+ * annotation.
+ *
+ * @param forwardName the name of the forward
+ * ({@link org.apache.ti.pageflow.annotations.ti.forward @ti.forward}) to resolve.
+ */
+ public Forward(String forwardName) {
+ setName(forwardName);
+ }
+
+ /**
+ * Constructor which accepts the name of a forward defined by the
+ * {@link org.apache.ti.pageflow.annotations.ti.forward @ti.forward}
+ * annotation. The value returned from {@link #getPath} is resolved from this forward.
+ * Also accepts a form bean to make available in the request (or user session, as appropriate).
+ *
+ * @param forwardName the name of the forward
+ * ({@link org.apache.ti.pageflow.annotations.ti.forward @ti.forward}) to resolve.
+ * @param outputFormBean a form bean instance to make available in the request (or user session, as appropriate).
+ * See {@link #addOutputForm} for details about how this manifests itself.
+ */
+ public Forward(String forwardName, Object outputFormBean) {
+ this(forwardName);
+
+ if (outputFormBean != null) {
+ addOutputForm(outputFormBean);
+ }
+ }
+
+ /**
+ * Constructor which accepts the name of a forward defined by the
+ * {@link org.apache.ti.pageflow.annotations.ti.forward @ti.forward}
+ * annotation. The value returned from {@link #getPath}
+ * is resolved from this forward. Also accepts a named action output
+ * to make available in the request, through {@link PageFlowUtils#getActionOutput}..
+ *
+ * @param forwardName the name of the forward
+ * ({@link org.apache.ti.pageflow.annotations.ti.forward @ti.forward}) to resolve.
+ * @param actionOutputName the name of a action output to make available in the request.
+ * @param actionOutputValue the action output object to make available in the request.
+ */
+ public Forward(String forwardName, String actionOutputName, Object actionOutputValue) {
+ this(forwardName);
+ addActionOutput(actionOutputName, actionOutputValue);
+ }
+
+ /**
+ * Constructs a forward that returns the given URI for {@link #getPath}.
+ *
+ * @param uri the URI to return for {@link #getPath}.
+ */
+ public Forward(String forwardName, URI uri) {
+ this(forwardName);
+ setPath(uri.toString());
+ _explicitPath = true;
+ }
+
+ /**
+ * Constructs a forward that returns the given URL for {@link #getPath}. Because the URL path
+ * is absolute by nature, this forward will cause a browser redirect.
+ *
+ * @param url the URL to return for {@link #getPath}.
+ */
+ public Forward(String forwardName, URL url) {
+ this(forwardName);
+ setPath(url.toString());
+ _explicitPath = true;
+ }
+
+ public String getName() {
+ return _name;
+ }
+
+ public void setName(String name) {
+ _name = name;
+ }
+
+ /**
+ * Add a form bean that will be made available in the request (or user session, as
+ * appropriate) if this forward is returned by an action method in a {@link PageFlowController}.
+ * Specifically, each form bean is stored as a request attribute with a name determined by
+ * {@link PageFlowUtils#getFormBeanName}.
+ *
+ * @param formBean the form bean instance to add.
+ */
+ public final void addOutputForm(Object formBean) {
+ if (formBean == null) throw new IllegalArgumentException("The output form bean may not be null.");
+ if (_outputFormBeans == null) _outputFormBeans = new ArrayList();
+ _outputFormBeans.add(formBean);
+ }
+
+ /**
+ * Get all form beans attached to this forward through {@link #addOutputForm} or {@link #Forward(String, Object)}.
+ *
+ * @return an array of form bean instances that are attached to this forward.
+ */
+ public final Object[] getOutputForms() {
+ if (_outputFormBeans == null) return EMPTY_ACTION_FORM_ARRAY;
+ return _outputFormBeans.toArray(EMPTY_ACTION_FORM_ARRAY);
+ }
+
+ /**
+ * Get all form beans attached to this forward through {@link #addOutputForm} or {@link #Forward(String, Object)}.
+ *
+ * @return an List of form bean instances that are attached to this forward. <strong>May be <code>null</code></strong>.
+ */
+ public final List getOutputFormBeans() {
+ return _outputFormBeans;
+ }
+
+ /**
+ * Get the first output form bean that was added to this forward.
+ */
+ public Object getFirstOutputForm() {
+ if (_outputFormBeans == null || _outputFormBeans.size() == 0) {
+ if (_outputFormBeanType != null) {
+ try {
+ if (_log.isDebugEnabled()) {
+ _log.debug("Creating form bean of type " + _outputFormBeanType);
+ }
+
+ ReloadableClassHandler rch = Handlers.get().getReloadableClassHandler();
+ Object formBean = rch.newInstance(_outputFormBeanType);
+ addOutputForm(formBean);
+ return formBean;
+ } catch (Exception e) {
+ _log.error("Could not create form bean instance of " + _outputFormBeanType, e);
+ }
+ }
+
+ return null;
+ } else {
+ return _outputFormBeans.get(0);
+ }
+ }
+
+ /**
+ * Set the path to be returned by {@link #getPath}. This overrides any path or forward name
+ * set in a constructor.
+ *
+ * @param contextRelativePath the path to be returned by {@link #getPath}.
+ */
+ public void setPath(String contextRelativePath) {
+ _path = contextRelativePath;
+ }
+
+ public boolean isExplicitPath() {
+ return _explicitPath;
+ }
+
+ /**
+ * Get the path associated with this object. Resolve it from the name of a forward
+ * ({@link org.apache.ti.pageflow.annotations.ti.forward @ti.forward}) if necessary.
+ *
+ * @return a String that is the URI path.
+ * @see #Forward(String)
+ * @see #Forward(String, Object)
+ * @see #Forward(String, URI)
+ * @see #Forward(String, URL)
+ * @see #setPath
+ */
+ public String getPath() {
+ return _path;
+ }
+
+ /**
+ * Set the query string that will be appended to the URI returned by {@link #getPath}.
+ *
+ * @param queryString the query string that will be appended to the URI. If this string does not
+ * start with <code>'?'</code>, then this character will be prepended; if the string is
+ * <code>null</code>, the query string will be removed.
+ */
+ public void setQueryString(String queryString) {
+ if (queryString == null || queryString.length() == 0) {
+ _queryString = null;
+ } else if (queryString.charAt(0) == '?') {
+ _queryString = new InternalStringBuilder(queryString);
+ } else {
+ _queryString = new InternalStringBuilder("?").append(queryString);
+ }
+ }
+
+ /**
+ * Get the query string that will be appended to the URI returned by {@link #getPath}.
+ *
+ * @return the query string that will be appended to the URI, or <code>null</code> if there
+ * is no query string.
+ */
+ public String getQueryString() {
+ return _queryString != null ? _queryString.toString() : null;
+ }
+
+ /**
+ * Add a query parameter to the URI returned by {@link #getPath}.
+ *
+ * @param paramName the name of the query parameter.
+ * @param value the value of the query parameter, or <code>null</code> if there is no value.
+ */
+ public void addQueryParam(String paramName, String value) {
+ if (_queryString == null) {
+ _queryString = new InternalStringBuilder("?");
+ } else {
+ _queryString.append('&');
+ }
+
+ _queryString.append(paramName);
+
+ if (value != null) {
+ _queryString.append('=').append(value);
+ }
+ }
+
+ /**
+ * Add a query parameter with no value to the URI returned by {@link #getPath}.
+ *
+ * @param paramName the name of the query parameter.
+ */
+ public final void addQueryParam(String paramName) {
+ addQueryParam(paramName, null);
+ }
+
+ /**
+ * Adds an action output that will be made available in the request, through {@link PageFlowUtils#getActionOutput}.
+ *
+ * @param paramName the name of the action output.
+ * @param value the action output value.
+ */
+ public void addActionOutput(String paramName, Object value) {
+ if (paramName == null || paramName.length() == 0) {
+ throw new IllegalArgumentException("An action output name may not be null or empty.");
+ }
+
+ if (_actionOutputs == null) {
+ _actionOutputs = new HashMap();
+ }
+
+ _actionOutputs.put(paramName, value);
+ }
+
+ /**
+ * Get all action outputs that have been set on this forward.
+ *
+ * @return a Map of name/value pairs representing all action outputs.
+ * @see #addActionOutput
+ */
+ public Map getActionOutputs() {
+ return _actionOutputs;
+ }
+}
Added: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/IllegalActionOutputException.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/IllegalActionOutputException.java?rev=240168&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/IllegalActionOutputException.java (added)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/IllegalActionOutputException.java Thu Aug 25 22:46:03 2005
@@ -0,0 +1,102 @@
+/*
+ * 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;
+
+
+/**
+ * Exception that occurs when an action output has been added to a {@link Forward} that resolves to a
+ * {@link org.apache.ti.pageflow.annotations.ti.forward @ti.forward} annotation marked with
+ * <code>{@link org.apache.ti.pageflow.annotations.ti.forward#redirect redirect}=true</code>.
+ * action outputs may not be used on redirect forwards.
+ */
+public class IllegalActionOutputException extends FlowControllerException {
+
+ private String _forwardName;
+ private String _actionOutputName;
+
+
+ /**
+ * Constructor.
+ *
+ * @param forwardName the name of the relevant {@link Forward}.
+ * @param flowController the current {@link FlowController} instance.
+ * @param actionOutputName the name of the relevant action output.
+ */
+ public IllegalActionOutputException(String forwardName, FlowController flowController,
+ String actionOutputName) {
+ super(flowController);
+ _forwardName = forwardName;
+ _actionOutputName = actionOutputName;
+ }
+
+ /**
+ * Get the name of the relevant {@link Forward}.
+ *
+ * @return a String that is the name of the relevant {@link Forward}.
+ */
+ public String getForwardName() {
+ return _forwardName;
+ }
+
+ /**
+ * Set the name of the relevant {@link Forward}.
+ *
+ * @param forwardName a String that is the name of the relevant {@link Forward}.
+ */
+ public void setForwardName(String forwardName) {
+ _forwardName = forwardName;
+ }
+
+ /**
+ * Get the name of the relevant action output.
+ *
+ * @return a String that is the name of the relevant action output.
+ */
+ public String getActionOutputName() {
+ return _actionOutputName;
+ }
+
+ /**
+ * Set the name of the relevant action output.
+ *
+ * @param actionOutputName a String that is the name of the relevant action output.
+ */
+ public void setActionOutputName(String actionOutputName) {
+ _actionOutputName = actionOutputName;
+ }
+
+ protected Object[] getMessageArgs() {
+ return new Object[]{_forwardName, getActionName(), getFlowControllerURI(), _actionOutputName};
+ }
+
+ public String[] getMessageParts() {
+ return new String[]
+ {
+ "The forward \"", "\" on action ", " in page flow ", " has at least one action output (\"",
+ "\"), but is set to redirect=\"true\". action outputs may not be used on redirect forwards."
+ };
+ }
+
+ /**
+ * Tell whether the root cause may be session expiration in cases where the requested session ID is different than
+ * the actual session ID. In this case, the answer is <code>false</code>.
+ */
+ public boolean causeMayBeSessionExpiration() {
+ return false;
+ }
+}
Added: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/IllegalOutputFormException.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/IllegalOutputFormException.java?rev=240168&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/IllegalOutputFormException.java (added)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/IllegalOutputFormException.java Thu Aug 25 22:46:03 2005
@@ -0,0 +1,87 @@
+/*
+ * 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;
+
+
+/**
+ * Base type for errors related to output forms on Forwards.
+ *
+ * @see Forward#addOutputForm
+ */
+public abstract class IllegalOutputFormException extends FlowControllerException {
+
+ private String _forwardName;
+ private String _outputFormType;
+
+
+ /**
+ * @param forwardName the name of the relevant {@link Forward}.
+ * @param flowController the current {@link FlowController} instance.
+ * @param outputFormType the type name of the relevant output form.
+ */
+ public IllegalOutputFormException(String forwardName, FlowController flowController,
+ String outputFormType) {
+ super(flowController);
+ _forwardName = forwardName;
+ _outputFormType = outputFormType;
+ }
+
+ /**
+ * Get the name of the relevant {@link Forward}.
+ *
+ * @return a String that is the name of the relevant {@link Forward}.
+ */
+ public String getForwardName() {
+ return _forwardName;
+ }
+
+ /**
+ * Set the name of the relevant {@link Forward}.
+ *
+ * @param forwardName a String that is the name of the relevant {@link Forward}.
+ */
+ public void setForwardName(String forwardName) {
+ _forwardName = forwardName;
+ }
+
+ /**
+ * Get the type name of the relevant output form.
+ *
+ * @return a String that is the type name of the relevant output form.
+ */
+ public String getOutputFormType() {
+ return _outputFormType;
+ }
+
+ /**
+ * Set the type name of the relevant output form.
+ *
+ * @param outputFormType a String that is the type name of the relevant output form.
+ */
+ public void setOutputFormType(String outputFormType) {
+ _outputFormType = outputFormType;
+ }
+
+ /**
+ * Tell whether the root cause may be session expiration in cases where the requested session ID is different than
+ * the actual session ID. In this case, the answer is <code>false</code>.
+ */
+ public boolean causeMayBeSessionExpiration() {
+ return false;
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@struts.apache.org
For additional commands, e-mail: dev-help@struts.apache.org