001: /*
002: * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/servlets/InvokerServlet.java,v 1.15 2002/02/16 01:07:11 craigmcc Exp $
003: * $Revision: 1.15 $
004: * $Date: 2002/02/16 01:07:11 $
005: *
006: * ====================================================================
007: *
008: * The Apache Software License, Version 1.1
009: *
010: * Copyright (c) 1999 The Apache Software Foundation. All rights
011: * reserved.
012: *
013: * Redistribution and use in source and binary forms, with or without
014: * modification, are permitted provided that the following conditions
015: * are met:
016: *
017: * 1. Redistributions of source code must retain the above copyright
018: * notice, this list of conditions and the following disclaimer.
019: *
020: * 2. Redistributions in binary form must reproduce the above copyright
021: * notice, this list of conditions and the following disclaimer in
022: * the documentation and/or other materials provided with the
023: * distribution.
024: *
025: * 3. The end-user documentation included with the redistribution, if
026: * any, must include the following acknowlegement:
027: * "This product includes software developed by the
028: * Apache Software Foundation (http://www.apache.org/)."
029: * Alternately, this acknowlegement may appear in the software itself,
030: * if and wherever such third-party acknowlegements normally appear.
031: *
032: * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
033: * Foundation" must not be used to endorse or promote products derived
034: * from this software without prior written permission. For written
035: * permission, please contact apache@apache.org.
036: *
037: * 5. Products derived from this software may not be called "Apache"
038: * nor may "Apache" appear in their names without prior written
039: * permission of the Apache Group.
040: *
041: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
042: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
043: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
044: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
045: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
046: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
047: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
048: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
049: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
050: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
051: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
052: * SUCH DAMAGE.
053: * ====================================================================
054: *
055: * This software consists of voluntary contributions made by many
056: * individuals on behalf of the Apache Software Foundation. For more
057: * information on the Apache Software Foundation, please see
058: * <http://www.apache.org/>.
059: *
060: * [Additional notices, if required by prior licensing conditions]
061: *
062: */
063:
064: package org.apache.catalina.servlets;
065:
066: import java.io.IOException;
067: import javax.servlet.RequestDispatcher;
068: import javax.servlet.Servlet;
069: import javax.servlet.ServletException;
070: import javax.servlet.UnavailableException;
071: import javax.servlet.http.HttpServlet;
072: import javax.servlet.http.HttpServletRequest;
073: import javax.servlet.http.HttpServletRequestWrapper;
074: import javax.servlet.http.HttpServletResponse;
075: import org.apache.catalina.ContainerServlet;
076: import org.apache.catalina.Context;
077: import org.apache.catalina.Globals;
078: import org.apache.catalina.Wrapper;
079: import org.apache.catalina.util.StringManager;
080:
081: /**
082: * The default servlet-invoking servlet for most web applications,
083: * used to serve requests to servlets that have not been registered
084: * in the web application deployment descriptor.
085: *
086: * @author Craig R. McClanahan
087: * @version $Revision: 1.15 $ $Date: 2002/02/16 01:07:11 $
088: */
089:
090: public final class InvokerServlet extends HttpServlet implements
091: ContainerServlet {
092:
093: // ----------------------------------------------------- Instance Variables
094:
095: /**
096: * The Context container associated with our web application.
097: */
098: private Context context = null;
099:
100: /**
101: * The debugging detail level for this servlet.
102: */
103: private int debug = 0;
104:
105: /**
106: * The string manager for this package.
107: */
108: private static StringManager sm = StringManager
109: .getManager(Constants.Package);
110:
111: /**
112: * The Wrapper container associated with this servlet.
113: */
114: private Wrapper wrapper = null;
115:
116: // ----------------------------------------------- ContainerServlet Methods
117:
118: /**
119: * Return the Wrapper with which we are associated.
120: */
121: public Wrapper getWrapper() {
122:
123: return (this .wrapper);
124:
125: }
126:
127: /**
128: * Set the Wrapper with which we are associated.
129: *
130: * @param wrapper The new wrapper
131: */
132: public void setWrapper(Wrapper wrapper) {
133:
134: this .wrapper = wrapper;
135: if (wrapper == null)
136: context = null;
137: else
138: context = (Context) wrapper.getParent();
139:
140: }
141:
142: // --------------------------------------------------------- Public Methods
143:
144: /**
145: * Finalize this servlet.
146: */
147: public void destroy() {
148:
149: ; // No actions necessary
150:
151: }
152:
153: /**
154: * Process a GET request for the specified resource.
155: *
156: * @param request The servlet request we are processing
157: * @param response The servlet response we are creating
158: *
159: * @exception IOException if an input/output error occurs
160: * @exception ServletException if a servlet-specified error occurs
161: */
162: public void doGet(HttpServletRequest request,
163: HttpServletResponse response) throws IOException,
164: ServletException {
165:
166: serveRequest(request, response);
167:
168: }
169:
170: /**
171: * Process a HEAD request for the specified resource.
172: *
173: * @param request The servlet request we are processing
174: * @param response The servlet response we are creating
175: *
176: * @exception IOException if an input/output error occurs
177: * @exception ServletException if a servlet-specified error occurs
178: */
179: public void doHead(HttpServletRequest request,
180: HttpServletResponse response) throws IOException,
181: ServletException {
182:
183: serveRequest(request, response);
184:
185: }
186:
187: /**
188: * Process a POST request for the specified resource.
189: *
190: * @param request The servlet request we are processing
191: * @param response The servlet response we are creating
192: *
193: * @exception IOException if an input/output error occurs
194: * @exception ServletException if a servlet-specified error occurs
195: */
196: public void doPost(HttpServletRequest request,
197: HttpServletResponse response) throws IOException,
198: ServletException {
199:
200: serveRequest(request, response);
201:
202: }
203:
204: /**
205: * Initialize this servlet.
206: */
207: public void init() throws ServletException {
208:
209: // Ensure that our ContainerServlet properties have been set
210: if ((wrapper == null) || (context == null))
211: throw new UnavailableException(sm
212: .getString("invokerServlet.noWrapper"));
213:
214: // Set our properties from the initialization parameters
215: String value = null;
216: try {
217: value = getServletConfig().getInitParameter("debug");
218: debug = Integer.parseInt(value);
219: } catch (Throwable t) {
220: ;
221: }
222: if (debug >= 1)
223: log("init: Associated with Context '" + context.getPath()
224: + "'");
225:
226: }
227:
228: // -------------------------------------------------------- Private Methods
229:
230: /**
231: * Serve the specified request, creating the corresponding response.
232: * After the first time a particular servlet class is requested, it will
233: * be served directly (like any registered servlet) because it will have
234: * been registered and mapped in our associated Context.
235: *
236: * @param request The servlet request we are processing
237: * @param response The servlet response we are creating
238: *
239: * @exception IOException if an input/output error occurs
240: * @exception ServletException if a servlet-specified error occurs
241: */
242: public void serveRequest(HttpServletRequest request,
243: HttpServletResponse response) throws IOException,
244: ServletException {
245:
246: // Disallow calling this servlet via a named dispatcher
247: if (request.getAttribute(Globals.NAMED_DISPATCHER_ATTR) != null)
248: throw new ServletException(sm
249: .getString("invokerServlet.notNamed"));
250:
251: // Identify the input parameters and our "included" state
252: String inRequestURI = null;
253: String inServletPath = null;
254: String inPathInfo = null;
255: boolean included = (request
256: .getAttribute(Globals.REQUEST_URI_ATTR) != null);
257:
258: if (included) {
259: inRequestURI = (String) request
260: .getAttribute(Globals.REQUEST_URI_ATTR);
261: inServletPath = (String) request
262: .getAttribute(Globals.SERVLET_PATH_ATTR);
263: inPathInfo = (String) request
264: .getAttribute(Globals.PATH_INFO_ATTR);
265: } else {
266: inRequestURI = request.getRequestURI();
267: inServletPath = request.getServletPath();
268: inPathInfo = request.getPathInfo();
269: }
270: if (debug >= 1) {
271: log("included='" + included + "', requestURI='"
272: + inRequestURI + "'");
273: log(" servletPath='" + inServletPath + "', pathInfo='"
274: + inPathInfo + "'");
275: }
276:
277: // Make sure a servlet name or class name was specified
278: if (inPathInfo == null) {
279: if (debug >= 1)
280: log("Invalid pathInfo '" + inPathInfo + "'");
281: if (included)
282: throw new ServletException(sm.getString(
283: "invokerServlet.invalidPath", inRequestURI));
284: else {
285: response.sendError(HttpServletResponse.SC_NOT_FOUND,
286: inRequestURI);
287: return;
288: }
289: }
290:
291: // Identify the outgoing servlet name or class, and outgoing path info
292: String pathInfo = inPathInfo;
293: String servletClass = pathInfo.substring(1);
294: int slash = servletClass.indexOf('/');
295: // if (debug >= 2)
296: // log(" Calculating with servletClass='" + servletClass +
297: // "', pathInfo='" + pathInfo + "', slash=" + slash);
298: if (slash >= 0) {
299: pathInfo = servletClass.substring(slash);
300: servletClass = servletClass.substring(0, slash);
301: } else {
302: pathInfo = "";
303: }
304: if (debug >= 1)
305: log("Processing servlet '" + servletClass
306: + "' with path info '" + pathInfo + "'");
307: String name = "org.apache.catalina.INVOKER." + servletClass;
308: String pattern = inServletPath + "/" + servletClass + "/*";
309: Wrapper wrapper = null;
310:
311: // Synchronize to avoid race conditions when multiple requests
312: // try to initialize the same servlet at the same time
313: synchronized (this ) {
314:
315: // Are we referencing an existing servlet class or name?
316: wrapper = (Wrapper) context.findChild(servletClass);
317: if (wrapper == null)
318: wrapper = (Wrapper) context.findChild(name);
319: if (wrapper != null) {
320: if (debug >= 1)
321: log("Using wrapper for servlet '"
322: + wrapper.getName() + "' with mapping '"
323: + pattern + "'");
324: context.addServletMapping(pattern, wrapper.getName());
325: }
326:
327: // No, create a new wrapper for the specified servlet class
328: else {
329:
330: if (debug >= 1)
331: log("Creating wrapper for '" + servletClass
332: + "' with mapping '" + pattern + "'");
333:
334: try {
335: wrapper = context.createWrapper();
336: wrapper.setName(name);
337: wrapper.setLoadOnStartup(1);
338: wrapper.setServletClass(servletClass);
339: context.addChild(wrapper);
340: context.addServletMapping(pattern, name);
341: } catch (Throwable t) {
342: log(sm.getString("invokerServlet.cannotCreate",
343: inRequestURI), t);
344: context.removeServletMapping(pattern);
345: context.removeChild(wrapper);
346: if (included)
347: throw new ServletException(sm.getString(
348: "invokerServlet.cannotCreate",
349: inRequestURI), t);
350: else {
351: response.sendError(
352: HttpServletResponse.SC_NOT_FOUND,
353: inRequestURI);
354: return;
355: }
356: }
357: }
358:
359: }
360:
361: // Create a request wrapper to pass on to the invoked servlet
362: InvokerHttpRequest wrequest = new InvokerHttpRequest(request);
363: wrequest.setRequestURI(inRequestURI);
364: StringBuffer sb = new StringBuffer(inServletPath);
365: sb.append("/");
366: sb.append(servletClass);
367: wrequest.setServletPath(sb.toString());
368: if ((pathInfo == null) || (pathInfo.length() < 1)) {
369: wrequest.setPathInfo(null);
370: wrequest.setPathTranslated(null);
371: } else {
372: wrequest.setPathInfo(pathInfo);
373: wrequest.setPathTranslated(getServletContext().getRealPath(
374: pathInfo));
375: }
376:
377: // Allocate a servlet instance to perform this request
378: Servlet instance = null;
379: try {
380: // if (debug >= 2)
381: // log(" Allocating servlet instance");
382: instance = wrapper.allocate();
383: } catch (ServletException e) {
384: log(sm.getString("invokerServlet.allocate", inRequestURI),
385: e);
386: context.removeServletMapping(pattern);
387: context.removeChild(wrapper);
388: Throwable rootCause = e.getRootCause();
389: if (rootCause == null)
390: rootCause = e;
391: if (rootCause instanceof ClassNotFoundException) {
392: response.sendError(HttpServletResponse.SC_NOT_FOUND,
393: inRequestURI);
394: return;
395: } else if (rootCause instanceof IOException) {
396: throw (IOException) rootCause;
397: } else if (rootCause instanceof RuntimeException) {
398: throw (RuntimeException) rootCause;
399: } else if (rootCause instanceof ServletException) {
400: throw (ServletException) rootCause;
401: } else {
402: throw new ServletException(sm.getString(
403: "invokerServlet.allocate", inRequestURI),
404: rootCause);
405: }
406: } catch (Throwable e) {
407: log(sm.getString("invokerServlet.allocate", inRequestURI),
408: e);
409: context.removeServletMapping(pattern);
410: context.removeChild(wrapper);
411: throw new ServletException(sm.getString(
412: "invokerServlet.allocate", inRequestURI), e);
413: }
414:
415: // After loading the wrapper, restore some of the fields when including
416: if (included) {
417: wrequest.setRequestURI(request.getRequestURI());
418: wrequest.setPathInfo(request.getPathInfo());
419: wrequest.setServletPath(request.getServletPath());
420: }
421:
422: // Invoke the service() method of the allocated servlet
423: try {
424: String jspFile = wrapper.getJspFile();
425: if (jspFile != null)
426: request.setAttribute(Globals.JSP_FILE_ATTR, jspFile);
427: else
428: request.removeAttribute(Globals.JSP_FILE_ATTR);
429: request.setAttribute(Globals.INVOKED_ATTR, request
430: .getServletPath());
431: // if (debug >= 2)
432: // log(" Calling service() method, jspFile=" +
433: // jspFile);
434: instance.service(wrequest, response);
435: request.removeAttribute(Globals.INVOKED_ATTR);
436: request.removeAttribute(Globals.JSP_FILE_ATTR);
437: } catch (IOException e) {
438: // if (debug >= 2)
439: // log(" service() method IOException", e);
440: request.removeAttribute(Globals.INVOKED_ATTR);
441: request.removeAttribute(Globals.JSP_FILE_ATTR);
442: try {
443: wrapper.deallocate(instance);
444: } catch (Throwable f) {
445: ;
446: }
447: throw e;
448: } catch (UnavailableException e) {
449: // if (debug >= 2)
450: // log(" service() method UnavailableException", e);
451: context.removeServletMapping(pattern);
452: request.removeAttribute(Globals.INVOKED_ATTR);
453: request.removeAttribute(Globals.JSP_FILE_ATTR);
454: try {
455: wrapper.deallocate(instance);
456: } catch (Throwable f) {
457: ;
458: }
459: throw e;
460: } catch (ServletException e) {
461: // if (debug >= 2)
462: // log(" service() method ServletException", e);
463: request.removeAttribute(Globals.INVOKED_ATTR);
464: request.removeAttribute(Globals.JSP_FILE_ATTR);
465: try {
466: wrapper.deallocate(instance);
467: } catch (Throwable f) {
468: ;
469: }
470: throw e;
471: } catch (RuntimeException e) {
472: // if (debug >= 2)
473: // log(" service() method RuntimeException", e);
474: request.removeAttribute(Globals.INVOKED_ATTR);
475: request.removeAttribute(Globals.JSP_FILE_ATTR);
476: try {
477: wrapper.deallocate(instance);
478: } catch (Throwable f) {
479: ;
480: }
481: throw e;
482: } catch (Throwable e) {
483: // if (debug >= 2)
484: // log(" service() method Throwable", e);
485: request.removeAttribute(Globals.INVOKED_ATTR);
486: request.removeAttribute(Globals.JSP_FILE_ATTR);
487: try {
488: wrapper.deallocate(instance);
489: } catch (Throwable f) {
490: ;
491: }
492: throw new ServletException("Invoker service() exception", e);
493: }
494:
495: // Deallocate the allocated servlet instance
496: try {
497: // if (debug >= 2)
498: // log(" deallocate servlet instance");
499: wrapper.deallocate(instance);
500: } catch (ServletException e) {
501: log(
502: sm.getString("invokerServlet.deallocate",
503: inRequestURI), e);
504: throw e;
505: } catch (Throwable e) {
506: log(
507: sm.getString("invokerServlet.deallocate",
508: inRequestURI), e);
509: throw new ServletException(sm.getString(
510: "invokerServlet.deallocate", inRequestURI), e);
511: }
512:
513: }
514:
515: }
|