Re: ServletDirectory resource

 Hi all!

 I made some modifications in the servlet support of jigsaw in order
 to remove some bugs. One of These bugs appears when the Servlet class 
 file is in the classpath. In this case, the servlet is destroyed and 
 inited on each invocation. This is due to the LocalServletLoader.

 new version of LocalServletLoader.java (in w3c/jigsaw/servlet/ )

---------------
// ServletLoader.java
// $Id: LocalServletLoader.java,v 1.9 1997/09/15 09:56:30 bmahe Exp $
// (c) COPYRIGHT MIT and INRIA, 1996.
// Please first read the full copyright statement in file COPYRIGHT.html

package w3c.jigsaw.servlet;

import java.io.*;
import java.net.*;
import java.util.*;
import java.util.zip.*;

class ServletClassEntry {
  
  long   classStamp   = 0;
  Class  servletClass = null;
  File   classFile    = null;
  boolean systemClass = false;

  public boolean isModified() {
    return (classFile.lastModified() > classStamp);
  }

  public void update() {
    classStamp   = classFile.lastModified();
  }

  public ServletClassEntry (File classFile, 
			    Class servletClass, 
			    boolean systemClass) 
  {
    this.classFile    = classFile;
    this.servletClass = servletClass;
    this.classStamp   = classFile.lastModified();
    this.systemClass  =  systemClass;
  }

}


/**
 * LocalServletLoader : 
 * @author Benoit Mahe <bmahe@inria.fr>
 */


public class LocalServletLoader extends ClassLoader {
  private static final boolean debug = false;
  private Hashtable classes = null;

  ServletWrapper wrapper = null;

  private void trace(String msg) {
    System.out.println("["+wrapper.getURLPath()+"]: "+msg);
  }

  private String packaged(String name) {
    String cname = new String(name);
    try {
      if (cname.endsWith(".class")) {
	int idx = cname.lastIndexOf(".");
	cname = cname.substring(0,idx);
      } 
      return cname.replace('.', '/')+".class";
    } catch (Exception ex) {
      return null;
    }
  }


  /**
   * Given the class name, return its File name.
   * @param name The class to be loaded.
   * @return The File for the class.
   */

  protected File locateClass(String name) {
    File classfile = null;
    File base = wrapper.getServletDirectory();
    String cname = null;

    cname = packaged(name);
    classfile = new File(base, cname);

    if (classfile != null)
      if (classfile.exists()) return classfile;
    
    String classpath = (String)System.getProperties().get("java.class.path");
    StringTokenizer st = new StringTokenizer(classpath, ":");
    while (st.hasMoreTokens()) {
      String path = st.nextToken();
      if (path.endsWith(".zip")) {
	try {
	  ZipFile zfile = new ZipFile(path);
	  ZipEntry zentry = zfile.getEntry(cname);
	  if (zentry != null)
	    return new File(path);
	} catch (IOException ex) {}
      } else {
	classfile = new File(path,cname);
	if (classfile.exists())
	  return classfile;
      }
    }
    return null;
  }
  

  public URL getResource(String name) {
    String url = wrapper.getServletDirectory().getAbsolutePath();
    // Return the location of that resource (name resolved by j.l.Class)
    if ( File.separatorChar != '/' )
      url = url.replace(File.separatorChar, '/');
    try {
      return new URL("file", "localhost", url+"/"+name);
    } catch (MalformedURLException ex) {
      // Shouldn't fall here
      return null;
    }
  }
  
  /**
   * Get a resource as a stream.
   * @param name The name of the resource to locate.
   */
  
  public InputStream getResourceAsStream(String name) {
    try {
      URLConnection c = getResource(name).openConnection();
      return c.getInputStream();
    } catch (IOException ex) {
      return null;
    }
  }
  
  protected Class loadClassFile(File file) 
    throws ClassNotFoundException
  {
    byte data[] = null;
    if ( file == null )
      throw new ClassNotFoundException("invalid servlet base");
    if ( debug )
      trace(" located at "+file);
    try {
      BufferedInputStream in      = 
	new BufferedInputStream( new FileInputStream( file) );
      ByteArrayOutputStream out   = new ByteArrayOutputStream(512);
      byte                  buf[] = new byte[512];
      for (int got = 0 ; (got = in.read(buf)) > 0 ; )
	out.write(buf, 0, got);
      data = out.toByteArray();
      in.close();
    } catch (Exception ex) {
      if (debug) 
	ex.printStackTrace();
      throw new ClassNotFoundException(file.getAbsolutePath());
    }
    // Define the class:
    return defineClass(data, 0, data.length);
  }

  protected Class loadServletClass(String name, boolean resolve)
    throws ClassNotFoundException
  {
    Class c = null;
    if ( debug )
      trace("loading servlet class : "+name);

    // Look for a cached class first:
    ServletClassEntry entry = (ServletClassEntry)classes.get(name);
    if (entry != null) {
      if (! entry.isModified())
	return entry.servletClass;
      else if (! entry.systemClass) {
	entry.servletClass =  loadClassFile(entry.classFile);
	if ( resolve )
	  resolveClass(entry.servletClass);
	entry.update();
	return entry.servletClass;
      }
    }

    SecurityManager s = System.getSecurityManager();
    if ( s != null ) {
      int i = name.lastIndexOf('.');
      if ( i >= 0 )
	s.checkPackageAccess(name.substring(0, i));
    }

    File  file    = locateClass(name);
    // Then look for a system class:
    try {
      if ((c = findSystemClass(name)) != null) {
	classes.put(name, new ServletClassEntry(file,c,true));
    	return c;
      }
    } catch (Exception ex) {}

    c             = loadClassFile(file);
    if ( resolve )
      resolveClass(c);
    classes.put(name, new ServletClassEntry(file,c,false));
    if ( debug )
      trace(name+": loading done.");
    return c;
  }

  protected Class loadClass(String name, boolean resolve)
    throws ClassNotFoundException
  {
    Class c = null;
    if ( debug )
      trace("loading class : "+name);

    // Look for a cached class first:
    ServletClassEntry entry = (ServletClassEntry)classes.get(name);
    if (entry != null) {
      if (! entry.isModified())
	return entry.servletClass;
      else if (! entry.systemClass) {
	entry.servletClass =  loadClassFile(entry.classFile);
	if ( resolve )
	  resolveClass(entry.servletClass);
	entry.update();
	return entry.servletClass;
      }
    }

    SecurityManager s = System.getSecurityManager();
    if ( s != null ) {
      int i = name.lastIndexOf('.');
      if ( i >= 0 )
	s.checkPackageAccess(name.substring(0, i));
    }
    
    // Then look for a system class:
    try {
      if ((c = findSystemClass(name)) != null)
    	return c;
    } catch (Exception ex) {
    }

    File  file    = locateClass(name);
    c             = loadClassFile(file);
    if ( resolve )
      resolveClass(c);
    classes.put(name, new ServletClassEntry(file,c,false));
    if ( debug )
      trace(name+": loading done.");
    return c;
  }

  protected LocalServletLoader(ServletWrapper wrapper) {
    super();
    this.wrapper = wrapper;
    this.classes = new Hashtable(13);
  }

  protected LocalServletLoader(LocalServletLoader loader) {
    super();
    this.wrapper = loader.wrapper;
    //    this.classes = loader.classes;
    this.classes = new Hashtable(13);
  }

  public File getClassFile(String name) {
    ServletClassEntry entry = (ServletClassEntry)classes.get(name);
    if (entry != null)
      return entry.classFile;
    return null;
  }

  public boolean classChanged(String name) {
    ServletClassEntry entry = (ServletClassEntry)classes.get(name);
    if (entry != null) {
      if (debug) {
	System.out.println("entry    : "+name);
	System.out.println("file     : "+entry.classFile.getAbsolutePath());
	System.out.println("Stamp    : "+entry.classStamp);
	System.out.println("System   : "+entry.systemClass);
	System.out.println("modified : "+entry.isModified());
      }
      return entry.isModified();
    }
    return true;
  }

}

---------------

  in ServletWrapper.java change method launchServlet() by

  protected boolean launchServlet() {
    // Get and check the servlet class:
    if ( servlet != null )
      destroyServlet();
    String clsname = getServletClass();
    if ( clsname == null ) {
      getServer().errlog(this, "no servlet class attribute defined.");
      return false;
    } else {
      Class c = null;
      try {
	if (loader.classChanged(clsname))
	  loader = new LocalServletLoader(this.loader);
	c = loader.loadServletClass(clsname, true);
      } catch (ClassNotFoundException ex) {
	if ( debug )
	  ex.printStackTrace();
	String msg = ("unable to load servlet class \""+
		      getServletClass()+
		      "\" : "+
		      ex.getMessage());
	getServer().errlog(msg);
      }
      return (c != null) ? launchServlet(c) : false;
    }
  }

 
----------------

 in JigsawHttpServletRequest.java change method getPathTranslated by

   public  String getPathTranslated()
  {
    String pathinfo = getPathInfo();
    if ( pathinfo != null ) {
      httpd server = request.getClient().getServer();
      HTTPResource root = server.root;
      try {
	LookupState ls = new LookupState(pathinfo);
	LookupResult lr = new LookupResult(root);
	HTTPResource path = null;
	if (root.lookup(ls,lr))
	  path = lr.getTarget();
	if (path != null)
	  if (path instanceof FileResource)
	    return ((FileResource)path).getFile().getAbsolutePath();
	  else if (path instanceof DirectoryResource)
	    return ((DirectoryResource)path).getDirectory().getAbsolutePath();
	  else return null;
	else return null;
      }
      catch (HTTPException ex) {return null;}
    }
    return null;
  }

 thanks to Andreas Bufe <AndreasBufe@compuserve.com>
 
--------

 in JigsawHttpServletResponse.java change method containsHeader

 public boolean containsHeader(String header) {
    return reply.hasHeader(header);
  }

-------

 So, that's all. (I hope :) )
 I made some tests and it seems to work correctly now.

 
- Benoît Mahé -------------------------------------------------------
World Wide Web Consortium                       bmahe@sophia.inria.fr 
Architecture domain - Jigsaw Team               tel : 04 93 65 79 89
---------------------------------------------------------------------

Received on Tuesday, 16 September 1997 04:35:20 UTC