classentry.java

来自「RESIN 3.2 最新源码」· Java 代码 · 共 494 行

JAVA
494
字号
/* * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved * * This file is part of Resin(R) Open Source * * Each copy or derived work must preserve the copyright notice and this * notice unmodified. * * Resin Open Source is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Resin Open Source is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty * of NON-INFRINGEMENT.  See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with Resin Open Source; if not, write to the * *   Free Software Foundation, Inc. *   59 Temple Place, Suite 330 *   Boston, MA 02111-1307  USA * * @author Scott Ferguson */package com.caucho.loader;import com.caucho.log.Log;import com.caucho.make.DependencyContainer;import com.caucho.util.ByteBuffer;import com.caucho.util.L10N;import com.caucho.util.QDate;import com.caucho.vfs.Depend;import com.caucho.vfs.Dependency;import com.caucho.vfs.JarPath;import com.caucho.vfs.Path;import com.caucho.vfs.PersistentDependency;import com.caucho.vfs.ReadStream;import java.io.IOException;import java.lang.ref.WeakReference;import java.security.CodeSource;import java.util.logging.Level;import java.util.logging.Logger;/** * Describes a cached loaded class entry. */public class ClassEntry implements Dependency {  private static final L10N L = new L10N(ClassEntry.class);  private static final Logger log    = Logger.getLogger(ClassEntry.class.getName());    private static boolean _hasJNIReload;  private static boolean _hasAnnotations;  private DynamicClassLoader _loader;  private String _name;      private Path _classPath;  private PersistentDependency _depend;  private boolean _classIsModified;      private Path _sourcePath;  private long _sourceLastModified;  private long _sourceLength;  private ClassPackage _classPackage;  private CodeSource _codeSource;  private ClassNotFoundException _exn;      private WeakReference<Class> _clRef;  /**   * Create a loaded class entry   *   * @param name the classname   * @param sourcePath path to the source Java file   * @param classPath path to the compiled class file   */  public ClassEntry(DynamicClassLoader loader,                    String name, Path sourcePath,                    Path classPath,		    CodeSource codeSource)  {    _loader = loader;    _name = name;    _classPath = classPath;    setDependPath(classPath);    if (sourcePath != null && ! sourcePath.equals(classPath)) {      _sourcePath = sourcePath;            _sourceLastModified = sourcePath.getLastModified();      _sourceLength = sourcePath.getLength();    }    _codeSource = codeSource;    /*    if (codePath == null)      codePath = classPath;    if (_loader.getSecurityManager() != null) {      try {        _codeSource = new CodeSource(new URL(codePath.getURL()), null);      } catch (Exception e) {        e.printStackTrace();      }    }    */  }  /**   * Create a loaded class entry   *   * @param name the classname   * @param sourcePath path to the source Java file   * @param classPath path to the compiled class file   */  public ClassEntry(Loader loader,                    String name, Path sourcePath,                    Path classPath)  {    this(loader.getLoader(), name, sourcePath, classPath,	 loader.getCodeSource(classPath));  }  public String getName()  {    return _name;  }  /**   * returns the class loader.   */  public DynamicClassLoader getClassLoader()  {    return _loader;  }  public CodeSource getCodeSource()  {    return _codeSource;  }  public Path getSourcePath()  {    return _sourcePath;  }  /**   * Sets the depend path.   */  protected void setDependPath(Path dependPath)  {    if (dependPath instanceof JarPath)      _depend = ((JarPath) dependPath).getDepend();    else      _depend = new Depend(dependPath);  }  /**   * Adds the dependencies, returning true if it's adding itself.   */  protected boolean addDependencies(DependencyContainer container)  {    if (_classPath instanceof JarPath) {      container.add(_depend);      return false;    }    else if (_hasJNIReload) {      container.add(this);      return true;    }    else if (_sourcePath == null) {      container.add(_depend);      return false;    }    else {      container.add(this);      return true;    }  }    public void setSourceLength(long length)  {    _sourceLength = length;  }    public void setSourceLastModified(long lastModified)  {    _sourceLastModified = lastModified;  }    public ClassPackage getClassPackage()  {    return _classPackage;  }  public void setClassPackage(ClassPackage pkg)  {    _classPackage = pkg;  }  /**   * Returns true if the source file has been modified.   */  public boolean isModified()  {    if (_depend.isModified()) {      if (log.isLoggable(Level.FINE))        log.fine("class modified: " + _depend);      return reloadIsModified();    }    else if (_sourcePath == null)      return false;          else if (_sourcePath.getLastModified() != _sourceLastModified) {      if (log.isLoggable(Level.FINE))        log.fine("source modified time: " + _sourcePath +                 " old:" + QDate.formatLocal(_sourceLastModified) +                 " new:" + QDate.formatLocal(_sourcePath.getLastModified()));      if (! compileIsModified()) {	return false;      }            boolean isModified = reloadIsModified();      return isModified;    }    else if (_sourcePath.getLength() != _sourceLength) {      if (log.isLoggable(Level.FINE))        log.fine("source modified length: " + _sourcePath +                 " old:" + _sourceLength +                 " new:" + _sourcePath.getLength());      if (! compileIsModified())	return false;      return reloadIsModified();    }    else {      return false;    }  }  /**   * Returns true if the source file has been modified.   */  public boolean logModified(Logger log)  {    if (_depend.logModified(log)) {      return true;    }    else if (_sourcePath == null)      return false;          else if (_sourcePath.getLastModified() != _sourceLastModified) {      log.info("source modified time: " + _sourcePath +	       " old:" + QDate.formatLocal(_sourceLastModified) +	       " new:" + QDate.formatLocal(_sourcePath.getLastModified()));      return true;    }    else if (_sourcePath.getLength() != _sourceLength) {      log.info("source modified length: " + _sourcePath +	       " old:" + _sourceLength +	       " new:" + _sourcePath.getLength());      return true;    }    else {      return false;    }  }  /**   * Returns true if the compile doesn't avoid the dependency.   */  public boolean compileIsModified()  {    return true;  }  /**   * Returns true if the reload doesn't avoid the dependency.   */  public boolean reloadIsModified()  {    if (_classIsModified) {      return true;    }    if (! _hasJNIReload || ! _classPath.canRead()) {      return true;    }        try {      long length = _classPath.getLength();      Class cl = _clRef != null ? _clRef.get() : null;	      if (cl == null) {	return false;      }      if (_hasAnnotations && requireReload(cl))	return true;	          ReadStream is = _classPath.openRead();      byte []bytecode = new byte[(int) length];	          try {	is.readAll(bytecode, 0, bytecode.length);      } finally {	is.close();      }      int result = reloadNative(cl, bytecode, 0, bytecode.length);	      if (result != 0) {	_classIsModified = true;	return true;      }      setDependPath(_classPath);            if (_sourcePath != null) {	_sourceLastModified = _sourcePath.getLastModified();	_sourceLength = _sourcePath.getLength();      }      log.info("Reloading " + cl.getName());      return false;    } catch (Exception e) {      log.log(Level.WARNING, e.toString(), e);      _classIsModified = true;      return true;    }  }  /**   * Returns the path to the class file.   */  public Path getClassPath()  {    return _classPath;  }  public Class getEntryClass()  {    return _clRef != null ? _clRef.get() : null;  }  public void setEntryClass(Class cl)  {    _clRef = new WeakReference<Class>(cl);  }  /**   * preload actions.   */  public void preLoad()    throws ClassNotFoundException  {  }  /**   * Loads the contents of the class file into the buffer.   */  public void load(ByteBuffer buffer)    throws IOException  {    synchronized (this) {      Path classPath = getClassPath();          buffer.clear();      int retry = 3;      for (int i = 0; i < retry; i++) {	long length = classPath.getLength();	long lastModified = classPath.getLastModified();      	if (length < 0)	  throw new IOException("missing class: " + classPath);      	ReadStream is = classPath.openRead();      	try {	  buffer.setLength((int) length);	  int results = is.readAll(buffer.getBuffer(), 0, (int) length);	  if (results == length	      && length == classPath.getLength()	      && lastModified == classPath.getLastModified()) {	    return;	  }	} finally {	  is.close();	}		log.warning(L.l("{0}: class file length mismatch expected={1}",			this, length));      }    }  }  /**   * post-load actions.   */  public boolean postLoad()  {    return false;  }  public static boolean hasJNIReload()  {    return _hasJNIReload;  }  private static boolean requireReload(Class cl)  {    return cl.isAnnotationPresent(RequireReload.class);  }  public String toString()  {    if (_sourcePath == null)      return "ClassEntry[" + _classPath + "]";    else      return "ClassEntry[" + _classPath + ", src=" + _sourcePath + "]";  }  public static native boolean canReloadNative();  public static native int reloadNative(Class cl,		  		        byte []bytes, int offset, int length);  class ReloadThread implements Runnable {    private volatile boolean _isDone;    public boolean isDone()    {      return _isDone;    }        public void run()    {    }  }    static {    try {      System.loadLibrary("resin_os");      _hasJNIReload = canReloadNative();      if (_hasJNIReload)	log.config("In-place class redefinition (HotSwap) is available.");      else	log.config("In-place class redefinition (HotSwap) is not available.  In-place class reloading during development requires a compatible JDK and -Xdebug.");    } catch (Throwable e) {      log.fine(e.toString());            log.log(Level.FINEST, e.toString(), e);      // log.config("In-place class redefinition (HotSwap) is not available.\n" + e);    }        try {      Class reloadClass = Class.forName("com.caucho.loader.RequireReload");            Object.class.getAnnotation(reloadClass);      _hasAnnotations = true;    } catch (Throwable e) {    }  }}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?