001: package com.quadcap.http.servlets.jsp;
002:
003: /* Copyright 1999 - 2003 Quadcap Software. All rights reserved.
004: *
005: * This software is distributed under the Quadcap Free Software License.
006: * This software may be used or modified for any purpose, personal or
007: * commercial. Open Source redistributions are permitted. Commercial
008: * redistribution of larger works derived from, or works which bundle
009: * this software requires a "Commercial Redistribution License"; see
010: * http://www.quadcap.com/purchase.
011: *
012: * Redistributions qualify as "Open Source" under one of the following terms:
013: *
014: * Redistributions are made at no charge beyond the reasonable cost of
015: * materials and delivery.
016: *
017: * Redistributions are accompanied by a copy of the Source Code or by an
018: * irrevocable offer to provide a copy of the Source Code for up to three
019: * years at the cost of materials and delivery. Such redistributions
020: * must allow further use, modification, and redistribution of the Source
021: * Code under substantially the same terms as this license.
022: *
023: * Redistributions of source code must retain the copyright notices as they
024: * appear in each source code file, these license terms, and the
025: * disclaimer/limitation of liability set forth as paragraph 6 below.
026: *
027: * Redistributions in binary form must reproduce this Copyright Notice,
028: * these license terms, and the disclaimer/limitation of liability set
029: * forth as paragraph 6 below, in the documentation and/or other materials
030: * provided with the distribution.
031: *
032: * The Software is provided on an "AS IS" basis. No warranty is
033: * provided that the Software is free of defects, or fit for a
034: * particular purpose.
035: *
036: * Limitation of Liability. Quadcap Software shall not be liable
037: * for any damages suffered by the Licensee or any third party resulting
038: * from use of the Software.
039: */
040:
041: import java.io.BufferedOutputStream;
042: import java.io.BufferedReader;
043: import java.io.ByteArrayInputStream;
044: import java.io.DataInputStream;
045: import java.io.File;
046: import java.io.FileOutputStream;
047: import java.io.FileReader;
048: import java.io.IOException;
049: import java.io.LineNumberReader;
050: import java.io.PrintWriter;
051: import java.io.Reader;
052:
053: import java.util.Hashtable;
054: import java.util.Properties;
055: import java.util.Vector;
056:
057: import javax.servlet.Servlet;
058: import javax.servlet.ServletConfig;
059: import javax.servlet.ServletContext;
060: import javax.servlet.ServletException;
061: import javax.servlet.SingleThreadModel;
062:
063: import javax.servlet.http.HttpServlet;
064: import javax.servlet.http.HttpServletRequest;
065: import javax.servlet.http.HttpServletResponse;
066:
067: import javax.servlet.jsp.HttpJspPage;
068:
069: import org.xml.sax.DocumentHandler;
070: import org.xml.sax.EntityResolver;
071: import org.xml.sax.InputSource;
072: import org.xml.sax.SAXException;
073:
074: import com.quadcap.io.HtmlifyWriter;
075: import com.quadcap.io.NullOutputStream;
076:
077: import com.quadcap.util.ConfigString;
078: import com.quadcap.util.Debug;
079: import com.quadcap.util.Util;
080:
081: /**
082: * "The" JSP Servlet.
083: *
084: * @author Stan Bailes
085: */
086: public class JspServlet extends HttpServlet {
087: ClassLoader parentClassLoader;
088: ServletConfig config;
089: ServletContext context;
090: File repository;
091: Hashtable pages = new Hashtable();
092: JspClassLoader classLoader = null;
093: JavaCompiler javaCompiler = null;
094:
095: public void init(ServletConfig config) throws ServletException {
096: new JspFactory();
097: super .init(config);
098: this .config = config;
099: this .context = config.getServletContext();
100: this .repository = (File) context.getAttribute("repository");
101:
102: // For windows, the classpath needs to be quoted. So we invent
103: // 'wq', the 'windows quote' variable. sheesh.
104: Properties p = new Properties();
105: p.putAll(System.getProperties());
106: if (File.pathSeparatorChar == ';') {
107: p.put("wq", "\"");
108: } else {
109: p.put("wq", "");
110: }
111:
112: String jc = config.getInitParameter("compiler");
113: if (jc == null || jc.trim().length() == 0) {
114: /*{com.quadcap.util.Config-vars.xml-2000}
115: * <config-var>
116: * <config-name>jsp.compiler</config-name>
117: * <config-dflt>jikes</config-dflt>
118: * <config-desc>Choices are 'jikes' or 'javac'.</config-desc>
119: * </config-var>
120: */
121: ConfigString cs = ConfigString
122: .find("jsp.compiler", "jikes");
123: if (cs != null)
124: jc = cs.toString();
125: }
126: this .javaCompiler = null;
127: if (jc.equalsIgnoreCase("dynamic")) {
128: // jikes if possible, otherwise fallback to javac
129: if (Util.execCommand("jikes -v", new NullOutputStream(),
130: new NullOutputStream()) == -1) {
131: jc = "javac";
132: } else {
133: jc = "jikes";
134: }
135: }
136:
137: if (jc.equalsIgnoreCase("javac")) {
138: this .javaCompiler = new Javac();
139: } else {
140: this .javaCompiler = new JavaCompiler();
141: }
142: this .javaCompiler.init(getServletContext(), repository, config
143: .getInitParameter("compile." + jc), p);
144: this .parentClassLoader = (ClassLoader) context
145: .getAttribute("com.quadcap.classLoader");
146: if (parentClassLoader == null) {
147: this .parentClassLoader = this .getClass().getClassLoader();
148: }
149: refreshClassLoader();
150: }
151:
152: void refreshClassLoader() {
153: this .classLoader = new JspClassLoader(parentClassLoader,
154: repository);
155: }
156:
157: protected void service(HttpServletRequest request,
158: HttpServletResponse response) throws IOException,
159: ServletException {
160: String name = request.getServletPath();
161: response.setContentType("text/html");
162: response.setHeader("Expires", "0");
163:
164: JspPage page = null;
165: try {
166: page = getJspPageForName(name, response);
167: } catch (JspException e) {
168: if (e.getReportedError())
169: return;
170: throw e;
171: }
172: if (page == null) {
173: response.sendError(HttpServletResponse.SC_NOT_FOUND,
174: "Not found: " + request.getRequestURI());
175: return;
176: }
177: if (page instanceof SingleThreadModel) {
178: synchronized (page) {
179: page._jspService(request, response);
180: }
181: } else {
182: page._jspService(request, response);
183: }
184: }
185:
186: JspPage getJspPageForName(String name, HttpServletResponse response)
187: throws IOException, ServletException {
188: JspObject jsp = (JspObject) pages.get(name);
189: boolean found = jsp != null;
190: if (jsp == null) {
191: if (context.getResource(name) == null) {
192: return null;
193: }
194: synchronized (this ) {
195: jsp = new JspObject(config.getServletContext(),
196: repository, name);
197: }
198: }
199: JspPage p = jsp.getJspPage();
200: if (p == null || jsp.needRecompile()) {
201: if (p != null) {
202: unload(p);
203: jsp.setJspPage(null);
204: }
205: loadJspPage(jsp, response);
206: }
207: if (!found)
208: pages.put(name, jsp);
209: return jsp.getJspPage();
210: }
211:
212: void unload(JspPage page) {
213: page.jspDestroy();
214: refreshClassLoader();
215: }
216:
217: static Object compileLock = new Object();
218:
219: JspPage loadJspPage(JspObject jsp, HttpServletResponse response)
220: throws IOException, ServletException, JspException {
221: if (Trace.level() > 1) {
222: Debug.println("loadPage(" + jsp.getFullClassName() + ")");
223: }
224: JspPage page = null;
225: try {
226: if (jsp.needRecompile()) {
227: synchronized (compileLock) {
228: compilePage(jsp, response);
229: }
230: }
231: Class jspClass = classLoader.loadClass(jsp
232: .getFullClassName());
233: page = (JspPage) jspClass.newInstance();
234: page.init(getServletConfig());
235: page.jspInit();
236: jsp.setJspPage(page);
237: } catch (JspException e) {
238: throw e;
239: } catch (Throwable t) {
240: Debug.print(t);
241: throw new ServletException(t.toString());
242: }
243: return page;
244: }
245:
246: void compilePage(JspObject jsp, HttpServletResponse response)
247: throws IOException, ServletException,
248: ClassNotFoundException {
249: translatePage(jsp);
250: try {
251: javaCompiler.compile(jsp.getJavaFile(), jsp.getClassFile());
252: } catch (JspException e) {
253: File javaFile = jsp.getJavaFile();
254: FileReader jr = new FileReader(javaFile);
255: LineNumberReader r = new LineNumberReader(jr);
256: PrintWriter pw = response.getWriter();
257: HtmlifyWriter w = new HtmlifyWriter(pw);
258: ByteArrayInputStream bis = new ByteArrayInputStream(e
259: .toString().getBytes());
260: DataInputStream dis = new DataInputStream(bis);
261: boolean done = false;
262: int fl = -1, ll = -1, fc = -1, lc = -1;
263: int linep = 0;
264: String line = null;
265: pw.println("<html><head><title>Compile Error</title>");
266: pw.println("<style type=\"text/css\">");
267: pw.println(".errMsg {");
268: pw.println(" background-color: #202020;");
269: pw.println(" color: #ffff00;");
270: pw.println(" font-size: bigger;");
271: pw.println("}");
272: pw.println(".errText {");
273: pw.println(" background-color: #80a0c0;");
274: pw.println(" color: #000000;");
275: pw.println(" font-size: bigger;");
276: pw.println("}");
277: pw.println("</style>");
278: pw.println("</head>");
279: pw.println("<body bgcolor=#a0c0e0 text=#000000>");
280: pw.print("<h2>Compile Error for ");
281: pw.print(jsp.getName());
282: pw.println("</h2><pre>");
283: String errMsg = "";
284:
285: while (!done) {
286: if (fl < 0) {
287: String errLine = dis.readLine();
288: Debug.println("errLine = " + errLine);
289: if (errLine != null) {
290: try {
291: String eline = errLine;
292: int idx = errLine.indexOf(".java:");
293: if (idx > 0)
294: eline = errLine.substring(idx);
295: Vector v = Util.split(eline, ':');
296: for (int i = 0; i < v.size(); i++) {
297: Debug.println("" + i + ": "
298: + v.elementAt(i));
299: }
300: if (v.size() >= 5) {
301: fl = Integer.parseInt(v.elementAt(1)
302: .toString());
303: fc = Integer.parseInt(v.elementAt(2)
304: .toString());
305: ll = Integer.parseInt(v.elementAt(3)
306: .toString());
307: lc = Integer.parseInt(v.elementAt(4)
308: .toString());
309: if (v.size() > 6) {
310: errMsg = v.elementAt(6).toString();
311: }
312: }
313: } catch (Exception ce) {
314: Debug.print(ce);
315: ll = fl;
316: lc = fc;
317: errMsg = errLine;
318: }
319: } else {
320: fl = fc = ll = lc = -1;
321: }
322: }
323: while (fl < 0 || r.getLineNumber() < fl) {
324: line = r.readLine();
325: if (r.getLineNumber() == fl)
326: break;
327: if (line == null) {
328: done = true;
329: break;
330: } else {
331: w.println(line);
332: linep = r.getLineNumber();
333: }
334: }
335: if (done)
336: break;
337: if (fl >= 0) {
338: if (linep < r.getLineNumber()) {
339: w.print(substring(line, 0, fc - 1));
340: pw.print("<b><span class=\"errText\">");
341: if (ll == r.getLineNumber()) {
342: w.print(substring(line, fc - 1, lc));
343: pw.print("</span></b>");
344: w.println(substring(line, lc));
345: } else {
346: w.println(substring(line, fc - 1));
347: while (ll < r.getLineNumber()) {
348: line = r.readLine();
349: if (line == null) {
350: pw.println("</span></b>");
351: done = true;
352: break;
353: }
354: }
355: if (done)
356: break;
357: w.print(substring(line, 0, lc));
358: pw.print("</span></b>");
359: w.println(substring(line, lc));
360: }
361: linep = r.getLineNumber();
362: }
363: fl = fc = ll = lc = -1;
364: pw.print("<i><span class=\"errMsg\">");
365: w.println(errMsg);
366: pw.println("</span></i>");
367: }
368: }
369: pw.println("</pre></body></html>");
370: e.setReportedError(true);
371: throw e;
372: }
373: }
374:
375: static String substring(String s, int f) {
376: int len = s.length();
377: if (f < 0)
378: f = 0;
379: if (f >= len)
380: f = len - 1;
381: return s.substring(f);
382: }
383:
384: static String substring(String s, int f, int t) {
385: int len = s.length();
386: if (f < 0)
387: f = 0;
388: if (f >= len)
389: f = len - 1;
390: if (t < 0)
391: t = 0;
392: if (t >= len)
393: t = len - 1;
394: return s.substring(f, t);
395: }
396:
397: void translatePage(JspObject jsp) throws IOException,
398: ServletException {
399: File javaFile = jsp.getJavaFile();
400:
401: if (javaFile.exists())
402: javaFile.delete();
403:
404: FileOutputStream jos = new FileOutputStream(javaFile);
405: BufferedOutputStream bos = new BufferedOutputStream(jos);
406: PrintWriter w = new PrintWriter(bos);
407:
408: try {
409: Reader r = jsp.getJspReader();
410:
411: try {
412: compileJsp(jsp, r, w);
413: } finally {
414: r.close();
415: }
416: } finally {
417: w.close();
418: }
419: }
420:
421: void compileJsp(JspObject jsp, Reader in, PrintWriter w)
422: throws IOException, ServletException {
423: try {
424: JspParser p = new JspParser();
425: JspHandler h = new JspHandler(context, p, w, jsp);
426: p.setDocumentHandler(h);
427: p.setJspHandler(h);
428: p.setEntityResolver(h);
429: p.parse(new InputSource(in));
430: } catch (SAXException e) {
431: throw new ServletException(e.toString());
432: }
433: }
434:
435: public void destroy() {
436: super .destroy();
437: }
438:
439: public String getServletInfo() {
440: return "Quadcap Jsp Servlet";
441: }
442: }
|