001: /*
002: * Copyright 1999-2001,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.core;
018:
019: import java.io.IOException;
020:
021: import javax.servlet.ServletException;
022: import javax.servlet.ServletRequest;
023: import javax.servlet.ServletRequestEvent;
024: import javax.servlet.ServletRequestListener;
025: import javax.servlet.http.HttpServletResponse;
026:
027: import org.apache.catalina.Context;
028: import org.apache.catalina.Globals;
029: import org.apache.catalina.HttpRequest;
030: import org.apache.catalina.Logger;
031: import org.apache.catalina.Request;
032: import org.apache.catalina.Response;
033: import org.apache.catalina.ValveContext;
034: import org.apache.catalina.Wrapper;
035: import org.apache.catalina.util.StringManager;
036: import org.apache.catalina.valves.ValveBase;
037: import org.apache.commons.logging.Log;
038: import org.apache.commons.logging.LogFactory;
039: import org.apache.tomcat.util.buf.MessageBytes;
040: import org.apache.tomcat.util.log.SystemLogHandler;
041:
042: /**
043: * Valve that implements the default basic behavior for the
044: * <code>StandardContext</code> container implementation.
045: * <p>
046: * <b>USAGE CONSTRAINT</b>: This implementation is likely to be useful only
047: * when processing HTTP requests.
048: *
049: * @author Craig R. McClanahan
050: * @version $Revision: 1.14 $ $Date: 2004/02/27 14:58:42 $
051: */
052:
053: final class StandardContextValve extends ValveBase {
054:
055: // ----------------------------------------------------- Instance Variables
056:
057: /**
058: * The descriptive information related to this implementation.
059: */
060: private static final String info = "org.apache.catalina.core.StandardContextValve/1.0";
061:
062: /**
063: * The string manager for this package.
064: */
065: private static final StringManager sm = StringManager
066: .getManager(Constants.Package);
067:
068: private static Log log = LogFactory
069: .getLog(StandardContextValve.class);
070:
071: // ------------------------------------------------------------- Properties
072:
073: /**
074: * Return descriptive information about this Valve implementation.
075: */
076: public String getInfo() {
077:
078: return (info);
079:
080: }
081:
082: // --------------------------------------------------------- Public Methods
083:
084: /**
085: * Select the appropriate child Wrapper to process this request,
086: * based on the specified request URI. If no matching Wrapper can
087: * be found, return an appropriate HTTP error.
088: *
089: * @param request Request to be processed
090: * @param response Response to be produced
091: * @param valveContext Valve context used to forward to the next Valve
092: *
093: * @exception IOException if an input/output error occurred
094: * @exception ServletException if a servlet error occurred
095: */
096: public final void invoke(Request request, Response response,
097: ValveContext valveContext) throws IOException,
098: ServletException {
099:
100: // Disallow any direct access to resources under WEB-INF or META-INF
101: HttpRequest hreq = (HttpRequest) request;
102: MessageBytes requestPathMB = hreq.getRequestPathMB();
103: if ((requestPathMB.startsWithIgnoreCase("/META-INF/", 0))
104: || (requestPathMB.equalsIgnoreCase("/META-INF"))
105: || (requestPathMB.startsWithIgnoreCase("/WEB-INF/", 0))
106: || (requestPathMB.equalsIgnoreCase("/WEB-INF"))) {
107: String requestURI = hreq.getDecodedRequestURI();
108: notFound(requestURI, (HttpServletResponse) response
109: .getResponse());
110: return;
111: }
112:
113: // Wait if we are reloading
114: while (((StandardContext) container).getPaused()) {
115: try {
116: Thread.sleep(1000);
117: } catch (InterruptedException e) {
118: ;
119: }
120: }
121:
122: // Select the Wrapper to be used for this Request
123: Wrapper wrapper = request.getWrapper();
124: if (wrapper == null) {
125: String requestURI = hreq.getDecodedRequestURI();
126: notFound(requestURI, (HttpServletResponse) response
127: .getResponse());
128: return;
129: }
130:
131: // Normal request processing
132: if (((StandardContext) container).getSwallowOutput()) {
133: try {
134: SystemLogHandler.startCapture();
135: invokeInternal(wrapper, request, response);
136: } finally {
137: String log = SystemLogHandler.stopCapture();
138: if (log != null && log.length() > 0) {
139: container.getLogger().log(log);
140: }
141: }
142: } else {
143: invokeInternal(wrapper, request, response);
144: }
145:
146: }
147:
148: // -------------------------------------------------------- Private Methods
149:
150: /**
151: * Call invoke.
152: */
153: private void invokeInternal(Wrapper wrapper, Request request,
154: Response response) throws IOException, ServletException {
155:
156: Object instances[] = ((Context) container)
157: .getApplicationEventListeners();
158:
159: ServletRequestEvent event = null;
160:
161: if ((instances != null) && (instances.length > 0)) {
162: event = new ServletRequestEvent(
163: ((StandardContext) container).getServletContext(),
164: request.getRequest());
165: // create pre-service event
166: for (int i = 0; i < instances.length; i++) {
167: if (instances[i] == null)
168: continue;
169: if (!(instances[i] instanceof ServletRequestListener))
170: continue;
171: ServletRequestListener listener = (ServletRequestListener) instances[i];
172: try {
173: listener.requestInitialized(event);
174: } catch (Throwable t) {
175: log(sm.getString(
176: "requestListenerValve.requestInit",
177: instances[i].getClass().getName()), t);
178: ServletRequest sreq = request.getRequest();
179: sreq.setAttribute(Globals.EXCEPTION_ATTR, t);
180: return;
181: }
182: }
183: }
184:
185: wrapper.getPipeline().invoke(request, response);
186:
187: if ((instances != null) && (instances.length > 0)) {
188: // create post-service event
189: for (int i = 0; i < instances.length; i++) {
190: if (instances[i] == null)
191: continue;
192: if (!(instances[i] instanceof ServletRequestListener))
193: continue;
194: ServletRequestListener listener = (ServletRequestListener) instances[i];
195: try {
196: listener.requestDestroyed(event);
197: } catch (Throwable t) {
198: log(sm.getString(
199: "requestListenerValve.requestDestroy",
200: instances[i].getClass().getName()), t);
201: ServletRequest sreq = request.getRequest();
202: sreq.setAttribute(Globals.EXCEPTION_ATTR, t);
203: }
204: }
205: }
206:
207: }
208:
209: /**
210: * Report a "bad request" error for the specified resource. FIXME: We
211: * should really be using the error reporting settings for this web
212: * application, but currently that code runs at the wrapper level rather
213: * than the context level.
214: *
215: * @param requestURI The request URI for the requested resource
216: * @param response The response we are creating
217: */
218: private void badRequest(String requestURI,
219: HttpServletResponse response) {
220:
221: try {
222: response.sendError(HttpServletResponse.SC_BAD_REQUEST,
223: requestURI);
224: } catch (IllegalStateException e) {
225: ;
226: } catch (IOException e) {
227: ;
228: }
229:
230: }
231:
232: /**
233: * Report a "forbidden" error for the specified resource.
234: *
235: * @param requestURI The request URI for the requested resource
236: * @param response The response we are creating
237: */
238: private void forbidden(String requestURI,
239: HttpServletResponse response) {
240:
241: try {
242: response.sendError(HttpServletResponse.SC_FORBIDDEN,
243: requestURI);
244: } catch (IllegalStateException e) {
245: ;
246: } catch (IOException e) {
247: ;
248: }
249:
250: }
251:
252: /**
253: * Report a "not found" error for the specified resource. FIXME: We
254: * should really be using the error reporting settings for this web
255: * application, but currently that code runs at the wrapper level rather
256: * than the context level.
257: *
258: * @param requestURI The request URI for the requested resource
259: * @param response The response we are creating
260: */
261: private void notFound(String requestURI,
262: HttpServletResponse response) {
263:
264: try {
265: response.sendError(HttpServletResponse.SC_NOT_FOUND,
266: requestURI);
267: } catch (IllegalStateException e) {
268: ;
269: } catch (IOException e) {
270: ;
271: }
272:
273: }
274:
275: /**
276: * Log a message on the Logger associated with our Container (if any)
277: *
278: * @param message Message to be logged
279: */
280: private void log(String message) {
281:
282: Logger logger = null;
283: if (container != null)
284: logger = container.getLogger();
285: if (logger != null)
286: logger.log("StandardContextValve[" + container.getName()
287: + "]: " + message);
288: else {
289: String containerName = null;
290: if (container != null)
291: containerName = container.getName();
292: System.out.println("StandardContextValve[" + containerName
293: + "]: " + message);
294: }
295:
296: }
297:
298: /**
299: * Log a message on the Logger associated with our Container (if any)
300: *
301: * @param message Message to be logged
302: * @param throwable Associated exception
303: */
304: private void log(String message, Throwable throwable) {
305:
306: Logger logger = null;
307: if (container != null)
308: logger = container.getLogger();
309: if (logger != null)
310: logger.log("StandardContextValve[" + container.getName()
311: + "]: " + message, throwable);
312: else {
313: String containerName = null;
314: if (container != null)
315: containerName = container.getName();
316: System.out.println("StandardContextValve[" + containerName
317: + "]: " + message);
318: System.out.println("" + throwable);
319: throwable.printStackTrace(System.out);
320: }
321:
322: }
323:
324: }
|