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