1 /*
2 * The Apache Software License, Version 1.1
3 *
4 * Copyright (c) 1999 The Apache Software Foundation. All rights
5 * reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
17 * distribution.
18 *
19 * 3. The end-user documentation included with the redistribution, if
20 * any, must include the following acknowlegement:
21 * "This product includes software developed by the
22 * Apache Software Foundation (http://www.apache.org/)."
23 * Alternately, this acknowlegement may appear in the software itself,
24 * if and wherever such third-party acknowlegements normally appear.
25 *
26 * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
27 * Foundation" must not be used to endorse or promote products derived
28 * from this software without prior written permission. For written
29 * permission, please contact apache@apache.org.
30 *
31 * 5. Products derived from this software may not be called "Apache"
32 * nor may "Apache" appear in their names without prior written
33 * permission of the Apache Group.
34 *
35 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
39 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46 * SUCH DAMAGE.
47 * ====================================================================
48 *
49 * This software consists of voluntary contributions made by many
50 * individuals on behalf of the Apache Software Foundation. For more
51 * information on the Apache Software Foundation, please see
52 * <http://www.apache.org/>.
53 *
54 */
55
56 package org.apache.jasper.runtime;
57
58 import javax.servlet.Servlet;
59 import javax.servlet.ServletContext;
60 import javax.servlet.ServletConfig;
61 import javax.servlet.ServletException;
62 import javax.servlet.SingleThreadModel;
63 import javax.servlet.http.HttpServlet;
64 import javax.servlet.http.HttpServletRequest;
65 import javax.servlet.http.HttpServletResponse;
66 import javax.servlet.jsp.HttpJspPage;
67 import javax.servlet.jsp.JspFactory;
68
69 import java.util.Hashtable;
70 import java.util.Enumeration;
71 import java.io.File;
72 import java.io.PrintWriter;
73 import java.io.IOException;
74 import java.io.FileNotFoundException;
75
76 import org.apache.jasper.JasperException;
77 import org.apache.jasper.Constants;
78 import org.apache.jasper.Options;
79
80
81 /**
82 * The JSP engine (a.k.a Jasper)!
83 *
84 * @author Anil K. Vijendran
85 * @author Harish Prabandham
86 */
87 public class JspServlet extends HttpServlet {
88 class JspServletWrapper {
89 HttpJspPage theServlet;
90 String jspUri;
91 boolean isErrorPage;
92
93 JspServletWrapper(String jspUri, boolean isErrorPage) {
94 this.jspUri = jspUri;
95 this.isErrorPage = isErrorPage;
96 this.theServlet = null;
97 }
98
99 private void load() throws JasperException, ServletException {
100 try {
101 Class servletClass = loader.getJspServletClass(jspUri);
102 // This is for the original protocol.
103 destroy();
104 theServlet = (HttpJspPage) servletClass.newInstance();
105 } catch (Exception ex) {
106 throw new JasperException(ex);
107 }
108 theServlet.init(JspServlet.this.config);
109 if (theServlet instanceof HttpJspBase) {
110 ((HttpJspBase)theServlet).setClassLoader(JspServlet.this.parentClassLoader);
111 }
112 }
113
114 private void loadIfNecessary(HttpServletRequest req, HttpServletResponse res)
115 throws JasperException, ServletException, FileNotFoundException
116 {
117 // First try context attribute; if that fails then use the
118 // classpath init parameter.
119
120 // Should I try to concatenate them if both are non-null?
121
122 String cp = (String) context.getAttribute(Constants.SERVLET_CLASSPATH);
123
124 String accordingto;
125
126 if (cp == null || cp.equals("")) {
127 accordingto = "according to the init parameter is";
128 cp = options.getClassPath();
129 } else
130 accordingto = "according to the Servlet Engine is";
131
132
133 Constants.message("jsp.message.cp_is",
134 new Object[] { accordingto, cp },
135 Constants.MED_VERBOSITY);
136
137 if (loader.loadJSP(jspUri, cp, isErrorPage, req, res) || theServlet == null) {
138 load();
139 }
140 }
141
142 public void service(HttpServletRequest request,
143 HttpServletResponse response,
144 boolean precompile)
145 throws ServletException, IOException, FileNotFoundException
146 {
147 try {
148 loadIfNecessary(request, response);
149
150 // If a page is to only to be precompiled return.
151 if (precompile)
152 return;
153
154 if (theServlet instanceof SingleThreadModel) {
155 // sync on the wrapper so that the freshness
156 // of the page is determined right before servicing
157 synchronized (this) {
158 theServlet.service(request, response);
159 }
160 } else {
161 theServlet.service(request, response);
162 }
163
164 } catch (FileNotFoundException ex) {
165 response.sendError(HttpServletResponse.SC_NOT_FOUND,
166 Constants.getString("jsp.error.file.not.found",
167 new Object[] {
168 ex.getMessage()
169 }));
170
171 return;
172 }
173 }
174
175 public void destroy() {
176 if (theServlet != null)
177 theServlet.destroy();
178 }
179 }
180
181
182 ServletContext context = null;
183 Hashtable jsps = new Hashtable();
184 ServletConfig config;
185 JspLoader loader;
186 Options options;
187 ClassLoader parentClassLoader;
188 ServletEngine engine;
189 String serverInfo;
190
191 static boolean firstTime = true;
192
193 public void init(ServletConfig config)
194 throws ServletException
195 {
196 super.init(config);
197 this.config = config;
198 this.context = config.getServletContext();
199 this.serverInfo = context.getServerInfo();
200 this.engine = ServletEngine.getServletEngine(serverInfo);
201
202 if (engine == null)
203 Constants.message("jsp.error.bad-servlet-engine", Constants.FATAL_ERRORS);
204 else {
205 options = new Options(config, context);
206
207 parentClassLoader = (ClassLoader) context.getAttribute(Constants.SERVLET_CLASS_LOADER);
208 if (parentClassLoader == null)
209 parentClassLoader = this.getClass().getClassLoader();
210
211 Constants.message("jsp.message.parent_class_loader_is",
212 new Object[] {
213 parentClassLoader.toString()
214 }, Constants.MED_VERBOSITY);
215
216 this.loader = new JspLoader(context,
217 parentClassLoader,
218 options);
219
220 if (firstTime) {
221 firstTime = false;
222 Constants.message("jsp.message.scratch.dir.is",
223 new Object[] {
224 options.scratchDir().toString()
225 }, Constants.LOW_VERBOSITY );
226 Constants.message("jsp.message.dont.modify.servlets", Constants.LOW_VERBOSITY);
227 }
228
229 }
230
231 JspFactory.setDefaultFactory(new JspFactoryImpl());
232 }
233
234 private void serviceJspFile(HttpServletRequest request,
235 HttpServletResponse response, String jspUri,
236 Throwable exception, boolean precompile)
237 throws ServletException, IOException
238 {
239 boolean isErrorPage = exception != null;
240
241 JspServletWrapper wrapper = (JspServletWrapper) jsps.get(jspUri);
242 if (wrapper == null) {
243 wrapper = new JspServletWrapper(jspUri, isErrorPage);
244 jsps.put(jspUri, wrapper);
245 }
246
247 wrapper.service(request, response, precompile);
248 }
249
250
251 final void unknownException(HttpServletResponse response,
252 Throwable t)
253 {
254 PrintWriter writer = new PrintWriter(System.err, true);
255 if (options.sendErrorToClient()) {
256 try {
257 response.setContentType ("text/html");
258 writer = response.getWriter ();
259 } catch (IOException ioex) {
260 writer = new PrintWriter(System.err, true);
261 }
262 }
263 writer.println(Constants.getString("jsp.error.unknownException"));
264
265 if (options.sendErrorToClient()) {
266 writer.println("<pre>");
267 }
268
269 if (t instanceof JasperException) {
270 Throwable x = ((JasperException) t).getRootCause();
271 (x != null ? x : t).printStackTrace (writer);
272 } else {
273 t.printStackTrace (writer);
274 }
275
276 if (options.sendErrorToClient()) {
277 writer.println("</pre>");
278 }
279
280 if (!options.sendErrorToClient()) {
281 try {
282 String message = t.getMessage ();
283 if (message == null)
284 message = "No detailed message";
285 response.sendError(HttpServletResponse.
286 SC_INTERNAL_SERVER_ERROR, message);
287 } catch (IOException ex) {
288 }
289 }
290 }
291
292 boolean preCompile(HttpServletRequest request)
293 throws ServletException
294 {
295 boolean precompile = false;
296 String precom = request.getParameter(Constants.PRECOMPILE);
297 String qString = request.getQueryString();
298
299 if (precom != null) {
300 if (precom.equals("true"))
301 precompile = true;
302 else if (precom.equals("false"))
303 precompile = false;
304 else {
305 // This is illegal.
306 throw new ServletException("Can't have request parameter " +
307 " jsp_precomile set to " + precom);
308 }
309 }
310 else if (qString != null && (qString.startsWith(Constants.PRECOMPILE) ||
311 qString.indexOf("&" + Constants.PRECOMPILE)
312 != -1))
313 precompile = true;
314
315 return precompile;
316 }
317
318
319
320 public void service (HttpServletRequest request,
321 HttpServletResponse response)
322 throws ServletException, IOException
323 {
324 try {
325 String includeUri
326 = (String) request.getAttribute(Constants.INC_REQUEST_URI);
327
328 String jspUri;
329
330 if (includeUri == null)
331 jspUri = request.getServletPath();
332 else
333 jspUri = includeUri;
334
335 boolean precompile = preCompile(request);
336
337 if (Constants.matchVerbosity(Constants.MED_VERBOSITY)) {
338 System.err.println("JspEngine --> "+jspUri);
339 System.err.println("\t ServletPath: "+request.getServletPath());
340 System.err.println("\t PathInfo: "+request.getPathInfo());
341 System.err.println("\t RealPath: "
342 +getServletConfig().getServletContext().getRealPath(jspUri));
343 System.err.println("\t RequestURI: "+request.getRequestURI());
344 System.err.println("\t QueryString: "+request.getQueryString());
345 System.err.println("\t Request Params: ");
346 Enumeration e = request.getParameterNames();
347 while (e.hasMoreElements()) {
348 String name = (String) e.nextElement();
349 System.err.println("\t\t "+name+" = "+request.getParameter(name));
350 }
351 }
352 serviceJspFile(request, response, jspUri, null, precompile);
353
354 } catch (RuntimeException e) {
355 throw e;
356 } catch (ServletException e) {
357 throw e;
358 } catch (Exception e) {
359 throw new ServletException(e);
360 } catch (Throwable t) {
361 unknownException(response, t);
362 }
363 }
364
365 public void destroy() {
366 if (Constants.matchVerbosity(2))
367 System.err.println("JspServlet.destroy()");
368 Enumeration servlets = jsps.elements();
369 while (servlets.hasMoreElements())
370 ((JspServletWrapper) servlets.nextElement()).destroy();
371 }
372
373 }