blob: 8fdfbc135f41ac5f617ec954bf83eac21980529b [file] [log] [blame]
// Copyright 2006, 2007, 2008, 2009, 2010 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.
package org.apache.tapestry5;
import org.apache.tapestry5.internal.ServletContextSymbolProvider;
import org.apache.tapestry5.internal.TapestryAppInitializer;
import org.apache.tapestry5.ioc.Registry;
import org.apache.tapestry5.ioc.def.ModuleDef;
import org.apache.tapestry5.ioc.services.SymbolProvider;
import org.apache.tapestry5.services.HttpServletRequestHandler;
import org.apache.tapestry5.services.ServletApplicationInitializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* The TapestryFilter is responsible for intercepting all requests into the web application. It
* identifies the requests
* that are relevant to Tapestry, and lets the servlet container handle the rest. It is also
* responsible for
* initializing Tapestry.
* <p/>
* The application is primarily configured via context-level init parameters.
* <p/>
* <dl>
* <dt>tapestry.app-package</dt>
* <dd>The application package (used to search for pages, components, etc.)</dd>
* </dl>
* <p>
* In addition, a JVM system property affects configuration: <code>tapestry.execution-mode</code>
* (with default value "production"). This property is a comma-separated list of execution modes.
* For each mode, an additional init parameter is checked for:
* <code>tapestry.<em>mode</em>-modules</code>; this is a comma-separated list of module class names
* to load. In this way, more precise control over the available modules can be obtained which is
* often needed during testing.
*/
public class TapestryFilter implements Filter
{
private final Logger logger = LoggerFactory.getLogger(TapestryFilter.class);
private FilterConfig config;
private Registry registry;
private HttpServletRequestHandler handler;
/**
* Key under which that Tapestry IoC {@link org.apache.tapestry5.ioc.Registry} is stored in the
* ServletContext. This
* allows other code, beyond Tapestry, to obtain the Registry and, from it, any Tapestry
* services. Such code should
* be careful about invoking {@link org.apache.tapestry5.ioc.Registry#cleanupThread()}
* appropriately.
*/
public static final String REGISTRY_CONTEXT_NAME = "org.apache.tapestry5.application-registry";
/**
* Initializes the filter using the {@link TapestryAppInitializer}. The application name is the
* capitalization of
* the filter name (as specified in web.xml).
*/
public final void init(FilterConfig filterConfig) throws ServletException
{
config = filterConfig;
ServletContext context = config.getServletContext();
String filterName = config.getFilterName();
SymbolProvider provider = new ServletContextSymbolProvider(context);
String executionMode = System.getProperty("tapestry.execution-mode", "production");
TapestryAppInitializer appInitializer = new TapestryAppInitializer(logger, provider,
filterName, "servlet", executionMode);
appInitializer.addModules(provideExtraModuleDefs(context));
registry = appInitializer.createRegistry();
context.setAttribute(REGISTRY_CONTEXT_NAME, registry);
ServletApplicationInitializer ai = registry.getService("ServletApplicationInitializer",
ServletApplicationInitializer.class);
ai.initializeApplication(filterConfig.getServletContext());
registry.performRegistryStartup();
handler = registry.getService("HttpServletRequestHandler", HttpServletRequestHandler.class);
init(registry);
appInitializer.announceStartup();
}
protected final FilterConfig getFilterConfig()
{
return config;
}
/**
* Invoked from {@link #init(FilterConfig)} after the Registry has been created, to allow any
* additional
* initialization to occur. This implementation does nothing, and my be overriden in subclasses.
*
* @param registry
* from which services may be extracted
* @throws ServletException
*/
protected void init(Registry registry) throws ServletException
{
}
/**
* Overridden in subclasses to provide additional module definitions beyond those normally
* located. This
* implementation returns an empty array.
*/
protected ModuleDef[] provideExtraModuleDefs(ServletContext context)
{
return new ModuleDef[0];
}
public final void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException
{
try
{
boolean handled = handler.service((HttpServletRequest) request,
(HttpServletResponse) response);
if (!handled)
chain.doFilter(request, response);
}
finally
{
registry.cleanupThread();
}
}
/**
* Shuts down and discards the registry. Invokes
* {@link #destroy(org.apache.tapestry5.ioc.Registry)} to allow
* subclasses to peform any shutdown logic, then shuts down the registry, and removes it from
* the ServletContext.
*/
public final void destroy()
{
destroy(registry);
registry.shutdown();
config.getServletContext().removeAttribute(REGISTRY_CONTEXT_NAME);
registry = null;
config = null;
handler = null;
}
/**
* Invoked from {@link #destroy()} to allow subclasses to add additional shutdown logic to the
* filter. The Registry
* will be shutdown after this call. This implementation does nothing, and may be overridden in
* subclasses.
*
* @param registry
*/
protected void destroy(Registry registry)
{
}
}