001: /*
002: * Copyright 1999,2004 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.apache.catalina.servlets;
018:
019: import java.io.IOException;
020:
021: import javax.servlet.Servlet;
022: import javax.servlet.ServletException;
023: import javax.servlet.UnavailableException;
024: import javax.servlet.http.HttpServlet;
025: import javax.servlet.http.HttpServletRequest;
026: import javax.servlet.http.HttpServletResponse;
027:
028: import org.apache.catalina.ContainerServlet;
029: import org.apache.catalina.Context;
030: import org.apache.catalina.Globals;
031: import org.apache.catalina.Wrapper;
032: import org.apache.catalina.util.StringManager;
033:
034: /**
035: * The default servlet-invoking servlet for most web applications,
036: * used to serve requests to servlets that have not been registered
037: * in the web application deployment descriptor.
038: *
039: * @author Craig R. McClanahan
040: * @version $Revision: 1.6 $ $Date: 2004/02/27 14:58:46 $
041: */
042:
043: public final class InvokerServlet extends HttpServlet implements
044: ContainerServlet {
045:
046: // ----------------------------------------------------- Instance Variables
047:
048: /**
049: * The Context container associated with our web application.
050: */
051: private Context context = null;
052:
053: /**
054: * The debugging detail level for this servlet.
055: */
056: private int debug = 0;
057:
058: /**
059: * The string manager for this package.
060: */
061: private static StringManager sm = StringManager
062: .getManager(Constants.Package);
063:
064: /**
065: * The Wrapper container associated with this servlet.
066: */
067: private Wrapper wrapper = null;
068:
069: // ----------------------------------------------- ContainerServlet Methods
070:
071: /**
072: * Return the Wrapper with which we are associated.
073: */
074: public Wrapper getWrapper() {
075:
076: return (this .wrapper);
077:
078: }
079:
080: /**
081: * Set the Wrapper with which we are associated.
082: *
083: * @param wrapper The new wrapper
084: */
085: public void setWrapper(Wrapper wrapper) {
086:
087: this .wrapper = wrapper;
088: if (wrapper == null)
089: context = null;
090: else
091: context = (Context) wrapper.getParent();
092:
093: }
094:
095: // --------------------------------------------------------- Public Methods
096:
097: /**
098: * Finalize this servlet.
099: */
100: public void destroy() {
101:
102: ; // No actions necessary
103:
104: }
105:
106: /**
107: * Process a GET request for the specified resource.
108: *
109: * @param request The servlet request we are processing
110: * @param response The servlet response we are creating
111: *
112: * @exception IOException if an input/output error occurs
113: * @exception ServletException if a servlet-specified error occurs
114: */
115: public void doGet(HttpServletRequest request,
116: HttpServletResponse response) throws IOException,
117: ServletException {
118:
119: serveRequest(request, response);
120:
121: }
122:
123: /**
124: * Process a HEAD request for the specified resource.
125: *
126: * @param request The servlet request we are processing
127: * @param response The servlet response we are creating
128: *
129: * @exception IOException if an input/output error occurs
130: * @exception ServletException if a servlet-specified error occurs
131: */
132: public void doHead(HttpServletRequest request,
133: HttpServletResponse response) throws IOException,
134: ServletException {
135:
136: serveRequest(request, response);
137:
138: }
139:
140: /**
141: * Process a POST request for the specified resource.
142: *
143: * @param request The servlet request we are processing
144: * @param response The servlet response we are creating
145: *
146: * @exception IOException if an input/output error occurs
147: * @exception ServletException if a servlet-specified error occurs
148: */
149: public void doPost(HttpServletRequest request,
150: HttpServletResponse response) throws IOException,
151: ServletException {
152:
153: serveRequest(request, response);
154:
155: }
156:
157: /**
158: * Initialize this servlet.
159: */
160: public void init() throws ServletException {
161:
162: // Ensure that our ContainerServlet properties have been set
163: if ((wrapper == null) || (context == null))
164: throw new UnavailableException(sm
165: .getString("invokerServlet.noWrapper"));
166:
167: // Set our properties from the initialization parameters
168: String value = null;
169: try {
170: value = getServletConfig().getInitParameter("debug");
171: debug = Integer.parseInt(value);
172: } catch (Throwable t) {
173: ;
174: }
175: if (debug >= 1)
176: log("init: Associated with Context '" + context.getPath()
177: + "'");
178:
179: }
180:
181: // -------------------------------------------------------- Private Methods
182:
183: /**
184: * Serve the specified request, creating the corresponding response.
185: * After the first time a particular servlet class is requested, it will
186: * be served directly (like any registered servlet) because it will have
187: * been registered and mapped in our associated Context.
188: *
189: * @param request The servlet request we are processing
190: * @param response The servlet response we are creating
191: *
192: * @exception IOException if an input/output error occurs
193: * @exception ServletException if a servlet-specified error occurs
194: */
195: public void serveRequest(HttpServletRequest request,
196: HttpServletResponse response) throws IOException,
197: ServletException {
198:
199: // Disallow calling this servlet via a named dispatcher
200: if (request.getAttribute(Globals.NAMED_DISPATCHER_ATTR) != null)
201: throw new ServletException(sm
202: .getString("invokerServlet.notNamed"));
203:
204: // Identify the input parameters and our "included" state
205: String inRequestURI = null;
206: String inServletPath = null;
207: String inPathInfo = null;
208: boolean included = (request
209: .getAttribute(Globals.INCLUDE_REQUEST_URI_ATTR) != null);
210:
211: if (included) {
212: inRequestURI = (String) request
213: .getAttribute(Globals.INCLUDE_REQUEST_URI_ATTR);
214: inServletPath = (String) request
215: .getAttribute(Globals.INCLUDE_SERVLET_PATH_ATTR);
216: inPathInfo = (String) request
217: .getAttribute(Globals.INCLUDE_PATH_INFO_ATTR);
218: } else {
219: inRequestURI = request.getRequestURI();
220: inServletPath = request.getServletPath();
221: inPathInfo = request.getPathInfo();
222: }
223: if (debug >= 1) {
224: log("included='" + included + "', requestURI='"
225: + inRequestURI + "'");
226: log(" servletPath='" + inServletPath + "', pathInfo='"
227: + inPathInfo + "'");
228: }
229:
230: // Make sure a servlet name or class name was specified
231: if (inPathInfo == null) {
232: if (debug >= 1)
233: log("Invalid pathInfo '" + inPathInfo + "'");
234: if (included)
235: throw new ServletException(sm.getString(
236: "invokerServlet.invalidPath", inRequestURI));
237: else {
238: response.sendError(HttpServletResponse.SC_NOT_FOUND,
239: inRequestURI);
240: return;
241: }
242: }
243:
244: // Identify the outgoing servlet name or class, and outgoing path info
245: String pathInfo = inPathInfo;
246: String servletClass = pathInfo.substring(1);
247: int slash = servletClass.indexOf('/');
248: // if (debug >= 2)
249: // log(" Calculating with servletClass='" + servletClass +
250: // "', pathInfo='" + pathInfo + "', slash=" + slash);
251: if (slash >= 0) {
252: pathInfo = servletClass.substring(slash);
253: servletClass = servletClass.substring(0, slash);
254: } else {
255: pathInfo = "";
256: }
257:
258: if (servletClass.startsWith("org.apache.catalina")) {
259: response.sendError(HttpServletResponse.SC_NOT_FOUND,
260: inRequestURI);
261: return;
262: }
263:
264: if (debug >= 1)
265: log("Processing servlet '" + servletClass
266: + "' with path info '" + pathInfo + "'");
267: String name = "org.apache.catalina.INVOKER." + servletClass;
268: String pattern = inServletPath + "/" + servletClass + "/*";
269: Wrapper wrapper = null;
270:
271: // Synchronize to avoid race conditions when multiple requests
272: // try to initialize the same servlet at the same time
273: synchronized (this ) {
274:
275: // Are we referencing an existing servlet class or name?
276: wrapper = (Wrapper) context.findChild(servletClass);
277: if (wrapper == null)
278: wrapper = (Wrapper) context.findChild(name);
279: if (wrapper != null) {
280: String actualServletClass = wrapper.getServletClass();
281: if ((actualServletClass != null)
282: && (actualServletClass
283: .startsWith("org.apache.catalina"))) {
284: response.sendError(
285: HttpServletResponse.SC_NOT_FOUND,
286: inRequestURI);
287: return;
288: }
289: if (debug >= 1)
290: log("Using wrapper for servlet '"
291: + wrapper.getName() + "' with mapping '"
292: + pattern + "'");
293: context.addServletMapping(pattern, wrapper.getName());
294: }
295:
296: // No, create a new wrapper for the specified servlet class
297: else {
298:
299: if (debug >= 1)
300: log("Creating wrapper for '" + servletClass
301: + "' with mapping '" + pattern + "'");
302:
303: try {
304: wrapper = context.createWrapper();
305: wrapper.setName(name);
306: wrapper.setLoadOnStartup(1);
307: wrapper.setServletClass(servletClass);
308: context.addChild(wrapper);
309: context.addServletMapping(pattern, name);
310: } catch (Throwable t) {
311: log(sm.getString("invokerServlet.cannotCreate",
312: inRequestURI), t);
313: context.removeServletMapping(pattern);
314: context.removeChild(wrapper);
315: if (included)
316: throw new ServletException(sm.getString(
317: "invokerServlet.cannotCreate",
318: inRequestURI), t);
319: else {
320: response.sendError(
321: HttpServletResponse.SC_NOT_FOUND,
322: inRequestURI);
323: return;
324: }
325: }
326: }
327:
328: }
329:
330: // Create a request wrapper to pass on to the invoked servlet
331: InvokerHttpRequest wrequest = new InvokerHttpRequest(request);
332: wrequest.setRequestURI(inRequestURI);
333: StringBuffer sb = new StringBuffer(inServletPath);
334: sb.append("/");
335: sb.append(servletClass);
336: wrequest.setServletPath(sb.toString());
337: if ((pathInfo == null) || (pathInfo.length() < 1)) {
338: wrequest.setPathInfo(null);
339: wrequest.setPathTranslated(null);
340: } else {
341: wrequest.setPathInfo(pathInfo);
342: wrequest.setPathTranslated(getServletContext().getRealPath(
343: pathInfo));
344: }
345:
346: // Allocate a servlet instance to perform this request
347: Servlet instance = null;
348: try {
349: // if (debug >= 2)
350: // log(" Allocating servlet instance");
351: instance = wrapper.allocate();
352: } catch (ServletException e) {
353: log(sm.getString("invokerServlet.allocate", inRequestURI),
354: e);
355: context.removeServletMapping(pattern);
356: context.removeChild(wrapper);
357: Throwable rootCause = e.getRootCause();
358: if (rootCause == null)
359: rootCause = e;
360: if (rootCause instanceof ClassNotFoundException) {
361: response.sendError(HttpServletResponse.SC_NOT_FOUND,
362: inRequestURI);
363: return;
364: } else if (rootCause instanceof IOException) {
365: throw (IOException) rootCause;
366: } else if (rootCause instanceof RuntimeException) {
367: throw (RuntimeException) rootCause;
368: } else if (rootCause instanceof ServletException) {
369: throw (ServletException) rootCause;
370: } else {
371: throw new ServletException(sm.getString(
372: "invokerServlet.allocate", inRequestURI),
373: rootCause);
374: }
375: } catch (Throwable e) {
376: log(sm.getString("invokerServlet.allocate", inRequestURI),
377: e);
378: context.removeServletMapping(pattern);
379: context.removeChild(wrapper);
380: throw new ServletException(sm.getString(
381: "invokerServlet.allocate", inRequestURI), e);
382: }
383:
384: // After loading the wrapper, restore some of the fields when including
385: if (included) {
386: wrequest.setRequestURI(request.getRequestURI());
387: wrequest.setPathInfo(request.getPathInfo());
388: wrequest.setServletPath(request.getServletPath());
389: }
390:
391: // Invoke the service() method of the allocated servlet
392: try {
393: String jspFile = wrapper.getJspFile();
394: if (jspFile != null)
395: request.setAttribute(Globals.JSP_FILE_ATTR, jspFile);
396: else
397: request.removeAttribute(Globals.JSP_FILE_ATTR);
398: request.setAttribute(Globals.INVOKED_ATTR, request
399: .getServletPath());
400: // if (debug >= 2)
401: // log(" Calling service() method, jspFile=" +
402: // jspFile);
403: instance.service(wrequest, response);
404: request.removeAttribute(Globals.INVOKED_ATTR);
405: request.removeAttribute(Globals.JSP_FILE_ATTR);
406: } catch (IOException e) {
407: // if (debug >= 2)
408: // log(" service() method IOException", e);
409: request.removeAttribute(Globals.INVOKED_ATTR);
410: request.removeAttribute(Globals.JSP_FILE_ATTR);
411: try {
412: wrapper.deallocate(instance);
413: } catch (Throwable f) {
414: ;
415: }
416: throw e;
417: } catch (UnavailableException e) {
418: // if (debug >= 2)
419: // log(" service() method UnavailableException", e);
420: context.removeServletMapping(pattern);
421: request.removeAttribute(Globals.INVOKED_ATTR);
422: request.removeAttribute(Globals.JSP_FILE_ATTR);
423: try {
424: wrapper.deallocate(instance);
425: } catch (Throwable f) {
426: ;
427: }
428: throw e;
429: } catch (ServletException e) {
430: // if (debug >= 2)
431: // log(" service() method ServletException", e);
432: request.removeAttribute(Globals.INVOKED_ATTR);
433: request.removeAttribute(Globals.JSP_FILE_ATTR);
434: try {
435: wrapper.deallocate(instance);
436: } catch (Throwable f) {
437: ;
438: }
439: throw e;
440: } catch (RuntimeException e) {
441: // if (debug >= 2)
442: // log(" service() method RuntimeException", e);
443: request.removeAttribute(Globals.INVOKED_ATTR);
444: request.removeAttribute(Globals.JSP_FILE_ATTR);
445: try {
446: wrapper.deallocate(instance);
447: } catch (Throwable f) {
448: ;
449: }
450: throw e;
451: } catch (Throwable e) {
452: // if (debug >= 2)
453: // log(" service() method Throwable", e);
454: request.removeAttribute(Globals.INVOKED_ATTR);
455: request.removeAttribute(Globals.JSP_FILE_ATTR);
456: try {
457: wrapper.deallocate(instance);
458: } catch (Throwable f) {
459: ;
460: }
461: throw new ServletException("Invoker service() exception", e);
462: }
463:
464: // Deallocate the allocated servlet instance
465: try {
466: // if (debug >= 2)
467: // log(" deallocate servlet instance");
468: wrapper.deallocate(instance);
469: } catch (ServletException e) {
470: log(
471: sm.getString("invokerServlet.deallocate",
472: inRequestURI), e);
473: throw e;
474: } catch (Throwable e) {
475: log(
476: sm.getString("invokerServlet.deallocate",
477: inRequestURI), e);
478: throw new ServletException(sm.getString(
479: "invokerServlet.deallocate", inRequestURI), e);
480: }
481:
482: }
483:
484: }
|