1 // Copyright 2006, 2007, 2008 The Apache Software Foundation
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 package org.apache.tapestry5;
16
17 import org.apache.tapestry5.internal.ServletContextSymbolProvider;
18 import org.apache.tapestry5.internal.TapestryAppInitializer;
19 import org.apache.tapestry5.ioc.Registry;
20 import org.apache.tapestry5.ioc.def.ModuleDef;
21 import org.apache.tapestry5.ioc.services;
22 import org.apache.tapestry5.services.HttpServletRequestHandler;
23 import org.apache.tapestry5.services.ServletApplicationInitializer;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
26
27 import javax.servlet;
28 import javax.servlet.http.HttpServletRequest;
29 import javax.servlet.http.HttpServletResponse;
30 import java.io.IOException;
31 import java.util.Formatter;
32 import java.util.List;
33
34 /**
35 * The TapestryFilter is responsible for intercepting all requests into the web application. It identifies the requests
36 * that are relevant to Tapestry, and lets the servlet container handle the rest. It is also responsible for
37 * initializing Tapestry.
38 * <p/>
39 * <p/>
40 * The application is configured via context-level init parameters.
41 * <p/>
42 * <dl> <dt> tapestry.app-package</dt> <dd> The application package (used to search for pages, components, etc.)</dd>
43 * </dl>
44 */
45 public class TapestryFilter implements Filter
46 {
47 private final Logger logger = LoggerFactory.getLogger(TapestryFilter.class);
48
49 private FilterConfig config;
50
51 private Registry registry;
52
53 private HttpServletRequestHandler handler;
54
55 /**
56 * Key under which that Tapestry IoC {@link org.apache.tapestry5.ioc.Registry} is stored in the ServletContext. This
57 * allows other code, beyond Tapestry, to obtain the Registry and, from it, any Tapestry services. Such code should
58 * be careful about invoking {@link org.apache.tapestry5.ioc.Registry#cleanupThread()} appopriately.
59 */
60 public static final String REGISTRY_CONTEXT_NAME = "org.apache.tapestry5.application-registry";
61
62 /**
63 * Initializes the filter using the {@link TapestryAppInitializer}. The application name is the capitalization of
64 * the filter name (as specified in web.xml).
65 */
66 public final void init(FilterConfig filterConfig) throws ServletException
67 {
68 config = filterConfig;
69
70 ServletContext context = config.getServletContext();
71
72 String filterName = config.getFilterName();
73
74 SymbolProvider provider = new ServletContextSymbolProvider(context);
75
76 TapestryAppInitializer appInitializer = new TapestryAppInitializer(provider, filterName, "servlet");
77
78 appInitializer.addModules(provideExtraModuleDefs(context));
79
80 registry = appInitializer.getRegistry();
81
82 context.setAttribute(REGISTRY_CONTEXT_NAME, registry);
83
84 long start = appInitializer.getStartTime();
85
86 long toRegistry = appInitializer.getRegistryCreatedTime();
87
88 ServletApplicationInitializer ai = registry.getService("ServletApplicationInitializer",
89 ServletApplicationInitializer.class);
90
91 ai.initializeApplication(filterConfig.getServletContext());
92
93 registry.performRegistryStartup();
94
95 handler = registry.getService("HttpServletRequestHandler", HttpServletRequestHandler.class);
96
97 SymbolSource source = registry.getService("SymbolSource", SymbolSource.class);
98
99 init(registry);
100
101 long toFinish = System.currentTimeMillis();
102
103 StringBuilder buffer = new StringBuilder("Startup status:\n\n");
104 Formatter f = new Formatter(buffer);
105
106 f.format("Application '%s' (Tapestry version %s).\n\n" +
107 "Startup time: %,d ms to build IoC Registry, %,d ms overall.\n\n" +
108 "Startup services status:\n",
109 filterName,
110 source.valueForSymbol(SymbolConstants.TAPESTRY_VERSION),
111 toRegistry - start, toFinish - start);
112
113 int unrealized = 0;
114
115 ServiceActivityScoreboard scoreboard = registry
116 .getService(ServiceActivityScoreboard.class);
117
118 List<ServiceActivity> serviceActivity = scoreboard.getServiceActivity();
119
120 int longest = 0;
121
122 // One pass to find the longest name, and to count the unrealized services.
123
124 for (ServiceActivity activity : serviceActivity)
125 {
126 Status status = activity.getStatus();
127
128 longest = Math.max(longest, activity.getServiceId().length());
129
130 if (status == Status.DEFINED || status == Status.VIRTUAL) unrealized++;
131 }
132
133 String formatString = "%" + longest + "s: %s\n";
134
135 // A second pass to output all the services
136
137 for (ServiceActivity activity : serviceActivity)
138 {
139 f.format(formatString, activity.getServiceId(), activity.getStatus().name());
140 }
141
142 f.format("\n%4.2f%% unrealized services (%d/%d)\n", 100. * unrealized / serviceActivity.size(), unrealized,
143 serviceActivity.size());
144
145 logger.info(buffer.toString());
146 }
147
148 protected final FilterConfig getFilterConfig()
149 {
150 return config;
151 }
152
153 /**
154 * Invoked from {@link #init(FilterConfig)} after the Registry has been created, to allow any additional
155 * initialization to occur. This implementation does nothing, and my be overriden in subclasses.
156 *
157 * @param registry from which services may be extracted
158 * @throws ServletException
159 */
160 protected void init(Registry registry) throws ServletException
161 {
162
163 }
164
165 /**
166 * Overridden in subclasses to provide additional module definitions beyond those normally located. This
167 * implementation returns an empty array.
168 */
169 protected ModuleDef[] provideExtraModuleDefs(ServletContext context)
170 {
171 return new ModuleDef[0];
172 }
173
174 public final void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
175 throws IOException, ServletException
176 {
177 try
178 {
179 boolean handled = handler.service((HttpServletRequest) request, (HttpServletResponse) response);
180
181 if (!handled) chain.doFilter(request, response);
182 }
183 finally
184 {
185 registry.cleanupThread();
186 }
187 }
188
189 /**
190 * Shuts down and discards the registry. Invokes {@link #destroy(org.apache.tapestry5.ioc.Registry)} to allow
191 * subclasses to peform any shutdown logic, then shuts down the registry, and removes it from the ServletContext.
192 */
193 public final void destroy()
194 {
195 destroy(registry);
196
197 registry.shutdown();
198
199 config.getServletContext().removeAttribute(REGISTRY_CONTEXT_NAME);
200
201 registry = null;
202 config = null;
203 handler = null;
204 }
205
206 /**
207 * Invoked from {@link #destroy()} to allow subclasses to add additional shutdown logic to the filter. The Registry
208 * will be shutdown after this call. This implementation does nothing, and may be overridden in subclasses.
209 *
210 * @param registry
211 */
212 protected void destroy(Registry registry)
213 {
214
215 }
216 }