Source code: org/apache/tapestry/ApplicationServlet.java
1 /* $$ Clover has instrumented this file $$ */// Copyright 2004 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.tapestry;
16
17 import java.io.IOException;
18 import java.io.InputStream;
19 import java.util.Locale;
20
21 import javax.servlet.ServletConfig;
22 import javax.servlet.ServletException;
23 import javax.servlet.http.Cookie;
24 import javax.servlet.http.HttpServlet;
25 import javax.servlet.http.HttpServletRequest;
26 import javax.servlet.http.HttpServletResponse;
27
28 import org.apache.commons.logging.Log;
29 import org.apache.commons.logging.LogFactory;
30 import org.apache.hivemind.ClassResolver;
31 import org.apache.hivemind.Registry;
32 import org.apache.hivemind.impl.DefaultClassResolver;
33 import org.apache.hivemind.impl.RegistryBuilder;
34 import org.apache.tapestry.request.RequestContext;
35 import org.apache.tapestry.services.ApplicationGlobals;
36 import org.apache.tapestry.services.ApplicationInitializer;
37 import org.apache.tapestry.services.RequestServicer;
38 import org.apache.tapestry.spec.IApplicationSpecification;
39 import org.apache.tapestry.util.exception.ExceptionAnalyzer;
40
41 /**
42 * Links a servlet container with a Tapestry application. The servlet has some
43 * responsibilities related to bootstrapping the application (in terms of
44 * logging, reading the {@link ApplicationSpecification specification}, etc.).
45 * It is also responsible for creating or locating the {@link IEngine} and delegating
46 * incoming requests to it.
47 *
48 * <p>The servlet init parameter
49 * <code>org.apache.tapestry.specification-path</code>
50 * should be set to the complete resource path (within the classpath)
51 * to the application specification, i.e.,
52 * <code>/com/foo/bar/MyApp.application</code>.
53 *
54 * <p>In some servlet containers (notably
55 * <a href="www.bea.com"/>WebLogic</a>)
56 * it is necessary to invoke {@link HttpSession#setAttribute(String,Object)}
57 * in order to force a persistent value to be replicated to the other
58 * servers in the cluster. Tapestry applications usually only have a single
59 * persistent value, the {@link IEngine engine}. For persistence to
60 * work in such an environment, the
61 * JVM system property <code>org.apache.tapestry.store-engine</code>
62 * must be set to <code>true</code>. This will force the application
63 * servlet to restore the engine into the {@link HttpSession} at the
64 * end of each request cycle.
65 *
66 * <p>As of release 1.0.1, it is no longer necessary for a {@link HttpSession}
67 * to be created on the first request cycle. Instead, the HttpSession is created
68 * as needed by the {@link IEngine} ... that is, when a visit object is created,
69 * or when persistent page state is required. Otherwise, for sessionless requests,
70 * an {@link IEngine} from a {@link Pool} is used. Additional work must be done
71 * so that the {@link IEngine} can change locale <em>without</em> forcing
72 * the creation of a session; this involves the servlet and the engine storing
73 * locale information in a {@link Cookie}.
74 *
75 * <p>
76 * As of release 3.1, this servlet will also create a HiveMind Registry and manage it.
77 *
78 * @author Howard Lewis Ship
79 *
80 */
81
82 public class ApplicationServlet extends HttpServlet
83 {public static com.cortexeb.tools.clover.d __CLOVER_3_0 = com.cortexeb.tools.clover.aq.getRecorder(new char[] {67,58,92,119,111,114,107,115,112,97,99,101,92,106,97,107,97,114,116,97,45,116,97,112,101,115,116,114,121,92,102,114,97,109,101,119,111,114,107,92,116,97,114,103,101,116,92,99,108,111,118,101,114,45,100,98},1096998272901L);
84 private static final Log LOG = LogFactory.getLog(ApplicationServlet.class);
85
86 /**
87 * Name of the cookie written to the client web browser to
88 * identify the locale.
89 *
90 */
91
92 public static final String LOCALE_COOKIE_NAME = "org.apache.tapestry.locale";
93
94 /**
95 * The application specification, which is read once and kept in memory
96 * thereafter.
97 *
98 */
99
100 private IApplicationSpecification _specification;
101
102 /**
103 * Invokes {@link #doService(HttpServletRequest, HttpServletResponse)}.
104 *
105 * @since 1.0.6
106 *
107 */
108
109 public void doGet(HttpServletRequest request, HttpServletResponse response)
110 throws IOException, ServletException
111 {try { __CLOVER_3_0.M[129]++;
112 __CLOVER_3_0.S[468]++;doService(request, response);
113 } finally { }}
114
115 /**
116 * @since 2.3
117 *
118 */
119
120 private ClassResolver _resolver;
121
122 /**
123 * @since 3.1
124 */
125
126 private Registry _registry;
127
128 /**
129 * @since 3.1
130 */
131 private RequestServicer _requestServicer;
132
133 /**
134 * Handles the GET and POST requests. Performs the following:
135 * <ul>
136 * <li>Construct a {@link RequestContext}
137 * <li>Invoke {@link #getEngine(RequestContext)} to get or create the {@link IEngine}
138 * <li>Invoke {@link IEngine#service(RequestContext)} on the application
139 * </ul>
140 */
141
142 protected void doService(HttpServletRequest request, HttpServletResponse response)
143 throws IOException, ServletException
144 {try { __CLOVER_3_0.M[130]++;
145 __CLOVER_3_0.S[469]++;try
146 {
147 __CLOVER_3_0.S[470]++;_requestServicer.service(request, response);
148 }
149 catch (ServletException ex)
150 {
151 __CLOVER_3_0.S[471]++;log("ServletException", ex);
152
153 __CLOVER_3_0.S[472]++;show(ex);
154
155 // Rethrow it.
156
157 __CLOVER_3_0.S[473]++;throw ex;
158 }
159 catch (IOException ex)
160 {
161 __CLOVER_3_0.S[474]++;log("IOException", ex);
162
163 __CLOVER_3_0.S[475]++;show(ex);
164
165 // Rethrow it.
166
167 __CLOVER_3_0.S[476]++;throw ex;
168 }
169 } finally { }}
170
171 protected void show(Exception ex)
172 {try { __CLOVER_3_0.M[131]++;
173 __CLOVER_3_0.S[477]++;System.err.println("\n\n**********************************************************\n\n");
174
175 __CLOVER_3_0.S[478]++;new ExceptionAnalyzer().reportException(ex, System.err);
176
177 __CLOVER_3_0.S[479]++;System.err.println("\n**********************************************************\n");
178
179 } finally { }}
180
181 /**
182 * Invokes {@link #doService(HttpServletRequest, HttpServletResponse)}.
183 *
184 *
185 */
186
187 public void doPost(HttpServletRequest request, HttpServletResponse response)
188 throws IOException, ServletException
189 {try { __CLOVER_3_0.M[132]++;
190 __CLOVER_3_0.S[480]++;doService(request, response);
191 } finally { }}
192
193 /**
194 * Returns the application specification, which is read
195 * by the {@link #init(ServletConfig)} method.
196 *
197 * @deprecated Use {@link RequestContext#getApplicationSpecification()} instead.
198 */
199
200 public IApplicationSpecification getApplicationSpecification()
201 {try { __CLOVER_3_0.M[133]++;
202 __CLOVER_3_0.S[481]++;return _specification;
203 } finally { }}
204
205 /**
206 * Reads the application specification when the servlet is
207 * first initialized. All {@link IEngine engine instances}
208 * will have access to the specification via the servlet.
209 *
210 * @see #getApplicationSpecification()
211 * @see #constructApplicationSpecification()
212 * @see #createResourceResolver()
213 *
214 */
215
216 public void init(ServletConfig config) throws ServletException
217 {try { __CLOVER_3_0.M[134]++;
218 __CLOVER_3_0.S[482]++;super.init(config);
219
220 __CLOVER_3_0.S[483]++;_resolver = createClassResolver();
221
222 __CLOVER_3_0.S[484]++;try
223 {
224
225 __CLOVER_3_0.S[485]++;constructRegistry();
226
227 __CLOVER_3_0.S[486]++;initializeApplication();
228 }
229 catch (Exception ex)
230 {
231 __CLOVER_3_0.S[487]++;show(ex);
232
233 __CLOVER_3_0.S[488]++;throw new ServletException(TapestryMessages.servletInitFailure(ex), ex);
234 }
235 } finally { }}
236
237 /**
238 * Invoked from {@link #init(ServletConfig)} to create a resource resolver
239 * for the servlet (which will utlimately be shared and used through the
240 * application).
241 *
242 * <p>This implementation constructs a {@link DefaultResourceResolver}, subclasses
243 * may provide a different implementation.
244 *
245 * @see #getResourceResolver()
246 * @since 2.3
247 *
248 */
249
250 protected ClassResolver createClassResolver() throws ServletException
251 {try { __CLOVER_3_0.M[135]++;
252 __CLOVER_3_0.S[489]++;return new DefaultClassResolver();
253 } finally { }}
254
255 /**
256 * Closes the stream, ignoring any exceptions.
257 *
258 */
259
260 protected void close(InputStream stream)
261 {try { __CLOVER_3_0.M[136]++;
262 __CLOVER_3_0.S[490]++;try
263 {
264 __CLOVER_3_0.S[491]++;if ((((stream != null) && (++__CLOVER_3_0.CT[105] != 0)) || (++__CLOVER_3_0.CF[105] == 0))){
265 __CLOVER_3_0.S[492]++;stream.close();}
266 }
267 catch (IOException ex)
268 {
269 // Ignore it.
270 }
271 } finally { }}
272
273
274
275 /**
276 * Invoked from the {@link IEngine engine}, just prior to starting to
277 * render a response, when the locale has changed. The servlet writes a
278 * {@link Cookie} so that, on subsequent request cycles, an engine localized
279 * to the selected locale is chosen.
280 *
281 * <p>At this time, the cookie is <em>not</em> persistent. That may
282 * change in subsequent releases.
283 *
284 * @since 1.0.1
285 */
286
287 public static void writeLocaleCookie(Locale locale, IEngine engine, RequestContext cycle)
288 {try { __CLOVER_3_0.M[137]++;
289 __CLOVER_3_0.S[493]++;if ((((LOG.isDebugEnabled()) && (++__CLOVER_3_0.CT[106] != 0)) || (++__CLOVER_3_0.CF[106] == 0))){
290 __CLOVER_3_0.S[494]++;LOG.debug("Writing locale cookie " + locale);}
291
292 __CLOVER_3_0.S[495]++;Cookie cookie = new Cookie(LOCALE_COOKIE_NAME, locale.toString());
293 __CLOVER_3_0.S[496]++;cookie.setPath(engine.getServletPath());
294
295 __CLOVER_3_0.S[497]++;cycle.addCookie(cookie);
296 } finally { }}
297
298 /**
299 * Returns a resource resolver that can access classes and resources related
300 * to the current web application context. Relies on
301 * {@link java.lang.Thread#getContextClassLoader()}, which is set by
302 * most modern servlet containers.
303 *
304 * @since 2.3
305 *
306 */
307
308 public ClassResolver getClassResolver()
309 {try { __CLOVER_3_0.M[138]++;
310 __CLOVER_3_0.S[498]++;return _resolver;
311 } finally { }}
312
313 /**
314 * Invoked from {@link #init(ServletConfig)} to construct the Registry to
315 * be used by the application.
316 *
317 * @since 3.1
318 */
319 protected void constructRegistry()
320 {try { __CLOVER_3_0.M[139]++;
321 // This will expand in the future.
322
323 __CLOVER_3_0.S[499]++;_registry = RegistryBuilder.constructDefaultRegistry();
324 } finally { }}
325
326 /**
327 * Invoked from {@link #init(ServletConfig)}, after the registry has
328 * been constructed, to bootstrap the application via the
329 * <code>tapestry.MasterApplicationInitializer</code> service.
330 */
331 protected void initializeApplication()
332 {try { __CLOVER_3_0.M[140]++;
333 __CLOVER_3_0.S[500]++;ApplicationInitializer ai =
334 (ApplicationInitializer) _registry.getService(
335 "tapestry.init.MasterInitializer",
336 ApplicationInitializer.class);
337
338 __CLOVER_3_0.S[501]++;ai.initialize(this);
339
340 __CLOVER_3_0.S[502]++;_registry.cleanupThread();
341
342 // This is temporary, since most of the code still gets the
343 // specification from the servlet --- in fact, has to downcase
344 // RequestContext.getServlet() to do so.
345
346 __CLOVER_3_0.S[503]++;ApplicationGlobals ag =
347 (ApplicationGlobals) _registry.getService(
348 "tapestry.globals.ApplicationGlobals",
349 ApplicationGlobals.class);
350
351 __CLOVER_3_0.S[504]++;_specification = ag.getSpecification();
352
353 __CLOVER_3_0.S[505]++;_requestServicer =
354 (RequestServicer) _registry.getService(
355 "tapestry.request.RequestServicerPipeline",
356 RequestServicer.class);
357 } finally { }}
358
359 /**
360 * Returns the Registry used by the application.
361 *
362 * @since 3.1
363 */
364 public Registry getRegistry()
365 {try { __CLOVER_3_0.M[141]++;
366 __CLOVER_3_0.S[506]++;return _registry;
367 } finally { }}
368
369 /**
370 * Shuts down the registry (if it exists).
371 *
372 * @since 3.1
373 */
374 public void destroy()
375 {try { __CLOVER_3_0.M[142]++;
376 __CLOVER_3_0.S[507]++;if ((((_registry != null) && (++__CLOVER_3_0.CT[107] != 0)) || (++__CLOVER_3_0.CF[107] == 0))){
377 {
378 __CLOVER_3_0.S[508]++;_registry.shutdown();
379 __CLOVER_3_0.S[509]++;_registry = null;
380 }}
381 } finally { }}
382
383 }