Quadcap Embeddable Server

com/quadcap/http/servlets/jsp/JspServlet.java

Go to the documentation of this file.
00001 package com.quadcap.http.servlets.jsp; 00002 00003 /* Copyright 1999 - 2003 Quadcap Software. All rights reserved. 00004 * 00005 * This software is distributed under the Quadcap Free Software License. 00006 * This software may be used or modified for any purpose, personal or 00007 * commercial. Open Source redistributions are permitted. Commercial 00008 * redistribution of larger works derived from, or works which bundle 00009 * this software requires a "Commercial Redistribution License"; see 00010 * http://www.quadcap.com/purchase. 00011 * 00012 * Redistributions qualify as "Open Source" under one of the following terms: 00013 * 00014 * Redistributions are made at no charge beyond the reasonable cost of 00015 * materials and delivery. 00016 * 00017 * Redistributions are accompanied by a copy of the Source Code or by an 00018 * irrevocable offer to provide a copy of the Source Code for up to three 00019 * years at the cost of materials and delivery. Such redistributions 00020 * must allow further use, modification, and redistribution of the Source 00021 * Code under substantially the same terms as this license. 00022 * 00023 * Redistributions of source code must retain the copyright notices as they 00024 * appear in each source code file, these license terms, and the 00025 * disclaimer/limitation of liability set forth as paragraph 6 below. 00026 * 00027 * Redistributions in binary form must reproduce this Copyright Notice, 00028 * these license terms, and the disclaimer/limitation of liability set 00029 * forth as paragraph 6 below, in the documentation and/or other materials 00030 * provided with the distribution. 00031 * 00032 * The Software is provided on an "AS IS" basis. No warranty is 00033 * provided that the Software is free of defects, or fit for a 00034 * particular purpose. 00035 * 00036 * Limitation of Liability. Quadcap Software shall not be liable 00037 * for any damages suffered by the Licensee or any third party resulting 00038 * from use of the Software. 00039 */ 00040 00041 import java.io.BufferedOutputStream; 00042 import java.io.BufferedReader; 00043 import java.io.ByteArrayInputStream; 00044 import java.io.DataInputStream; 00045 import java.io.File; 00046 import java.io.FileOutputStream; 00047 import java.io.FileReader; 00048 import java.io.IOException; 00049 import java.io.LineNumberReader; 00050 import java.io.PrintWriter; 00051 import java.io.Reader; 00052 00053 import java.util.Hashtable; 00054 import java.util.Properties; 00055 import java.util.Vector; 00056 00057 import javax.servlet.Servlet; 00058 import javax.servlet.ServletConfig; 00059 import javax.servlet.ServletContext; 00060 import javax.servlet.ServletException; 00061 import javax.servlet.SingleThreadModel; 00062 00063 import javax.servlet.http.HttpServlet; 00064 import javax.servlet.http.HttpServletRequest; 00065 import javax.servlet.http.HttpServletResponse; 00066 00067 import javax.servlet.jsp.HttpJspPage; 00068 00069 import org.xml.sax.DocumentHandler; 00070 import org.xml.sax.EntityResolver; 00071 import org.xml.sax.InputSource; 00072 import org.xml.sax.SAXException; 00073 00074 import com.quadcap.io.HtmlifyWriter; 00075 import com.quadcap.io.NullOutputStream; 00076 00077 import com.quadcap.util.ConfigString; 00078 import com.quadcap.util.Debug; 00079 import com.quadcap.util.Util; 00080 00081 /** 00082 * "The" JSP Servlet. 00083 * 00084 * @author Stan Bailes 00085 */ 00086 public class JspServlet extends HttpServlet { 00087 ClassLoader parentClassLoader; 00088 ServletConfig config; 00089 ServletContext context; 00090 File repository; 00091 Hashtable pages = new Hashtable(); 00092 JspClassLoader classLoader = null; 00093 JavaCompiler javaCompiler = null; 00094 00095 public void init(ServletConfig config) throws ServletException { 00096 new JspFactory(); 00097 super.init(config); 00098 this.config = config; 00099 this.context = config.getServletContext(); 00100 this.repository = (File)context.getAttribute("repository"); 00101 00102 // For windows, the classpath needs to be quoted. So we invent 00103 // 'wq', the 'windows quote' variable. sheesh. 00104 Properties p = new Properties(); 00105 p.putAll(System.getProperties()); 00106 if (File.pathSeparatorChar == ';') { 00107 p.put("wq", "\""); 00108 } else { 00109 p.put("wq", ""); 00110 } 00111 00112 String jc = config.getInitParameter("compiler"); 00113 if (jc == null || jc.trim().length() == 0) { 00114 /*{com.quadcap.util.Config-vars.xml-2000} 00115 * <config-var> 00116 * <config-name>jsp.compiler</config-name> 00117 * <config-dflt>jikes</config-dflt> 00118 * <config-desc>Choices are 'jikes' or 'javac'.</config-desc> 00119 * </config-var> 00120 */ 00121 ConfigString cs = ConfigString.find("jsp.compiler", "jikes"); 00122 if (cs != null) jc = cs.toString(); 00123 } 00124 this.javaCompiler = null; 00125 if (jc.equalsIgnoreCase("dynamic")) { 00126 // jikes if possible, otherwise fallback to javac 00127 if (Util.execCommand("jikes -v", 00128 new NullOutputStream(), 00129 new NullOutputStream()) == -1) { 00130 jc = "javac"; 00131 } else { 00132 jc = "jikes"; 00133 } 00134 } 00135 00136 if (jc.equalsIgnoreCase("javac")) { 00137 this.javaCompiler = new Javac(); 00138 } else { 00139 this.javaCompiler = new JavaCompiler(); 00140 } 00141 this.javaCompiler.init(getServletContext(), 00142 repository, 00143 config.getInitParameter("compile." + jc), 00144 p); 00145 this.parentClassLoader = 00146 (ClassLoader)context.getAttribute("com.quadcap.classLoader"); 00147 if (parentClassLoader == null) { 00148 this.parentClassLoader = this.getClass().getClassLoader(); 00149 } 00150 refreshClassLoader(); 00151 } 00152 00153 void refreshClassLoader() { 00154 this.classLoader = new JspClassLoader(parentClassLoader, repository); 00155 } 00156 00157 protected void service(HttpServletRequest request, 00158 HttpServletResponse response) 00159 throws IOException, ServletException 00160 { 00161 String name = request.getServletPath(); 00162 response.setContentType("text/html"); 00163 response.setHeader("Expires", "0"); 00164 00165 JspPage page = null; 00166 try { 00167 page = getJspPageForName(name, response); 00168 } catch (JspException e) { 00169 if (e.getReportedError()) return; 00170 throw e; 00171 } 00172 if (page == null) { 00173 response.sendError(HttpServletResponse.SC_NOT_FOUND, 00174 "Not found: " + request.getRequestURI()); 00175 return; 00176 } 00177 if (page instanceof SingleThreadModel) { 00178 synchronized (page) { 00179 page._jspService(request, response); 00180 } 00181 } else { 00182 page._jspService(request, response); 00183 } 00184 } 00185 00186 JspPage getJspPageForName(String name, HttpServletResponse response) 00187 throws IOException, ServletException 00188 { 00189 JspObject jsp = (JspObject)pages.get(name); 00190 boolean found = jsp != null; 00191 if (jsp == null) { 00192 if (context.getResource(name) == null) { 00193 return null; 00194 } 00195 synchronized (this) { 00196 jsp = new JspObject(config.getServletContext(), 00197 repository, name); 00198 } 00199 } 00200 JspPage p = jsp.getJspPage(); 00201 if (p == null || jsp.needRecompile()) { 00202 if (p != null) { 00203 unload(p); 00204 jsp.setJspPage(null); 00205 } 00206 loadJspPage(jsp, response); 00207 } 00208 if (!found) pages.put(name, jsp); 00209 return jsp.getJspPage(); 00210 } 00211 00212 void unload(JspPage page) { 00213 page.jspDestroy(); 00214 refreshClassLoader(); 00215 } 00216 00217 static Object compileLock = new Object(); 00218 00219 JspPage loadJspPage(JspObject jsp, HttpServletResponse response) 00220 throws IOException, ServletException, JspException 00221 { 00222 if (Trace.level() > 1) { 00223 Debug.println("loadPage(" + jsp.getFullClassName() + ")"); 00224 } 00225 JspPage page = null; 00226 try { 00227 if (jsp.needRecompile()) { 00228 synchronized (compileLock) { 00229 compilePage(jsp, response); 00230 } 00231 } 00232 Class jspClass = classLoader.loadClass(jsp.getFullClassName()); 00233 page = (JspPage)jspClass.newInstance(); 00234 page.init(getServletConfig()); 00235 page.jspInit(); 00236 jsp.setJspPage(page); 00237 } catch (JspException e) { 00238 throw e; 00239 } catch (Throwable t) { 00240 Debug.print(t); 00241 throw new ServletException(t.toString()); 00242 } 00243 return page; 00244 } 00245 00246 void compilePage(JspObject jsp, HttpServletResponse response) 00247 throws IOException, ServletException, ClassNotFoundException 00248 { 00249 translatePage(jsp); 00250 try { 00251 javaCompiler.compile(jsp.getJavaFile(), jsp.getClassFile()); 00252 } catch (JspException e) { 00253 File javaFile = jsp.getJavaFile(); 00254 FileReader jr = new FileReader(javaFile); 00255 LineNumberReader r = new LineNumberReader(jr); 00256 PrintWriter pw = response.getWriter(); 00257 HtmlifyWriter w = new HtmlifyWriter(pw); 00258 ByteArrayInputStream bis = new ByteArrayInputStream(e.toString().getBytes()); 00259 DataInputStream dis = new DataInputStream(bis); 00260 boolean done = false; 00261 int fl = -1, ll = -1, fc = -1, lc = -1; 00262 int linep = 0; 00263 String line = null; 00264 pw.println("<html><head><title>Compile Error</title>"); 00265 pw.println("<style type=\"text/css\">"); 00266 pw.println(".errMsg {"); 00267 pw.println(" background-color: #202020;"); 00268 pw.println(" color: #ffff00;"); 00269 pw.println(" font-size: bigger;"); 00270 pw.println("}"); 00271 pw.println(".errText {"); 00272 pw.println(" background-color: #80a0c0;"); 00273 pw.println(" color: #000000;"); 00274 pw.println(" font-size: bigger;"); 00275 pw.println("}"); 00276 pw.println("</style>"); 00277 pw.println("</head>"); 00278 pw.println("<body bgcolor=#a0c0e0 text=#000000>"); 00279 pw.print("<h2>Compile Error for "); 00280 pw.print(jsp.getName()); 00281 pw.println("</h2><pre>"); 00282 String errMsg = ""; 00283 00284 while (!done) { 00285 if (fl < 0) { 00286 String errLine = dis.readLine(); 00287 Debug.println("errLine = " + errLine); 00288 if (errLine != null) { 00289 try { 00290 String eline = errLine; 00291 int idx = errLine.indexOf(".java:"); 00292 if (idx > 0) eline = errLine.substring(idx); 00293 Vector v = Util.split(eline, ':'); 00294 for (int i = 0; i < v.size(); i++) { 00295 Debug.println("" + i + ": " + v.elementAt(i)); 00296 } 00297 if (v.size() >= 5) { 00298 fl = Integer.parseInt(v.elementAt(1).toString()); 00299 fc = Integer.parseInt(v.elementAt(2).toString()); 00300 ll = Integer.parseInt(v.elementAt(3).toString()); 00301 lc = Integer.parseInt(v.elementAt(4).toString()); 00302 if (v.size() > 6) { 00303 errMsg = v.elementAt(6).toString(); 00304 } 00305 } 00306 } catch (Exception ce) { 00307 Debug.print(ce); 00308 ll = fl; lc = fc; 00309 errMsg = errLine; 00310 } 00311 } else { 00312 fl = fc = ll = lc = -1; 00313 } 00314 } 00315 while (fl < 0 || r.getLineNumber() < fl) { 00316 line = r.readLine(); 00317 if (r.getLineNumber() == fl) break; 00318 if (line == null) { 00319 done = true; 00320 break; 00321 } 00322 else { 00323 w.println(line); 00324 linep = r.getLineNumber(); 00325 } 00326 } 00327 if (done) break; 00328 if (fl >= 0) { 00329 if (linep < r.getLineNumber()) { 00330 w.print(substring(line, 0, fc-1)); 00331 pw.print("<b><span class=\"errText\">"); 00332 if (ll == r.getLineNumber()) { 00333 w.print(substring(line, fc-1, lc)); 00334 pw.print("</span></b>"); 00335 w.println(substring(line, lc)); 00336 } else { 00337 w.println(substring(line, fc-1)); 00338 while (ll < r.getLineNumber()) { 00339 line = r.readLine(); 00340 if (line == null) { 00341 pw.println("</span></b>"); 00342 done = true; 00343 break; 00344 } 00345 } 00346 if (done) break; 00347 w.print(substring(line, 0, lc)); 00348 pw.print("</span></b>"); 00349 w.println(substring(line, lc)); 00350 } 00351 linep = r.getLineNumber(); 00352 } 00353 fl = fc = ll = lc = -1; 00354 pw.print("<i><span class=\"errMsg\">"); 00355 w.println(errMsg); 00356 pw.println("</span></i>"); 00357 } 00358 } 00359 pw.println("</pre></body></html>"); 00360 e.setReportedError(true); 00361 throw e; 00362 } 00363 } 00364 00365 static String substring(String s, int f) { 00366 int len = s.length(); 00367 if (f < 0) f = 0; 00368 if (f >= len) f = len-1; 00369 return s.substring(f); 00370 } 00371 00372 static String substring(String s, int f, int t) { 00373 int len = s.length(); 00374 if (f < 0) f = 0; 00375 if (f >= len) f = len-1; 00376 if (t < 0) t = 0; 00377 if (t >= len) t = len-1; 00378 return s.substring(f, t); 00379 } 00380 00381 void translatePage(JspObject jsp) throws IOException, ServletException { 00382 File javaFile = jsp.getJavaFile(); 00383 00384 if (javaFile.exists()) javaFile.delete(); 00385 00386 FileOutputStream jos = new FileOutputStream(javaFile); 00387 BufferedOutputStream bos = new BufferedOutputStream(jos); 00388 PrintWriter w = new PrintWriter(bos); 00389 00390 try { 00391 Reader r = jsp.getJspReader(); 00392 00393 try { 00394 compileJsp(jsp, r, w); 00395 } finally { 00396 r.close(); 00397 } 00398 } finally { 00399 w.close(); 00400 } 00401 } 00402 00403 void compileJsp(JspObject jsp, Reader in, PrintWriter w) 00404 throws IOException, ServletException 00405 { 00406 try { 00407 JspParser p = new JspParser(); 00408 JspHandler h = new JspHandler(context, p, w, jsp); 00409 p.setDocumentHandler(h); 00410 p.setJspHandler(h); 00411 p.setEntityResolver(h); 00414 throw new ServletException(e.toString()); 00415 } 00416 } 00417 00418 public void destroy() { 00419 super.destroy(); 00420 } 00421 00422 public String getServletInfo() { 00423 return "Quadcap Jsp Servlet"; 00424 } 00425 }