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 [3/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/core/urltemplates/URLTemplatesFactory.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/core/urltemplates/URLTemplatesFactory.java?rev=240168&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/core/urltemplates/URLTemplatesFactory.java (added)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/core/urltemplates/URLTemplatesFactory.java Thu Aug 25 22:46:03 2005
@@ -0,0 +1,191 @@
+/*
+ * Copyright 2005 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.core.urltemplates;
+
+import org.apache.commons.chain.web.WebContext;
+import org.apache.ti.core.factory.Factory;
+import org.apache.ti.core.urls.TemplatedURLFormatter;
+import org.apache.ti.pageflow.ContainerAdapter;
+import org.apache.ti.pageflow.xwork.PageFlowActionContext;
+import org.apache.ti.util.SourceResolver;
+
+import java.util.Collection;
+
+/**
+ * Access point to URL templates (an optional config file to help format
+ * rewritten URLs) used by a {@link org.apache.ti.core.urls.TemplatedURLFormatter}
+ * via the {@link org.apache.ti.core.urls.URLRewriterService}.
+ */
+public abstract class URLTemplatesFactory extends Factory {
+
+ private static final String URL_TEMPLATE_FACTORY_ATTR = "_netui:urlTemplatesFactory";
+
+ // Constants for URL template types
+ public static final String DEFAULT_TEMPLATE = "default";
+ public static final String SECURE_DEFAULT_TEMPLATE = "secure-default";
+ public static final String ACTION_TEMPLATE = "action";
+ public static final String SECURE_ACTION_TEMPLATE = "secure-action";
+ public static final String RESOURCE_TEMPLATE = "resource";
+ public static final String SECURE_RESOURCE_TEMPLATE = "secure-resource";
+ public static final String RENDER_TEMPLATE = "render";
+ public static final String SECURE_RENDER_TEMPLATE = "secure-render";
+
+ /**
+ * Default value for path from the web app to the URL templates.
+ */
+ public static final String DEFAULT_URL_TEMPLATE_CONFIG_FILE_PATH = "/WEB-INF/beehive-url-template-config.xml";
+
+ // Path to the URL templates config file.
+ private String _configFilePath = DEFAULT_URL_TEMPLATE_CONFIG_FILE_PATH;
+
+ // The known tokens (collection of String objects) in a valid template.
+ private Collection _knownTokens = null;
+
+ // The required tokens (collection of String objects) in a valid template.
+ private Collection _requiredTokens = null;
+
+ /**
+ * Gets the URLTemplatesFactory instance attribute of the application.
+ *
+ * @return the URLTemplatesFactory instance from the application scope.
+ */
+ public static URLTemplatesFactory getURLTemplatesFactory() {
+ return (URLTemplatesFactory)
+ PageFlowActionContext.get().getApplication().get(URL_TEMPLATE_FACTORY_ATTR);
+ }
+
+ /**
+ * Adds a given URLTemplatesFactory instance as an attribute of the application.
+ */
+ public static void initApplication(WebContext webContext, URLTemplatesFactory defaultFactory,
+ TemplatedURLFormatter formatter, ContainerAdapter containerAdapter,
+ SourceResolver sourceResolver) {
+ // URLTemplatesFactory has not been initialized,
+ // get a URLTemplatesFactory object from the containerAdapter.
+ URLTemplatesFactory templatesFactory = createURLTemplatesFactory(defaultFactory, containerAdapter);
+
+ // get the known/req tokens from the default formatter for the factory to use to verify templates
+ templatesFactory.setKnownTokens(formatter.getKnownTokens());
+ templatesFactory.setRequiredTokens(formatter.getRequiredTokens());
+ templatesFactory.load(webContext, sourceResolver);
+ webContext.getApplicationScope().put(URL_TEMPLATE_FACTORY_ATTR, templatesFactory);
+ }
+
+ /**
+ * Get an uninitialized instance of a container specific URLTemplatesFactory
+ * from the ContainerAdapter. If none exists, this returns an instance of a given default.
+ * Caller should then set the known
+ * and required tokens, call the {@link URLTemplatesFactory#load}
+ * method and {@link URLTemplatesFactory#initApplication}.
+ * <p/>
+ * <p/>
+ * IMPORTANT NOTE - Always try to get the application instance from the ServletContext
+ * by calling {@link URLTemplatesFactory#getURLTemplatesFactory}.
+ * Then, if a new URLTemplatesFactory must be created, call this method.
+ * </p>
+ *
+ * @return a container specific implementation of URLTemplatesFactory, or
+ * {@link org.apache.ti.pageflow.internal.DefaultURLTemplatesFactory}.
+ */
+ private static URLTemplatesFactory createURLTemplatesFactory(URLTemplatesFactory defaultFactory,
+ ContainerAdapter containerAdapter) {
+ // get the URLTemplatesFactory from the containerAdapter.
+ URLTemplatesFactory factory = (URLTemplatesFactory) containerAdapter.getFactory(URLTemplatesFactory.class, null, null);
+
+ // if there's no URLTemplatesFactory, use our default impl.
+ return factory != null ? factory : defaultFactory;
+ }
+
+ /**
+ * Allow clients to set their own URL template config file name/path.
+ *
+ * @param configFilePath An absolute path from the web app root to the URL template config file.
+ */
+ public void setConfigFilePath(String configFilePath) {
+ if (configFilePath == null) {
+ throw new IllegalArgumentException("Config file path cannot be null.");
+ }
+
+ _configFilePath = configFilePath;
+ }
+
+ /**
+ * Allow clients to define a set of known tokens for the
+ * template verification. Tokens are expected to be qualified
+ * in braces. E.g. {url:path}
+ * <p/>
+ * The template verification will ensure the known tokens in the
+ * URL template conforms to a valid format.
+ *
+ * @param knownTokens The set of known tokens for a valid template.
+ */
+ public void setKnownTokens(Collection knownTokens) {
+ _knownTokens = knownTokens;
+ }
+
+ /**
+ * Allow clients to define a set of required tokens for the
+ * template verification. Tokens are expected to be qualified
+ * in braces. E.g. {url:path}
+ * <p/>
+ * The template verification will ensure the URL template conforms to
+ * a valid format for known tokens and contains the required tokens.
+ * </p>
+ *
+ * @param requiredTokens The set of required tokens in a valid template.
+ */
+ public void setRequiredTokens(Collection requiredTokens) {
+ _requiredTokens = requiredTokens;
+ }
+
+ /**
+ * Returns URL template given the name of the template.
+ *
+ * @param name name of the template
+ * @return template
+ */
+ public abstract URLTemplate getURLTemplate(String name);
+
+ /**
+ * Returns URL template name of the given type (by key) from the
+ * desired reference group.
+ *
+ * @param refGroupName name of a group of templates from the config file.
+ * @param key type of the template
+ * @return template name
+ */
+ public abstract String getTemplateNameByRef(String refGroupName, String key);
+
+ /**
+ * Initialization method that parses the URL template config file to
+ * get the URL templates and template reference groups.
+ */
+ protected abstract void load(WebContext webContext, SourceResolver sourceResolver);
+
+ protected String getConfigFilePath() {
+ return _configFilePath;
+ }
+
+ protected Collection getKnownTokens() {
+ return _knownTokens;
+ }
+
+ protected Collection getRequiredTokens() {
+ return _requiredTokens;
+ }
+}
Added: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/ActionNotFoundException.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/ActionNotFoundException.java?rev=240168&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/ActionNotFoundException.java (added)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/ActionNotFoundException.java Thu Aug 25 22:46:03 2005
@@ -0,0 +1,56 @@
+/*
+ * 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;
+
+
+/**
+ * Exception that occurs when the user tries to execute an action that does not exist on the page flow.
+ */
+public class ActionNotFoundException extends FlowControllerException {
+
+ private Object _form;
+
+
+ public ActionNotFoundException(FlowController fc) {
+ super(fc);
+ _form = PageFlowActionContext.get().getFormBean();
+ }
+
+ protected Object[] getMessageArgs() {
+ return new Object[]{getActionName(), getFlowControllerURI(), _form != null ? _form.getClass().getName() : null};
+ }
+
+ protected String[] getMessageParts() {
+ String formDescrip = _form != null ? "(form " + _form.getClass().getName() + ") " : "";
+ return new String[]{"Unable to find action ", " (form=", ") in Page Flow ", "."};
+ }
+
+ protected Object getForm() {
+ return _form;
+ }
+
+ /**
+ * 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/ActionResolver.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/ActionResolver.java?rev=240168&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/ActionResolver.java (added)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/ActionResolver.java Thu Aug 25 22:46:03 2005
@@ -0,0 +1,45 @@
+/*
+ * 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;
+
+
+/**
+ * Interface for controller classes that resolve actions to URIs.
+ */
+public interface ActionResolver {
+
+ /**
+ * Get the path for addressing this object within an application.
+ */
+ public String getPath();
+
+ /**
+ * Get the namespace associated with this ActionResolver.
+ */
+ public String getNamespace();
+
+ /**
+ * Get the ModuleConfig associated with this ActionResolver.
+ */
+ public ModuleConfig getModuleConfig();
+
+ /**
+ * Called on this object for non-lookup (refresh) requests.
+ */
+ public void refresh();
+}
Added: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/ActionResult.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/ActionResult.java?rev=240168&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/ActionResult.java (added)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/ActionResult.java Thu Aug 25 22:46:03 2005
@@ -0,0 +1,48 @@
+/*
+ * 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 java.io.PrintWriter;
+
+/**
+ * Encapsulation of the results returned by {@link PageFlowUtils#strutsLookup}.
+ */
+public interface ActionResult {
+
+ public String getURI();
+
+ public boolean isRedirect();
+
+ public boolean isError();
+
+ public int getStatusCode();
+
+ public String getStatusMessage();
+
+ /**
+ * @deprecated This method now always returns false; compilation no longer happens at runtime. It will be removed
+ * in the next major release.
+ */
+ public boolean hadCompileErrors();
+
+ /**
+ * @deprecated This method has no effect; compilation no longer happens at runtime. It will be removed in the next
+ * major release.
+ */
+ public void printCompileErrors(PrintWriter writer);
+}
Added: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/AutoRegisterActionServlet.java.disabled
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/AutoRegisterActionServlet.java.disabled?rev=240168&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/AutoRegisterActionServlet.java.disabled (added)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/AutoRegisterActionServlet.java.disabled Thu Aug 25 22:46:03 2005
@@ -0,0 +1,380 @@
+/*
+ * 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.util.internal.InternalStringBuilder;
+
+import org.apache.ti.pageflow.internal.InternalConstants;
+import org.apache.ti.pageflow.internal.InternalUtils;
+import org.apache.ti.pageflow.internal.AdapterManager;
+import org.apache.ti.pageflow.xwork.ModuleConfig;
+import org.apache.ti.util.Bundle;
+import org.apache.ti.util.internal.DiscoveryUtils;
+import org.apache.ti.util.config.ConfigUtil;
+import org.apache.ti.util.config.bean.ModuleConfigLocators;
+import org.apache.ti.util.config.bean.PageflowConfig;
+import org.apache.ti.util.logging.Logger;
+import org.apache.commons.digester.Digester;
+import org.apache.struts.Globals;
+import org.apache.struts.action.ActionServlet;
+import org.apache.struts.action.DynaActionFormClass;
+import org.apache.struts.action.RequestProcessor;
+import org.apache.struts.config.ControllerConfig;
+import org.apache.struts.config.FormBeanConfig;
+import org.apache.struts.config.MessageResourcesConfig;
+import org.apache.struts.config.ModuleConfig;
+import org.apache.struts.config.ModuleConfigFactory;
+import org.apache.struts.config.impl.ModuleConfigImpl;
+import org.apache.struts.util.RequestUtils;
+import org.xml.sax.InputSource;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.UnavailableException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Iterator;
+
+import org.apache.ti.util.internal.concurrent.InternalConcurrentHashMap;
+
+
+/**
+ * ActionServlet that automatically registers requested Struts modules based on a set of module configuration file
+ * locators. The user may specify {@link ModuleConfigLocator} classes in /WEB-INF/beehive-netui-config.xml using the
+ * <code><module-config-locators></code> element.
+ */
+public class AutoRegisterActionServlet extends ActionServlet
+{
+
+ public void init()
+ throws ServletException
+ {
+ }
+
+ /**
+ * This override of the base class process() registers a Struts module on the fly if the
+ * config file can be found in our standard place (named in our standard way), regardless
+ * of whether the module is configured in web.xml.
+ */
+ protected void process( HttpServletRequest request, HttpServletResponse response )
+ throws IOException, ServletException
+ {
+ //
+ // First wrap the request with an object that contains request-scoped values that our runtime uses. This
+ // is faster than sticking everything into attributes on the request (then basically reading from a HashMap).
+ //
+ PageFlowRequestWrapper requestWrapper = PageFlowRequestWrapper.wrapRequest( request );
+ request = requestWrapper;
+
+ ServletContext servletContext = getServletContext();
+ String modulePath = PageFlowUtils.getModulePathForRequestPath( InternalUtils.getRequestPath( request ) );
+ ModuleConfig registeredApp;
+
+ //
+ // Get the registered Struts module for the request.
+ //
+ registeredApp = getModuleConfig( modulePath, request, response );
+
+ //
+ // If we've dynamically registered a module, then we need to override the base process() behavior to select the
+ // module. Note that we don't want to synchronize the call to process().
+ //
+ if ( registeredApp != null )
+ {
+ //
+ // Try to select the appropriate Struts module and delegate to its RequestProcessor.
+ //
+ ModuleConfig moduleConfig = InternalUtils.selectModule( modulePath, request, servletContext );
+ RequestProcessor requestProcessor = getRequestProcessor( moduleConfig );
+ requestProcessor.process( request, response );
+ }
+ else
+ {
+
+ //
+ // This is the same as the base process() behavior, but it checks for a missing module-configuration.
+ //
+ ModuleConfig moduleConfig = null;
+
+ if ( InternalUtils.getModuleConfig( RequestUtils.getModuleName( request, servletContext ), servletContext ) != null )
+ {
+ String modulePrefix = RequestUtils.getModuleName( request, servletContext );
+ moduleConfig = InternalUtils.selectModule( modulePrefix, request, servletContext );
+ }
+
+ String servletPath = InternalUtils.getRequestPath( request );
+ RequestProcessor rp = moduleConfig != null ? getRequestProcessor( moduleConfig ) : null;
+
+ if ( rp != null && moduleCanHandlePath( moduleConfig, rp, servletPath ) )
+ {
+ rp.process( request, response );
+ }
+ else
+ {
+ //
+ // Initialize the ServletContext in the request. Often, we need access to the ServletContext when we only
+ // have a ServletRequest.
+ //
+ InternalUtils.setServletContext( request, getServletContext() );
+
+ if ( processUnhandledAction( request, response, servletPath ) ) return;
+
+ String originalServletPath = requestWrapper.getOriginalServletPath();
+ if ( originalServletPath != null )
+ {
+ servletPath = originalServletPath;
+ modulePath = PageFlowUtils.getModulePathForRequestPath( originalServletPath );
+ }
+
+ if ( _log.isErrorEnabled() )
+ {
+ InternalStringBuilder msg = new InternalStringBuilder( "No module configuration registered for " );
+ msg.append( servletPath ).append( " (module path " ).append( modulePath ).append( ")." );
+ _log.error( msg.toString() );
+ }
+
+ //
+ // If we're not in production mode, send a diagnostic on the response; otherwise, simply send a 404.
+ //
+ if ( modulePath.length() == 0 ) modulePath = "/";
+ InternalUtils.sendDevTimeError( "PageFlow_NoModuleConf", null, HttpServletResponse.SC_NOT_FOUND,
+ request, response, servletContext,
+ new Object[]{ servletPath, modulePath } );
+ }
+ }
+ }
+
+ public void destroy()
+ {
+ super.destroy();
+ }
+
+ /**
+ * Last chance to handle an unhandled action URI.
+ * @return <code>true</code> if this method handled it (by forwarding somewhere or writing to the response).
+ */
+ protected boolean processUnhandledAction( HttpServletRequest request, HttpServletResponse response, String uri )
+ throws IOException, ServletException
+ {
+ return false;
+ }
+}
+/*
+ * 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.util.internal.InternalStringBuilder;
+
+import org.apache.ti.pageflow.internal.InternalConstants;
+import org.apache.ti.pageflow.internal.InternalUtils;
+import org.apache.ti.pageflow.internal.AdapterManager;
+import org.apache.ti.pageflow.xwork.ModuleConfig;
+import org.apache.ti.util.Bundle;
+import org.apache.ti.util.internal.DiscoveryUtils;
+import org.apache.ti.util.config.ConfigUtil;
+import org.apache.ti.util.config.bean.ModuleConfigLocators;
+import org.apache.ti.util.config.bean.PageflowConfig;
+import org.apache.ti.util.logging.Logger;
+import org.apache.commons.digester.Digester;
+import org.apache.struts.Globals;
+import org.apache.struts.action.ActionServlet;
+import org.apache.struts.action.DynaActionFormClass;
+import org.apache.struts.action.RequestProcessor;
+import org.apache.struts.config.ControllerConfig;
+import org.apache.struts.config.FormBeanConfig;
+import org.apache.struts.config.MessageResourcesConfig;
+import org.apache.struts.config.ModuleConfig;
+import org.apache.struts.config.ModuleConfigFactory;
+import org.apache.struts.config.impl.ModuleConfigImpl;
+import org.apache.struts.util.RequestUtils;
+import org.xml.sax.InputSource;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.UnavailableException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Iterator;
+
+import org.apache.ti.util.internal.concurrent.InternalConcurrentHashMap;
+
+
+/**
+ * ActionServlet that automatically registers requested Struts modules based on a set of module configuration file
+ * locators. The user may specify {@link ModuleConfigLocator} classes in /WEB-INF/beehive-netui-config.xml using the
+ * <code><module-config-locators></code> element.
+ */
+public class AutoRegisterActionServlet extends ActionServlet
+{
+
+ public void init()
+ throws ServletException
+ {
+ }
+
+ /**
+ * This override of the base class process() registers a Struts module on the fly if the
+ * config file can be found in our standard place (named in our standard way), regardless
+ * of whether the module is configured in web.xml.
+ */
+ protected void process( HttpServletRequest request, HttpServletResponse response )
+ throws IOException, ServletException
+ {
+ //
+ // First wrap the request with an object that contains request-scoped values that our runtime uses. This
+ // is faster than sticking everything into attributes on the request (then basically reading from a HashMap).
+ //
+ PageFlowRequestWrapper requestWrapper = PageFlowRequestWrapper.wrapRequest( request );
+ request = requestWrapper;
+
+ ServletContext servletContext = getServletContext();
+ String modulePath = PageFlowUtils.getModulePathForRequestPath( InternalUtils.getRequestPath( request ) );
+ ModuleConfig registeredApp;
+
+ //
+ // Get the registered Struts module for the request.
+ //
+ registeredApp = getModuleConfig( modulePath, request, response );
+
+ //
+ // If we've dynamically registered a module, then we need to override the base process() behavior to select the
+ // module. Note that we don't want to synchronize the call to process().
+ //
+ if ( registeredApp != null )
+ {
+ //
+ // Try to select the appropriate Struts module and delegate to its RequestProcessor.
+ //
+ ModuleConfig moduleConfig = InternalUtils.selectModule( modulePath, request, servletContext );
+ RequestProcessor requestProcessor = getRequestProcessor( moduleConfig );
+ requestProcessor.process( request, response );
+ }
+ else
+ {
+
+ //
+ // This is the same as the base process() behavior, but it checks for a missing module-configuration.
+ //
+ ModuleConfig moduleConfig = null;
+
+ if ( InternalUtils.getModuleConfig( RequestUtils.getModuleName( request, servletContext ), servletContext ) != null )
+ {
+ String modulePrefix = RequestUtils.getModuleName( request, servletContext );
+ moduleConfig = InternalUtils.selectModule( modulePrefix, request, servletContext );
+ }
+
+ String servletPath = InternalUtils.getRequestPath( request );
+ RequestProcessor rp = moduleConfig != null ? getRequestProcessor( moduleConfig ) : null;
+
+ if ( rp != null && moduleCanHandlePath( moduleConfig, rp, servletPath ) )
+ {
+ rp.process( request, response );
+ }
+ else
+ {
+ //
+ // Initialize the ServletContext in the request. Often, we need access to the ServletContext when we only
+ // have a ServletRequest.
+ //
+ InternalUtils.setServletContext( request, getServletContext() );
+
+ if ( processUnhandledAction( request, response, servletPath ) ) return;
+
+ String originalServletPath = requestWrapper.getOriginalServletPath();
+ if ( originalServletPath != null )
+ {
+ servletPath = originalServletPath;
+ modulePath = PageFlowUtils.getModulePathForRequestPath( originalServletPath );
+ }
+
+ if ( _log.isErrorEnabled() )
+ {
+ InternalStringBuilder msg = new InternalStringBuilder( "No module configuration registered for " );
+ msg.append( servletPath ).append( " (module path " ).append( modulePath ).append( ")." );
+ _log.error( msg.toString() );
+ }
+
+ //
+ // If we're not in production mode, send a diagnostic on the response; otherwise, simply send a 404.
+ //
+ if ( modulePath.length() == 0 ) modulePath = "/";
+ InternalUtils.sendDevTimeError( "PageFlow_NoModuleConf", null, HttpServletResponse.SC_NOT_FOUND,
+ request, response, servletContext,
+ new Object[]{ servletPath, modulePath } );
+ }
+ }
+ }
+
+ public void destroy()
+ {
+ super.destroy();
+ }
+
+ /**
+ * Last chance to handle an unhandled action URI.
+ * @return <code>true</code> if this method handled it (by forwarding somewhere or writing to the response).
+ */
+ protected boolean processUnhandledAction( HttpServletRequest request, HttpServletResponse response, String uri )
+ throws IOException, ServletException
+ {
+ return false;
+ }
+}
Added: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/ContainerAdapter.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/ContainerAdapter.java?rev=240168&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/ContainerAdapter.java (added)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/ContainerAdapter.java Thu Aug 25 22:46:03 2005
@@ -0,0 +1,187 @@
+/*
+ * 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.FactoryConfig;
+import org.apache.ti.pageflow.adapter.Adapter;
+
+import javax.security.auth.login.LoginException;
+
+
+/**
+ * Adapter interface for plugging into various containers. An implementor of this interface is "discovered" at
+ * runtime. The discovery process is as follows:
+ * <ul>
+ * <li>
+ * A list of META-INF/services/org.apache.ti.pageflow.ContainerAdapter resources is obtained
+ * from classpath. This means, for example, that a file called
+ * "org.apache.ti.pageflow.ContainerAdapter" under directory META-INF/services would be
+ * found inside any JAR file on classpath.
+ * </li>
+ * <li>
+ * Inside each of these resources is the name of a class that implements ContainerAdapter. This class
+ * is loaded, and its {@link #accept accept} method is called.
+ * </li>
+ * <li>
+ * If {@link #accept accept} returns <code>true</code>, then that implementation class is chosen as the current
+ * adapter; otherwise, the next one in the list is tried.
+ * </li>
+ * <li>If no adapters are discovered, an instance of {@link DefaultContainerAdapter} is used.
+ * </ul>
+ */
+public interface ContainerAdapter
+ extends Adapter {
+
+ /**
+ * Tell whether the server is running in production mode.
+ *
+ * @return <code>true</code> if the server is running in production mode.
+ */
+ public boolean isInProductionMode();
+
+ /**
+ * Tell whether a web application resource requires a secure transport protocol. This is
+ * determined from web.xml; for example, the following block specifies that all resources under
+ * /login require a secure transport protocol.
+ * <pre>
+ * <security-constraint>
+ * <web-resource-collection>
+ * <web-resource-name>Secure PageFlow - begin</web-resource-name>
+ * <url-pattern>/login/*</url-pattern>
+ * </web-resource-collection>
+ * <user-data-constraint>
+ * <transport-guarantee>CONFIDENTIAL</transport-guarantee>
+ * </user-data-constraint>
+ * </security-constraint>
+ * </pre>
+ *
+ * @param path a webapp-relative path for a resource.
+ * @return <code>Boolean.TRUE</code> if a transport-guarantee of <code>CONFIDENTIAL</code> or
+ * <code>INTEGRAL</code> is associated with the given resource; <code>Boolean.FALSE</code>
+ * a transport-guarantee of <code>NONE</code> is associated with the given resource; or
+ * <code>null</code> if there is no transport-guarantee associated with the given resource.
+ */
+ public SecurityProtocol getSecurityProtocol(String path);
+
+ /**
+ * Cause the server to do a security check for the given path. If required, it does a redirect to
+ * change the scheme (http/https).
+ *
+ * @param path the webapp-relative path on which to run security checks.
+ * @return <code>true</code> if a redirect occurred.
+ */
+ boolean doSecurityRedirect(String path);
+
+
+ /**
+ * Get the port on which the server is listening for unsecure connections.
+ *
+ * @return the port on which the server is listening for unsecure connections.
+ */
+ public int getListenPort();
+
+ /**
+ * Get the port on which the server is listening for secure connections.
+ *
+ * @return the port on which the server is listening for secure connections.
+ */
+ public int getSecureListenPort();
+
+ /**
+ * Log in the user, using "weak" username/password authentication.
+ *
+ * @param username the user's login name.
+ * @param password the user's password.
+ * @throws LoginException if the authentication failed
+ */
+ public void login(String username, String password)
+ throws LoginException;
+
+ /**
+ * Log out the current user.
+ *
+ * @param invalidateSessions if <code>true</code>, the session is invalidated (on all single-signon webapps);
+ * otherwise the session and its data are left intact. To invalidate the session in only the
+ * current webapp, set this parameter to <code>false</code> and call invalidate() on the HttpSession.
+ */
+ public void logout(boolean invalidateSessions);
+
+ /**
+ * Return the webapp context path for the given request. This differs from HttpServletRequest.getContextPath()
+ * only in that it will return a valid value even if the request is for the default webapp.
+ */
+ public String getFullContextPath();
+
+ /**
+ * Ensure that the given session attribute is replicated in a cluster for session failover.
+ * This method does not need to be implemented for servers that do not support clustering and
+ * session failover.
+ *
+ * @param attrName the name of the session attribute for which failover should be ensured.
+ * @param attrVal the value of the given session attribute.
+ */
+ public void ensureFailover(String attrName, Object attrVal);
+
+ /**
+ * Called at the beginning of each processed request.
+ */
+ public void beginRequest();
+
+ /**
+ * Called at the end of each processed request.
+ */
+ public void endRequest();
+
+ /**
+ * Get a context object to support Beehive Controls.
+ *
+ * @return a new ControlBeanContext.
+ */
+ public Object createControlBeanContext();
+
+ /**
+ * Get the name of the platform, which may be used to find platform-specific configuration files.
+ *
+ * @return the name of the platform
+ */
+ public String getPlatformName();
+
+ /**
+ * Get an event reporter, which will be notified of events like "page flow created", "action raised", etc.
+ */
+ public PageFlowEventReporter getEventReporter();
+
+ /**
+ * Generic method to get a Factory class that may be container dependent.
+ * <p/>
+ * <p/>
+ * This method is called to get the following Factory implementations:
+ * </p>
+ * <ul>
+ * <li>{@link org.apache.ti.core.urltemplates.URLTemplatesFactory}</li>
+ * </ul>
+ *
+ * @param classType the class type that the factory should extend or implement.
+ * @param id can be used for the case where there is more than one possible Factory
+ * that extends or implaments the class type.
+ * @param config a configuration object passed to a {@link org.apache.ti.core.factory.Factory}
+ * @return a Factory class that extends or implemtents the given class type.
+ */
+ public Factory getFactory(Class classType, String id, FactoryConfig config);
+}
Added: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/ControlFieldInitializationException.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/ControlFieldInitializationException.java?rev=240168&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/ControlFieldInitializationException.java (added)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/ControlFieldInitializationException.java Thu Aug 25 22:46:03 2005
@@ -0,0 +1,46 @@
+/*
+ * 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 thrown when there are errors initializing an annotated Control field.
+ */
+public class ControlFieldInitializationException
+ extends PageFlowManagedObjectException {
+
+ private String _fieldName;
+
+ /**
+ * Construct with no error message.
+ */
+ public ControlFieldInitializationException(String fieldName, PageFlowManagedObject object, Throwable cause) {
+ super(object, cause);
+ _fieldName = fieldName;
+ }
+
+ protected Object[] getMessageArgs() {
+ return new Object[]{_fieldName, getManagedObject().getDisplayName()};
+ }
+
+ protected String[] getMessageParts() {
+ return new String[]
+ {
+ "Exception occurred when initializing field ", " on page flow ", "."
+ };
+ }
+}
Added: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/DefaultContainerAdapter.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/DefaultContainerAdapter.java?rev=240168&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/DefaultContainerAdapter.java (added)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/DefaultContainerAdapter.java Thu Aug 25 22:46:03 2005
@@ -0,0 +1,225 @@
+/*
+ * 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.commons.chain.web.WebContext;
+import org.apache.ti.core.factory.Factory;
+import org.apache.ti.core.factory.FactoryConfig;
+import org.apache.ti.pageflow.internal.PageFlowBeanContext;
+import org.apache.ti.pageflow.xwork.PageFlowActionContext;
+import org.apache.ti.util.logging.Logger;
+
+import javax.security.auth.login.LoginException;
+
+
+/**
+ * Default implementation of a container adapter.
+ */
+public abstract class DefaultContainerAdapter
+ implements ContainerAdapter {
+
+ private static final Logger _log = Logger.getInstance(DefaultContainerAdapter.class);
+
+ private static boolean _productionMode = true;
+
+ private PageFlowEventReporter _eventReporter;
+
+ static {
+ String productionModeFlag = System.getProperty("beehive.productionmode");
+
+ if (productionModeFlag != null) {
+ _productionMode = Boolean.valueOf(productionModeFlag).booleanValue();
+ } else {
+ //
+ // This is our default definition of "production mode": when asserts are disabled (the following statement
+ // sets _productionMode to false when asserts are enabled).
+ //
+ assert (_productionMode = false) || true;
+ }
+ }
+
+ protected DefaultContainerAdapter() {
+ }
+
+ /**
+ * Tell whether the system is in production mode.
+ *
+ * @return <code>true</code> if the system property "beehive.productionmode" is set to "true", or if asserts are
+ * disabled for this class in the case where the system property has no value; <code>false</code> if the
+ * system property is set to "false", or if asserts are enabled for this class in the case where the
+ * system property has no value.
+ */
+ public boolean isInProductionMode() {
+ return _productionMode;
+ }
+
+ /**
+ * Tell whether a web application resource requires a secure transport protocol. This default implementation
+ * simply returns {@link SecurityProtocol#UNSPECIFIED} for all paths.
+ *
+ * @param path a webapp-relative path for a resource.
+ * @return {@link SecurityProtocol#UNSPECIFIED}.
+ */
+ public SecurityProtocol getSecurityProtocol(String path) {
+ // TODO: implement this based on parsing of web.xml
+ return SecurityProtocol.UNSPECIFIED;
+ }
+
+ /**
+ * Cause the server to do a security check for the given path. This default implementation does nothing.
+ *
+ * @return <code>false</code>
+ */
+ public boolean doSecurityRedirect(String path) {
+ return false;
+ }
+
+ /**
+ * Get the port on which the server is listening for unsecure connections. This default implementation always
+ * returns <code>-1</code>.
+ *
+ * @return <code>-1</code>.
+ */
+ public int getListenPort() {
+ // TODO: have a configuration in netui-config.xml to specify this; an alternative to having to have an adapter.
+ return -1;
+ }
+
+ /**
+ * Get the port on which the server is listening for secure connections. This default implementation always
+ * returns <code>-1</code>.
+ *
+ * @return <code>-1</code>.
+ */
+ public int getSecureListenPort() {
+ // TODO: have a configuration in netui-config.xml to specify this; an alternative to having to have an adapter.
+ return -1;
+ }
+
+ /**
+ * Log in the user, using "weak" username/password authentication. This default implementation always throws
+ * {@link UnsupportedOperationException}.
+ *
+ * @throws UnsupportedOperationException in all cases.
+ */
+ public void login(String username, String password)
+ throws LoginException {
+ throw new UnsupportedOperationException("login is not supported by "
+ + DefaultContainerAdapter.class.getName());
+ }
+
+ /**
+ * Log out the user. This default implementation always throws {@link UnsupportedOperationException}.
+ *
+ * @throws UnsupportedOperationException in all cases.
+ */
+ public void logout(boolean invalidateSessions) {
+ throw new UnsupportedOperationException("logout is not supported by "
+ + DefaultContainerAdapter.class.getName());
+ }
+
+ public String getFullContextPath() {
+ return PageFlowActionContext.get().getRequestContextPath();
+ }
+
+ /**
+ * Ensure that the given session attribute is replicated in a cluster for session failover.
+ * This method does not need to be implemented for servers that do not support clustering and
+ * session failover. The default implementation does nothing.
+ *
+ * @param attrName the name of the session attribute for which failover should be ensured.
+ * @param attrVal the value of the given session attribute.
+ */
+ public void ensureFailover(String attrName, Object attrVal) {
+ }
+
+ /**
+ * Called at the beginning of each processed request. This default implementation does nothing.
+ */
+ public void beginRequest() {
+ }
+
+ /**
+ * Called at the end of each processed request. This default implementation does nothing.
+ */
+ public void endRequest() {
+ }
+
+ /**
+ * Get a context object to support Beehive Controls. This default implementation returns an instance of
+ * {@link PageFlowBeanContext}.
+ *
+ * @return a new ControlBeanContext.
+ */
+ public Object createControlBeanContext() {
+ return new PageFlowBeanContext();
+ }
+
+ /**
+ * Set the AdapterContext.
+ *
+ * @param context the AdapterContext to set.
+ */
+ public void initialize(WebContext context) {
+ _eventReporter = createEventReporter(context);
+ }
+
+ /**
+ * Get the name of the platform, which may be used to find platform-specific configuration files. This default
+ * implementation returns "generic".
+ *
+ * @return the name of the platform ("generic" in this default implementation).
+ */
+ public String getPlatformName() {
+ return "generic";
+ }
+
+ /**
+ * Get an event reporter, which will be notified of events like "page flow created", "action raised", etc.
+ * This default implementation returns an instance of {@link DefaultPageFlowEventReporter}.
+ *
+ * @return a {@link PageFlowEventReporter}.
+ */
+ public PageFlowEventReporter getEventReporter() {
+ return _eventReporter;
+ }
+
+ protected PageFlowEventReporter createEventReporter(WebContext context) {
+ return new DefaultPageFlowEventReporter();
+ }
+
+ /**
+ * Generic method to get a Factory class that may be container dependent.
+ * <p/>
+ * <p/>
+ * This method is called to get the following Factory implementations:
+ * </p>
+ * <ul>
+ * <li>{@link org.apache.ti.core.urltemplates.URLTemplatesFactory}</li>
+ * </ul>
+ *
+ * @param factoryType the class type that the factory should extend or implement
+ * @param id can be used for the case where there is more than one possible Factory
+ * that extends or implaments the class type.
+ * @param config a configuration object passed to a {@link org.apache.ti.core.factory.Factory}
+ * @return a Factory class that extends or implemtents the given class type.
+ */
+ public Factory getFactory(Class factoryType, String id, FactoryConfig config) {
+ return null;
+ }
+}
Added: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/DefaultPageFlowEventReporter.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/DefaultPageFlowEventReporter.java?rev=240168&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/DefaultPageFlowEventReporter.java (added)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/DefaultPageFlowEventReporter.java Thu Aug 25 22:46:03 2005
@@ -0,0 +1,181 @@
+/*
+ * 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;
+import org.apache.ti.util.internal.InternalStringBuilder;
+import org.apache.ti.util.logging.Logger;
+
+/**
+ * Default event reporter. Logs every event when the log level is set to "debug" or "trace".
+ */
+public class DefaultPageFlowEventReporter
+ extends PageFlowEventReporter {
+
+ private static final Logger _log = Logger.getInstance(DefaultPageFlowEventReporter.class);
+
+ protected DefaultPageFlowEventReporter() {
+ super();
+ }
+
+ public void actionRaised(FlowController flowController) {
+ if (_log.isDebugEnabled()) {
+ PageFlowActionContext context = PageFlowActionContext.get();
+ LogMsg msg = new LogMsg("actionRaised");
+ msg.addParam("FlowController", flowController);
+ msg.addParam("ActionName", context.getName());
+ msg.addParam("formBean", context.getFormBean());
+ msg.addParam("Request", context.getRequestPath());
+ _log.debug(msg);
+ }
+ }
+
+ public void actionSuccess(FlowController flowController, Forward result, long timeTakenMillis) {
+ if (_log.isDebugEnabled()) {
+ PageFlowActionContext context = PageFlowActionContext.get();
+ LogMsg msg = new LogMsg("actionSuccess");
+ msg.addParam("FlowController", flowController);
+ msg.addParam("ActionName", context.getName());
+ msg.addParam("formBean", context.getFormBean());
+ msg.addParam("Request", context.getRequestPath());
+ msg.addParam("forward", result);
+ msg.addParam("TimeTakenMillis", new Long(timeTakenMillis));
+ _log.debug(msg);
+ }
+ }
+
+ public void exceptionRaised(Throwable ex, FlowController flowController) {
+ if (_log.isDebugEnabled()) {
+ PageFlowActionContext context = PageFlowActionContext.get();
+ LogMsg msg = new LogMsg("exceptionRaised");
+ msg.addParam("Throwable", ex);
+ msg.addParam("ActionName", context.getName());
+ msg.addParam("formBean", context.getFormBean());
+ msg.addParam("FlowController", flowController);
+ msg.addParam("Request", context.getRequestPath());
+ _log.debug(msg);
+ }
+ }
+
+ public void exceptionHandled(Throwable ex, FlowController flowController, Forward result,
+ long timeTakenMillis) {
+ if (_log.isDebugEnabled()) {
+ PageFlowActionContext context = PageFlowActionContext.get();
+ LogMsg msg = new LogMsg("exceptionHandled");
+ msg.addParam("Throwable", ex);
+ msg.addParam("ActionName", context.getName());
+ msg.addParam("formBean", context.getFormBean());
+ msg.addParam("FlowController", flowController);
+ msg.addParam("Request", context.getRequestPath());
+ msg.addParam("forward", result);
+ msg.addParam("TimeTakenMillis", new Long(timeTakenMillis));
+ _log.debug(msg);
+ }
+ }
+
+ public void flowControllerCreated(FlowController flowController) {
+ if (_log.isDebugEnabled()) {
+ PageFlowActionContext context = PageFlowActionContext.get();
+ LogMsg msg = new LogMsg("flowControllerCreated");
+ msg.addParam("FlowController", flowController);
+ msg.addParam("Request", context.getRequestPath());
+ _log.debug(msg);
+ }
+ }
+
+ public void flowControllerDestroyed(FlowController flowController, Object storageLocation) {
+ if (_log.isDebugEnabled()) {
+ LogMsg msg = new LogMsg("flowControllerDestroyed");
+ msg.addParam("FlowController", flowController);
+ msg.addParam("StorageLocation", storageLocation);
+ _log.debug(msg);
+ }
+ }
+
+ public void beginActionRequest() {
+ if (_log.isDebugEnabled()) {
+ PageFlowActionContext context = PageFlowActionContext.get();
+ LogMsg msg = new LogMsg("beginActionRequest");
+ msg.addParam("Request", context.getRequestPath());
+ _log.debug(msg);
+ }
+ }
+
+ public void endActionRequest(long timeTakenMillis) {
+ if (_log.isDebugEnabled()) {
+ PageFlowActionContext context = PageFlowActionContext.get();
+ LogMsg msg = new LogMsg("endActionRequest");
+ msg.addParam("Request", context.getRequestPath());
+ msg.addParam("TimeTakenMillis", new Long(timeTakenMillis));
+ _log.debug(msg);
+ }
+ }
+
+ public void beginPageRequest() {
+ if (_log.isDebugEnabled()) {
+ PageFlowActionContext context = PageFlowActionContext.get();
+ LogMsg msg = new LogMsg("beginPageRequest");
+ msg.addParam("Request", context.getRequestPath());
+ _log.debug(msg);
+ }
+ }
+
+ public void endPageRequest(long timeTakenMillis) {
+ if (_log.isDebugEnabled()) {
+ PageFlowActionContext context = PageFlowActionContext.get();
+ LogMsg msg = new LogMsg("endPageRequest");
+ msg.addParam("Request", context.getRequestPath());
+ msg.addParam("TimeTakenMillis", new Long(timeTakenMillis));
+ _log.debug(msg);
+ }
+ }
+
+ public void flowControllerRegistered(ModuleConfig moduleConfig) {
+ if (_log.isDebugEnabled()) {
+ LogMsg msg = new LogMsg("flowControllerRegistered");
+ msg.addParam("Namespace", moduleConfig.getNamespace());
+ msg.addParam("ControllerClassName", moduleConfig.getControllerClassName());
+ msg.addParam("ModuleConfig", moduleConfig);
+ _log.debug(msg);
+ }
+ }
+
+ protected static class LogMsg {
+
+ private String _eventName;
+ private InternalStringBuilder _logMessage;
+
+ public LogMsg(String eventName) {
+ _eventName = eventName;
+ }
+
+ public void addParam(String name, Object value) {
+ if (_logMessage == null) {
+ _logMessage = new InternalStringBuilder(_eventName).append(": ");
+ } else {
+ _logMessage.append(", ");
+ }
+
+ _logMessage.append(name).append('=').append(value);
+ }
+
+ public String toString() {
+ return _logMessage == null ? _eventName : _logMessage.toString();
+ }
+ }
+}
Added: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/DoubleSubmitException.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/DoubleSubmitException.java?rev=240168&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/DoubleSubmitException.java (added)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/DoubleSubmitException.java Thu Aug 25 22:46:03 2005
@@ -0,0 +1,55 @@
+/*
+ * 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 javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * Exception thrown when an action marked with the
+ * {@link org.apache.ti.pageflow.annotations.ti.action#preventDoubleSubmit @ti.action(preventDoubleSubmit=...}
+ * annotation attribute has been submitted to more than once.
+ */
+public class DoubleSubmitException
+ extends FlowControllerException
+ implements ResponseErrorCodeSender {
+
+ DoubleSubmitException(FlowController fc) {
+ super(fc);
+ }
+
+ protected Object[] getMessageArgs() {
+ return new Object[]{getActionName(), getFlowControllerURI()};
+ }
+
+ protected String[] getMessageParts() {
+ return new String[]{"A double-submit occurred for action ", " in page flow ", "."};
+ }
+
+ public void sendResponseErrorCode(HttpServletResponse response) throws IOException {
+ response.sendError(HttpServletResponse.SC_BAD_REQUEST, getLocalizedMessage());
+ }
+
+ /**
+ * 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>true</code>.
+ */
+ public boolean causeMayBeSessionExpiration() {
+ return true;
+ }
+}
Added: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/EmptyNestingStackException.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/EmptyNestingStackException.java?rev=240168&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/EmptyNestingStackException.java (added)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/EmptyNestingStackException.java Thu Aug 25 22:46:03 2005
@@ -0,0 +1,50 @@
+/*
+ * 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 the user invokes an action in a nested page flow that uses a
+ * <code>{@link org.apache.ti.pageflow.annotations.ti.forward @ti.forward}(</code>...<code>
+ * returnAction="</code><i>action-name-in-calling-pageflow</i><code>")</code>
+ * annotation, but there is no calling page flow. This can happen in iterative
+ * development mode when you have modified files and caused the web application to be redeployed,
+ * or when the session expires.
+ */
+public class EmptyNestingStackException extends FlowControllerException {
+
+ public EmptyNestingStackException(FlowController fc) {
+ super(fc);
+ }
+
+ protected Object[] getMessageArgs() {
+ return new Object[]{getActionName(), getFlowControllerURI()};
+ }
+
+ protected String[] getMessageParts() {
+ return new String[]{"Empty nesting stack for returned action ", " from Page Flow ", "."};
+ }
+
+ /**
+ * 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>true</code>.
+ */
+ public boolean causeMayBeSessionExpiration() {
+ return true;
+ }
+}
Added: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/ExpressionMessage.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/ExpressionMessage.java?rev=240168&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/ExpressionMessage.java (added)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/ExpressionMessage.java Thu Aug 25 22:46:03 2005
@@ -0,0 +1,107 @@
+/*
+ * 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.ActionMessage;
+import org.apache.ti.pageflow.internal.InternalConstants;
+
+/**
+ * Extension of the base Struts ActionMessage; instead of retrieving messages and their arguments from message
+ * resources, it calculates them by evaluating JSP 2.0-style expressions (or, in the degenerate case, from hardcoded
+ * strings).
+ */
+public class ExpressionMessage
+ extends ActionMessage {
+
+ /**
+ * Constructor, using an array for the message arguments.
+ *
+ * @param expression the JSP 2.0-style expression (e.g., <code>${pageFlow.myProperty}</code>) or literal string
+ * that will be used as the message.
+ * @param messageArgExpressions an array of JSP 2.0-style expressions <i>or</i> raw Objects to be used as arguments
+ * to the message. Expressions are evaluated; all other Objects are passed as-is.
+ */
+ public ExpressionMessage(String expression, Object[] messageArgExpressions) {
+ super(InternalConstants.MESSAGE_IS_EXPRESSION_PREFIX + expression, prefixArgs(messageArgExpressions));
+ }
+
+ /**
+ * Constructor, for a message without message arguments.
+ *
+ * @param expression the JSP 2.0-style expression (e.g., <code>${pageFlow.myProperty}</code>) or literal string
+ * that will be used as the message.
+ */
+ public ExpressionMessage(String expression) {
+ this(expression, null);
+ }
+
+ /**
+ * Constructor, for a message with a single argument.
+ *
+ * @param expression the JSP 2.0-style expression (e.g., <code>${pageFlow.myProperty}</code>) or literal string
+ * that will be used as the message.
+ * @param messageArgExpression a JSP 2.0-style expression <i>or</i> raw Object to be used the argument
+ * to the message. Expressions are evaluated; all other Objects are passed as-is.
+ */
+ public ExpressionMessage(String expression, Object messageArgExpression) {
+ this(expression, new Object[]{messageArgExpression});
+ }
+
+ /**
+ * Constructor, for a message with two arguments.
+ *
+ * @param expression the JSP 2.0-style expression (e.g., <code>${pageFlow.myProperty}</code>) or literal string
+ * that will be used as the message.
+ * @param messageArgExpression1 a JSP 2.0-style expression <i>or</i> raw Object to be used the first argument
+ * to the message. Expressions are evaluated; all other Objects are passed as-is.
+ * @param messageArgExpression2 a JSP 2.0-style expression <i>or</i> raw Object to be used the second argument
+ * to the message. Expressions are evaluated; all other Objects are passed as-is.
+ */
+ public ExpressionMessage(String expression, Object messageArgExpression1, Object messageArgExpression2) {
+ this(expression, new Object[]{messageArgExpression1, messageArgExpression2});
+ }
+
+ /**
+ * Constructor, for a message with two arguments.
+ *
+ * @param expression the JSP 2.0-style expression (e.g., <code>${pageFlow.myProperty}</code>) or literal string
+ * that will be used as the message.
+ * @param messageArgExpression1 a JSP 2.0-style expression <i>or</i> raw Object to be used the first argument
+ * to the message. Expressions are evaluated; all other Objects are passed as-is.
+ * @param messageArgExpression2 a JSP 2.0-style expression <i>or</i> raw Object to be used the second argument
+ * to the message. Expressions are evaluated; all other Objects are passed as-is.
+ * @param messageArgExpression3 a JSP 2.0-style expression <i>or</i> raw Object to be used the third argument
+ * to the message. Expressions are evaluated; all other Objects are passed as-is.
+ */
+ public ExpressionMessage(String expression, Object messageArgExpression1, Object messageArgExpression2,
+ Object messageArgExpression3) {
+ this(expression, new Object[]{messageArgExpression1, messageArgExpression2, messageArgExpression3});
+ }
+
+ private static Object[] prefixArgs(Object[] messageArgExpressions) {
+ if (messageArgExpressions == null) return null;
+
+ Object[] ret = new Object[messageArgExpressions.length];
+
+ for (int i = 0; i < messageArgExpressions.length; i++) {
+ ret[i] = InternalConstants.MESSAGE_IS_EXPRESSION_PREFIX + messageArgExpressions[i];
+ }
+
+ return ret;
+ }
+}
Added: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/FacesBackingBean.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/FacesBackingBean.java?rev=240168&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/FacesBackingBean.java (added)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/FacesBackingBean.java Thu Aug 25 22:46:03 2005
@@ -0,0 +1,200 @@
+/*
+ * 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.StorageHandler;
+import org.apache.ti.pageflow.internal.CachedFacesBackingInfo;
+import org.apache.ti.pageflow.internal.CachedSharedFlowRefInfo;
+import org.apache.ti.pageflow.internal.InternalConstants;
+import org.apache.ti.pageflow.internal.InternalUtils;
+import org.apache.ti.util.internal.cache.ClassLevelCache;
+import org.apache.ti.util.logging.Logger;
+
+import java.lang.reflect.Field;
+import java.util.Collections;
+import java.util.Map;
+
+/**
+ * <p/>
+ * A JavaServer Faces backing bean. An instance of this class will be created whenever a corresponding JSF path is
+ * requested (e.g., an instance of foo.MyPage will be created for the webapp-relative path "/foo/MyPage.faces"). The
+ * instance will be released (removed from the user session) when a non-matching path is requested. A faces backing
+ * bean can hold component references and event/command handlers, and it can raise actions with normal JSF command event
+ * handlers that are annotated with {@link org.apache.ti.pageflow.annotations.ti.commandHandler @ti.commandHandler}.
+ * The bean instance can be bound to with a JSF-style expression like <code>#{backing.myComponent}</code>.
+ * </p>
+ * <p/>
+ * JSF backing beans are configured using the
+ * {@link org.apache.ti.pageflow.annotations.ti.facesBacking @ti.facesBacking} annotation.
+ * </p>
+ */
+public abstract class FacesBackingBean
+ extends PageFlowManagedObject {
+
+ private static final String CACHED_INFO_KEY = "cachedInfo";
+ private static final Logger _log = Logger.getInstance(FacesBackingBean.class);
+
+ private Map _pageInputs;
+
+
+ /**
+ * Store this object in the user session, in the appropriate place. Used by the framework; normally should not be
+ * called directly.
+ */
+ public void persistInSession() {
+ StorageHandler sh = Handlers.get().getStorageHandler();
+ String attrName = InternalUtils.getScopedAttrName(InternalConstants.FACES_BACKING_ATTR);
+ sh.setAttribute(attrName, this);
+ }
+
+ /**
+ * Remove this instance from the session.
+ */
+ protected void removeFromSession() {
+ StorageHandler sh = Handlers.get().getStorageHandler();
+ String attrName = InternalUtils.getScopedAttrName(InternalConstants.FACES_BACKING_ATTR);
+
+ sh.removeAttribute(attrName);
+ }
+
+ /**
+ * Ensures that any changes to this object will be replicated in a cluster (for failover),
+ * even if the replication scheme uses a change-detection algorithm that relies on
+ * HttpSession.setAttribute to be aware of changes. Note that this method is used by the framework
+ * and does not need to be called explicitly in most cases.
+ */
+ public void ensureFailover() {
+ StorageHandler sh = Handlers.get().getStorageHandler();
+ String attr = InternalUtils.getScopedAttrName(InternalConstants.FACES_BACKING_ATTR);
+ sh.ensureFailover(attr, this);
+ }
+
+ /**
+ * Get the display name for the bean. For FacesBackingBeans, this is simply the class name.
+ */
+ public String getDisplayName() {
+ return getClass().getName();
+ }
+
+ /**
+ * Reinitialize the bean for a new request. Used by the framework; normally should not be called directly.
+ */
+ public void reinitialize() {
+ super.reinitialize();
+
+ if (_pageInputs == null) {
+ Map map = InternalUtils.getActionOutputMap(false);
+ if (map != null) _pageInputs = Collections.unmodifiableMap(map);
+ }
+
+ //
+ // Initialize the page flow field.
+ //
+ Field pageFlowMemberField = getCachedInfo().getPageFlowMemberField();
+
+ // TODO: should we add a compiler warning if this field isn't transient? All this reinitialization logic is
+ // for the transient case.
+ if (fieldIsUninitialized(pageFlowMemberField)) {
+ PageFlowController pfc = PageFlowUtils.getCurrentPageFlow();
+ initializeField(pageFlowMemberField, pfc);
+ }
+
+ //
+ // Initialize the shared flow fields.
+ //
+ CachedSharedFlowRefInfo.SharedFlowFieldInfo[] sharedFlowMemberFields =
+ getCachedInfo().getSharedFlowMemberFields();
+
+ if (sharedFlowMemberFields != null) {
+ for (int i = 0; i < sharedFlowMemberFields.length; i++) {
+ CachedSharedFlowRefInfo.SharedFlowFieldInfo fi = sharedFlowMemberFields[i];
+ Field field = fi.field;
+
+ if (fieldIsUninitialized(field)) {
+ Map/*< String, SharedFlowController >*/ sharedFlows = PageFlowUtils.getSharedFlows();
+ String name = fi.sharedFlowName;
+ SharedFlowController sf = name != null ? (SharedFlowController) sharedFlows.get(name) : null;
+
+ if (sf != null) {
+ initializeField(field, sf);
+ } else {
+ _log.error("Could not find shared flow with name \"" + fi.sharedFlowName
+ + "\" to initialize field " + field.getName() + " in " + getClass().getName());
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Get a page input that was passed from a Page Flow action as an "action output".
+ *
+ * @param pageInputName the name of the page input. This is the same as the name of the "action output".
+ * @return the value of the page input, or <code>null</code> if the given one does not exist.
+ */
+ protected Object getPageInput(String pageInputName) {
+ return _pageInputs != null ? _pageInputs.get(pageInputName) : null;
+ }
+
+ /**
+ * Get the map of all page inputs that was passed from a Page Flow action as "action outputs".
+ *
+ * @return a Map of page-input-name (String) to page-input-value (Object).
+ */
+ public Map getPageInputMap() {
+ return _pageInputs;
+ }
+
+ private CachedFacesBackingInfo getCachedInfo() {
+ ClassLevelCache cache = ClassLevelCache.getCache(getClass());
+ CachedFacesBackingInfo info = (CachedFacesBackingInfo) cache.getCacheObject(CACHED_INFO_KEY);
+
+ if (info == null) {
+ info = new CachedFacesBackingInfo(getClass());
+ cache.setCacheObject(CACHED_INFO_KEY, info);
+ }
+
+ return info;
+ }
+
+ /**
+ * Callback that is invoked when this backing bean is restored as the page itself is restored through a
+ * {@link org.apache.ti.pageflow.annotations.ti.forward @ti.forward} or
+ * {@link org.apache.ti.pageflow.annotations.ti.simpleAction @ti.simpleAction} with
+ * {@link org.apache.ti.pageflow.annotations.ti.forward#navigateTo() navigateTo}={@link org.apache.ti.pageflow.annotations.ti.NavigateTo#currentPage ti.NavigateTo.currentPage}
+ * or
+ * {@link org.apache.ti.pageflow.annotations.ti.forward#navigateTo() navigateTo}={@link org.apache.ti.pageflow.annotations.ti.NavigateTo#currentPage ti.NavigateTo.previousPage}.
+ */
+ protected void onRestore() {
+ }
+
+ /**
+ * Restore this bean (set it as the current one from some dormant state). This is a framework-invoked method that
+ * should not normally be called directly.
+ */
+ public void restore() {
+ reinitialize();
+ StorageHandler sh = Handlers.get().getStorageHandler();
+ String attrName = InternalUtils.getScopedAttrName(InternalConstants.FACES_BACKING_ATTR);
+ sh.setAttribute(attrName, this);
+ Map newActionOutputs = InternalUtils.getActionOutputMap(false);
+ if (newActionOutputs != null) _pageInputs = newActionOutputs;
+ onRestore();
+ }
+}
Added: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/FacesBackingBeanFactory.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/FacesBackingBeanFactory.java?rev=240168&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/FacesBackingBeanFactory.java (added)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/FacesBackingBeanFactory.java Thu Aug 25 22:46:03 2005
@@ -0,0 +1,225 @@
+/*
+ * 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.internal.AnnotationReader;
+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.PageflowFactories;
+import org.apache.ti.schema.config.PageflowFactory;
+import org.apache.ti.util.config.ConfigUtil;
+import org.apache.ti.util.internal.FileUtils;
+import org.apache.ti.util.logging.Logger;
+
+import java.util.Map;
+
+
+/**
+ * Factory for creating "backing beans" for JavaServer Faces pages.
+ */
+public class FacesBackingBeanFactory
+ extends Factory
+ implements InternalConstants {
+
+ private static final Logger _log = Logger.getInstance(FacesBackingBeanFactory.class);
+
+ private static final String CONTEXT_ATTR = InternalConstants.ATTR_PREFIX + "jsfBackingFactory";
+
+ protected void onCreate() {
+ }
+
+ protected FacesBackingBeanFactory() {
+ }
+
+ public static void init(Map appScope) {
+ PageflowFactories factoriesBean = ConfigUtil.getConfig().getPageflowFactories();
+ FacesBackingBeanFactory factory = null;
+
+ if (factoriesBean != null) {
+ PageflowFactory fcFactoryBean = factoriesBean.getFacesBackingBeanFactory();
+ factory = (FacesBackingBeanFactory) FactoryUtils.getFactory(fcFactoryBean, FacesBackingBeanFactory.class);
+ }
+
+ if (factory == null) factory = new FacesBackingBeanFactory();
+ 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 FacesBackingBeanFactory.
+ *
+ * @return a FacesBackingBeanFactory for the given application. It may or may not be a cached instance.
+ */
+ public static FacesBackingBeanFactory get() {
+ Map appScope = PageFlowActionContext.get().getApplication();
+ FacesBackingBeanFactory factory = (FacesBackingBeanFactory) appScope.get(CONTEXT_ATTR);
+ assert factory != null
+ : FacesBackingBeanFactory.class.getName() + " was not found in application attribute " + CONTEXT_ATTR;
+ factory.reinit();
+ return factory;
+ }
+
+ /**
+ * Get the "backing bean" associated with the JavaServer Faces page for a request.
+ */
+ public FacesBackingBean getFacesBackingBeanForRequest() {
+ String uri = PageFlowActionContext.get().getRequestPath();
+ assert uri.charAt(0) == '/' : uri;
+ String backingClassName = FileUtils.stripFileExtension(uri.substring(1).replace('/', '.'));
+ FacesBackingBean currentBean = InternalUtils.getFacesBackingBean();
+
+ //
+ // If there is no current backing bean, or if the current one doesn't match the desired classname, create one.
+ //
+ if (currentBean == null || !currentBean.getClass().getName().equals(backingClassName)) {
+ FacesBackingBean bean = null;
+
+ if (FileUtils.uriEndsWith(uri, FACES_EXTENSION) || FileUtils.uriEndsWith(uri, JSF_EXTENSION)) {
+ bean = loadFacesBackingBean(backingClassName);
+
+ //
+ // If we didn't create (or failed to create) a backing bean, and if this is a JSF request, then create
+ // a default one. This ensures that there will be a place for things like page inputs, that get stored
+ // in the backing bean across postbacks to the same JSF.
+ //
+ if (bean == null) bean = new DefaultFacesBackingBean();
+
+ //
+ // If we created a backing bean, invoke its create callback, and tell it to store itself in the session.
+ //
+ if (bean != null) {
+ try {
+ bean.create();
+ } catch (Exception e) {
+ _log.error("Error while creating backing bean instance of " + backingClassName, e);
+ }
+
+ bean.persistInSession();
+ return bean;
+ }
+ }
+
+ //
+ // We didn't create a backing bean. If there's one in the session (an inappropriate one), remove it.
+ //
+ InternalUtils.removeCurrentFacesBackingBean();
+ } else if (currentBean != null) {
+ if (_log.isDebugEnabled()) {
+ _log.debug("Using existing backing bean instance " + currentBean + " for request " +
+ PageFlowActionContext.get().getRequestPath());
+ }
+
+ currentBean.reinitialize();
+ }
+
+ return currentBean;
+ }
+
+ /**
+ * Load a "backing bean" associated with the JavaServer Faces page for a request.
+ *
+ * @param backingClassName the name of the backing bean class.
+ * @return an initialized FacesBackingBean, or <code>null</code> if an error occurred.
+ */
+ protected FacesBackingBean loadFacesBackingBean(String backingClassName) {
+ try {
+ Class backingClass = null;
+
+ try {
+ backingClass = getFacesBackingBeanClass(backingClassName);
+ } catch (ClassNotFoundException e) {
+ // ignore -- we deal with this and log this immediately below. getFacesBackingBeanClass() by default
+ // does not throw this exception, but a derived version might.
+ }
+
+ if (backingClass == null) {
+ if (_log.isTraceEnabled()) {
+ _log.trace("No backing bean class " + backingClassName + " found for request "
+ + PageFlowActionContext.get().getRequestPath());
+ }
+ } else {
+ AnnotationReader annReader = Handlers.get().getAnnotationHandler().getAnnotationReader(backingClass);
+
+ if (annReader.getJpfAnnotation(backingClass, "facesBacking") != null) {
+ if (_log.isDebugEnabled()) {
+ _log.debug("Found backing class " + backingClassName + " for request "
+ + PageFlowActionContext.get().getRequestPath()
+ + "; creating a new instance.");
+ }
+
+ return getFacesBackingBeanInstance(backingClass);
+ } else {
+ if (_log.isDebugEnabled()) {
+ _log.debug("Found matching backing class " + backingClassName + " for request "
+ + PageFlowActionContext.get().getRequestPath()
+ + ", but it does not have the " + ANNOTATION_QUALIFIER
+ + "facesBacking annotation.");
+ }
+ }
+ }
+ } catch (InstantiationException e) {
+ _log.error("Could not create backing bean instance of " + backingClassName, e);
+ } catch (IllegalAccessException e) {
+ _log.error("Could not create backing bean instance of " + backingClassName, e);
+ }
+
+ return null;
+ }
+
+ private static class DefaultFacesBackingBean
+ extends FacesBackingBean {
+
+ }
+
+ /**
+ * Get a FacesBackingBean class. By default, this loads the class using the thread context class loader.
+ *
+ * @param className the name of the {@link FacesBackingBean} class to load.
+ * @return the loaded {@link FacesBackingBean} class.
+ * @throws ClassNotFoundException if the requested class could not be found.
+ */
+ public Class getFacesBackingBeanClass(String className)
+ throws ClassNotFoundException {
+ return Handlers.get().getReloadableClassHandler().loadCachedClass(className);
+ }
+
+ /**
+ * Get a FacesBackingBean instance, given a FacesBackingBean class.
+ *
+ * @param beanClass the Class, which must be assignable to {@link FacesBackingBean}.
+ * @return a new FacesBackingBean instance.
+ */
+ public FacesBackingBean getFacesBackingBeanInstance(Class beanClass)
+ throws InstantiationException, IllegalAccessException {
+ assert FacesBackingBean.class.isAssignableFrom(beanClass)
+ : "Class " + beanClass.getName() + " does not extend " + FacesBackingBean.class.getName();
+ return (FacesBackingBean) beanClass.newInstance();
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@struts.apache.org
For additional commands, e-mail: dev-help@struts.apache.org