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.jsp;
031:
032: import com.caucho.log.Log;
033: import com.caucho.server.connection.CauchoRequest;
034: import com.caucho.server.connection.CauchoResponse;
035: import com.caucho.server.connection.RequestAdapter;
036: import com.caucho.server.connection.ResponseAdapter;
037: import com.caucho.server.webapp.WebApp;
038: import com.caucho.util.L10N;
039: import com.caucho.vfs.ClientDisconnectException;
040: import com.caucho.vfs.JarPath;
041: import com.caucho.vfs.Path;
042: import com.caucho.vfs.Vfs;
043:
044: import javax.servlet.*;
045: import javax.servlet.http.HttpServletRequest;
046: import javax.servlet.http.HttpServletResponse;
047: import java.io.FileNotFoundException;
048: import java.io.IOException;
049: import java.util.logging.Level;
050: import java.util.logging.Logger;
051:
052: /**
053: * Base servlet for both JSP and XTP. It's primarily responsible for
054: * returning the proper error messages when things go wrong.
055: *
056: * <p>The manager create the compiled JSP and XTP pages. The manager
057: * returns a Page object which is actually executed.
058: *
059: * @see JspManager
060: * @see XtpManager
061: * @see Page
062: */
063: abstract public class QServlet implements Servlet {
064: static final String COPYRIGHT = "Copyright(c) 1998-2008 Caucho Technology. All rights reserved.";
065:
066: private static final Logger log = Log.open(QServlet.class);
067: private static final L10N L = new L10N(QServlet.class);
068:
069: protected WebApp _webApp;
070: private PageManager _manager;
071:
072: private ServletConfig _config;
073:
074: /**
075: * Initialize the servlet. If necessary, convert the ServletContext
076: * to a CauchoWebApp. Also, read the configuration Registry
077: * it it hasn't been read yet.
078: */
079: public void init(ServletConfig config) throws ServletException {
080: ServletContext cxt = config.getServletContext();
081: _webApp = (WebApp) cxt;
082:
083: _config = config;
084:
085: log.finer(config.getServletName() + " init");
086: }
087:
088: /**
089: * JspServlet and XtpServlet will set the PageManager with this method.
090: */
091: protected void setManager(PageManager manager) {
092: _manager = manager;
093: }
094:
095: protected PageManager getManager() {
096: return _manager;
097: }
098:
099: /**
100: * Override the Servlet method to return the generated application.
101: */
102: public ServletContext getServletContext() {
103: return _webApp;
104: }
105:
106: /**
107: * Returns the config.
108: */
109: public ServletConfig getServletConfig() {
110: return _config;
111: }
112:
113: /**
114: * Returns the init parameter
115: */
116: public String getInitParameter(String name) {
117: return _config.getInitParameter(name);
118: }
119:
120: /**
121: * The service method gets the JSP/XTP page and executes it. The
122: * request and response objects are converted to Caucho objects so
123: * other servlet runners will produce the same results as the Caucho
124: * servlet runner.
125: */
126: public void service(ServletRequest req, ServletResponse res)
127: throws ServletException, IOException {
128: CauchoRequest request;
129: CauchoResponse response;
130: ResponseAdapter resAdapt = null;
131:
132: if (req instanceof CauchoRequest)
133: request = (CauchoRequest) req;
134: else
135: request = RequestAdapter.create((HttpServletRequest) req,
136: _webApp);
137:
138: if (res instanceof CauchoResponse)
139: response = (CauchoResponse) res;
140: else {
141: resAdapt = ResponseAdapter
142: .create((HttpServletResponse) res);
143: response = resAdapt;
144: }
145:
146: Page page = null;
147:
148: try {
149: page = getPage(request, response);
150:
151: if (page == null) {
152: response.sendError(HttpServletResponse.SC_NOT_FOUND);
153: return;
154: }
155:
156: page.service(request, response);
157: } catch (JspParseException e) {
158: if (e.getErrorPage() != null)
159: forwardErrorPage(request, response, e, e.getErrorPage());
160: else
161: throw new ServletException(e);
162: } catch (ClientDisconnectException e) {
163: throw e;
164: } catch (Throwable e) {
165: if (page != null
166: && page.getErrorPage() != null
167: && forwardErrorPage(request, response, e, page
168: .getErrorPage())) {
169: } else if (e instanceof IOException) {
170: log.log(Level.FINE, e.toString(), e);
171: throw (IOException) e;
172: } else if (e instanceof ServletException) {
173: log.log(Level.FINE, e.toString(), e);
174: throw (ServletException) e;
175: } else {
176: log.log(Level.FINE, e.toString(), e);
177: throw new ServletException(e);
178: }
179: }
180:
181: if (resAdapt != null) {
182: resAdapt.close();
183: ResponseAdapter.free(resAdapt);
184: }
185: }
186:
187: /**
188: * Creates and returns a new page.
189: *
190: * @param request the servlet request
191: * @param response the servlet response
192: *
193: * @return the compiled page
194: */
195: public Page getPage(HttpServletRequest request,
196: HttpServletResponse response) throws Exception {
197: try {
198: Page page = getSubPage(request, response);
199:
200: return page;
201: } catch (JspParseException e) {
202: if (e.getErrorPage() != null) {
203: if (e.getCause() != null
204: && !(e instanceof JspLineParseException))
205: forwardErrorPage(request, response, e.getCause(), e
206: .getErrorPage());
207: else
208: forwardErrorPage(request, response, e, e
209: .getErrorPage());
210:
211: return null;
212: } else
213: throw e;
214: }
215: }
216:
217: /**
218: * Given a request and response, returns the compiled Page. For example,
219: * JspManager will return the JspPage and XtpManager will
220: * return the XtpPage.
221: *
222: * @param req servlet request for generating the page.
223: * @param res servlet response to any needed error messages.
224: */
225: private Page getSubPage(HttpServletRequest req,
226: HttpServletResponse res) throws Exception {
227: CauchoRequest cauchoRequest = null;
228:
229: initGetPage();
230:
231: /*
232: if (! _webApp.isActive())
233: throw new UnavailableException("JSP compilation unavailable during restart", 10);
234: */
235:
236: if (req instanceof CauchoRequest)
237: cauchoRequest = (CauchoRequest) req;
238:
239: String servletPath;
240:
241: if (cauchoRequest != null)
242: servletPath = cauchoRequest.getPageServletPath();
243: else
244: servletPath = RequestAdapter.getPageServletPath(req);
245:
246: if (servletPath == null)
247: servletPath = "/";
248:
249: String uri;
250: String pageURI;
251:
252: if (cauchoRequest != null)
253: uri = cauchoRequest.getPageURI();
254: else
255: uri = RequestAdapter.getPageURI(req);
256:
257: Path appDir = _webApp.getAppDir();
258:
259: String realPath;
260: Path subcontext;
261:
262: Page page;
263: ServletConfig config = null;
264:
265: String jspPath = (String) req
266: .getAttribute("caucho.jsp.jsp-file");
267: if (jspPath != null) {
268: req.removeAttribute("caucho.jsp.jsp-file");
269:
270: subcontext = getPagePath(jspPath);
271:
272: return _manager.getPage(uri, jspPath, subcontext, config);
273: }
274:
275: String pathInfo;
276:
277: if (cauchoRequest != null)
278: pathInfo = cauchoRequest.getPagePathInfo();
279: else
280: pathInfo = RequestAdapter.getPagePathInfo(req);
281:
282: subcontext = getPagePath(servletPath);
283: if (subcontext != null)
284: return _manager.getPage(servletPath, subcontext);
285:
286: if (pathInfo == null) {
287: realPath = _webApp.getRealPath(servletPath);
288: subcontext = appDir.lookupNative(realPath);
289:
290: return _manager.getPage(servletPath, subcontext);
291: }
292:
293: subcontext = getPagePath(servletPath + pathInfo);
294: if (subcontext != null)
295: return _manager.getPage(servletPath + pathInfo, subcontext);
296:
297: // If servlet path exists, can't use pathInfo to lookup servlet,
298: // because /jsp/WEB-INF would be a security hole
299: if (servletPath != null && !servletPath.equals("")) {
300: // server/0035
301: throw new FileNotFoundException(L.l(
302: "{0} was not found on this server.", uri));
303: // return null;
304: }
305:
306: subcontext = getPagePath(pathInfo);
307: if (subcontext != null)
308: return _manager.getPage(pathInfo, subcontext);
309:
310: subcontext = getPagePath(uri);
311: if (subcontext == null)
312: throw new FileNotFoundException(L.l(
313: "{0} was not found on this server.", uri));
314:
315: return _manager.getPage(uri, subcontext);
316: }
317:
318: private void initGetPage() {
319: // marks the listener array as used
320: _webApp.getJspApplicationContext().getELListenerArray();
321: }
322:
323: public Page getPage(String uri, String pageURI, ServletConfig config)
324: throws Exception {
325: Path path = getPagePath(pageURI);
326:
327: if (path == null)
328: return null;
329:
330: return _manager.getPage(uri, pageURI, path, config);
331: }
332:
333: /**
334: * Returns the path to be used as the servlet name.
335: */
336: private Path getPagePath(String pathName) {
337: Path appDir = _webApp.getAppDir();
338: String realPath = _webApp.getRealPath(pathName);
339: Path path = appDir.lookupNative(realPath);
340:
341: if (path.isFile() && path.canRead())
342: return path;
343:
344: java.net.URL url;
345: ClassLoader loader = _webApp.getClassLoader();
346: if (loader != null) {
347: url = _webApp.getClassLoader().getResource(pathName);
348:
349: String name = url != null ? url.toString() : null;
350:
351: path = null;
352: if (url != null
353: && (name.endsWith(".jar") || name.endsWith(".zip")))
354: path = JarPath.create(Vfs.lookup(url.toString()))
355: .lookup(pathName);
356: else if (url != null)
357: path = Vfs.lookup(url.toString());
358:
359: if (path != null && path.isFile() && path.canRead())
360: return path;
361: }
362:
363: url = ClassLoader.getSystemResource(pathName);
364: String name = url != null ? url.toString() : null;
365:
366: path = null;
367: if (url != null
368: && (name.endsWith(".jar") || name.endsWith(".zip")))
369: path = JarPath.create(Vfs.lookup(url.toString())).lookup(
370: pathName);
371: else if (url != null)
372: path = Vfs.lookup(url.toString());
373:
374: if (path != null && path.isFile() && path.canRead())
375: return path;
376: else
377: return null;
378: }
379:
380: /**
381: * Remove the page from any cache.
382: */
383: public void killPage(HttpServletRequest request,
384: HttpServletResponse response, Page page) {
385: _manager.killPage(request, response, page);
386: }
387:
388: /**
389: * Forwards an error to the proper error page.
390: *
391: * @param req the servlet request
392: * @param res the servlet response
393: * @param e the exception
394: * @param errorPage the error page
395: */
396: private boolean forwardErrorPage(HttpServletRequest req,
397: HttpServletResponse res, Throwable e, String errorPage)
398: throws ServletException, IOException {
399: req.setAttribute("javax.servlet.jsp.jspException", e);
400: req.setAttribute("javax.servlet.error.exception_type", e);
401: req.setAttribute("javax.servlet.error.request_uri", req
402: .getRequestURI());
403:
404: if (res instanceof CauchoResponse) {
405: CauchoResponse cauchoResponse = (CauchoResponse) res;
406: cauchoResponse.killCache();
407: cauchoResponse.setNoCache(true);
408: }
409:
410: RequestDispatcher rd = req.getRequestDispatcher(errorPage);
411:
412: if (rd == null)
413: return false;
414:
415: rd.forward(req, res);
416:
417: return true;
418: }
419:
420: public void destroy() {
421: _manager.destroy();
422:
423: log.finer(_config.getServletName() + " destroy");
424: }
425: }
|