001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free Software Foundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Scott Ferguson
028: */
029:
030: package com.caucho.server.dispatch;
031:
032: import com.caucho.jsp.Page;
033: import com.caucho.jsp.QServlet;
034: import com.caucho.log.Log;
035: import com.caucho.util.L10N;
036:
037: import javax.servlet.FilterChain;
038: import javax.servlet.ServletContext;
039: import javax.servlet.ServletException;
040: import javax.servlet.ServletRequest;
041: import javax.servlet.ServletResponse;
042: import javax.servlet.SingleThreadModel;
043: import javax.servlet.http.HttpServletRequest;
044: import javax.servlet.http.HttpServletResponse;
045: import java.io.FileNotFoundException;
046: import java.io.IOException;
047: import java.lang.ref.SoftReference;
048: import java.util.logging.Logger;
049:
050: /**
051: * Represents the final servlet in a filter chain.
052: */
053: public class PageFilterChain implements FilterChain {
054: private static final Logger log = Logger
055: .getLogger(PageFilterChain.class.getName());
056: private static final L10N L = new L10N(PageFilterChain.class);
057:
058: public static String SERVLET_NAME = "javax.servlet.error.servlet_name";
059: public static String SERVLET_EXN = "javax.servlet.error.exception";
060:
061: private ServletContext _application;
062: private QServlet _servlet;
063: private String _jspFile;
064: private ServletConfigImpl _config;
065: private ServletContext _servletContext;
066: private SoftReference<Page> _pageRef;
067: private boolean _isSingleThread;
068:
069: /**
070: * Create the filter chain servlet.
071: *
072: * @param servlet the JSP servlet
073: */
074: PageFilterChain(ServletContext application, QServlet servlet) {
075: _application = application;
076: _servlet = servlet;
077: }
078:
079: /**
080: * Create the filter chain servlet.
081: *
082: * @param servlet the JSP servlet
083: */
084: PageFilterChain(ServletContext application, QServlet servlet,
085: String jspFile, ServletConfigImpl config) {
086: _application = application;
087: _servlet = servlet;
088: _jspFile = jspFile;
089: _config = config;
090: }
091:
092: /**
093: * Sets the servlet context.
094: */
095: public void setServletContext(ServletContext servletContext) {
096: _servletContext = servletContext;
097: }
098:
099: /**
100: * Gets the servlet context.
101: */
102: public ServletContext getServletContext() {
103: return _servletContext;
104: }
105:
106: /**
107: * Returns the servlet.
108: */
109: public QServlet getServlet() {
110: return _servlet;
111: }
112:
113: /**
114: * Invokes the final servlet at the end of the chain.
115: *
116: * @param req the servlet request
117: * @param res the servlet response
118: */
119: public void doFilter(ServletRequest request,
120: ServletResponse response) throws ServletException,
121: IOException {
122: HttpServletRequest req = (HttpServletRequest) request;
123: HttpServletResponse res = (HttpServletResponse) response;
124: FileNotFoundException notFound = null;
125:
126: SoftReference<Page> pageRef = _pageRef;
127:
128: Page page;
129:
130: if (pageRef != null)
131: page = pageRef.get();
132: else
133: page = null;
134:
135: if (page == null || page.cauchoIsModified()) {
136: try {
137: _pageRef = null;
138:
139: page = compilePage(page, req, res);
140:
141: if (page != null) {
142: _pageRef = new SoftReference<Page>(page);
143:
144: _isSingleThread = page instanceof SingleThreadModel;
145: }
146: } catch (FileNotFoundException e) {
147: page = null;
148:
149: notFound = e;
150: }
151: }
152:
153: if (page == null) {
154: // jsp/01cg
155: if (notFound == null)
156: return;
157:
158: String errorUri = (String) req
159: .getAttribute("javax.servlet.error.request_uri");
160: String uri = (String) req
161: .getAttribute("javax.servlet.include.request_uri");
162: String forward = (String) req
163: .getAttribute("caucho.forward");
164:
165: // jsp/01ch
166: if (uri != null) {
167: //throw new FileNotFoundException(uri);
168: throw notFound;
169: } else if (forward != null) {
170: //throw new FileNotFoundException(req.getRequestURI());
171: throw notFound;
172: } else if (errorUri != null) {
173: //throw new FileNotFoundException(errorUri);
174: throw notFound;
175: }
176:
177: ((HttpServletResponse) res)
178: .sendError(HttpServletResponse.SC_NOT_FOUND);
179: } else if (req instanceof HttpServletRequest) {
180: try {
181: if (_isSingleThread) {
182: synchronized (page) {
183: page.pageservice(req, res);
184: }
185: } else
186: page.pageservice(req, res);
187: } catch (ServletException e) {
188: request.setAttribute(SERVLET_EXN, e);
189: if (_config != null)
190: request.setAttribute(SERVLET_NAME, _config
191: .getServletName());
192: throw e;
193: } catch (IOException e) {
194: request.setAttribute(SERVLET_EXN, e);
195: if (_config != null)
196: request.setAttribute(SERVLET_NAME, _config
197: .getServletName());
198: throw e;
199: } catch (RuntimeException e) {
200: request.setAttribute(SERVLET_EXN, e);
201: if (_config != null)
202: request.setAttribute(SERVLET_NAME, _config
203: .getServletName());
204: throw e;
205: }
206: }
207: }
208:
209: /**
210: * Compiles the page, returning the new page.
211: */
212: private Page compilePage(Page oldPage, HttpServletRequest req,
213: HttpServletResponse res) throws ServletException,
214: FileNotFoundException {
215: Page newPage = null;
216:
217: if (oldPage != null && !oldPage.startRecompiling()) {
218: return oldPage;
219: }
220:
221: try {
222: if (_jspFile != null) {
223: req.setAttribute("caucho.jsp.jsp-file", _jspFile);
224: req.setAttribute("caucho.jsp.servlet-config", _config);
225: }
226:
227: if (_config != null)
228: newPage = (Page) _config.createServlet(false);
229: else {
230: newPage = _servlet.getPage(req, res);
231:
232: if (newPage != null && !newPage.isInit()) {
233: ServletConfigImpl config = new ServletConfigImpl();
234: config.setServletContext(_application);
235: config.setServletName(req.getServletPath());
236: newPage.init(config);
237: }
238: }
239:
240: // XXX: In theory, should let the requests drain. In practice,
241: // the JSP destroy() method doesn't do anything.
242: if (oldPage != null && !oldPage.isDead())
243: oldPage.destroy();
244:
245: if (newPage != null)
246: newPage._caucho_use();
247:
248: return newPage;
249: } catch (ServletException e) {
250: throw e;
251: } catch (RuntimeException e) {
252: throw e;
253: } catch (FileNotFoundException e) {
254: throw e;
255: } catch (Exception e) {
256: throw new ServletException(e);
257: } finally {
258: if (_jspFile != null) {
259: req.removeAttribute("caucho.jsp.jsp-file");
260: req.removeAttribute("caucho.jsp.servlet-config");
261: }
262: }
263: }
264:
265: public String toString() {
266: if (_config != null)
267: return getClass().getSimpleName() + "[" + _config + "]";
268: else
269: return getClass().getSimpleName() + "[" + _servlet + "]";
270: }
271: }
|