Search in sources :

Example 1 with AddedClass

use of org.fakereplace.replacement.AddedClass in project fakereplace by fakereplace.

the class WildflyAutoUpdate method runUpdate.

public static synchronized Result runUpdate(ModuleClassLoader classLoader) {
    String moduleName = classLoader.getModule().getIdentifier().getName();
    if (moduleName.startsWith(DEPLOYMENT)) {
        moduleName = moduleName.substring(DEPLOYMENT.length());
    }
    String sourcePaths = System.getProperty(FAKEREPLACE_SOURCE_PATHS + moduleName);
    if (sourcePaths == null) {
        return Result.NO_CHANGE;
    }
    List<Path> paths = Arrays.stream(sourcePaths.split(",")).map((s) -> Paths.get(s)).collect(Collectors.toList());
    try {
        for (Path base : paths) {
            final Map<String, Long> timestamps = new HashMap<>();
            scan(base, base, timestamps);
            List<String> toUpdate = new ArrayList<>();
            List<String> added = new ArrayList<>();
            List<String> replace = new ArrayList<>();
            for (Map.Entry<String, Long> entry : timestamps.entrySet()) {
                String name = entry.getKey();
                if (name.endsWith(".java")) {
                    String baseName = name.substring(0, name.length() - 5);
                    Long last = replacedTimestamps.get(baseName);
                    if (last != null) {
                        if (last < entry.getValue()) {
                            toUpdate.add(baseName);
                            replacedTimestamps.put(baseName, entry.getValue());
                            replace.add(baseName);
                        }
                    } else {
                        URL res = classLoader.getResource(baseName + ".class");
                        if (res != null) {
                            URLConnection con = res.openConnection();
                            long lm = con.getLastModified();
                            if (lm < entry.getValue()) {
                                toUpdate.add(baseName);
                                replacedTimestamps.put(baseName, entry.getValue());
                                replace.add(baseName);
                            }
                        } else {
                            toUpdate.add(baseName);
                            replacedTimestamps.put(baseName, entry.getValue());
                            added.add(baseName);
                        }
                    }
                }
            }
            if (!toUpdate.isEmpty()) {
                System.out.println("Fakereplace detected the following source files have been changed: " + toUpdate);
                ClassLoaderCompiler compiler = new ClassLoaderCompiler(classLoader, base, toUpdate);
                compiler.compile();
                Map<String, byte[]> byteMap = REPLACED_CLASSES.computeIfAbsent(classLoader, k -> new HashMap<>());
                AddedClass[] addedClass = new AddedClass[added.size()];
                for (int i = 0; i < added.size(); ++i) {
                    String className = added.get(i);
                    addedClass[i] = new AddedClass(className, compiler.getOutput().get(className).toByteArray(), classLoader);
                    byteMap.put(className, compiler.getOutput().get(className).toByteArray());
                }
                ClassDefinition[] classDefinition = new ClassDefinition[replace.size()];
                for (int i = 0; i < replace.size(); ++i) {
                    String className = replace.get(i);
                    classDefinition[i] = new ClassDefinition(classLoader.loadClass(className.replace("/", ".")), compiler.getOutput().get(className).toByteArray());
                    byteMap.put(className, compiler.getOutput().get(className).toByteArray());
                }
                try {
                    Fakereplace.redefine(classDefinition, addedClass);
                } catch (Exception e) {
                    System.err.println("Hot replace failed, redeploy required" + e.getMessage());
                    return Result.REDEPLOY_REQUIRED;
                }
                return Result.RELOAD;
            }
        }
        return Result.NO_CHANGE;
    } catch (Exception e) {
        System.err.println("Check for updated classes failed");
        e.printStackTrace();
    } finally {
        // something in the compiler clears the TCCL, fix it up
        Thread.currentThread().setContextClassLoader(classLoader);
    }
    return Result.NO_CHANGE;
}
Also used : Path(java.nio.file.Path) Arrays(java.util.Arrays) Files(java.nio.file.Files) URL(java.net.URL) IOException(java.io.IOException) HashMap(java.util.HashMap) Collectors(java.util.stream.Collectors) ArrayList(java.util.ArrayList) ClassDefinition(java.lang.instrument.ClassDefinition) List(java.util.List) Fakereplace(org.fakereplace.core.Fakereplace) Paths(java.nio.file.Paths) URLConnection(java.net.URLConnection) Map(java.util.Map) ModuleClassLoader(org.jboss.modules.ModuleClassLoader) Path(java.nio.file.Path) WeakHashMap(java.util.WeakHashMap) AddedClass(org.fakereplace.replacement.AddedClass) HashMap(java.util.HashMap) WeakHashMap(java.util.WeakHashMap) ArrayList(java.util.ArrayList) AddedClass(org.fakereplace.replacement.AddedClass) ClassDefinition(java.lang.instrument.ClassDefinition) URL(java.net.URL) URLConnection(java.net.URLConnection) IOException(java.io.IOException) HashMap(java.util.HashMap) Map(java.util.Map) WeakHashMap(java.util.WeakHashMap)

Example 2 with AddedClass

use of org.fakereplace.replacement.AddedClass in project fakereplace by fakereplace.

the class ClassReplacer method replaceQueuedClasses.

public void replaceQueuedClasses(boolean useFakereplace) {
    try {
        ClassDefinition[] definitions = new ClassDefinition[queuedClassReplacements.size()];
        AddedClass[] newClasses = new AddedClass[addedClasses.size()];
        for (Class<?> o : queuedClassReplacements.keySet()) {
            Class<?> n = queuedClassReplacements.get(o);
            String newName = o.getName();
            String oldName = n.getName();
            nameReplacements.put(oldName, newName);
        }
        for (Entry<Class<?>, String> o : addedClasses.entrySet()) {
            nameReplacements.put(o.getKey().getName(), o.getValue());
        }
        int count = 0;
        for (Class<?> o : queuedClassReplacements.keySet()) {
            Class<?> n = queuedClassReplacements.get(o);
            CtClass nc = pool.get(n.getName());
            if (nc.isFrozen()) {
                nc.defrost();
            }
            for (String oldName : nameReplacements.keySet()) {
                String newName = nameReplacements.get(oldName);
                nc.replaceClassName(oldName, newName);
            }
            nc.setName(o.getName());
            ClassDefinition cd = new ClassDefinition(o, nc.toBytecode());
            definitions[count++] = cd;
        }
        count = 0;
        for (Entry<Class<?>, String> o : addedClasses.entrySet()) {
            CtClass nc = pool.get(o.getKey().getName());
            if (nc.isFrozen()) {
                nc.defrost();
            }
            for (String newName : nameReplacements.keySet()) {
                String oldName = nameReplacements.get(newName);
                nc.replaceClassName(newName, oldName);
            }
            AddedClass ncd = new AddedClass(o.getValue(), nc.toBytecode(), o.getKey().getClassLoader());
            newClasses[count++] = ncd;
        }
        if (useFakereplace) {
            Fakereplace.redefine(definitions, newClasses);
        } else {
            Fakereplace.getInstrumentation().redefineClasses(definitions);
        }
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}
Also used : CtClass(javassist.CtClass) CtClass(javassist.CtClass) AddedClass(org.fakereplace.replacement.AddedClass) AddedClass(org.fakereplace.replacement.AddedClass) ClassDefinition(java.lang.instrument.ClassDefinition)

Example 3 with AddedClass

use of org.fakereplace.replacement.AddedClass in project fakereplace by fakereplace.

the class FakeReplaceServlet method doPost.

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    try {
        ObjectInputStream in = new ObjectInputStream(req.getInputStream());
        String deployment = in.readUTF();
        ServiceController<DeploymentUnit> deploymentService = deploymentService(deployment);
        Module module = deploymentService.getValue().getAttachment(Attachments.MODULE);
        int size = in.readInt();
        ClassDefinition[] definitions = new ClassDefinition[size];
        for (int i = 0; i < size; ++i) {
            String className = in.readUTF();
            byte[] data = (byte[]) in.readObject();
            Class clazz = module.getClassLoader().loadClass(className);
            ClassDefinition d = new ClassDefinition(clazz, data);
            definitions[i] = d;
        }
        size = in.readInt();
        AddedClass[] added = new AddedClass[size];
        for (int i = 0; i < size; ++i) {
            String className = in.readUTF();
            byte[] data = (byte[]) in.readObject();
            added[i] = new AddedClass(className, data, module.getClassLoader());
        }
        size = in.readInt();
        Map<String, byte[]> resources = new HashMap<>();
        for (int i = 0; i < size; ++i) {
            String resourceName = in.readUTF();
            byte[] data = (byte[]) in.readObject();
            resources.put(resourceName, data);
        }
        updateResource(resources, deploymentService);
        Fakereplace.redefine(definitions, added);
    } catch (ClassNotFoundException e) {
        throw new ServletException(e);
    }
}
Also used : HashMap(java.util.HashMap) AddedClass(org.fakereplace.replacement.AddedClass) ClassDefinition(java.lang.instrument.ClassDefinition) ServletException(javax.servlet.ServletException) AddedClass(org.fakereplace.replacement.AddedClass) Module(org.jboss.modules.Module) DeploymentUnit(org.jboss.as.server.deployment.DeploymentUnit) ObjectInputStream(java.io.ObjectInputStream)

Example 4 with AddedClass

use of org.fakereplace.replacement.AddedClass in project fakereplace by fakereplace.

the class Fakereplace method redefine.

public static void redefine(ClassDefinition[] classes, AddedClass[] addedData, boolean wait) {
    try {
        for (AddedClass i : addedData) {
            ClassFile cf = new ClassFile(new DataInputStream(new ByteArrayInputStream(i.getData())));
            mainTransformer.addNewClass(new NewClassData(i.getClassName(), i.getLoader(), cf));
        }
        for (ClassDefinition i : classes) {
            ClassDataStore.instance().markClassReplaced(i.getDefinitionClass());
            BaseClassData baseClassData = ClassDataStore.instance().getBaseClassData(i.getDefinitionClass().getClassLoader(), i.getDefinitionClass().getName());
            if (baseClassData != null) {
                ClassDataStore.instance().saveClassData(i.getDefinitionClass().getClassLoader(), i.getDefinitionClass().getName(), new ClassDataBuilder(baseClassData));
            }
        }
        for (AddedClass c : addedData) {
            ClassLookupManager.addClassInfo(c.getClassName(), c.getLoader(), c.getData());
        }
        inst.redefineClasses(classes);
        clearJvmCaches();
        if (wait) {
            mainTransformer.waitForTasks();
        }
    } catch (Throwable e) {
        try {
            // dump the classes to /tmp so we can look at them
            for (ClassDefinition d : classes) {
                try {
                    ByteArrayInputStream bin = new ByteArrayInputStream(d.getDefinitionClassFile());
                    DataInputStream dis = new DataInputStream(bin);
                    final ClassFile file = new ClassFile(dis);
                    Transformer.getManipulator().transformClass(file, d.getDefinitionClass().getClassLoader(), true, new HashSet<>());
                    String dumpDir = AgentOptions.getOption(AgentOption.DUMP_DIR);
                    if (dumpDir != null) {
                        FileOutputStream s = new FileOutputStream(dumpDir + '/' + d.getDefinitionClass().getName() + "1.class");
                        DataOutputStream dos = new DataOutputStream(s);
                        file.write(dos);
                        dos.flush();
                        dos.close();
                        // s.write(d.getDefinitionClassFile());
                        s.close();
                    }
                } catch (IOException a) {
                    a.printStackTrace();
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        throw (new RuntimeException(e));
    }
}
Also used : ClassFile(javassist.bytecode.ClassFile) DataOutputStream(java.io.DataOutputStream) AddedClass(org.fakereplace.replacement.AddedClass) IOException(java.io.IOException) DataInputStream(java.io.DataInputStream) ClassDefinition(java.lang.instrument.ClassDefinition) ClassDataBuilder(org.fakereplace.data.ClassDataBuilder) IOException(java.io.IOException) UnmodifiableClassException(java.lang.instrument.UnmodifiableClassException) BaseClassData(org.fakereplace.data.BaseClassData) ByteArrayInputStream(java.io.ByteArrayInputStream) NewClassData(org.fakereplace.api.NewClassData) FileOutputStream(java.io.FileOutputStream) HashSet(java.util.HashSet)

Example 5 with AddedClass

use of org.fakereplace.replacement.AddedClass in project fakereplace by fakereplace.

the class ClassReplacer method replaceQueuedClasses.

public void replaceQueuedClasses(boolean useFakereplace) {
    try {
        ClassDefinition[] definitions = new ClassDefinition[queuedClassReplacements.size()];
        AddedClass[] newClasses = new AddedClass[addedClasses.size()];
        for (Class<?> o : queuedClassReplacements.keySet()) {
            Class<?> n = queuedClassReplacements.get(o);
            String newName = o.getName();
            String oldName = n.getName();
            nameReplacements.put(oldName, newName);
        }
        for (Entry<Class<?>, String> o : addedClasses.entrySet()) {
            nameReplacements.put(o.getKey().getName(), o.getValue());
        }
        int count = 0;
        for (Class<?> o : queuedClassReplacements.keySet()) {
            Class<?> n = queuedClassReplacements.get(o);
            CtClass nc = pool.get(n.getName());
            if (nc.isFrozen()) {
                nc.defrost();
            }
            for (String oldName : nameReplacements.keySet()) {
                String newName = nameReplacements.get(oldName);
                nc.replaceClassName(oldName, newName);
            }
            nc.setName(o.getName());
            ClassDefinition cd = new ClassDefinition(o, nc.toBytecode());
            definitions[count++] = cd;
        }
        count = 0;
        for (Entry<Class<?>, String> o : addedClasses.entrySet()) {
            CtClass nc = pool.get(o.getKey().getName());
            if (nc.isFrozen()) {
                nc.defrost();
            }
            for (String newName : nameReplacements.keySet()) {
                String oldName = nameReplacements.get(newName);
                nc.replaceClassName(newName, oldName);
            }
            AddedClass ncd = new AddedClass(o.getValue(), nc.toBytecode(), o.getKey().getClassLoader());
            newClasses[count++] = ncd;
        }
        if (useFakereplace) {
            Fakereplace.redefine(definitions, newClasses);
        } else {
            Fakereplace.getInstrumentation().redefineClasses(definitions);
        }
        queuedClassReplacements.clear();
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}
Also used : CtClass(javassist.CtClass) CtClass(javassist.CtClass) AddedClass(org.fakereplace.replacement.AddedClass) AddedClass(org.fakereplace.replacement.AddedClass) ClassDefinition(java.lang.instrument.ClassDefinition)

Aggregations

ClassDefinition (java.lang.instrument.ClassDefinition)5 AddedClass (org.fakereplace.replacement.AddedClass)5 IOException (java.io.IOException)2 HashMap (java.util.HashMap)2 CtClass (javassist.CtClass)2 ByteArrayInputStream (java.io.ByteArrayInputStream)1 DataInputStream (java.io.DataInputStream)1 DataOutputStream (java.io.DataOutputStream)1 FileOutputStream (java.io.FileOutputStream)1 ObjectInputStream (java.io.ObjectInputStream)1 UnmodifiableClassException (java.lang.instrument.UnmodifiableClassException)1 URL (java.net.URL)1 URLConnection (java.net.URLConnection)1 Files (java.nio.file.Files)1 Path (java.nio.file.Path)1 Paths (java.nio.file.Paths)1 ArrayList (java.util.ArrayList)1 Arrays (java.util.Arrays)1 HashSet (java.util.HashSet)1 List (java.util.List)1