enhancerfixup.java

来自「RESIN 3.2 最新源码」· Java 代码 · 共 1,033 行 · 第 1/2 页

JAVA
1,033
字号
/* * 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.enhancer;import com.caucho.bytecode.*;import com.caucho.java.WorkDir;import com.caucho.java.gen.JavaClassGenerator;import com.caucho.loader.DynamicClassLoader;import com.caucho.util.L10N;import com.caucho.vfs.JarPath;import com.caucho.vfs.Path;import com.caucho.vfs.ReadStream;import com.caucho.vfs.Vfs;import com.caucho.vfs.WriteStream;import java.net.URL;import java.util.ArrayList;import java.util.logging.Logger;/** * Class loader which checks for changes in class files and automatically * picks up new jars. * * <p>DynamicClassLoaders can be chained creating one virtual class loader. * From the perspective of the JDK, it's all one classloader.  Internally, * the class loader chain searches like a classpath. */public class EnhancerFixup {  private static final L10N L = new L10N(EnhancerFixup.class);  private static final Logger log = Logger.getLogger(EnhancerFixup.class.getName());  private static final int ACC_PUBLIC = 0x1;  private static final int ACC_PRIVATE = 0x2;  private static final int ACC_PROTECTED = 0x4;  private JavaClassGenerator _javaGen = new JavaClassGenerator();  private JavaClassLoader _jClassLoader;  private DynamicClassLoader _loader;  private Path _workPath;  private String _baseSuffix = "";  private String _extSuffix = "__ResinExt";  private ArrayList<ClassEnhancer> _enhancerList =    new ArrayList<ClassEnhancer>();  private boolean _isParentStarted;  /**   * Sets the class loader.   */  public void setClassLoader(DynamicClassLoader loader)  {    _loader = loader;  }  /**   * Returns the parsed class loader.   */  public void setJavaClassLoader(JavaClassLoader jClassLoader)  {    _jClassLoader = jClassLoader;  }  /**   * Returns the parsed class loader.   */  public JavaClassLoader getJavaClassLoader()  {    return _jClassLoader;  }  /**   * Gets the work path.   */  public Path getWorkPath()  {    if (_workPath != null)      return _workPath;    else      return WorkDir.getLocalWorkDir();  }  /**   * Sets the work path.   */  public void setWorkPath(Path workPath)  {    _workPath = workPath;  }  /**   * Gets the work path.   */  public final Path getPreWorkPath()  {    return getWorkPath().lookup("pre-enhance");  }  /**   * Gets the work path.   */  public final Path getPostWorkPath()  {    return getWorkPath().lookup("post-enhance");  }  /**   * Adds a class enhancer.   */  public void addEnhancer(ClassEnhancer enhancer)  {    _enhancerList.add(enhancer);  }  protected void fixup(String className, String extClassName)    throws Exception  {    Path prePath = getPreWorkPath();    Path postPath = getPostWorkPath();    Path source = getSource(className);    if (source == null || ! source.canRead())      return;    Path ext = prePath.lookup(extClassName.replace('.', '/') + ".class");    Path target = postPath.lookup(className.replace('.', '/') + ".class");    try {      target.getParent().mkdirs();    } catch (Throwable e) {    }    if (source != null)      mergeClasses(className, target, source, ext);    else      mergeClasses(className, target, ext);    int p = className.lastIndexOf('.');    Path preTargetDir;    Path targetDir;    String classSuffix;    String prefix = "";    if (p > 0) {      prefix = className.substring(0, p).replace('.', '/');      preTargetDir = prePath.lookup(prefix);      targetDir = postPath.lookup(prefix);      classSuffix = className.substring(p + 1);    }    else {      preTargetDir = prePath;      targetDir = postPath;      classSuffix = className;    }    prefix = prefix.replace('/', '.');    if (! prefix.equals(""))      prefix = prefix + ".";    String extSuffix;    p = extClassName.lastIndexOf('.');    if (p > 0)      extSuffix = extClassName.substring(p + 1);    else      extSuffix = extClassName;    fixupPreSubClasses(preTargetDir, targetDir,                       extSuffix, classSuffix);    fixupPostSubClasses(targetDir, prefix, classSuffix);  }  private void fixupPreSubClasses(Path preTargetDir, Path targetDir,                                  String extSuffix, String classSuffix)    throws Exception  {    String []list = preTargetDir.list();    for (int i = 0; i < list.length; i++) {      String name = list[i];      if (name.startsWith(extSuffix + '$') &&          name.endsWith(".class")) {        int p = name.indexOf('$');        String targetClass = (classSuffix + '$' +                              name.substring(p + 1, name.length() - 6));        Path subTarget = targetDir.lookup(targetClass + ".class");        Path extPath = preTargetDir.lookup(name);        renameSubClass(classSuffix, subTarget, extPath);        //if (_loader != null)        //  _loader.addPathClass(prefix + targetClass, subTarget);      }      else if (name.startsWith(extSuffix + '-') &&               name.endsWith(".class")) {        int p = name.indexOf('-');        String targetClass = (classSuffix + '-' +                              name.substring(p + 1, name.length() - 6));        Path subTarget = targetDir.lookup(targetClass + ".class");        Path extPath = preTargetDir.lookup(name);        renameSubClass(classSuffix, subTarget, extPath);        //if (_loader != null)        //  _loader.addPathClass(prefix + targetClass, subTarget);      }    }  }  private void fixupPostSubClasses(Path targetDir,                                   String prefix,                                   String classSuffix)    throws Exception  {    String []list = targetDir.list();    for (int i = 0; i < list.length; i++) {      String name = list[i];      if (! name.endsWith(".class"))        continue;      String className = name.substring(0, name.length() - ".class".length());      if (name.startsWith(classSuffix + '$')) {        if (_loader != null)          _loader.addPathClass(prefix + className, targetDir.lookup(name));      }      else if (name.startsWith(classSuffix + '-')) {        if (_loader != null)          _loader.addPathClass(prefix + className, targetDir.lookup(name));      }      else if (name.startsWith(classSuffix + '+')) {        if (_loader != null)          _loader.addPathClass(prefix + className, targetDir.lookup(name));      }    }  }  /**   * Merges the two classes.   */  protected void renameSubClass(String className,                                Path targetPath,                                Path extPath)    throws Exception  {    JavaClass extClass = null;    ByteCodeParser parser = new ByteCodeParser();    parser = new ByteCodeParser();    parser.setClassLoader(new JavaClassLoader());    ReadStream is = extPath.openRead();    try {      extClass = parser.parse(is);    } finally {      if (is != null)        is.close();    }    cleanExtConstantPool(className, extClass);    WriteStream os = targetPath.openWrite();    try {      extClass.write(os);    } finally {      os.close();    }  }  /**   * Renamed the super() methods   */  protected void renameExtSuperMethods(String className,                                       JavaClass baseClass,                                       JavaClass extClass)    throws Exception  {    ArrayList<ConstantPoolEntry> entries;    entries = extClass.getConstantPool().getEntries();    className = className.replace('.', '/');    String baseName = className + _baseSuffix;    String extName = className + "__ResinExt";    for (int i = 0; i < entries.size(); i++) {      ConstantPoolEntry entry = entries.get(i);      if (entry instanceof MethodRefConstant) {        MethodRefConstant methodRef = (MethodRefConstant) entry;        if (! methodRef.getClassName().equals(baseName))          continue;        String methodName = methodRef.getName();        String type = methodRef.getType();        if (findMethod(baseClass, methodName, type) == null)          continue;        if (findMethod(extClass, methodName, type) == null)          continue;        if (methodName.equals("<init>")) {          methodName = "__init__super";          // methodRef.setNameAndType(methodName, type);        }	/* jpa/0h28, shouldn't automatically change this        else {          methodName = methodName + "__super";          methodRef.setNameAndType(methodName, type);        }	*/      }    }  }  /**   * Moves all methods in the base to the __super methods   */  private void moveSuperMethods(String className,                                JavaClass baseClass,                                JavaClass extClass)  {    className = className.replace('.', '/');    ArrayList<JavaMethod> methods = baseClass.getMethodList();    // Move the __super methods    ArrayList<JavaMethod> extMethods = extClass.getMethodList();    for (int i = 0; i < extMethods.size(); i++) {      JavaMethod extMethod = extMethods.get(i);      fixupExtMethod(baseClass, extClass, extMethod);      String baseName = extMethod.getName();      if (baseName.endsWith("__super"))        continue;      String superName = baseName + "__super";      int j;      for (j = 0; j < methods.size(); j++) {        JavaMethod method = methods.get(j);        String type = method.getDescriptor();        if (! method.getName().equals(baseName)	    || ! method.getDescriptor().equals(extMethod.getDescriptor()))          continue;        if (baseName.equals("<init>")) {          baseClass.getConstantPool().addUTF8("__init__super");          mergeInitMethods(baseClass, method, extClass, extMethod);          break;        }        if (baseName.equals("<clinit>")) {          concatenateMethods(baseClass, method, extClass, extMethod);          break;        }        baseClass.getConstantPool().addUTF8(superName);        method.setName(superName);        baseClass.getConstantPool().addUTF8(type);        method.setDescriptor(type);        // set the super methods private        int flags = method.getAccessFlags();        flags = (flags & ~ACC_PUBLIC & ~ACC_PROTECTED) | ACC_PRIVATE;        method.setAccessFlags(flags);        break;      }    }  }  /**   * Concatenates methods   */  private void concatenateMethods(JavaClass baseClass, JavaMethod baseMethod,                                  JavaClass extClass, JavaMethod extMethod)  {    extMethod = extMethod.export(extClass, baseClass);    baseMethod.concatenate(extMethod);  }  /**   * Merges the init methods   */  private void mergeInitMethods(JavaClass baseClass, JavaMethod baseMethod,                                JavaClass extClass, JavaMethod extMethod)  {    extMethod = extMethod.export(extClass, baseClass);    baseMethod.setName("__init__super");    baseClass.getMethodList().add(extMethod);    try {      InitAnalyzer initAnalyzer = new InitAnalyzer();      CodeEnhancer baseEnhancer = new CodeEnhancer(baseClass, baseMethod.getCode());      baseEnhancer.analyze(initAnalyzer);      int offset = initAnalyzer.getOffset();      byte []code = new byte[offset];      byte []oldCode = baseEnhancer.getCode();      System.arraycopy(oldCode, 0, code, 0, offset);      baseEnhancer.remove(0, offset);      baseEnhancer.update();      CodeEnhancer extEnhancer = new CodeEnhancer(baseClass, extMethod.getCode());      extEnhancer.add(0, code, 0, code.length);      ExtMethodAnalyzer extMethodAnalyzer	= new ExtMethodAnalyzer(baseClass, extMethod, offset);      extEnhancer.analyze(extMethodAnalyzer);      extEnhancer.update();      CodeAttribute baseCode = baseMethod.getCode();      CodeAttribute extCode = extMethod.getCode();      if (extCode.getMaxStack() < baseCode.getMaxStack())        extCode.setMaxStack(baseCode.getMaxStack());      // XXX: needs tests badly      extCode.removeAttribute("LocalVariableTable");      extCode.removeAttribute("LineNumberTable");      baseCode.removeAttribute("LocalVariableTable");      baseCode.removeAttribute("LineNumberTable");      /*        baseMethod.concatenate(extMethod);      */    } catch (RuntimeException e) {      throw e;    } catch (Exception e) {      throw new RuntimeException(e);    }  }  /**   * Merges the init methods   */  private void fixupExtMethod(JavaClass baseClass,			      JavaClass extClass,			      JavaMethod extMethod)  {    try {      if (extMethod.getName().endsWith("__super"))	return;            CodeEnhancer extEnhancer	= new CodeEnhancer(extClass, extMethod.getCode());      ExtMethodAnalyzer extMethodAnalyzer	= new ExtMethodAnalyzer(baseClass, extMethod, 0);      extEnhancer.analyze(extMethodAnalyzer);      extEnhancer.update();    } catch (RuntimeException e) {      throw e;    } catch (Exception e) {      throw new RuntimeException(e);    }  }  /**   * Adds the methods from the ext to the base   */  private void addExtInterfaces(JavaClass baseClass, JavaClass extClass)  {    for (String name : extClass.getInterfaceNames()) {      baseClass.getConstantPool().addClass(name);

⌨️ 快捷键说明

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