001: /*
002: GNUJSP - a free JSP implementation
003: Copyright (C) 1998-1999, Vincent Partington <vinny@klomp.org>
004:
005: This program is free software; you can redistribute it and/or
006: modify it under the terms of the GNU General Public License
007: as published by the Free Software Foundation; either version 2
008: of the License, or (at your option) any later version.
009:
010: This program is distributed in the hope that it will be useful,
011: but WITHOUT ANY WARRANTY; without even the implied warranty of
012: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
013: GNU General Public License for more details.
014:
015: You should have received a copy of the GNU General Public License
016: along with this program; if not, write to the Free Software
017: Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
018: */
019:
020: package org.gjt.jsp;
021:
022: import java.io.File;
023: import java.io.IOException;
024: import java.io.PrintWriter;
025: import java.lang.reflect.Field;
026: import java.lang.reflect.InvocationTargetException;
027: import java.lang.reflect.Method;
028: import java.util.Enumeration;
029: import java.util.Hashtable;
030: import java.util.StringTokenizer;
031: import java.util.Vector;
032:
033: import javax.servlet.Servlet;
034: import javax.servlet.ServletConfig;
035: import javax.servlet.ServletException;
036: import javax.servlet.http.HttpServlet;
037: import javax.servlet.http.HttpServletRequest;
038: import javax.servlet.http.HttpServletResponse;
039:
040: public class JSPServlet extends HttpServlet {
041: boolean correctlyInitialized = false;
042: File repository;
043: String[] compiler;
044: boolean checkDependencies = true;
045: boolean debug = false;
046: String defaultContentType = "text/html";
047: boolean checkUri = false;
048: String jspExtension = ".jsp";
049: String pageBase = "";
050:
051: JSPClassLoader jspClassLoader;
052: Hashtable jspServlets;
053:
054: public void init(ServletConfig config) throws ServletException {
055: super .init(config);
056:
057: String s;
058: Vector v;
059: StringTokenizer toker;
060:
061: // get repository where generated java and class files are stored
062: s = config.getInitParameter("repository");
063: if (s == null) {
064: throw new ServletException(
065: "mandatory init parameter repository has not been specified");
066: }
067: repository = new File(s);
068: try {
069: repository = new File(repository.getCanonicalPath());
070: } catch (IOException ioexc) {
071: repository = new File(repository.getAbsolutePath());
072: }
073:
074: // get compiler command line
075: s = config.getInitParameter("compiler");
076: if (s == null) {
077: s = "builtin-javac -classpath %classpath%"
078: + File.pathSeparator
079: + "%repository% -d %repository% -deprecation %source%";
080: }
081: v = new Vector();
082: toker = new StringTokenizer(s);
083: while (toker.hasMoreTokens()) {
084: v.addElement(toker.nextToken());
085: }
086: if (v.size() <= 1) {
087: throw new ServletException(
088: "init parameter compiler does not specify the compiler's parameters");
089: }
090: compiler = new String[v.size()];
091: v.copyInto(compiler);
092:
093: // get check dependency settings
094: s = config.getInitParameter("checkdependencies");
095: if (s != null
096: && (s.equalsIgnoreCase("false") || s
097: .equalsIgnoreCase("no"))) {
098: checkDependencies = false;
099: }
100:
101: // get debug setting
102: s = config.getInitParameter("debug");
103: if (s != null
104: && (s.equalsIgnoreCase("true") || s
105: .equalsIgnoreCase("yes"))) {
106: debug = true;
107: }
108:
109: // get default content-type
110: s = config.getInitParameter("defaultcontenttype");
111: if (s != null) {
112: defaultContentType = s;
113: }
114:
115: s = config.getInitParameter("pagebase");
116: if (s != null) {
117: pageBase = s;
118: }
119:
120: jspClassLoader = new JSPClassLoader(repository, config, debug);
121: jspServlets = new Hashtable();
122: correctlyInitialized = true;
123: }
124:
125: protected void service(HttpServletRequest request,
126: HttpServletResponse response) throws IOException,
127: ServletException {
128: int i, j;
129: File jspFile;
130: String s, className;
131: Servlet srv;
132: JSPCompiler jspCompiler;
133:
134: if (!correctlyInitialized) {
135: throw new ServletException(
136: "This servlet has not been initialized correctly");
137: }
138:
139: try {
140: jspFile = new File(request.getRealPath(request
141: .getPathInfo()));
142: try {
143: jspFile = new File(jspFile.getCanonicalPath());
144: } catch (IOException ioexc) {
145: jspFile = new File(jspFile.getAbsolutePath());
146: }
147: className = JSPCompiler.getClassNameForJspFile(jspFile);
148:
149: // try to load jsp servlet from cache or class file
150: srv = (Servlet) jspServlets.get(className);
151: if (srv == null) {
152: srv = loadServlet(className);
153: }
154:
155: // unload servlet if dependencies demand it
156: if (checkDependencies && srv != null) {
157: if (checkServletDependencies(srv.getClass())) {
158: unloadServlet(srv);
159: refreshClassLoader(srv.getClass());
160: srv = null;
161: }
162: }
163:
164: // compile & load jsp servlet if we haven't loaded it yet
165: if (srv == null) {
166: jspCompiler = new JSPCompiler(this , jspFile, className,
167: request);
168: jspCompiler.compile();
169:
170: srv = loadServlet(className);
171: if (srv == null) {
172: throw new JSPException(
173: "Could not load jsp servlet class "
174: + className);
175: }
176: }
177: } catch (JSPException jspexc) {
178: if (debug) {
179: getServletConfig().getServletContext().log(
180: jspexc.getHttpErrorCode()
181: + " JSP compile-time error: "
182: + jspexc.getMessage());
183: }
184: response.setStatus(jspexc.getHttpErrorCode(),
185: "JSP compile-time error");
186: response.setContentType("text/html");
187: PrintWriter out = response.getWriter();
188: out
189: .println("<HTML><HEAD><TITLE>"
190: + jspexc.getHttpErrorCode()
191: + " JSP compile-time error</TITLE></HEAD><BODY>"
192: + "<H2>"
193: + jspexc.getHttpErrorCode()
194: + " JSP compile-time error</H2>"
195: + "The JSP page you requested could not be served because the following error(s) occured:<BR><PRE>");
196: out.println(jspexc.getMessage());
197: out.println("</PRE></BODY></HTML>");
198: out.close();
199: return;
200: }
201:
202: // run jsp servlet
203: srv.service(request, response);
204: }
205:
206: public void destroy() {
207: super .destroy();
208:
209: if (correctlyInitialized) {
210: Enumeration e;
211: Servlet srv;
212:
213: e = jspServlets.elements();
214: while (e.hasMoreElements()) {
215: srv = (Servlet) e.nextElement();
216: unloadServlet(srv);
217: }
218: }
219: }
220:
221: public String getServletInfo() {
222: return "GNUJSP JSPServlet";
223: }
224:
225: private Servlet loadServlet(String className) throws JSPException {
226: Class c;
227: Field fld;
228: Servlet srv;
229:
230: // load servlet class
231: try {
232: c = jspClassLoader.loadClass(className);
233: if (c == null)
234: return null;
235: } catch (ClassNotFoundException cnfexc) {
236: return null;
237: }
238:
239: // check compiler version dependency
240: try {
241: fld = c.getField("__compilerVersionNr");
242: if (fld.getInt(null) != JSPCompiler.COMPILER_VERSION_NR) {
243: refreshClassLoader(c);
244: return null;
245: }
246: } catch (IllegalAccessException fiaexc) {
247: throw new JSPException(
248: "Jsp servlet class "
249: + className
250: + " does not have a public static __compilerVersionNr field");
251: } catch (NoSuchFieldException nsfexc) {
252: throw new JSPException(
253: "Jsp servlet class "
254: + className
255: + " does not have a __compilerVersionNr field of type int");
256: } catch (SecurityException secexc) {
257: throw new JSPException(
258: "Jsp servlet class "
259: + className
260: + " has a security problem with its __compilerVersionNr field");
261: }
262:
263: // check servlet's other dependencies
264: if (checkDependencies && checkServletDependencies(c)) {
265: refreshClassLoader(c);
266: return null;
267: }
268:
269: // instantiate servlet
270: try {
271: srv = (Servlet) c.newInstance();
272: } catch (IllegalAccessException iaexc) {
273: throw new JSPException(
274: "Could not instantiate jsp servlet class "
275: + className
276: + " because of an illegal access exception");
277: } catch (InstantiationException iexc) {
278: throw new JSPException(
279: "Could not instantiate jsp servlet class "
280: + className
281: + " because it is an interface or an abstract class");
282: }
283:
284: // init servlet
285: try {
286: srv.init(getServletConfig());
287: } catch (Exception exc) {
288: }
289:
290: jspServlets.put(className, srv);
291:
292: return srv;
293: }
294:
295: private void unloadServlet(Servlet srv) {
296: try {
297: srv.destroy();
298: } catch (Exception exc) {
299: }
300:
301: jspServlets.remove(srv.getClass().getName());
302: }
303:
304: private boolean checkServletDependencies(Class c)
305: throws JSPException {
306: Method meth;
307:
308: try {
309: // invoke dependency checking method
310: meth = c.getMethod("__checkDependencies", new Class[0]);
311: return ((Boolean) meth.invoke(null, new Object[0]))
312: .booleanValue();
313: } catch (IllegalAccessException iaexc) {
314: throw new JSPException(
315: "Jsp servlet class "
316: + c.getName()
317: + " does not have a public static __checkDependencies() method");
318: } catch (InvocationTargetException itexc) {
319: throw new JSPException(
320: "Jsp servlet class "
321: + c.getName()
322: + "'s __checkDependencies() method threw an exception: "
323: + itexc.getTargetException());
324: } catch (NoSuchMethodException nsfexc) {
325: throw new JSPException(
326: "Jsp servlet class "
327: + c.getName()
328: + " does not have a __checkDependencies() method that returns a boolean");
329: } catch (SecurityException secexc) {
330: throw new JSPException(
331: "Jsp servlet class "
332: + c.getName()
333: + " has a security problem with its __checkDependencies() method");
334: }
335: }
336:
337: private void refreshClassLoader(Class c) {
338: if (c.getClassLoader() == jspClassLoader) {
339: jspClassLoader = new JSPClassLoader(repository,
340: getServletConfig(), debug);
341: }
342: }
343:
344: private static String urlDecode(String val) {
345: StringBuffer buf = new StringBuffer(val.length());
346: char c;
347:
348: for (int i = 0; i < val.length(); i++) {
349: c = val.charAt(i);
350: if (c == '%') {
351: try {
352: buf.append((char) Integer.parseInt(val.substring(
353: i + 1, i + 3), 16));
354: i += 2;
355: continue;
356: } catch (Exception e) {
357: }
358: } else if (c == '+') {
359: buf.append(' ');
360: continue;
361: }
362: buf.append(c);
363: }
364: return buf.toString();
365: }
366: }
|