Search in sources :

Example 1 with NewClassData

use of org.fakereplace.api.NewClassData 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 2 with NewClassData

use of org.fakereplace.api.NewClassData in project fakereplace by fakereplace.

the class ResteasyClassChangeAware method afterChange.

@Override
public void afterChange(final List<ChangedClass> changed, final List<NewClassData> added) {
    boolean requiresRestart = false;
    ClassLoader classLoader = null;
    for (final ChangedClass c : changed) {
        if (!c.getChangedAnnotationsByType(Path.class).isEmpty() || c.getChangedClass().isAnnotationPresent(Path.class)) {
            requiresRestart = true;
            classLoader = c.getChangedClass().getClassLoader();
            break;
        }
    }
    Set<String> addedResources = new HashSet<>();
    for (NewClassData add : added) {
        AnnotationsAttribute attribute = (AnnotationsAttribute) add.getClassFile().getAttribute(AnnotationsAttribute.visibleTag);
        if (attribute == null) {
            continue;
        }
        if (attribute.getAnnotation(Path.class.getName()) != null) {
            addedResources.add(add.getClassName());
            requiresRestart = true;
        }
        if (classLoader == null) {
            classLoader = add.getClassLoader();
        }
    }
    if (requiresRestart) {
        for (final Object servlet : InstanceTracker.get(ResteasyExtension.SERVLET_DISPATCHER)) {
            try {
                final ResteasyServletConfig config = (ResteasyServletConfig) servlet.getClass().getField(ResteasyTransformer.FIELD_NAME).get(servlet);
                if (config.getClassLoader() == classLoader) {
                    StringBuilder res = new StringBuilder(config.getServletContext().getInitParameter(RESOURCES));
                    for (String add : addedResources) {
                        res.append(",").append(add);
                    }
                    ResteasyServletContext sc = new ResteasyServletContext(config.getServletContext());
                    sc.getInitParams().put(RESOURCES, res.toString());
                    config.setServletContext(sc);
                    final Set<String> doNotClear = (Set<String>) servlet.getClass().getField(ResteasyTransformer.PARAMETER_FIELD_NAME).get(servlet);
                    clearContext(config.getServletContext(), doNotClear);
                    final ClassLoader old = Thread.currentThread().getContextClassLoader();
                    Thread.currentThread().setContextClassLoader(classLoader);
                    try {
                        servlet.getClass().getMethod("destroy").invoke(servlet);
                        servlet.getClass().getMethod("init", ServletConfig.class).invoke(servlet, config);
                    } finally {
                        Thread.currentThread().setContextClassLoader(old);
                    }
                }
            } catch (Exception e) {
                logger.debug("Could not restart RESTeasy", e);
            }
        }
        for (final Object filter : InstanceTracker.get(ResteasyExtension.FILTER_DISPATCHER)) {
            try {
                final ResteasyFilterConfig config = (ResteasyFilterConfig) filter.getClass().getField(ResteasyTransformer.FIELD_NAME).get(filter);
                if (config.getClassLoader() == classLoader) {
                    StringBuilder res = new StringBuilder((String) config.getServletContext().getAttribute(RESOURCES));
                    for (String add : addedResources) {
                        res.append(",").append(add);
                    }
                    ResteasyServletContext sc = new ResteasyServletContext(config.getServletContext());
                    sc.getInitParams().put(RESOURCES, res.toString());
                    config.setServletContext(sc);
                    final Set<String> doNotClear = (Set<String>) filter.getClass().getField(ResteasyTransformer.PARAMETER_FIELD_NAME).get(filter);
                    clearContext(config.getServletContext(), doNotClear);
                    final ClassLoader old = Thread.currentThread().getContextClassLoader();
                    Thread.currentThread().setContextClassLoader(classLoader);
                    try {
                        filter.getClass().getMethod("destroy").invoke(filter);
                        filter.getClass().getMethod("init", FilterConfig.class).invoke(filter, config);
                    } finally {
                        Thread.currentThread().setContextClassLoader(old);
                    }
                }
            } catch (Exception e) {
                logger.debug("Could not restart RESTeasy", e);
            }
        }
    }
}
Also used : Path(javax.ws.rs.Path) Set(java.util.Set) HashSet(java.util.HashSet) AnnotationsAttribute(javassist.bytecode.AnnotationsAttribute) ServletConfig(javax.servlet.ServletConfig) NewClassData(org.fakereplace.api.NewClassData) FilterConfig(javax.servlet.FilterConfig) ChangedClass(org.fakereplace.api.ChangedClass) HashSet(java.util.HashSet)

Aggregations

HashSet (java.util.HashSet)2 NewClassData (org.fakereplace.api.NewClassData)2 ByteArrayInputStream (java.io.ByteArrayInputStream)1 DataInputStream (java.io.DataInputStream)1 DataOutputStream (java.io.DataOutputStream)1 FileOutputStream (java.io.FileOutputStream)1 IOException (java.io.IOException)1 ClassDefinition (java.lang.instrument.ClassDefinition)1 UnmodifiableClassException (java.lang.instrument.UnmodifiableClassException)1 Set (java.util.Set)1 AnnotationsAttribute (javassist.bytecode.AnnotationsAttribute)1 ClassFile (javassist.bytecode.ClassFile)1 FilterConfig (javax.servlet.FilterConfig)1 ServletConfig (javax.servlet.ServletConfig)1 Path (javax.ws.rs.Path)1 ChangedClass (org.fakereplace.api.ChangedClass)1 BaseClassData (org.fakereplace.data.BaseClassData)1 ClassDataBuilder (org.fakereplace.data.ClassDataBuilder)1 AddedClass (org.fakereplace.replacement.AddedClass)1