Search in sources :

Example 1 with LoadtimeInstrumentationPlugin

use of org.springsource.loaded.LoadtimeInstrumentationPlugin in project spring-loaded by spring-projects.

the class SpringLoadedPreProcessor method preProcess.

/**
	 * Main entry point to Spring Loaded when it is running as an agent. This method will use the classLoader and the
	 * class name in order to determine whether the type should be made reloadable. Non-reloadable types will at least
	 * get their call sites rewritten.
	 *
	 * @param classLoader the classloader loading this type
	 * @param slashedClassName the slashed class name (e.g. java/lang/String) being loaded
	 * @param protectionDomain the protection domain for the loaded class
	 * @param bytes the class bytes for the class being loaded
	 * @return potentially modified bytes
	 */
public byte[] preProcess(ClassLoader classLoader, String slashedClassName, ProtectionDomain protectionDomain, byte[] bytes) {
    if (disabled) {
        return bytes;
    }
    // TODO need configurable debug here, ability to dump any code before/after
    for (Plugin plugin : getGlobalPlugins()) {
        if (plugin instanceof LoadtimeInstrumentationPlugin) {
            LoadtimeInstrumentationPlugin loadtimeInstrumentationPlugin = (LoadtimeInstrumentationPlugin) plugin;
            if (loadtimeInstrumentationPlugin.accept(slashedClassName, classLoader, protectionDomain, bytes)) {
                bytes = loadtimeInstrumentationPlugin.modify(slashedClassName, classLoader, bytes);
            }
        }
    }
    tryToEnsureSystemClassesInitialized(slashedClassName);
    TypeRegistry typeRegistry = TypeRegistry.getTypeRegistryFor(classLoader);
    if (GlobalConfiguration.verboseMode && log.isLoggable(Level.INFO)) {
        logPreProcess(classLoader, slashedClassName, typeRegistry);
    }
    if (typeRegistry == null) {
        // A null type registry indicates nothing is being made reloadable for the classloader
        if (classLoader == null && slashedClassName != null) {
            // Indicates loading of a system class
            if (systemClassesContainingReflection.contains(slashedClassName)) {
                try {
                    // TODO [perf] why are we not using the cache here, is it because the list is so short?
                    RewriteResult rr = SystemClassReflectionRewriter.rewrite(slashedClassName, bytes);
                    if (GlobalConfiguration.verboseMode && log.isLoggable(Level.INFO)) {
                        log.info("System class rewritten: name=" + slashedClassName + " rewrite summary=" + rr.summarize());
                    }
                    systemClassesRequiringInitialization.put(slashedClassName, rr.bits);
                    return rr.bytes;
                } catch (Exception re) {
                    re.printStackTrace();
                }
            } else if (slashedClassName.equals("java/lang/invoke/InnerClassLambdaMetafactory")) {
                bytes = Java8.enhanceInnerClassLambdaMetaFactory(bytes);
                return bytes;
            } else if ((GlobalConfiguration.investigateSystemClassReflection || GlobalConfiguration.rewriteAllSystemClasses) && SystemClassReflectionInvestigator.investigate(slashedClassName, bytes, GlobalConfiguration.investigateSystemClassReflection) > 0) {
                // This block can help when you suspect there is a system class using reflection and that
                // class isn't on the 'shortlist' (in systemClassesContainingReflection). Basically turn on the
                // options to trigger this investigation then add them to the shortlist if it looks like they need rewriting.
                RewriteResult rr = SystemClassReflectionRewriter.rewrite(slashedClassName, bytes);
                if (GlobalConfiguration.rewriteAllSystemClasses) {
                    systemClassesRequiringInitialization.put(slashedClassName, rr.bits);
                    return rr.bytes;
                } else {
                    System.err.println("Type " + slashedClassName + " rewrite summary: " + rr.summarize());
                    return bytes;
                }
            }
        }
        return bytes;
    }
    // What happens here? The aim is to determine if the type should be made reloadable.
    // 1. If NO, but something in this classloader might be, then rewrite the call sites.
    // 2. If NO, and nothing in this classloader might be, return the original bytes.
    // 3. If YES, make the type reloadable (including rewriting call sites)
    ReloadableTypeNameDecision isReloadableTypeName = typeRegistry.isReloadableTypeName(slashedClassName, protectionDomain, bytes);
    if (isReloadableTypeName.isReloadable && GlobalConfiguration.explainMode && log.isLoggable(Level.INFO)) {
        log.info("[explanation] Based on the name, type " + slashedClassName + " is considered to be reloadable");
    }
    //		}
    if (isReloadableTypeName.isReloadable) {
        if (!firstReloadableTypeHit) {
            firstReloadableTypeHit = true;
            // TODO move into the ctor for ReloadableType so that it can't block loading
            tryToEnsureSystemClassesInitialized(slashedClassName);
        }
        if (GlobalConfiguration.isRuntimeLogging && log.isLoggable(Level.INFO)) {
            log.info("processing " + slashedClassName + " as a reloadable type");
        }
        try {
            // TODO decide one way or the other on slashed/dotted from preprocessor to infrastructure
            String dottedClassName = slashedClassName.replace('/', '.');
            String watchPath = getWatchPathFromProtectionDomain(protectionDomain, slashedClassName);
            if (watchPath == null) {
                // For a CGLIB generated type, we may still need to make the type reloadable.  For example:
                // type: com/vmware/rabbit/ApplicationContext$$EnhancerByCGLIB$$512eb60c
                // codesource determined to be: file:/Users/aclement/springsource/tc-server-developer-2.1.1.RELEASE/spring-insight-instance/wtpwebapps/hello-rabbit-client/WEB-INF/lib/cglib-nodep-2.2.jar <no signer certificates>
                // But if the type 'com/vmware/rabbit/ApplicationContext' is reloadable, then this should be too
                boolean makeReloadableAnyway = false;
                int cglibIndex = slashedClassName.indexOf("$$EnhancerBy");
                if (cglibIndex != -1) {
                    String originalType = slashedClassName.substring(0, cglibIndex);
                    if (GlobalConfiguration.isRuntimeLogging && log.isLoggable(Level.INFO)) {
                        log.info("Appears to be a CGLIB type, checking if type " + originalType + " is reloadable");
                    }
                    TypeRegistry currentRegistry = typeRegistry;
                    while (currentRegistry != null) {
                        ReloadableType originalReloadable = currentRegistry.getReloadableType(originalType);
                        if (originalReloadable != null) {
                            makeReloadableAnyway = true;
                            break;
                        }
                        currentRegistry = currentRegistry.getParentRegistry();
                    }
                //						if (typeRegistry.isReloadableTypeName(originalType)) {
                //							if (GlobalConfiguration.isRuntimeLogging && log.isLoggable(Level.INFO)) {
                //								log.info("Type " + originalType + " is reloadable, so making CGLIB type " + slashedClassName
                //										+ " reloadable");
                //							}
                //							makeReloadableAnyway = true;
                //						}
                }
                int cglibIndex2 = makeReloadableAnyway ? -1 : slashedClassName.indexOf("$$FastClassByCGLIB");
                if (cglibIndex2 != -1) {
                    String originalType = slashedClassName.substring(0, cglibIndex2);
                    if (GlobalConfiguration.isRuntimeLogging && log.isLoggable(Level.INFO)) {
                        log.info("Appears to be a CGLIB FastClass type, checking if type " + originalType + " is reloadable");
                    }
                    TypeRegistry currentRegistry = typeRegistry;
                    while (currentRegistry != null) {
                        ReloadableType originalReloadable = currentRegistry.getReloadableType(originalType);
                        if (originalReloadable != null) {
                            makeReloadableAnyway = true;
                            break;
                        }
                        currentRegistry = currentRegistry.getParentRegistry();
                    }
                //						if (typeRegistry.isReloadableTypeName(originalType)) {
                //							if (GlobalConfiguration.isRuntimeLogging && log.isLoggable(Level.INFO)) {
                //								log.info("Type " + originalType + " is reloadable, so making CGLIB type " + slashedClassName
                //										+ " reloadable");
                //							}
                //							makeReloadableAnyway = true;
                //						}
                }
                int proxyIndex = makeReloadableAnyway ? -1 : slashedClassName.indexOf("$Proxy");
                if (proxyIndex == 0 || (proxyIndex > 0 && slashedClassName.charAt(proxyIndex - 1) == '/')) {
                    // Determine if the interfaces being implemented are reloadable
                    String[] interfacesImplemented = Utils.discoverInterfaces(bytes);
                    if (interfacesImplemented != null) {
                        for (int i = 0; i < interfacesImplemented.length; i++) {
                            TypeRegistry currentRegistry = typeRegistry;
                            while (currentRegistry != null) {
                                ReloadableType originalReloadable = currentRegistry.getReloadableType(interfacesImplemented[i]);
                                if (originalReloadable != null) {
                                    makeReloadableAnyway = true;
                                    break;
                                }
                                currentRegistry = currentRegistry.getParentRegistry();
                            }
                        //								if (typeRegistry.isReloadableTypeName(interfacesImplemented[i])) {
                        //									makeReloadableAnyway = true;
                        //								}
                        }
                    }
                }
                // all classloaders below one loading reloadable stuff should also load reloadable stuff.
                if (!makeReloadableAnyway && classLoader.getClass().getName().endsWith("GroovyClassLoader$InnerLoader")) {
                    makeReloadableAnyway = true;
                }
                if (!makeReloadableAnyway) {
                    //						else {
                    if (GlobalConfiguration.verboseMode) {
                        Log.log("Cannot watch " + slashedClassName + ": not making it reloadable");
                    }
                    if (needsClientSideRewriting(slashedClassName)) {
                        bytes = typeRegistry.methodCallRewriteUseCacheIfAvailable(slashedClassName, bytes);
                    }
                    return bytes;
                //						}
                }
            }
            ReloadableType rtype = typeRegistry.addType(dottedClassName, bytes);
            if (rtype == null && GlobalConfiguration.callsideRewritingOn) {
                // it is not a candidate for being made reloadable (maybe it is an annotation type)
                // but we still need to rewrite call sites.
                bytes = typeRegistry.methodCallRewrite(bytes);
            } else {
                if (GlobalConfiguration.fileSystemMonitoring && watchPath != null) {
                    typeRegistry.monitorForUpdates(rtype, watchPath);
                }
                return rtype.bytesLoaded;
            }
        } catch (RuntimeException re) {
            log.throwing("SpringLoadedPreProcessor", "preProcess", re);
            throw re;
        }
    } else {
        try {
            // with due to GroovyPlugin class that intercepts define in that infrastructure
            if (needsClientSideRewriting(slashedClassName) && (classLoader == null || !classLoader.getClass().getName().equals("org.codehaus.groovy.runtime.callsite.CallSiteClassLoader"))) {
                bytes = typeRegistry.methodCallRewriteUseCacheIfAvailable(slashedClassName, bytes);
            }
        } catch (Throwable t) {
            log.log(Level.SEVERE, "Unexpected problem transforming call sites", t);
        }
    }
    return bytes;
}
Also used : LoadtimeInstrumentationPlugin(org.springsource.loaded.LoadtimeInstrumentationPlugin) TypeRegistry(org.springsource.loaded.TypeRegistry) ReloadableTypeNameDecision(org.springsource.loaded.TypeRegistry.ReloadableTypeNameDecision) ReloadableType(org.springsource.loaded.ReloadableType) RewriteResult(org.springsource.loaded.SystemClassReflectionRewriter.RewriteResult) LoadtimeInstrumentationPlugin(org.springsource.loaded.LoadtimeInstrumentationPlugin) IsReloadableTypePlugin(org.springsource.loaded.IsReloadableTypePlugin) Plugin(org.springsource.loaded.Plugin)

Example 2 with LoadtimeInstrumentationPlugin

use of org.springsource.loaded.LoadtimeInstrumentationPlugin in project spring-loaded by spring-projects.

the class SuperLoader method findClass.

public Class<?> findClass(String name) throws ClassNotFoundException {
    if (SubLoader.DEBUG_LOADING) {
        System.out.println("> SuperLoader: findClass(" + name + ")");
    }
    Class<?> c = null;
    // Look in the filesystem first
    try {
        for (int i = 0; i < folders.length; i++) {
            File f = new File(folders[i], name.replace('.', '/') + ".class");
            if (f.exists()) {
                byte[] data = Utils.loadBytesFromStream(new FileInputStream(f));
                TypeRegistry tr = TypeRegistry.getTypeRegistryFor(this);
                if (tr != null) {
                    // not yet doing this - the testcase tends to do any client side rewriting for this
                    ReloadableType rtype = tr.addType(name, data);
                    data = rtype.bytesLoaded;
                }
                if (SubLoader.DEBUG_LOADING) {
                    System.out.println("  SuperLoader: found in folder: '" + folders[i] + "'");
                }
                c = defineClass(name, data, 0, data.length);
                break;
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    if (c == null) {
        // Try the jar
        try {
            for (int i = 0; i < jars.length; i++) {
                // System.out.println("Checking jar for "+name);
                ZipFile zipfile = new ZipFile(jars[i]);
                String slashedClassName = name.replace('.', '/');
                ZipEntry zipentry = zipfile.getEntry(slashedClassName + ".class");
                if (zipentry != null) {
                    byte[] data = Utils.loadBytesFromStream(zipfile.getInputStream(zipentry));
                    TypeRegistry tr = TypeRegistry.getTypeRegistryFor(this);
                    //						data = new SpringLoadedPreProcessor().preProcess(this, slashedClassName, null, data);
                    if (tr != null) {
                        // Give the plugins a chance to rewrite stuff too
                        for (org.springsource.loaded.Plugin plugin : SpringLoadedPreProcessor.getGlobalPlugins()) {
                            if (plugin instanceof LoadtimeInstrumentationPlugin) {
                                LoadtimeInstrumentationPlugin loadtimeInstrumentationPlugin = (LoadtimeInstrumentationPlugin) plugin;
                                if (loadtimeInstrumentationPlugin.accept(slashedClassName, this, null, data)) {
                                    data = loadtimeInstrumentationPlugin.modify(slashedClassName, this, data);
                                }
                            }
                        }
                        //System.out.println("Transforming " + name);
                        data = tr.methodCallRewrite(data);
                    }
                    if (SubLoader.DEBUG_LOADING) {
                        System.out.println("  SuperLoader: found in zip: '" + jars[i] + "'");
                    }
                    c = defineClass(name, data, 0, data.length);
                    break;
                }
                zipfile.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    if (c == null) {
        throw new ClassNotFoundException(name);
    }
    return c;
}
Also used : LoadtimeInstrumentationPlugin(org.springsource.loaded.LoadtimeInstrumentationPlugin) ZipEntry(java.util.zip.ZipEntry) TypeRegistry(org.springsource.loaded.TypeRegistry) FileInputStream(java.io.FileInputStream) IOException(java.io.IOException) ReloadableType(org.springsource.loaded.ReloadableType) ZipFile(java.util.zip.ZipFile) File(java.io.File) ZipFile(java.util.zip.ZipFile)

Example 3 with LoadtimeInstrumentationPlugin

use of org.springsource.loaded.LoadtimeInstrumentationPlugin in project spring-loaded by spring-projects.

the class TestClassloaderWithRewriting method findClass.

public Class<?> findClass(String name) throws ClassNotFoundException {
    Class<?> c = null;
    // Look in the filesystem first
    try {
        for (int i = 0; i < folders.length; i++) {
            File f = new File(folders[i], name.replace('.', '/') + ".class");
            if (f.exists()) {
                byte[] data = Utils.loadBytesFromStream(new FileInputStream(f));
                TypeRegistry tr = TypeRegistry.getTypeRegistryFor(this);
                if (tr != null) {
                    if (useRegistry) {
                        ReloadableType rt = tr.addType(name, data);
                        if (rt == null) {
                            System.out.println("Not made reloadable " + name);
                        } else {
                            return rt.getClazz();
                        }
                    }
                // not yet doing this - the testcase tends to do any client side rewriting for this
                }
                c = defineClass(name, data, 0, data.length);
                break;
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    Exception ex = null;
    if (c == null) {
        // Try the jar
        try {
            for (int i = 0; i < jars.length; i++) {
                // System.out.println("Checking jar for "+name);
                ZipFile zipfile = new ZipFile(jars[i]);
                String slashedClassName = name.replace('.', '/');
                ZipEntry zipentry = zipfile.getEntry(slashedClassName + ".class");
                if (zipentry != null) {
                    byte[] data = Utils.loadBytesFromStream(zipfile.getInputStream(zipentry));
                    TypeRegistry tr = TypeRegistry.getTypeRegistryFor(this);
                    if (tr != null) {
                        // Give the plugins a chance to rewrite stuff too
                        for (org.springsource.loaded.Plugin plugin : SpringLoadedPreProcessor.getGlobalPlugins()) {
                            if (plugin instanceof LoadtimeInstrumentationPlugin) {
                                LoadtimeInstrumentationPlugin loadtimeInstrumentationPlugin = (LoadtimeInstrumentationPlugin) plugin;
                                if (loadtimeInstrumentationPlugin.accept(slashedClassName, this, null, data)) {
                                    data = loadtimeInstrumentationPlugin.modify(slashedClassName, this, data);
                                }
                            }
                        }
                        // TODO make conditional?
                        if (slashedClassName.equals("net/sf/cglib/core/ReflectUtils")) {
                            // intercept call to defineclass so we can make it reloadable.  In practice this isn't necessary
                            // as the springloadedpreprocessor will get called
                            data = RewriteReflectUtilsDefineClass.rewriteReflectUtilsDefineClass(data);
                        }
                        //System.out.println("Transforming " + name);
                        data = tr.methodCallRewrite(data);
                    }
                    c = defineClass(name, data, 0, data.length);
                    break;
                }
            }
        // zipfile.close();
        } catch (Exception e) {
            ex = e;
            e.printStackTrace(System.err);
        }
    }
    if (c == null) {
        if (ex != null) {
            throw new ClassNotFoundException(name, ex);
        } else {
            throw new ClassNotFoundException(name);
        }
    }
    return c;
}
Also used : LoadtimeInstrumentationPlugin(org.springsource.loaded.LoadtimeInstrumentationPlugin) ZipEntry(java.util.zip.ZipEntry) TypeRegistry(org.springsource.loaded.TypeRegistry) FileInputStream(java.io.FileInputStream) IOException(java.io.IOException) ReloadableType(org.springsource.loaded.ReloadableType) ZipFile(java.util.zip.ZipFile) File(java.io.File) ZipFile(java.util.zip.ZipFile)

Example 4 with LoadtimeInstrumentationPlugin

use of org.springsource.loaded.LoadtimeInstrumentationPlugin in project spring-loaded by spring-projects.

the class SubLoader method findClass.

public Class<?> findClass(String name) throws ClassNotFoundException {
    //		System.out.println(">> SubLoader.findClass(" + name + ")");
    Class<?> c = null;
    // Look in the filesystem first
    try {
        for (int i = 0; i < folders.length; i++) {
            File f = new File(folders[i], name.replace('.', '/') + ".class");
            if (f.exists()) {
                byte[] data = Utils.loadBytesFromStream(new FileInputStream(f));
                TypeRegistry tr = TypeRegistry.getTypeRegistryFor(this);
                if (tr != null) {
                    // not yet doing this - the testcase tends to do any client side rewriting for this
                    ReloadableType rtype = tr.addType(name, data);
                    data = rtype.bytesLoaded;
                }
                c = defineClass(name, data, 0, data.length);
                break;
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
        throw new RuntimeException("Problem defining class", e);
    }
    if (c == null) {
        // Try the jar
        try {
            for (int i = 0; i < jars.length; i++) {
                // System.out.println("Checking jar for "+name);
                ZipFile zipfile = new ZipFile(jars[i]);
                String slashedClassName = name.replace('.', '/');
                ZipEntry zipentry = zipfile.getEntry(slashedClassName + ".class");
                if (zipentry != null) {
                    byte[] data = Utils.loadBytesFromStream(zipfile.getInputStream(zipentry));
                    TypeRegistry tr = TypeRegistry.getTypeRegistryFor(this);
                    if (tr != null) {
                        // Give the plugins a chance to rewrite stuff too
                        for (org.springsource.loaded.Plugin plugin : SpringLoadedPreProcessor.getGlobalPlugins()) {
                            if (plugin instanceof LoadtimeInstrumentationPlugin) {
                                LoadtimeInstrumentationPlugin loadtimeInstrumentationPlugin = (LoadtimeInstrumentationPlugin) plugin;
                                if (loadtimeInstrumentationPlugin.accept(slashedClassName, this, null, data)) {
                                    data = loadtimeInstrumentationPlugin.modify(slashedClassName, this, data);
                                }
                            }
                        }
                        //System.out.println("Transforming " + name);
                        data = tr.methodCallRewrite(data);
                    }
                    c = defineClass(name, data, 0, data.length);
                    break;
                }
                zipfile.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("Problem defining class", e);
        }
    }
    if (c == null) {
        throw new ClassNotFoundException(name);
    }
    return c;
}
Also used : LoadtimeInstrumentationPlugin(org.springsource.loaded.LoadtimeInstrumentationPlugin) ZipEntry(java.util.zip.ZipEntry) TypeRegistry(org.springsource.loaded.TypeRegistry) FileInputStream(java.io.FileInputStream) IOException(java.io.IOException) ReloadableType(org.springsource.loaded.ReloadableType) ZipFile(java.util.zip.ZipFile) File(java.io.File) ZipFile(java.util.zip.ZipFile)

Aggregations

LoadtimeInstrumentationPlugin (org.springsource.loaded.LoadtimeInstrumentationPlugin)4 ReloadableType (org.springsource.loaded.ReloadableType)4 TypeRegistry (org.springsource.loaded.TypeRegistry)4 File (java.io.File)3 FileInputStream (java.io.FileInputStream)3 IOException (java.io.IOException)3 ZipEntry (java.util.zip.ZipEntry)3 ZipFile (java.util.zip.ZipFile)3 IsReloadableTypePlugin (org.springsource.loaded.IsReloadableTypePlugin)1 Plugin (org.springsource.loaded.Plugin)1 RewriteResult (org.springsource.loaded.SystemClassReflectionRewriter.RewriteResult)1 ReloadableTypeNameDecision (org.springsource.loaded.TypeRegistry.ReloadableTypeNameDecision)1