001: /*
002: * The Apache Software License, Version 1.1
003: *
004: * Copyright (c) 1999 The Apache Software Foundation. All rights
005: * reserved.
006: *
007: * Redistribution and use in source and binary forms, with or without
008: * modification, are permitted provided that the following conditions
009: * are met:
010: *
011: * 1. Redistributions of source code must retain the above copyright
012: * notice, this list of conditions and the following disclaimer.
013: *
014: * 2. Redistributions in binary form must reproduce the above copyright
015: * notice, this list of conditions and the following disclaimer in
016: * the documentation and/or other materials provided with the
017: * distribution.
018: *
019: * 3. The end-user documentation included with the redistribution, if
020: * any, must include the following acknowlegement:
021: * "This product includes software developed by the
022: * Apache Software Foundation (http://www.apache.org/)."
023: * Alternately, this acknowlegement may appear in the software itself,
024: * if and wherever such third-party acknowlegements normally appear.
025: *
026: * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
027: * Foundation" must not be used to endorse or promote products derived
028: * from this software without prior written permission. For written
029: * permission, please contact apache@apache.org.
030: *
031: * 5. Products derived from this software may not be called "Apache"
032: * nor may "Apache" appear in their names without prior written
033: * permission of the Apache Group.
034: *
035: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
036: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
037: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
038: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
039: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
040: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
041: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
042: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
043: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
044: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
045: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
046: * SUCH DAMAGE.
047: * ====================================================================
048: *
049: * This software consists of voluntary contributions made by many
050: * individuals on behalf of the Apache Software Foundation. For more
051: * information on the Apache Software Foundation, please see
052: * <http://www.apache.org/>.
053: *
054: */
055:
056: package com.rimfaxe.webserver.runtime;
057:
058: import java.io.IOException;
059: import java.io.InputStreamReader;
060:
061: import java.util.Enumeration;
062: import java.util.Hashtable;
063: import java.util.NoSuchElementException;
064:
065: import javax.servlet.Servlet;
066: import javax.servlet.ServletConfig;
067: import javax.servlet.ServletContext;
068: import javax.servlet.ServletRequest;
069: import javax.servlet.ServletResponse;
070: import javax.servlet.ServletException;
071:
072: import javax.servlet.http.HttpSession;
073: import javax.servlet.http.HttpServletRequest;
074: import javax.servlet.http.HttpServletResponse;
075: import javax.servlet.http.HttpServletResponseWrapper;
076:
077: import javax.servlet.jsp.PageContext;
078: import javax.servlet.jsp.JspFactory;
079: import javax.servlet.jsp.JspWriter;
080: import javax.servlet.jsp.tagext.BodyContent;
081: import javax.servlet.jsp.JspException;
082:
083: import com.rimfaxe.webserver.compiler.jsp.Constants;
084:
085: import com.rimfaxe.webserver.servletapi.*;
086:
087: /**
088: * Implementation of the PageContext class from the JSP spec.
089: *
090: * @author Anil K. Vijendran
091: * @author Larry Cable
092: * @author Hans Bergsten
093: * @author Pierre Delisle
094: */
095: public class PageContextImpl extends PageContext {
096:
097: PageContextImpl(JspFactory factory) {
098: this .factory = factory;
099: }
100:
101: public void initialize(Servlet servlet, ServletRequest request,
102: ServletResponse response, String errorPageURL,
103: boolean needsSession, int bufferSize, boolean autoFlush)
104: throws IOException, IllegalStateException,
105: IllegalArgumentException {
106: _initialize(servlet, request, response, errorPageURL,
107: needsSession, bufferSize, autoFlush);
108: }
109:
110: void _initialize(Servlet servlet, ServletRequest request,
111: ServletResponse response, String errorPageURL,
112: boolean needsSession, int bufferSize, boolean autoFlush)
113: throws IOException, IllegalStateException,
114: IllegalArgumentException {
115:
116: // initialize state
117:
118: this .servlet = servlet;
119: this .config = servlet.getServletConfig();
120: this .context = config.getServletContext();
121: this .needsSession = needsSession;
122: this .errorPageURL = errorPageURL;
123: this .bufferSize = bufferSize;
124: this .autoFlush = autoFlush;
125: this .request = request;
126: this .response = response;
127:
128: //System.out.println("PageContext errorurl="+errorPageURL);
129:
130: // setup session (if required)
131: if (request instanceof HttpServletRequest && needsSession)
132: this .session = ((HttpServletRequest) request).getSession();
133:
134: if (needsSession && session == null) {
135: System.out
136: .println("PageContext, Page needs a session and none is available");
137: throw new IllegalStateException(
138: "Page needs a session and none is available");
139: }
140:
141: // initialize the initial out ...
142: depth = -1;
143: if (this .baseOut == null) {
144: this .baseOut = _createOut(bufferSize, autoFlush);
145: } else {
146: this .baseOut.init(response, bufferSize, autoFlush);
147: }
148: this .out = baseOut;
149:
150: if (this .out == null) {
151: System.out
152: .println("PageContext, failed initialize JspWriter");
153: throw new IllegalStateException(
154: "failed initialize JspWriter");
155: }
156: // register names/values as per spec
157:
158: setAttribute(OUT, this .out);
159: setAttribute(REQUEST, request);
160: setAttribute(RESPONSE, response);
161:
162: if (session != null)
163: setAttribute(SESSION, session);
164:
165: setAttribute(PAGE, servlet);
166: setAttribute(CONFIG, config);
167: setAttribute(PAGECONTEXT, this );
168: setAttribute(APPLICATION, context);
169:
170: isIncluded = request
171: .getAttribute("javax.servlet.include.servlet_path") != null;
172: }
173:
174: public void release() {
175: out = baseOut;
176: try {
177: if (isIncluded) {
178: ((JspWriterImpl) out).flushBuffer();
179: // push it into the including jspWriter
180: } else {
181: out.flush();
182: }
183: } catch (IOException ex) {
184: //loghelper.log("Internal error flushing the buffer in release()");
185: }
186: servlet = null;
187: config = null;
188: context = null;
189: needsSession = false;
190: errorPageURL = null;
191: bufferSize = JspWriter.DEFAULT_BUFFER;
192: autoFlush = true;
193: request = null;
194: response = null;
195: depth = -1;
196: baseOut.recycle();
197: session = null;
198:
199: attributes.clear();
200: }
201:
202: public Object getAttribute(String name) {
203: return attributes.get(name);
204: }
205:
206: public Object getAttribute(String name, int scope) {
207: //System.out.println("PAGECONTEXTIMPL getAttribute");
208: switch (scope) {
209: case PAGE_SCOPE:
210: return attributes.get(name);
211:
212: case REQUEST_SCOPE:
213: return request.getAttribute(name);
214:
215: case SESSION_SCOPE:
216: if (session == null) {
217: //System.out.println("PAGECONTEXTIMPL getAttribute session == null");
218: throw new IllegalArgumentException(
219: "can't access SESSION_SCOPE without an HttpSession");
220: } else {
221: //System.out.println("PAGECONTEXTIMPL getAttribute("+name+") = "+session.getAttribute(name));
222: return session.getAttribute(name);
223: }
224:
225: case APPLICATION_SCOPE:
226: return context.getAttribute(name);
227:
228: default:
229: throw new IllegalArgumentException("unidentified scope");
230: }
231: }
232:
233: public void setAttribute(String name, Object attribute) {
234: attributes.put(name, attribute);
235: }
236:
237: public void setAttribute(String name, Object o, int scope) {
238: switch (scope) {
239: case PAGE_SCOPE:
240: attributes.put(name, o);
241: break;
242:
243: case REQUEST_SCOPE:
244: request.setAttribute(name, o);
245: break;
246:
247: case SESSION_SCOPE:
248: if (session == null)
249: throw new IllegalArgumentException(
250: "can't access SESSION_SCOPE without an HttpSession");
251: else
252: session.setAttribute(name, o);
253: break;
254:
255: case APPLICATION_SCOPE:
256: context.setAttribute(name, o);
257: break;
258:
259: default:
260: }
261: }
262:
263: public void removeAttribute(String name, int scope) {
264: switch (scope) {
265: case PAGE_SCOPE:
266: attributes.remove(name);
267: break;
268:
269: case REQUEST_SCOPE:
270: request.removeAttribute(name);
271: break;
272:
273: case SESSION_SCOPE:
274: if (session == null)
275: throw new IllegalArgumentException(
276: "can't access SESSION_SCOPE without an HttpSession");
277: else
278: session.removeAttribute(name);
279: // was:
280: // session.removeValue(name);
281: // REVISIT Verify this is correct - akv
282: break;
283:
284: case APPLICATION_SCOPE:
285: context.removeAttribute(name);
286: break;
287:
288: default:
289: }
290: }
291:
292: public int getAttributesScope(String name) {
293: if (attributes.get(name) != null)
294: return PAGE_SCOPE;
295:
296: if (request.getAttribute(name) != null)
297: return REQUEST_SCOPE;
298:
299: if (session != null) {
300: if (session.getAttribute(name) != null)
301: return SESSION_SCOPE;
302: }
303:
304: if (context.getAttribute(name) != null)
305: return APPLICATION_SCOPE;
306:
307: return 0;
308: }
309:
310: public Object findAttribute(String name) {
311: Object o = attributes.get(name);
312: if (o != null)
313: return o;
314:
315: o = request.getAttribute(name);
316: if (o != null)
317: return o;
318:
319: if (session != null) {
320: o = session.getAttribute(name);
321: if (o != null)
322: return o;
323: }
324:
325: return context.getAttribute(name);
326: }
327:
328: public Enumeration getAttributeNamesInScope(int scope) {
329: switch (scope) {
330: case PAGE_SCOPE:
331: return attributes.keys();
332:
333: case REQUEST_SCOPE:
334: return request.getAttributeNames();
335:
336: case SESSION_SCOPE:
337: if (session != null) {
338: return session.getAttributeNames();
339: } else
340: throw new IllegalArgumentException(
341: "can't access SESSION_SCOPE without an HttpSession");
342:
343: case APPLICATION_SCOPE:
344: return context.getAttributeNames();
345:
346: default:
347: return new Enumeration() { // empty enumeration
348: public boolean hasMoreElements() {
349: return false;
350: }
351:
352: public Object nextElement() {
353: throw new NoSuchElementException();
354: }
355: };
356: }
357: }
358:
359: public void removeAttribute(String name) {
360: try {
361: removeAttribute(name, PAGE_SCOPE);
362: removeAttribute(name, REQUEST_SCOPE);
363: if (session != null) {
364: removeAttribute(name, SESSION_SCOPE);
365: }
366: removeAttribute(name, APPLICATION_SCOPE);
367: } catch (Exception ex) {
368: // we remove as much as we can, and
369: // simply ignore possible exceptions
370: }
371: }
372:
373: public JspWriter getOut() {
374: return out;
375: }
376:
377: public HttpSession getSession() {
378: return session;
379: }
380:
381: public Servlet getServlet() {
382: return servlet;
383: }
384:
385: public ServletConfig getServletConfig() {
386: return config;
387: }
388:
389: public ServletContext getServletContext() {
390: return config.getServletContext();
391: }
392:
393: public ServletRequest getRequest() {
394: return request;
395: }
396:
397: public ServletResponse getResponse() {
398: return response;
399: }
400:
401: public Exception getException() {
402: return (Exception) request.getAttribute(EXCEPTION);
403: }
404:
405: public Object getPage() {
406: return servlet;
407: }
408:
409: private final String getAbsolutePathRelativeToContext(
410: String relativeUrlPath) {
411: String path = relativeUrlPath;
412:
413: if (!path.startsWith("/")) {
414: String uri = (String) request
415: .getAttribute("javax.servlet.include.servlet_path");
416: if (uri == null) {
417: uri = ((RimfaxeHttpServletRequest) request)
418: .getRealPath(relativeUrlPath);
419: }
420: String baseURI = uri.substring(0, uri.lastIndexOf('/'));
421: path = baseURI + '/' + path;
422:
423: }
424: /*else
425: {
426:
427: path = ((RimfaxeHttpServletRequest) request).prependRealPath(relativeUrlPath);
428:
429: }*/
430:
431: return path;
432: }
433:
434: public void include(String relativeUrlPath)
435: throws ServletException, IOException {
436: JspRuntimeLibrary.include((HttpServletRequest) request,
437: (HttpServletResponse) response, relativeUrlPath, out,
438: true);
439:
440: }
441:
442: public void forward(String relativeUrlPath)
443: throws ServletException, IOException {
444: // JSP.4.5 If the buffer was flushed, throw IllegalStateException
445: try {
446: out.clear();
447: } catch (IOException ex) {
448: throw new IllegalStateException(
449: Constants
450: .getString("jsp.error.attempt_to_clear_flushed_buffer"));
451: }
452:
453: // Make sure that the response object is not the wrapper for include
454: while (response instanceof ServletResponseWrapperInclude) {
455: response = ((ServletResponseWrapperInclude) response)
456: .getResponse();
457: }
458:
459: String path = getAbsolutePathRelativeToContext(relativeUrlPath);
460:
461: //System.out.println("Forward path "+path);
462:
463: String includeUri = (String) request
464: .getAttribute(Constants.INC_SERVLET_PATH);
465: if (includeUri != null)
466: request.removeAttribute(Constants.INC_SERVLET_PATH);
467: try {
468: context.getRequestDispatcher(path).forward(request,
469: response);
470: } finally {
471: if (includeUri != null)
472: request.setAttribute(Constants.INC_SERVLET_PATH,
473: includeUri);
474: request.setAttribute(Constants.FORWARD_SEEN, "true");
475: }
476: }
477:
478: protected BodyContent[] outs = new BodyContentImpl[0];
479: protected int depth = -1;
480:
481: public BodyContent pushBody() {
482: depth++;
483: if (depth >= outs.length) {
484: BodyContent[] newOuts = new BodyContentImpl[depth + 1];
485: for (int i = 0; i < outs.length; i++) {
486: newOuts[i] = outs[i];
487: }
488: newOuts[depth] = new BodyContentImpl(out);
489: outs = newOuts;
490: }
491: out = outs[depth];
492: return outs[depth];
493: }
494:
495: public JspWriter popBody() {
496: depth--;
497: if (depth >= 0) {
498: out = outs[depth];
499: } else {
500: out = baseOut;
501: }
502: return out;
503: }
504:
505: public void handlePageException(Exception ex) throws IOException,
506: ServletException {
507: // Should never be called since handleException() called with a
508: // Throwable in the generated servlet.
509: handlePageException((Throwable) ex);
510: }
511:
512: public void handlePageException(Throwable t) throws IOException,
513: ServletException {
514: // set the request attribute with the Throwable.
515: request.setAttribute("javax.servlet.jsp.jspException", t);
516:
517: if (errorPageURL != null && !errorPageURL.equals("")) {
518: try {
519: forward(errorPageURL);
520: } catch (IllegalStateException ise) {
521: include(errorPageURL);
522: }
523: } else {
524: // Otherwise throw the exception wrapped inside a ServletException.
525: // Set the exception as the root cause in the ServletException
526: // to get a stack trace for the real problem
527: if (t instanceof IOException)
528: throw (IOException) t;
529: if (t instanceof ServletException)
530: throw (ServletException) t;
531: if (t instanceof RuntimeException)
532: throw (RuntimeException) t;
533: if (t instanceof JspException) {
534: Throwable rootCause = ((JspException) t).getRootCause();
535: if (rootCause != null) {
536: throw new ServletException(t.getMessage(),
537: rootCause);
538: } else {
539: throw new ServletException(t);
540: }
541: }
542: throw new ServletException(t);
543: }
544: }
545:
546: protected JspWriterImpl _createOut(int bufferSize, boolean autoFlush)
547: throws IOException, IllegalArgumentException {
548: try {
549: return new JspWriterImpl(response, bufferSize, autoFlush);
550: } catch (Throwable t) {
551: //loghelper.log("creating out", t);
552: return null;
553: }
554: }
555:
556: /*
557: * fields
558: */
559:
560: // per Servlet state
561: protected Servlet servlet;
562: protected ServletConfig config;
563: protected ServletContext context;
564:
565: protected JspFactory factory;
566:
567: protected boolean needsSession;
568:
569: protected String errorPageURL;
570:
571: protected boolean autoFlush;
572: protected int bufferSize;
573:
574: // page scope attributes
575:
576: protected transient Hashtable attributes = new Hashtable(16);
577:
578: // per request state
579:
580: protected transient ServletRequest request;
581: protected transient ServletResponse response;
582: protected transient Object page;
583:
584: protected transient HttpSession session;
585:
586: protected boolean isIncluded;
587:
588: // initial output stream
589:
590: protected transient JspWriter out;
591: protected transient JspWriterImpl baseOut;
592:
593: }
|