001 // Copyright 2006, 2007, 2008, 2009 The Apache Software Foundation
002 //
003 // Licensed under the Apache License, Version 2.0 (the "License");
004 // you may not use this file except in compliance with the License.
005 // You may obtain a copy of the License at
006 //
007 // http://www.apache.org/licenses/LICENSE-2.0
008 //
009 // Unless required by applicable law or agreed to in writing, software
010 // distributed under the License is distributed on an "AS IS" BASIS,
011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012 // See the License for the specific language governing permissions and
013 // limitations under the License.
014
015 package org.apache.tapestry5;
016
017 import org.apache.tapestry5.internal.ServletContextSymbolProvider;
018 import org.apache.tapestry5.internal.TapestryAppInitializer;
019 import org.apache.tapestry5.ioc.Registry;
020 import org.apache.tapestry5.ioc.def.ModuleDef;
021 import org.apache.tapestry5.ioc.services.SymbolProvider;
022 import org.apache.tapestry5.services.HttpServletRequestHandler;
023 import org.apache.tapestry5.services.ServletApplicationInitializer;
024 import org.slf4j.Logger;
025 import org.slf4j.LoggerFactory;
026
027 import javax.servlet.*;
028 import javax.servlet.http.HttpServletRequest;
029 import javax.servlet.http.HttpServletResponse;
030 import java.io.IOException;
031
032 /**
033 * The TapestryFilter is responsible for intercepting all requests into the web application. It identifies the requests
034 * that are relevant to Tapestry, and lets the servlet container handle the rest. It is also responsible for
035 * initializing Tapestry.
036 * <p/>
037 * <p/>
038 * The application is configured via context-level init parameters.
039 * <p/>
040 * <dl> <dt> tapestry.app-package</dt> <dd> The application package (used to search for pages, components, etc.)</dd>
041 * </dl>
042 */
043 public class TapestryFilter implements Filter
044 {
045 private final Logger logger = LoggerFactory.getLogger(TapestryFilter.class);
046
047 private FilterConfig config;
048
049 private Registry registry;
050
051 private HttpServletRequestHandler handler;
052
053 /**
054 * Key under which that Tapestry IoC {@link org.apache.tapestry5.ioc.Registry} is stored in the ServletContext. This
055 * allows other code, beyond Tapestry, to obtain the Registry and, from it, any Tapestry services. Such code should
056 * be careful about invoking {@link org.apache.tapestry5.ioc.Registry#cleanupThread()} appopriately.
057 */
058 public static final String REGISTRY_CONTEXT_NAME = "org.apache.tapestry5.application-registry";
059
060 /**
061 * Initializes the filter using the {@link TapestryAppInitializer}. The application name is the capitalization of
062 * the filter name (as specified in web.xml).
063 */
064 public final void init(FilterConfig filterConfig) throws ServletException
065 {
066 config = filterConfig;
067
068 ServletContext context = config.getServletContext();
069
070 String filterName = config.getFilterName();
071
072 SymbolProvider provider = new ServletContextSymbolProvider(context);
073
074 TapestryAppInitializer appInitializer = new TapestryAppInitializer(logger, provider, filterName, "servlet");
075
076 appInitializer.addModules(provideExtraModuleDefs(context));
077
078 registry = appInitializer.createRegistry();
079
080 context.setAttribute(REGISTRY_CONTEXT_NAME, registry);
081
082 ServletApplicationInitializer ai = registry.getService("ServletApplicationInitializer",
083 ServletApplicationInitializer.class);
084
085 ai.initializeApplication(filterConfig.getServletContext());
086
087 registry.performRegistryStartup();
088
089 handler = registry.getService("HttpServletRequestHandler", HttpServletRequestHandler.class);
090
091 init(registry);
092
093 appInitializer.announceStartup();
094 }
095
096 protected final FilterConfig getFilterConfig()
097 {
098 return config;
099 }
100
101 /**
102 * Invoked from {@link #init(FilterConfig)} after the Registry has been created, to allow any additional
103 * initialization to occur. This implementation does nothing, and my be overriden in subclasses.
104 *
105 * @param registry from which services may be extracted
106 * @throws ServletException
107 */
108 protected void init(Registry registry) throws ServletException
109 {
110
111 }
112
113 /**
114 * Overridden in subclasses to provide additional module definitions beyond those normally located. This
115 * implementation returns an empty array.
116 */
117 protected ModuleDef[] provideExtraModuleDefs(ServletContext context)
118 {
119 return new ModuleDef[0];
120 }
121
122 public final void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
123 throws IOException, ServletException
124 {
125 try
126 {
127 boolean handled = handler.service((HttpServletRequest) request, (HttpServletResponse) response);
128
129 if (!handled) chain.doFilter(request, response);
130 }
131 finally
132 {
133 registry.cleanupThread();
134 }
135 }
136
137 /**
138 * Shuts down and discards the registry. Invokes {@link #destroy(org.apache.tapestry5.ioc.Registry)} to allow
139 * subclasses to peform any shutdown logic, then shuts down the registry, and removes it from the ServletContext.
140 */
141 public final void destroy()
142 {
143 destroy(registry);
144
145 registry.shutdown();
146
147 config.getServletContext().removeAttribute(REGISTRY_CONTEXT_NAME);
148
149 registry = null;
150 config = null;
151 handler = null;
152 }
153
154 /**
155 * Invoked from {@link #destroy()} to allow subclasses to add additional shutdown logic to the filter. The Registry
156 * will be shutdown after this call. This implementation does nothing, and may be overridden in subclasses.
157 *
158 * @param registry
159 */
160 protected void destroy(Registry registry)
161 {
162
163 }
164 }