Author: cpopetz
Date: 2008-12-22 11:49:56 -0500 (Mon, 22 Dec 2008)
New Revision: 9818
Modified:
trunk/src/main/org/jboss/seam/web/WicketFilter.java
trunk/src/wicket/org/jboss/seam/wicket/SeamWebApplication.java
trunk/src/wicket/org/jboss/seam/wicket/web/WicketFilterInstantiator.java
Log:
JBSEAM-3670: Wicket filter shouldn't unconditionally set up scopes.
Modified: trunk/src/main/org/jboss/seam/web/WicketFilter.java
===================================================================
--- trunk/src/main/org/jboss/seam/web/WicketFilter.java 2008-12-22 16:20:30 UTC (rev
9817)
+++ trunk/src/main/org/jboss/seam/web/WicketFilter.java 2008-12-22 16:49:56 UTC (rev
9818)
@@ -13,19 +13,19 @@
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletRequest;
import org.jboss.seam.Component;
import org.jboss.seam.ScopeType;
+import org.jboss.seam.Seam;
import org.jboss.seam.annotations.Install;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Observer;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.annotations.intercept.BypassInterceptors;
import org.jboss.seam.contexts.Contexts;
+import org.jboss.seam.contexts.ServletLifecycle;
import org.jboss.seam.core.Init;
import org.jboss.seam.deployment.HotDeploymentStrategy;
-import org.jboss.seam.servlet.ContextualHttpServletRequest;
@Scope(APPLICATION)
@Name("org.jboss.seam.web.wicketFilter")
@@ -49,6 +49,9 @@
private ClassLoader hotDeployClassLoader;
+ /*
+ * Upon initialization and re-initialization, lookup the hot deployment strategy and
grab its classloader, if it exists.
+ */
@Observer(value= {
"org.jboss.seam.postInitialization","org.jboss.seam.postReInitialization"}
)
public void postReInitialization()
{
@@ -65,23 +68,20 @@
public void doFilter(final ServletRequest servletRequest, final ServletResponse
servletResponse, final FilterChain chain) throws IOException, ServletException
{
+ /* If there is no delegate, we are a no-op filter */
if (delegate==null)
{
chain.doFilter(servletRequest, servletResponse);
}
else
{
- new ContextualHttpServletRequest((HttpServletRequest) servletRequest)
- {
- @Override
- public void process() throws Exception
- {
+ Init init = (Init) ServletLifecycle.getServletContext().getAttribute(
Seam.getComponentName(Init.class) );
/*
* We initialize the delegate on the first actual request and any time
the
* init timestamp changes, so that the WicketFilter gets reinitialized
whenever the
* hot deployment classloader detects changes, enabling wicket components
to be hot deployed.
*/
- if (lastInitTime != Init.instance().getTimestamp())
+ if (init != null && lastInitTime != init.getTimestamp())
{
delegate.destroy();
@@ -98,6 +98,10 @@
{
parameters.put("filterMappingUrlPattern", "/*");
}
+
+ /* Let the seam debug flag control the wicket configuration flag
(deployment vs. development) */
+ parameters.put("configuration",init.isDebug() ?
"development" : "deployment");
+
if (getApplicationFactoryClass() != null)
{
parameters.put("applicationFactoryClassName",
getApplicationFactoryClass());
@@ -123,22 +127,24 @@
if (hotDeployClassLoader != null)
Thread.currentThread().setContextClassLoader(previousClassLoader);
}
- lastInitTime = Init.instance().getTimestamp();
+ lastInitTime = init.getTimestamp();
}
delegate.doFilter(servletRequest, servletResponse, chain);
}
-
- }.run();
}
- }
@Override
public void init(FilterConfig filterConfig) throws ServletException
{
super.init(filterConfig);
-
- delegate = (javax.servlet.Filter)
Component.getInstance("org.jboss.seam.wicket.web.wicketFilterInstantiator",
ScopeType.STATELESS);
- savedConfig = filterConfig;
+ /* Save the configuration so that we can use it to re-initialize the wicket filter
at request time, as
+ * we may need to do it again if changes are hot deployed. Also, look up the
delegate now, as the presence
+ * of the delegate component implies the presence of the wicket classes
themselves.
+ */
+ if (delegate == null) {
+ delegate = (javax.servlet.Filter)
Component.getInstance("org.jboss.seam.wicket.web.wicketFilterInstantiator",
ScopeType.STATELESS);
+ savedConfig = filterConfig;
+ }
}
public String getApplicationClass()
Modified: trunk/src/wicket/org/jboss/seam/wicket/SeamWebApplication.java
===================================================================
--- trunk/src/wicket/org/jboss/seam/wicket/SeamWebApplication.java 2008-12-22 16:20:30 UTC
(rev 9817)
+++ trunk/src/wicket/org/jboss/seam/wicket/SeamWebApplication.java 2008-12-22 16:49:56 UTC
(rev 9818)
@@ -1,5 +1,7 @@
package org.jboss.seam.wicket;
+import javax.servlet.http.HttpServletRequest;
+
import org.apache.wicket.IRedirectListener;
import org.apache.wicket.Request;
import org.apache.wicket.RequestCycle;
@@ -10,15 +12,27 @@
import org.apache.wicket.markup.html.form.IOnChangeListener;
import org.apache.wicket.markup.html.link.ILinkListener;
import org.apache.wicket.protocol.http.WebApplication;
+import org.apache.wicket.protocol.http.WebRequest;
+import org.apache.wicket.protocol.http.WebRequestCycle;
import org.apache.wicket.protocol.http.WebRequestCycleProcessor;
+import org.apache.wicket.protocol.http.WebResponse;
import org.apache.wicket.protocol.http.WebSession;
import org.apache.wicket.protocol.http.request.WebRequestCodingStrategy;
import org.apache.wicket.request.IRequestCodingStrategy;
import org.apache.wicket.request.IRequestCycleProcessor;
import org.apache.wicket.request.target.component.IBookmarkablePageRequestTarget;
import
org.apache.wicket.request.target.component.listener.IListenerInterfaceRequestTarget;
+import org.jboss.seam.contexts.Contexts;
+import org.jboss.seam.contexts.Lifecycle;
+import org.jboss.seam.contexts.ServletLifecycle;
import org.jboss.seam.core.Conversation;
+import org.jboss.seam.core.ConversationPropagation;
+import org.jboss.seam.core.Events;
import org.jboss.seam.core.Manager;
+import org.jboss.seam.log.LogProvider;
+import org.jboss.seam.log.Logging;
+import org.jboss.seam.servlet.ServletRequestSessionMap;
+import org.jboss.seam.web.ServletContexts;
import org.jboss.seam.wicket.international.SeamStatusMessagesListener;
/**
@@ -30,7 +44,26 @@
public abstract class SeamWebApplication extends WebApplication
{
+ private static final LogProvider log =
Logging.getLogProvider(SeamWebApplication.class);
+
/**
+ * When operating in tests, it is sometimes useful to leave the contexts extant
+ * after a request, and destroy them upon the next request, so that models that use
injections
+ * can be queried post-request to determine their values.
+ */
+ protected boolean destroyContextsLazily = false;
+
+ public boolean isDestroyContextsLazily()
+ {
+ return destroyContextsLazily;
+ }
+
+ public void setDestroyContextsLazily(boolean destroyContextsLazily)
+ {
+ this.destroyContextsLazily = destroyContextsLazily;
+ }
+
+ /**
* Custom session with invalidation override. We can't just let Wicket
* invalidate the session as Seam might have to do some cleaning up to do.
*/
@@ -136,4 +169,91 @@
protected abstract Class getLoginPage();
+ /*
+ * Override to provide a seam-specific RequestCycle, which sets up seam contexts.
+ */
+ @Override
+ public RequestCycle newRequestCycle(final Request request, final Response response)
+ {
+ return new SeamWebRequestCycle(this, (WebRequest)request, (WebResponse)response);
+ }
+
+
+ /**
+ * A WebRequestCycle that sets up seam requests. Essentially this
+ * is similiar to the work of ContextualHttpServletRequest, but using the wicket API
+ * @author cpopetz
+ *
+ */
+ protected static class SeamWebRequestCycle extends WebRequestCycle {
+
+ public SeamWebRequestCycle(WebApplication application, WebRequest request, Response
response)
+ {
+ super(application, request, response);
+ }
+
+ @Override
+ protected void onBeginRequest()
+ {
+ HttpServletRequest httpRequest = ((WebRequest)request).getHttpServletRequest();
+
+ if (Contexts.getEventContext() != null &&
((SeamWebApplication)getApplication()).isDestroyContextsLazily() &&
ServletContexts.instance().getRequest() != httpRequest)
+ {
+ destroyContexts();
+ }
+
+ if (Contexts.getEventContext() == null)
+ {
+ ServletLifecycle.beginRequest(httpRequest);
+ ServletContexts.instance().setRequest(httpRequest);
+ ConversationPropagation.instance().restoreConversationId(
request.getParameterMap() );
+ Manager.instance().restoreConversation();
+ ServletLifecycle.resumeConversation(httpRequest);
+ Manager.instance().handleConversationPropagation( request.getParameterMap()
);
+
+ // Force creation of the session
+ if (httpRequest.getSession(false) == null)
+ {
+ httpRequest.getSession(true);
+ }
+ }
+ super.onBeginRequest();
+ Events.instance().raiseEvent("org.jboss.seam.wicket.beforeRequest");
+ }
+
+ @Override
+ protected void onEndRequest()
+ {
+ // TODO Auto-generated method stub
+ try
+ {
+ super.onEndRequest();
+
Events.instance().raiseEvent("org.jboss.seam.wicket.afterRequest");
+ }
+ finally
+ {
+ if (Contexts.getEventContext() != null &&
!((SeamWebApplication)getApplication()).isDestroyContextsLazily())
+ {
+ destroyContexts();
+ }
+ }
+ }
+
+ private void destroyContexts()
+ {
+ try {
+ HttpServletRequest httpRequest =
((WebRequest)request).getHttpServletRequest();
+ Manager.instance().endRequest( new ServletRequestSessionMap(httpRequest) );
+ ServletLifecycle.endRequest(httpRequest);
+ }
+ catch (Exception e)
+ {
+ /* Make sure we always clear out the thread locals */
+ Lifecycle.endRequest();
+ log.warn("ended request due to exception", e);
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
}
Modified: trunk/src/wicket/org/jboss/seam/wicket/web/WicketFilterInstantiator.java
===================================================================
--- trunk/src/wicket/org/jboss/seam/wicket/web/WicketFilterInstantiator.java 2008-12-22
16:20:30 UTC (rev 9817)
+++ trunk/src/wicket/org/jboss/seam/wicket/web/WicketFilterInstantiator.java 2008-12-22
16:49:56 UTC (rev 9818)
@@ -1,6 +1,3 @@
-/**
- *
- */
package org.jboss.seam.wicket.web;
import static org.jboss.seam.annotations.Install.BUILT_IN;
@@ -25,12 +22,20 @@
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.annotations.Unwrap;
import org.jboss.seam.annotations.intercept.BypassInterceptors;
+import org.jboss.seam.contexts.Lifecycle;
import org.jboss.seam.log.LogProvider;
import org.jboss.seam.log.Logging;
import org.jboss.seam.web.FilterConfigWrapper;
import org.jboss.seam.wicket.WebApplication;
import org.jboss.seam.wicket.ioc.WicketClassLoader;
+/**
+ * This component wraps the WicketFilter, encapsulates the class dependencies
+ * upon the wicket library, and propogates the configuration from seam's own
+ * WicketFilter, specified with web:wicket-wilter. It also sets up the
WicketClassLoader
+ * to instrument wicket components on the fly, if necessary.
+ *
+ */
@Name("org.jboss.seam.wicket.web.wicketFilterInstantiator")
@Install(precedence = BUILT_IN,
classDependencies={"org.apache.wicket.Application"})
@BypassInterceptors
@@ -46,55 +51,70 @@
{
return new WicketFilter()
{
-
private ClassLoader classLoader;
@Override
public void init(FilterConfig filterConfig) throws ServletException
{
- Map<String, String> parameters = new HashMap<String, String>();
- try
- {
-
- ClassLoader parent = Thread.currentThread().getContextClassLoader();
- File dir = getRealFile(filterConfig.getServletContext(),
DEFAULT_WICKET_COMPONENT_DIRECTORY_PATH);
- if (dir == null)
+ try
+ {
+ // We need the Application context active in order to lookup the
WebApplication component
+ Lifecycle.setupApplication();
+ Map<String, String> parameters = new HashMap<String,
String>();
+ try
{
- log.warn("No wicket components directory specified to give Seam
super powers to");
- this.classLoader = parent;
+ ClassLoader parent = Thread.currentThread().getContextClassLoader();
+
+ /* if there is a directory specified for which we should instrument
wicket components,
+ * create a WicketClassLoader to do that. Otherwise, just use the
contextClassLoader
+ */
+ File dir = getRealFile(filterConfig.getServletContext(),
DEFAULT_WICKET_COMPONENT_DIRECTORY_PATH);
+ if (dir == null)
+ {
+ log.warn("No wicket components directory specified to give Seam
super powers to");
+ this.classLoader = parent;
+ }
+ else
+ {
+ this.classLoader = new
WicketClassLoader(Thread.currentThread().getContextClassLoader(), new ClassPool(),
dir).instrument();
+ }
}
- else
+ catch (NotFoundException e)
{
- this.classLoader = new
WicketClassLoader(Thread.currentThread().getContextClassLoader(), new ClassPool(),
dir).instrument();
+ throw new ServletException(e);
}
- }
- catch (NotFoundException e)
- {
- throw new ServletException(e);
- }
- catch (CannotCompileException e)
- {
- throw new ServletException(e);
- }
- catch (ClassNotFoundException e)
- {
- throw new ServletException(e);
- }
- if (filterConfig.getInitParameter("applicationClassName") == null)
- {
- String applicationClass =
WebApplication.instance().getApplicationClass();
- if (applicationClass != null)
+ catch (CannotCompileException e)
{
- parameters.put("applicationClassName", applicationClass);
+ throw new ServletException(e);
}
- else
+ catch (ClassNotFoundException e)
{
- throw new IllegalStateException("Must set application-class using
<wicket:web-application /> in components.xml");
+ throw new ServletException(e);
}
+ /*
+ * If no applicationClassName has been specified on the filter, use the
name specified with
+ * <wicket:web-application/> in components.xml
+ */
+ if (filterConfig.getInitParameter("applicationClassName") ==
null)
+ {
+ String applicationClass =
WebApplication.instance().getApplicationClass();
+ if (applicationClass != null)
+ {
+ parameters.put("applicationClassName", applicationClass);
+ }
+ else
+ {
+ throw new IllegalStateException("Must set application-class
using <wicket:web-application /> in components.xml");
+ }
+ }
+ super.init(new FilterConfigWrapper(filterConfig, parameters));
}
- super.init(new FilterConfigWrapper(filterConfig, parameters));
+ finally
+ {
+ Lifecycle.cleanupApplication();
+ }
}
-
+
@Override
protected ClassLoader getClassLoader()
{