001: // AutoReloadServletLoader.java
002: // $Id: AutoReloadServletLoader.java,v 1.9 2001/05/14 14:06:46 ylafon Exp $
003: // (c) COPYRIGHT MIT and INRIA, 1998.
004: // Please first read the full copyright statement in file COPYRIGHT.html
005:
006: package org.w3c.jigsaw.servlet;
007:
008: import java.io.BufferedInputStream;
009: import java.io.ByteArrayOutputStream;
010: import java.io.File;
011: import java.io.FileInputStream;
012: import java.io.FilterInputStream;
013: import java.io.IOException;
014: import java.io.InputStream;
015: import java.io.PrintStream;
016:
017: import java.net.MalformedURLException;
018: import java.net.URL;
019: import java.net.URLConnection;
020:
021: import java.util.Hashtable;
022:
023: class ServletClassEntry {
024:
025: long classStamp = 0;
026: Class servletClass = null;
027: File classFile = null;
028: boolean systemClass = false;
029:
030: public boolean isModified() {
031: if (!systemClass)
032: return (classFile.lastModified() > classStamp);
033: return false;
034: }
035:
036: public void update() {
037: if (!systemClass)
038: classStamp = classFile.lastModified();
039: }
040:
041: public ServletClassEntry(Class servletClass) {
042: this .servletClass = servletClass;
043: this .systemClass = true;
044: }
045:
046: public ServletClassEntry(File classFile, Class servletClass) {
047: this .classFile = classFile;
048: this .servletClass = servletClass;
049: if (classFile != null)
050: this .classStamp = classFile.lastModified();
051: this .systemClass = false;
052: }
053:
054: }
055:
056: /**
057: * @version $Revision: 1.9 $
058: * @author Benoît Mahé (bmahe@w3.org)
059: */
060: public class AutoReloadServletLoader extends ClassLoader {
061: private static final boolean debug = false;
062: private Hashtable classes = null;
063: private int CLASSES_DEFAULT_SIZE = 13;
064:
065: JigsawServletContext context = null;
066:
067: private void trace(String msg) {
068: trace(msg, true);
069: }
070:
071: private void trace(String msg, boolean display) {
072: if (display)
073: System.out.println("[" + context.getServletDirectory()
074: + "]: " + msg);
075: }
076:
077: private String removeSpace(String string) {
078: int start = -1;
079: int end = string.length();
080: boolean spaces = false;
081: while (string.charAt(++start) == ' ') {
082: spaces = true;
083: }
084: ;
085: while (string.charAt(--end) == ' ') {
086: spaces = true;
087: }
088: ;
089: if (spaces)
090: return string.substring(start, ++end);
091: else
092: return new String(string);
093: }
094:
095: private String packaged(String name) {
096: String cname = removeSpace(name);
097: try {
098: if (cname.endsWith(".class")) {
099: int idx = cname.lastIndexOf('.');
100: if (idx != -1)
101: cname = cname.substring(0, idx);
102: }
103: return cname.replace('.', '/') + ".class";
104: } catch (Exception ex) {
105: return name;
106: }
107: }
108:
109: private String noext(String name) {
110: int idx = name.lastIndexOf(".class");
111: if ((idx != -1)
112: && ((idx + 6 == name.length()) || (Character
113: .isWhitespace(name.charAt(idx + 6))))) {
114: return name.substring(0, idx);
115: }
116: return name;
117: }
118:
119: protected boolean classChanged(String name) {
120: ServletClassEntry entry = (ServletClassEntry) classes
121: .get(noext(name));
122: if (entry != null) {
123: if (debug) {
124: System.out.println("entry : " + name);
125: if (!entry.systemClass) {
126: System.out.println("file : "
127: + entry.classFile.getAbsolutePath());
128: System.out
129: .println("Stamp : " + entry.classStamp);
130: }
131: System.out.println("System : " + entry.systemClass);
132: System.out.println("modified : " + entry.isModified());
133: }
134: return entry.isModified();
135: }
136: return false; //true
137: }
138:
139: /**
140: * Get a cached class.
141: * @return a Class instance
142: * @exception ClassNotFoundException if the Class can't be found
143: */
144: protected final Class getCachedClass(String name, boolean resolve)
145: throws ClassNotFoundException {
146: ServletClassEntry entry = (ServletClassEntry) classes
147: .get(noext(name));
148: if (entry != null) {
149: if (!entry.isModified()) {
150: trace(name + ": not modified", debug);
151: return entry.servletClass;
152: } else if (!entry.systemClass) {
153: entry.servletClass = loadClassFile(entry.classFile);
154: if (resolve)
155: resolveClass(entry.servletClass);
156: entry.update();
157: trace(name + ": reloaded", debug);
158: return entry.servletClass;
159: }
160: }
161: return null;
162: }
163:
164: protected void checkPackageAccess(String name) {
165: SecurityManager s = System.getSecurityManager();
166: if (s != null) {
167: int i = name.lastIndexOf('.');
168: if (i >= 0)
169: s.checkPackageAccess(name.substring(0, i));
170: }
171: }
172:
173: /**
174: * Given the class name, return its File name.
175: * @param name The class to be loaded.
176: * @return The File for the class.
177: */
178: protected File locateClass(String name) {
179: File classfile = null;
180: File base = context.getServletDirectory();
181: String cname = null;
182:
183: cname = packaged(name);
184: classfile = new File(base, cname);
185: if (classfile != null)
186: if (classfile.exists())
187: return classfile;
188:
189: return null;
190: }
191:
192: /**
193: * Load a Class from its class file..
194: * @return a Class instance
195: * @exception ClassNotFoundException if the Class can't be found
196: */
197: protected Class loadClassFile(File file)
198: throws ClassNotFoundException {
199: byte data[] = null;
200: if (file == null)
201: throw new ClassNotFoundException("invalid servlet base");
202: trace("located at " + file, debug);
203: try {
204: BufferedInputStream in = new BufferedInputStream(
205: new FileInputStream(file));
206: ByteArrayOutputStream out = new ByteArrayOutputStream(512);
207: byte buf[] = new byte[512];
208: for (int got = 0; (got = in.read(buf)) > 0;)
209: out.write(buf, 0, got);
210: data = out.toByteArray();
211: in.close();
212: } catch (Exception ex) {
213: if (debug)
214: ex.printStackTrace();
215: throw new ClassNotFoundException(file.getAbsolutePath());
216: }
217: // Define the class:
218: return defineClass(null, data, 0, data.length);
219: }
220:
221: /**
222: * Get a new class.
223: * @return a Class instance
224: * @exception ClassNotFoundException if the Class can't be found
225: */
226: protected final Class getNewClass(File classfile, String name,
227: boolean resolve) throws ClassNotFoundException {
228: Class c = null;
229: c = loadClassFile(classfile);
230: if (resolve)
231: resolveClass(c);
232: classes.put(noext(name), new ServletClassEntry(classfile, c));
233: trace(name + ": loading new class done.", debug);
234: return c;
235: }
236:
237: /**
238: * Load a class.
239: * @return a Class instance
240: * @exception ClassNotFoundException if the Class can't be found
241: */
242: protected Class loadClass(String name, boolean resolve)
243: throws ClassNotFoundException {
244: Class c = null;
245: trace(name + ": loading class", debug);
246: // Look for a cached class first:
247: c = getCachedClass(name, resolve);
248: if (c != null) {
249: return c;
250: }
251:
252: synchronized (this ) {
253: c = getCachedClass(name, resolve);
254: if (c != null)
255: return c;
256:
257: checkPackageAccess(name);
258:
259: File file = locateClass(name);
260:
261: if (file == null) {
262: // Then look for a system class:
263: try {
264: String noext = noext(name);
265: if ((c = findSystemClass(noext)) != null) {
266: trace(name + ": system class", debug);
267: classes.put(noext, new ServletClassEntry(c));
268: return c;
269: } else
270: throw new ClassNotFoundException(name);
271: } catch (Exception ex) {
272: throw new ClassNotFoundException(name);
273: }
274: }
275: // load the class
276: return getNewClass(file, name, resolve);
277: }
278: }
279:
280: public URL getResource(String name) {
281: URL resource = getSystemResource(name);
282: if (resource != null)
283: return resource;
284: String url = context.getServletDirectory().getAbsolutePath();
285: // Return the location of that resource (name resolved by j.l.Class)
286: if (File.separatorChar != '/')
287: url = url.replace(File.separatorChar, '/');
288: File file = new File(url, name);
289: if (!file.exists())
290: return null;
291: try {
292: return new URL("file", "localhost", url + "/" + name);
293: } catch (MalformedURLException ex) {
294: // Shouldn't fall here
295: return null;
296: }
297: }
298:
299: /**
300: * Get a resource as a stream.
301: * @param name The name of the resource to locate.
302: */
303:
304: public InputStream getResourceAsStream(String name) {
305: InputStream in = getSystemResourceAsStream(name);
306: if (in != null)
307: return in;
308: URL resource = getResource(name);
309: if (resource == null)
310: return null;
311: try {
312: URLConnection c = resource.openConnection();
313: return c.getInputStream();
314: } catch (IOException ex) {
315: return null;
316: }
317: }
318:
319: protected AutoReloadServletLoader(AutoReloadServletLoader loader) {
320: super ();
321: this .context = loader.context;
322: this .classes = loader.classes;
323: }
324:
325: protected AutoReloadServletLoader(JigsawServletContext context) {
326: super ();
327: this .context = context;
328: this .classes = new Hashtable(CLASSES_DEFAULT_SIZE);
329: }
330: }
|