001: // ========================================================================
002: // Copyright 199-2004 Mort Bay Consulting Pty. Ltd.
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: // http://www.apache.org/licenses/LICENSE-2.0
008: // Unless required by applicable law or agreed to in writing, software
009: // distributed under the License is distributed on an "AS IS" BASIS,
010: // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
011: // See the License for the specific language governing permissions and
012: // limitations under the License.
013: // ========================================================================
014:
015: package org.mortbay.jetty.servlet;
016:
017: import java.io.IOException;
018: import java.util.Collections;
019: import java.util.Enumeration;
020: import java.util.HashSet;
021: import java.util.Iterator;
022: import java.util.Map;
023:
024: import javax.servlet.RequestDispatcher;
025: import javax.servlet.ServletException;
026: import javax.servlet.ServletRequest;
027: import javax.servlet.ServletResponse;
028: import javax.servlet.http.HttpServletRequest;
029: import javax.servlet.http.HttpServletResponse;
030:
031: import org.mortbay.jetty.Handler;
032: import org.mortbay.jetty.HttpConnection;
033: import org.mortbay.jetty.Request;
034: import org.mortbay.jetty.handler.ContextHandler;
035: import org.mortbay.util.Attributes;
036: import org.mortbay.util.LazyList;
037: import org.mortbay.util.MultiMap;
038: import org.mortbay.util.UrlEncoded;
039:
040: /* ------------------------------------------------------------ */
041: /** Servlet RequestDispatcher.
042: *
043: * @author Greg Wilkins (gregw)
044: */
045: public class Dispatcher implements RequestDispatcher {
046: /** Dispatch include attribute names */
047: public final static String __INCLUDE_JETTY = "org.mortbay.jetty.included";
048: public final static String __INCLUDE_PREFIX = "javax.servlet.include.";
049: public final static String __INCLUDE_REQUEST_URI = "javax.servlet.include.request_uri";
050: public final static String __INCLUDE_CONTEXT_PATH = "javax.servlet.include.context_path";
051: public final static String __INCLUDE_SERVLET_PATH = "javax.servlet.include.servlet_path";
052: public final static String __INCLUDE_PATH_INFO = "javax.servlet.include.path_info";
053: public final static String __INCLUDE_QUERY_STRING = "javax.servlet.include.query_string";
054:
055: /** Dispatch include attribute names */
056: public final static String __FORWARD_JETTY = "org.mortbay.jetty.forwarded";
057: public final static String __FORWARD_PREFIX = "javax.servlet.forward.";
058: public final static String __FORWARD_REQUEST_URI = "javax.servlet.forward.request_uri";
059: public final static String __FORWARD_CONTEXT_PATH = "javax.servlet.forward.context_path";
060: public final static String __FORWARD_SERVLET_PATH = "javax.servlet.forward.servlet_path";
061: public final static String __FORWARD_PATH_INFO = "javax.servlet.forward.path_info";
062: public final static String __FORWARD_QUERY_STRING = "javax.servlet.forward.query_string";
063:
064: /** JSP attributes */
065: public final static String __JSP_FILE = "org.apache.catalina.jsp_file";
066:
067: /* ------------------------------------------------------------ */
068: /** Dispatch type from name
069: */
070: public static int type(String type) {
071: if ("request".equalsIgnoreCase(type))
072: return Handler.REQUEST;
073: if ("forward".equalsIgnoreCase(type))
074: return Handler.FORWARD;
075: if ("include".equalsIgnoreCase(type))
076: return Handler.INCLUDE;
077: if ("error".equalsIgnoreCase(type))
078: return Handler.ERROR;
079: throw new IllegalArgumentException(type);
080: }
081:
082: /* ------------------------------------------------------------ */
083: private ContextHandler _contextHandler;
084: private String _uri;
085: private String _path;
086: private String _dQuery;
087: private String _named;
088:
089: /* ------------------------------------------------------------ */
090: /**
091: * @param contextHandler
092: * @param uriInContext
093: * @param pathInContext
094: * @param query
095: */
096: public Dispatcher(ContextHandler contextHandler, String uri,
097: String pathInContext, String query) {
098: _contextHandler = contextHandler;
099: _uri = uri;
100: _path = pathInContext;
101: _dQuery = query;
102: }
103:
104: /* ------------------------------------------------------------ */
105: /** Constructor.
106: * @param servletHandler
107: * @param name
108: */
109: public Dispatcher(ContextHandler contextHandler, String name)
110: throws IllegalStateException {
111: _contextHandler = contextHandler;
112: _named = name;
113: }
114:
115: /* ------------------------------------------------------------ */
116: /*
117: * @see javax.servlet.RequestDispatcher#forward(javax.servlet.ServletRequest, javax.servlet.ServletResponse)
118: */
119: public void forward(ServletRequest request, ServletResponse response)
120: throws ServletException, IOException {
121: forward(request, response, Handler.FORWARD);
122: }
123:
124: /* ------------------------------------------------------------ */
125: /*
126: * @see javax.servlet.RequestDispatcher#forward(javax.servlet.ServletRequest, javax.servlet.ServletResponse)
127: */
128: public void error(ServletRequest request, ServletResponse response)
129: throws ServletException, IOException {
130: forward(request, response, Handler.ERROR);
131: }
132:
133: /* ------------------------------------------------------------ */
134: /*
135: * @see javax.servlet.RequestDispatcher#include(javax.servlet.ServletRequest, javax.servlet.ServletResponse)
136: */
137: public void include(ServletRequest request, ServletResponse response)
138: throws ServletException, IOException {
139: Request base_request = (request instanceof Request) ? ((Request) request)
140: : HttpConnection.getCurrentConnection().getRequest();
141: request.removeAttribute(__JSP_FILE); // TODO remove when glassfish 1044 is fixed
142:
143: // TODO - allow stream or writer????
144:
145: Attributes old_attr = base_request.getAttributes();
146: MultiMap old_params = base_request.getParameters();
147: try {
148: base_request.getConnection().include();
149: if (_named != null)
150: _contextHandler
151: .handle(_named, (HttpServletRequest) request,
152: (HttpServletResponse) response,
153: Handler.INCLUDE);
154: else {
155: String query = _dQuery;
156:
157: if (query != null) {
158: MultiMap parameters = new MultiMap();
159: UrlEncoded.decodeTo(query, parameters, request
160: .getCharacterEncoding());
161:
162: if (old_params != null && old_params.size() > 0) {
163: // Merge parameters.
164: Iterator iter = old_params.entrySet()
165: .iterator();
166: while (iter.hasNext()) {
167: Map.Entry entry = (Map.Entry) iter.next();
168: String name = (String) entry.getKey();
169: Object values = entry.getValue();
170: for (int i = 0; i < LazyList.size(values); i++)
171: parameters.add(name, LazyList.get(
172: values, i));
173: }
174:
175: }
176: base_request.setParameters(parameters);
177: }
178:
179: IncludeAttributes attr = new IncludeAttributes(old_attr);
180:
181: attr._requestURI = _uri;
182: attr._contextPath = _contextHandler.getContextPath();
183: attr._servletPath = null; // set by ServletHandler
184: attr._pathInfo = _path;
185: attr._query = query;
186:
187: base_request.setAttributes(attr);
188:
189: _contextHandler
190: .handle(_named == null ? _path : _named,
191: (HttpServletRequest) request,
192: (HttpServletResponse) response,
193: Handler.INCLUDE);
194: }
195: } finally {
196: base_request.setAttributes(old_attr);
197: base_request.getConnection().included();
198: base_request.setParameters(old_params);
199: }
200: }
201:
202: /* ------------------------------------------------------------ */
203: /*
204: * @see javax.servlet.RequestDispatcher#forward(javax.servlet.ServletRequest, javax.servlet.ServletResponse)
205: */
206: protected void forward(ServletRequest request,
207: ServletResponse response, int dispatch)
208: throws ServletException, IOException {
209: Request base_request = (request instanceof Request) ? ((Request) request)
210: : HttpConnection.getCurrentConnection().getRequest();
211: response.resetBuffer();
212: request.removeAttribute(__JSP_FILE); // TODO remove when glassfish 1044 is fixed
213:
214: String old_uri = base_request.getRequestURI();
215: String old_context_path = base_request.getContextPath();
216: String old_servlet_path = base_request.getServletPath();
217: String old_path_info = base_request.getPathInfo();
218: String old_query = base_request.getQueryString();
219: Attributes old_attr = base_request.getAttributes();
220: MultiMap old_params = base_request.getParameters();
221: try {
222: if (_named != null)
223: _contextHandler.handle(_named,
224: (HttpServletRequest) request,
225: (HttpServletResponse) response, dispatch);
226: else {
227: String query = _dQuery;
228:
229: if (query != null) {
230: MultiMap parameters = new MultiMap();
231: UrlEncoded.decodeTo(query, parameters, request
232: .getCharacterEncoding());
233:
234: if (old_params != null && old_params.size() > 0) {
235: // Merge parameters.
236: Iterator iter = old_params.entrySet()
237: .iterator();
238: while (iter.hasNext()) {
239: Map.Entry entry = (Map.Entry) iter.next();
240: String name = (String) entry.getKey();
241: Object values = entry.getValue();
242: for (int i = 0; i < LazyList.size(values); i++)
243: parameters.add(name, LazyList.get(
244: values, i));
245: }
246: }
247:
248: if (old_query != null && old_query.length() > 0)
249: query = query + "&" + old_query;
250:
251: base_request.setParameters(parameters);
252: base_request.setQueryString(query);
253: }
254:
255: ForwardAttributes attr = new ForwardAttributes(old_attr);
256:
257: attr._requestURI = old_uri;
258: attr._contextPath = old_context_path;
259: attr._servletPath = old_servlet_path;
260: attr._pathInfo = old_path_info;
261: attr._query = old_query;
262:
263: base_request.setRequestURI(_uri);
264: base_request.setContextPath(_contextHandler
265: .getContextPath());
266: base_request.setAttributes(attr);
267: base_request.setQueryString(query);
268:
269: _contextHandler.handle(_path,
270: (HttpServletRequest) request,
271: (HttpServletResponse) response, dispatch);
272:
273: if (base_request.getConnection().getResponse()
274: .isWriting()) {
275: try {
276: response.getWriter().close();
277: } catch (IllegalStateException e) {
278: response.getOutputStream().close();
279: }
280: } else {
281: try {
282: response.getOutputStream().close();
283: } catch (IllegalStateException e) {
284: response.getWriter().close();
285: }
286: }
287: }
288: } finally {
289: base_request.setRequestURI(old_uri);
290: base_request.setContextPath(old_context_path);
291: base_request.setServletPath(old_servlet_path);
292: base_request.setPathInfo(old_path_info);
293: base_request.setAttributes(old_attr);
294: base_request.setParameters(old_params);
295: base_request.setQueryString(old_query);
296: }
297: }
298:
299: /* ------------------------------------------------------------ */
300: /* ------------------------------------------------------------ */
301: /* ------------------------------------------------------------ */
302: private class ForwardAttributes implements Attributes {
303: Attributes _attr;
304:
305: String _requestURI;
306: String _contextPath;
307: String _servletPath;
308: String _pathInfo;
309: String _query;
310:
311: ForwardAttributes(Attributes attributes) {
312: _attr = attributes;
313: }
314:
315: /* ------------------------------------------------------------ */
316: public Object getAttribute(String key) {
317: if (Dispatcher.this ._named == null) {
318: if (key.equals(__FORWARD_PATH_INFO))
319: return _pathInfo;
320: if (key.equals(__FORWARD_REQUEST_URI))
321: return _requestURI;
322: if (key.equals(__FORWARD_SERVLET_PATH))
323: return _servletPath;
324: if (key.equals(__FORWARD_CONTEXT_PATH))
325: return _contextPath;
326: if (key.equals(__FORWARD_QUERY_STRING))
327: return _query;
328: }
329:
330: if (key.startsWith(__INCLUDE_PREFIX))
331: return null;
332:
333: if (key.equals(__FORWARD_JETTY))
334: return Boolean.TRUE;
335:
336: return _attr.getAttribute(key);
337: }
338:
339: /* ------------------------------------------------------------ */
340: public Enumeration getAttributeNames() {
341: HashSet set = new HashSet();
342: Enumeration e = _attr.getAttributeNames();
343: while (e.hasMoreElements()) {
344: String name = (String) e.nextElement();
345: if (!name.startsWith(__INCLUDE_PREFIX)
346: && !name.startsWith(__FORWARD_PREFIX))
347: set.add(name);
348: }
349:
350: if (_named == null) {
351: if (_pathInfo != null)
352: set.add(__FORWARD_PATH_INFO);
353: else
354: set.remove(__FORWARD_PATH_INFO);
355: set.add(__FORWARD_REQUEST_URI);
356: set.add(__FORWARD_SERVLET_PATH);
357: set.add(__FORWARD_CONTEXT_PATH);
358: if (_query != null)
359: set.add(__FORWARD_QUERY_STRING);
360: else
361: set.remove(__FORWARD_QUERY_STRING);
362: }
363:
364: return Collections.enumeration(set);
365: }
366:
367: /* ------------------------------------------------------------ */
368: public void setAttribute(String key, Object value) {
369: if (_named == null && key.startsWith("javax.servlet.")) {
370: if (key.equals(__FORWARD_PATH_INFO))
371: _pathInfo = (String) value;
372: else if (key.equals(__FORWARD_REQUEST_URI))
373: _requestURI = (String) value;
374: else if (key.equals(__FORWARD_SERVLET_PATH))
375: _servletPath = (String) value;
376: else if (key.equals(__FORWARD_CONTEXT_PATH))
377: _contextPath = (String) value;
378: else if (key.equals(__FORWARD_QUERY_STRING))
379: _query = (String) value;
380:
381: else if (value == null)
382: _attr.removeAttribute(key);
383: else
384: _attr.setAttribute(key, value);
385: } else if (value == null)
386: _attr.removeAttribute(key);
387: else
388: _attr.setAttribute(key, value);
389: }
390:
391: /* ------------------------------------------------------------ */
392: public String toString() {
393: return "FORWARD+" + _attr.toString();
394: }
395:
396: /* ------------------------------------------------------------ */
397: public void clearAttributes() {
398: throw new IllegalStateException();
399: }
400:
401: /* ------------------------------------------------------------ */
402: public void removeAttribute(String name) {
403: setAttribute(name, null);
404: }
405: }
406:
407: private class IncludeAttributes implements Attributes {
408: Attributes _attr;
409:
410: String _requestURI;
411: String _contextPath;
412: String _servletPath;
413: String _pathInfo;
414: String _query;
415:
416: IncludeAttributes(Attributes attributes) {
417: _attr = attributes;
418: }
419:
420: /* ------------------------------------------------------------ */
421: public Object getAttribute(String key) {
422: if (Dispatcher.this ._named == null) {
423: if (key.equals(__INCLUDE_PATH_INFO))
424: return _pathInfo;
425: if (key.equals(__INCLUDE_SERVLET_PATH))
426: return _servletPath;
427: if (key.equals(__INCLUDE_CONTEXT_PATH))
428: return _contextPath;
429: if (key.equals(__INCLUDE_QUERY_STRING))
430: return _query;
431: if (key.equals(__INCLUDE_REQUEST_URI))
432: return _requestURI;
433: } else {
434: if (key.startsWith(__INCLUDE_PREFIX))
435: return null;
436: }
437:
438: if (key.startsWith(__FORWARD_PREFIX))
439: return null;
440:
441: if (key.equals(__INCLUDE_JETTY))
442: return Boolean.TRUE;
443:
444: return _attr.getAttribute(key);
445: }
446:
447: /* ------------------------------------------------------------ */
448: public Enumeration getAttributeNames() {
449: HashSet set = new HashSet();
450: Enumeration e = _attr.getAttributeNames();
451: while (e.hasMoreElements()) {
452: String name = (String) e.nextElement();
453: if (!name.startsWith(__INCLUDE_PREFIX)
454: && !name.startsWith(__FORWARD_PREFIX))
455: set.add(name);
456: }
457:
458: if (_named == null) {
459: if (_pathInfo != null)
460: set.add(__INCLUDE_PATH_INFO);
461: else
462: set.remove(__INCLUDE_PATH_INFO);
463: set.add(__INCLUDE_REQUEST_URI);
464: set.add(__INCLUDE_SERVLET_PATH);
465: set.add(__INCLUDE_CONTEXT_PATH);
466: if (_query != null)
467: set.add(__INCLUDE_QUERY_STRING);
468: else
469: set.remove(__INCLUDE_QUERY_STRING);
470: }
471:
472: return Collections.enumeration(set);
473: }
474:
475: /* ------------------------------------------------------------ */
476: public void setAttribute(String key, Object value) {
477: if (_named == null && key.startsWith("javax.servlet.")) {
478: if (key.equals(__INCLUDE_PATH_INFO))
479: _pathInfo = (String) value;
480: else if (key.equals(__INCLUDE_REQUEST_URI))
481: _requestURI = (String) value;
482: else if (key.equals(__INCLUDE_SERVLET_PATH))
483: _servletPath = (String) value;
484: else if (key.equals(__INCLUDE_CONTEXT_PATH))
485: _contextPath = (String) value;
486: else if (key.equals(__INCLUDE_QUERY_STRING))
487: _query = (String) value;
488: else if (value == null)
489: _attr.removeAttribute(key);
490: else
491: _attr.setAttribute(key, value);
492: } else if (value == null)
493: _attr.removeAttribute(key);
494: else
495: _attr.setAttribute(key, value);
496: }
497:
498: /* ------------------------------------------------------------ */
499: public String toString() {
500: return "INCLUDE+" + _attr.toString();
501: }
502:
503: /* ------------------------------------------------------------ */
504: public void clearAttributes() {
505: throw new IllegalStateException();
506: }
507:
508: /* ------------------------------------------------------------ */
509: public void removeAttribute(String name) {
510: setAttribute(name, null);
511: }
512: }
513: };
|