KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > tapestry > ApplicationServlet


1 // Copyright 2004, 2005 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 JavaDoc;
18 import java.io.InputStream JavaDoc;
19 import java.util.Locale JavaDoc;
20
21 import javax.servlet.ServletConfig JavaDoc;
22 import javax.servlet.ServletContext JavaDoc;
23 import javax.servlet.ServletException JavaDoc;
24 import javax.servlet.http.Cookie JavaDoc;
25 import javax.servlet.http.HttpServlet JavaDoc;
26 import javax.servlet.http.HttpServletRequest JavaDoc;
27 import javax.servlet.http.HttpServletResponse JavaDoc;
28 import javax.servlet.http.HttpSession JavaDoc;
29
30 import org.apache.commons.logging.Log;
31 import org.apache.commons.logging.LogFactory;
32 import org.apache.hivemind.ClassResolver;
33 import org.apache.hivemind.ErrorHandler;
34 import org.apache.hivemind.Registry;
35 import org.apache.hivemind.Resource;
36 import org.apache.hivemind.impl.DefaultClassResolver;
37 import org.apache.hivemind.impl.RegistryBuilder;
38 import org.apache.hivemind.impl.StrictErrorHandler;
39 import org.apache.hivemind.impl.XmlModuleDescriptorProvider;
40 import org.apache.hivemind.util.ContextResource;
41 import org.apache.tapestry.services.ApplicationInitializer;
42 import org.apache.tapestry.services.ServletRequestServicer;
43 import org.apache.tapestry.spec.ApplicationSpecification;
44 import org.apache.tapestry.util.exception.ExceptionAnalyzer;
45
46 import com.sun.jndi.ldap.pool.Pool;
47
48 /**
49  * Links a servlet container with a Tapestry application. The servlet has some responsibilities
50  * related to bootstrapping the application (in terms of logging, reading the
51  * {@link ApplicationSpecification specification}, etc.). It is also responsible for creating or
52  * locating the {@link IEngine}and delegating incoming requests to it.
53  * <p>
54  * The servlet init parameter <code>org.apache.tapestry.specification-path</code> should be set to
55  * the complete resource path (within the classpath) to the application specification, i.e.,
56  * <code>/com/foo/bar/MyApp.application</code>.
57  * <p>
58  * In some servlet containers (notably <a HREF="www.bea.com"/>WebLogic </a>) it is necessary to
59  * invoke {@link HttpSession#setAttribute(String,Object)}in order to force a persistent value to be
60  * replicated to the other servers in the cluster. Tapestry applications usually only have a single
61  * persistent value, the {@link IEngine engine}. For persistence to work in such an environment,
62  * the JVM system property <code>org.apache.tapestry.store-engine</code> must be set to
63  * <code>true</code>. This will force the application servlet to restore the engine into the
64  * {@link HttpSession}at the end of each request cycle.
65  * <p>
66  * As of release 1.0.1, it is no longer necessary for a {@link HttpSession}to be created on the
67  * first request cycle. Instead, the HttpSession is created as needed by the {@link IEngine}...
68  * that is, when a visit object is created, or when persistent page state is required. Otherwise,
69  * for sessionless requests, an {@link IEngine}from a {@link Pool}is used. Additional work must be
70  * done so that the {@link IEngine}can change locale <em>without</em> forcing the creation of a
71  * session; this involves the servlet and the engine storing locale information in a {@link Cookie}.
72  * <p>
73  * As of release 4.0, this servlet will also create a HiveMind Registry and manage it.
74  *
75  * @author Howard Lewis Ship
76  */

77
78 public class ApplicationServlet extends HttpServlet JavaDoc
79 {
80     /**
81      * Prefix used to store the HiveMind Registry into the ServletContext. This string is suffixed
82      * with the servlet name (in case multiple Tapestry applications are executing within a single
83      * web application).
84      *
85      * @since 4.0
86      */

87
88     private static final String JavaDoc REGISTRY_KEY_PREFIX = "org.apache.tapestry.Registry:";
89
90     private static final Log LOG = LogFactory.getLog(ApplicationServlet.class);
91
92     /**
93      * Invokes {@link #doService(HttpServletRequest, HttpServletResponse)}.
94      *
95      * @since 1.0.6
96      */

97
98     public void doGet(HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response) throws IOException JavaDoc,
99             ServletException JavaDoc
100     {
101         doService(request, response);
102     }
103
104     /**
105      * @since 2.3
106      */

107
108     private ClassResolver _resolver;
109
110     /**
111      * The key used to store the registry into the ServletContext.
112      *
113      * @since 4.0
114      */

115
116     private String JavaDoc _registryKey;
117
118     /**
119      * @since 4.0
120      */

121
122     private Registry _registry;
123
124     /**
125      * @since 4.0
126      */

127     private ServletRequestServicer _requestServicer;
128
129     /**
130      * Handles the GET and POST requests. Performs the following:
131      * <ul>
132      * <li>Construct a {@link RequestContext}
133      * <li>Invoke {@link #getEngine(RequestContext)}to get or create the {@link IEngine}
134      * <li>Invoke {@link IEngine#service(RequestContext)}on the application
135      * </ul>
136      */

137
138     protected void doService(HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response)
139             throws IOException JavaDoc, ServletException JavaDoc
140     {
141         try
142         {
143             _registry.setupThread();
144
145             _requestServicer.service(request, response);
146         }
147         catch (ServletException JavaDoc ex)
148         {
149             log("ServletException", ex);
150
151             show(ex);
152
153             // Rethrow it.
154

155             throw ex;
156         }
157         catch (IOException JavaDoc ex)
158         {
159             log("IOException", ex);
160
161             show(ex);
162
163             // Rethrow it.
164

165             throw ex;
166         }
167         finally
168         {
169             _registry.cleanupThread();
170         }
171     }
172
173     protected void show(Exception JavaDoc ex)
174     {
175         System.err.println("\n\n**********************************************************\n\n");
176
177         new ExceptionAnalyzer().reportException(ex, System.err);
178
179         System.err.println("\n**********************************************************\n");
180
181     }
182
183     /**
184      * Invokes {@link #doService(HttpServletRequest, HttpServletResponse)}.
185      */

186
187     public void doPost(HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response)
188             throws IOException JavaDoc, ServletException JavaDoc
189     {
190         doService(request, response);
191     }
192
193     /**
194      * Reads the application specification when the servlet is first initialized. All
195      * {@link IEngine engine instances}will have access to the specification via the servlet.
196      *
197      * @see #constructApplicationSpecification()
198      * @see #createResourceResolver()
199      */

200
201     public void init(ServletConfig JavaDoc config) throws ServletException JavaDoc
202     {
203         String JavaDoc name = config.getServletName();
204
205         _registryKey = REGISTRY_KEY_PREFIX + name;
206
207         long startTime = System.currentTimeMillis();
208         long elapsedToRegistry = 0;
209
210         super.init(config);
211
212         _resolver = createClassResolver();
213
214         try
215         {
216             _registry = constructRegistry(config);
217
218             elapsedToRegistry = System.currentTimeMillis() - startTime;
219
220             initializeApplication();
221
222             config.getServletContext().setAttribute(_registryKey, _registry);
223         }
224         catch (Exception JavaDoc ex)
225         {
226             show(ex);
227
228             throw new ServletException JavaDoc(TapestryMessages.servletInitFailure(ex), ex);
229         }
230
231         long elapsedOverall = System.currentTimeMillis() - startTime;
232
233         LOG.info(TapestryMessages.servletInit(name, elapsedToRegistry, elapsedOverall));
234     }
235
236     /**
237      * Invoked from {@link #init(ServletConfig)}to create a resource resolver for the servlet
238      * (which will utlimately be shared and used through the application).
239      * <p>
240      * This implementation constructs a {@link DefaultResourceResolver}, subclasses may provide a
241      * different implementation.
242      *
243      * @see #getResourceResolver()
244      * @since 2.3
245      */

246
247     protected ClassResolver createClassResolver() throws ServletException JavaDoc
248     {
249         return new DefaultClassResolver();
250     }
251
252     /**
253      * Invoked from {@link #init(ServletConfig)}to construct the Registry to be used by the
254      * application.
255      * <p>
256      * This looks in the standard places (on the classpath), but also in the WEB-INF/name and
257      * WEB-INF folders (where name is the name of the servlet).
258      *
259      * @since 4.0
260      */

261     protected Registry constructRegistry(ServletConfig JavaDoc config)
262     {
263         ErrorHandler errorHandler = constructErrorHandler(config);
264
265         RegistryBuilder builder = new RegistryBuilder(errorHandler);
266
267         builder.addModuleDescriptorProvider(new XmlModuleDescriptorProvider(_resolver));
268
269         String JavaDoc name = config.getServletName();
270         ServletContext JavaDoc context = config.getServletContext();
271
272         addModuleIfExists(builder, context, "/WEB-INF/" + name + "/hivemodule.xml");
273         addModuleIfExists(builder, context, "/WEB-INF/hivemodule.xml");
274
275         return builder.constructRegistry(Locale.getDefault());
276     }
277
278     /**
279      * Invoked by {@link #constructRegistry(ServletConfig)} to create and return an
280      * {@link ErrorHandler} instance to be used when constructing the Registry (and then to handle
281      * any runtime exceptions). This implementation returns a new instance of
282      * {@link org.apache.hivemind.impl.StrictErrorHandler}.
283      *
284      * @since 4.0
285      */

286     protected ErrorHandler constructErrorHandler(ServletConfig JavaDoc config)
287     {
288         return new StrictErrorHandler();
289     }
290
291     /**
292      * Looks for a file in the servlet context; if it exists, it is expected to be a HiveMind module
293      * descriptor, and is added to the builder.
294      *
295      * @since 4.0
296      */

297
298     protected void addModuleIfExists(RegistryBuilder builder, ServletContext JavaDoc context, String JavaDoc path)
299     {
300         Resource r = new ContextResource(context, path);
301
302         if (r.getResourceURL() == null)
303             return;
304
305         builder.addModuleDescriptorProvider(new XmlModuleDescriptorProvider(_resolver, r));
306     }
307
308     /**
309      * Invoked from {@link #init(ServletConfig)}, after the registry has been constructed, to
310      * bootstrap the application via the <code>tapestry.MasterApplicationInitializer</code>
311      * service.
312      *
313      * @since 4.0
314      */

315     protected void initializeApplication()
316     {
317         ApplicationInitializer ai = (ApplicationInitializer) _registry.getService(
318                 "tapestry.init.MasterInitializer",
319                 ApplicationInitializer.class);
320
321         ai.initialize(this);
322
323         _registry.cleanupThread();
324
325         _requestServicer = (ServletRequestServicer) _registry.getService(
326                 "tapestry.request.ServletRequestServicer",
327                 ServletRequestServicer.class);
328     }
329
330     /**
331      * Shuts down the registry (if it exists).
332      *
333      * @since 4.0
334      */

335     public void destroy()
336     {
337         getServletContext().removeAttribute(_registryKey);
338
339         if (_registry != null)
340         {
341             _registry.shutdown();
342             _registry = null;
343         }
344     }
345 }
Popular Tags