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    }