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 + -
显示快捷键?