Annotation of java/classes/org/w3c/jigsaw/servlet/AutoReloadServletLoader.java, revision 1.12
1.1 bmahe 1: // AutoReloadServletLoader.java
1.12 ! ylafon 2: // $Id: AutoReloadServletLoader.java,v 1.11 2012/07/18 13:39:31 ylafon Exp $
1.1 bmahe 3: // (c) COPYRIGHT MIT and INRIA, 1998.
4: // Please first read the full copyright statement in file COPYRIGHT.html
1.8 ylafon 5:
1.1 bmahe 6: package org.w3c.jigsaw.servlet;
7:
1.8 ylafon 8: import java.io.BufferedInputStream;
9: import java.io.ByteArrayOutputStream;
10: import java.io.File;
11: import java.io.FileInputStream;
12: import java.io.IOException;
13: import java.io.InputStream;
14: import java.net.MalformedURLException;
15: import java.net.URL;
16: import java.net.URLConnection;
1.11 ylafon 17: import java.util.HashMap;
1.1 bmahe 18:
19: class ServletClassEntry {
1.8 ylafon 20:
1.10 ylafon 21: long classStamp = 0;
1.12 ! ylafon 22: Class<?> servletClass = null;
1.10 ylafon 23: File classFile = null;
1.1 bmahe 24: boolean systemClass = false;
25:
26: public boolean isModified() {
1.10 ylafon 27: if (!systemClass)
28: return (classFile.lastModified() > classStamp);
29: return false;
1.1 bmahe 30: }
31:
32: public void update() {
1.10 ylafon 33: if (!systemClass)
34: classStamp = classFile.lastModified();
1.1 bmahe 35: }
36:
1.12 ! ylafon 37: public ServletClassEntry(Class<?> servletClass) {
1.10 ylafon 38: this.servletClass = servletClass;
39: this.systemClass = true;
1.1 bmahe 40: }
41:
1.10 ylafon 42: public ServletClassEntry(File classFile,
1.12 ! ylafon 43: Class<?> servletClass) {
1.10 ylafon 44: this.classFile = classFile;
45: this.servletClass = servletClass;
46: if (classFile != null)
47: this.classStamp = classFile.lastModified();
48: this.systemClass = false;
1.1 bmahe 49: }
50:
51: }
52:
53: /**
1.10 ylafon 54: * @author Benoît Mahé (bmahe@w3.org)
1.12 ! ylafon 55: * @version $Revision: 1.11 $
1.1 bmahe 56: */
57: public class AutoReloadServletLoader extends ClassLoader {
58: private static final boolean debug = false;
1.12 ! ylafon 59: private HashMap<String, ServletClassEntry> classes = null;
1.1 bmahe 60: private int CLASSES_DEFAULT_SIZE = 13;
61:
62: JigsawServletContext context = null;
63:
64: private void trace(String msg) {
1.10 ylafon 65: trace(msg, true);
1.1 bmahe 66: }
67:
68: private void trace(String msg, boolean display) {
1.10 ylafon 69: if (display)
70: System.out.println("[" + context.getServletDirectory() + "]: " + msg);
1.1 bmahe 71: }
72:
73: private String removeSpace(String string) {
1.10 ylafon 74: int start = -1;
75: int end = string.length();
76: boolean spaces = false;
77: while (string.charAt(++start) == ' ') {
78: spaces = true;
79: }
80: while (string.charAt(--end) == ' ') {
81: spaces = true;
82: }
83: if (spaces)
84: return string.substring(start, ++end);
85: else
86: return new String(string);
1.1 bmahe 87: }
88:
89: private String packaged(String name) {
1.10 ylafon 90: String cname = removeSpace(name);
91: try {
92: if (cname.endsWith(".class")) {
93: int idx = cname.lastIndexOf('.');
94: if (idx != -1)
95: cname = cname.substring(0, idx);
96: }
97: return cname.replace('.', '/') + ".class";
98: } catch (Exception ex) {
99: return name;
100: }
1.1 bmahe 101: }
102:
103: private String noext(String name) {
1.10 ylafon 104: int idx = name.lastIndexOf(".class");
105: if ((idx != -1) &&
106: ((idx + 6 == name.length()) ||
107: (Character.isWhitespace(name.charAt(idx + 6))))) {
108: return name.substring(0, idx);
109: }
110: return name;
1.1 bmahe 111: }
112:
113: protected boolean classChanged(String name) {
1.11 ylafon 114: ServletClassEntry entry = classes.get(noext(name));
1.10 ylafon 115: if (entry != null) {
116: if (debug) {
117: System.out.println("entry : " + name);
118: if (!entry.systemClass) {
119: System.out.println("file : " +
120: entry.classFile.getAbsolutePath());
121: System.out.println("Stamp : " + entry.classStamp);
122: }
123: System.out.println("System : " + entry.systemClass);
124: System.out.println("modified : " + entry.isModified());
125: }
126: return entry.isModified();
127: }
128: return false; //true
1.1 bmahe 129: }
130:
1.4 bmahe 131: /**
132: * Get a cached class.
1.10 ylafon 133: *
1.4 bmahe 134: * @return a Class instance
1.10 ylafon 135: * @throws ClassNotFoundException if the Class can't be found
1.4 bmahe 136: */
1.12 ! ylafon 137: protected final Class<?> getCachedClass(String name, boolean resolve)
1.10 ylafon 138: throws ClassNotFoundException {
1.11 ylafon 139: ServletClassEntry entry = classes.get(noext(name));
1.10 ylafon 140: if (entry != null) {
141: if (!entry.isModified()) {
142: trace(name + ": not modified", debug);
143: return entry.servletClass;
144: } else if (!entry.systemClass) {
145: entry.servletClass = loadClassFile(entry.classFile);
146: if (resolve)
147: resolveClass(entry.servletClass);
148: entry.update();
149: trace(name + ": reloaded", debug);
150: return entry.servletClass;
151: }
152: }
153: return null;
1.1 bmahe 154: }
155:
156: protected void checkPackageAccess(String name) {
1.10 ylafon 157: SecurityManager s = System.getSecurityManager();
158: if (s != null) {
159: int i = name.lastIndexOf('.');
160: if (i >= 0)
161: s.checkPackageAccess(name.substring(0, i));
162: }
1.1 bmahe 163: }
164:
165: /**
166: * Given the class name, return its File name.
1.10 ylafon 167: *
1.1 bmahe 168: * @param name The class to be loaded.
169: * @return The File for the class.
170: */
171: protected File locateClass(String name) {
1.10 ylafon 172: File classfile = null;
173: File base = context.getServletDirectory();
174: String cname = null;
175:
176: cname = packaged(name);
177: classfile = new File(base, cname);
178: if (classfile != null && classfile.exists()) {
179: return classfile;
180: }
181: return null;
1.1 bmahe 182: }
183:
1.4 bmahe 184: /**
185: * Load a Class from its class file..
1.10 ylafon 186: *
1.4 bmahe 187: * @return a Class instance
1.10 ylafon 188: * @throws ClassNotFoundException if the Class can't be found
1.4 bmahe 189: */
1.12 ! ylafon 190: protected Class<?> loadClassFile(File file)
1.10 ylafon 191: throws ClassNotFoundException {
192: byte data[] = null;
193: if (file == null)
194: throw new ClassNotFoundException("invalid servlet base");
195: trace("located at " + file, debug);
196: try {
197: BufferedInputStream in =
198: new BufferedInputStream(new FileInputStream(file));
199: ByteArrayOutputStream out = new ByteArrayOutputStream(512);
200: byte buf[] = new byte[512];
201: for (int got = 0; (got = in.read(buf)) > 0; )
202: out.write(buf, 0, got);
203: data = out.toByteArray();
204: in.close();
205: } catch (Exception ex) {
206: if (debug)
207: ex.printStackTrace();
208: throw new ClassNotFoundException(file.getAbsolutePath());
209: }
210: // Define the class:
211: return defineClass(null, data, 0, data.length);
1.1 bmahe 212: }
213:
1.4 bmahe 214: /**
215: * Get a new class.
1.10 ylafon 216: *
1.4 bmahe 217: * @return a Class instance
1.10 ylafon 218: * @throws ClassNotFoundException if the Class can't be found
1.4 bmahe 219: */
1.12 ! ylafon 220: protected final Class<?> getNewClass(File classfile,
1.10 ylafon 221: String name,
222: boolean resolve)
223: throws ClassNotFoundException {
1.12 ! ylafon 224: Class<?> c = null;
1.10 ylafon 225: c = loadClassFile(classfile);
226: if (resolve)
227: resolveClass(c);
228: classes.put(noext(name), new ServletClassEntry(classfile, c));
229: trace(name + ": loading new class done.", debug);
230: return c;
1.1 bmahe 231: }
1.8 ylafon 232:
1.4 bmahe 233: /**
234: * Load a class.
1.10 ylafon 235: *
1.4 bmahe 236: * @return a Class instance
1.10 ylafon 237: * @throws ClassNotFoundException if the Class can't be found
1.4 bmahe 238: */
1.12 ! ylafon 239: protected Class<?> loadClass(String name, boolean resolve)
1.10 ylafon 240: throws ClassNotFoundException {
1.12 ! ylafon 241: Class<?> c = null;
1.10 ylafon 242: trace(name + ": loading class", debug);
243: // Look for a cached class first:
244: c = getCachedClass(name, resolve);
245: if (c != null) {
246: return c;
247: }
248:
249: synchronized (this) {
250: c = getCachedClass(name, resolve);
251: if (c != null) return c;
252:
253: checkPackageAccess(name);
254:
255: File file = locateClass(name);
256:
257: if (file == null) {
258: // Then look for a system class:
259: try {
260: String noext = noext(name);
261: if ((c = findSystemClass(noext)) != null) {
262: trace(name + ": system class", debug);
263: classes.put(noext, new ServletClassEntry(c));
264: return c;
265: } else
266: throw new ClassNotFoundException(name);
267: } catch (Exception ex) {
268: throw new ClassNotFoundException(name);
269: }
270: }
271: // load the class
272: return getNewClass(file, name, resolve);
273: }
1.2 bmahe 274: }
1.9 ylafon 275:
1.2 bmahe 276:
277: public URL getResource(String name) {
1.10 ylafon 278: URL resource = getSystemResource(name);
279: if (resource != null)
280: return resource;
281: String url = context.getServletDirectory().getAbsolutePath();
282: // Return the location of that resource (name resolved by j.l.Class)
283: if (File.separatorChar != '/')
284: url = url.replace(File.separatorChar, '/');
285: File file = new File(url, name);
286: if (!file.exists())
287: return null;
288: try {
289: return new URL("file", "localhost", url + "/" + name);
290: } catch (MalformedURLException ex) {
291: // Shouldn't fall here
292: return null;
293: }
1.2 bmahe 294: }
1.8 ylafon 295:
1.2 bmahe 296: /**
297: * Get a resource as a stream.
1.10 ylafon 298: *
1.2 bmahe 299: * @param name The name of the resource to locate.
300: */
1.8 ylafon 301:
1.2 bmahe 302: public InputStream getResourceAsStream(String name) {
1.10 ylafon 303: InputStream in = getSystemResourceAsStream(name);
304: if (in != null)
305: return in;
306: URL resource = getResource(name);
307: if (resource == null)
308: return null;
309: try {
310: URLConnection c = resource.openConnection();
311: return c.getInputStream();
312: } catch (IOException ex) {
313: return null;
314: }
1.1 bmahe 315: }
316:
317: protected AutoReloadServletLoader(AutoReloadServletLoader loader) {
1.10 ylafon 318: super();
319: this.context = loader.context;
320: this.classes = loader.classes;
1.1 bmahe 321: }
322:
323: protected AutoReloadServletLoader(JigsawServletContext context) {
1.10 ylafon 324: super();
325: this.context = context;
1.11 ylafon 326: this.classes = new HashMap<String, ServletClassEntry>(CLASSES_DEFAULT_SIZE);
1.1 bmahe 327: }
328: }
Webmaster