Search in sources :

Example 1 with ChangedClass

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

the class MainTransformer method transform.

@Override
public byte[] transform(final ClassLoader loader, final String className, final Class<?> classBeingRedefined, final ProtectionDomain protectionDomain, final byte[] classfileBuffer) throws IllegalClassFormatException {
    if (className == null) {
        // TODO: deal with lambdas
        return classfileBuffer;
    }
    boolean replaceable = Fakereplace.isClassReplaceable(className, loader);
    if (classBeingRedefined != null) {
        retransformationStarted = true;
        if (logClassRetransformation && replaceable) {
            log.info("Fakereplace is replacing class " + className);
        }
    }
    ChangedClassImpl changedClass = null;
    if (classBeingRedefined != null) {
        changedClass = new ChangedClassImpl(classBeingRedefined);
    }
    boolean changed = false;
    if (!replaceable && UnmodifiedFileIndex.isClassUnmodified(className)) {
        return null;
    }
    Set<Class<?>> classesToRetransform = new HashSet<>();
    final ClassFile file;
    try {
        Set<MethodInfo> modifiedMethods = new HashSet<>();
        file = new ClassFile(new DataInputStream(new ByteArrayInputStream(classfileBuffer)));
        for (final FakereplaceTransformer transformer : transformers) {
            if (transformer.transform(loader, className, classBeingRedefined, protectionDomain, file, classesToRetransform, changedClass, modifiedMethods)) {
                changed = true;
            }
        }
        if (!changed) {
            UnmodifiedFileIndex.markClassUnmodified(className);
            return null;
        } else {
            try {
                if (!modifiedMethods.isEmpty()) {
                    ClassPool classPool = new ClassPool();
                    if (loader == null) {
                        classPool.appendClassPath(new LoaderClassPath(ClassLoader.getSystemClassLoader()));
                    } else {
                        classPool.appendClassPath(new LoaderClassPath(loader));
                    }
                    classPool.appendSystemPath();
                    for (MethodInfo method : modifiedMethods) {
                        if (method.getCodeAttribute() != null) {
                            method.getCodeAttribute().computeMaxStack();
                            try {
                                method.rebuildStackMap(classPool);
                            } catch (BadBytecode e) {
                                Throwable root = e;
                                while (!(root instanceof NotFoundException) && root != null && root.getCause() != root) {
                                    root = root.getCause();
                                }
                                if (root instanceof NotFoundException) {
                                    NotFoundException cause = (NotFoundException) root;
                                    Bytecode bytecode = new Bytecode(file.getConstPool());
                                    bytecode.addNew(NoClassDefFoundError.class.getName());
                                    bytecode.add(Opcode.DUP);
                                    bytecode.addLdc(cause.getMessage());
                                    bytecode.addInvokespecial(NoClassDefFoundError.class.getName(), "<init>", "(Ljava/lang/String;)V");
                                    bytecode.add(Opcode.ATHROW);
                                    method.setCodeAttribute(bytecode.toCodeAttribute());
                                    method.getCodeAttribute().computeMaxStack();
                                    method.getCodeAttribute().setMaxLocals(DescriptorUtils.maxLocalsFromParameters(method.getDescriptor()) + 1);
                                    method.rebuildStackMap(classPool);
                                } else {
                                    throw e;
                                }
                            }
                        }
                    }
                }
            } catch (BadBytecode e) {
                throw new RuntimeException(e);
            }
            ByteArrayOutputStream bs = new ByteArrayOutputStream();
            file.write(new DataOutputStream(bs));
            // dump the class for debugging purposes
            final String dumpDir = AgentOptions.getOption(AgentOption.DUMP_DIR);
            if (dumpDir != null) {
                try {
                    File dump = new File(dumpDir + '/' + file.getName() + ".class");
                    dump.getParentFile().mkdirs();
                    FileOutputStream s = new FileOutputStream(dump);
                    DataOutputStream dos = new DataOutputStream(s);
                    file.write(dos);
                    s.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            if (!classesToRetransform.isEmpty()) {
                synchronized (this) {
                    retransformationOutstandingCount++;
                }
                Thread t = new Thread(() -> {
                    try {
                        Fakereplace.getInstrumentation().retransformClasses(classesToRetransform.toArray(new Class[classesToRetransform.size()]));
                    } catch (UnmodifiableClassException e) {
                        log.error("Failed to retransform classes", e);
                    } finally {
                        synchronized (MainTransformer.this) {
                            retransformationOutstandingCount--;
                            notifyAll();
                        }
                    }
                });
                t.setDaemon(true);
                t.start();
            }
            if (classBeingRedefined != null) {
                changedClasses.add(changedClass);
                queueIntegration();
            }
            return bs.toByteArray();
        }
    } catch (IOException e) {
        e.printStackTrace();
        throw new IllegalClassFormatException(e.getMessage());
    } catch (Throwable e) {
        e.printStackTrace();
        throw new RuntimeException(e);
    }
}
Also used : DataOutputStream(java.io.DataOutputStream) ClassPool(javassist.ClassPool) NotFoundException(javassist.NotFoundException) IllegalClassFormatException(java.lang.instrument.IllegalClassFormatException) BadBytecode(javassist.bytecode.BadBytecode) Bytecode(javassist.bytecode.Bytecode) HashSet(java.util.HashSet) ClassFile(javassist.bytecode.ClassFile) UnmodifiableClassException(java.lang.instrument.UnmodifiableClassException) ChangedClassImpl(org.fakereplace.replacement.notification.ChangedClassImpl) LoaderClassPath(javassist.LoaderClassPath) ByteArrayOutputStream(java.io.ByteArrayOutputStream) IOException(java.io.IOException) DataInputStream(java.io.DataInputStream) BadBytecode(javassist.bytecode.BadBytecode) NotFoundException(javassist.NotFoundException) IllegalClassFormatException(java.lang.instrument.IllegalClassFormatException) IOException(java.io.IOException) UnmodifiableClassException(java.lang.instrument.UnmodifiableClassException) ByteArrayInputStream(java.io.ByteArrayInputStream) FileOutputStream(java.io.FileOutputStream) ChangedClass(org.fakereplace.api.ChangedClass) MethodInfo(javassist.bytecode.MethodInfo) ClassFile(javassist.bytecode.ClassFile) File(java.io.File)

Example 2 with ChangedClass

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

the class MetawidgetClassChangeAware method clearMap.

public static void clearMap(List<ChangedClass> changed, Object i, String cacheName) {
    try {
        Field f = getField(i.getClass(), cacheName);
        f.setAccessible(true);
        Object map = f.get(i);
        for (ChangedClass c : changed) {
            remove.invoke(map, c.getChangedClass());
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}
Also used : Field(java.lang.reflect.Field) ChangedClass(org.fakereplace.api.ChangedClass)

Example 3 with ChangedClass

use of org.fakereplace.api.ChangedClass 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)

Example 4 with ChangedClass

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

the class WildflyHibernate5ClassChangeAware method afterChange.

@Override
public void afterChange(final List<ChangedClass> changed, final List<NewClassData> added) {
    boolean replace = false;
    for (ChangedClass changedClass : changed) {
        if (changedClass.getChangedClass().isAnnotationPresent(Entity.class) || !changedClass.getChangedAnnotationsByType(Entity.class).isEmpty()) {
            replace = true;
        }
    }
    if (!replace) {
        return;
    }
    final Set<PersistenceUnitServiceImpl> puServices = (Set<PersistenceUnitServiceImpl>) InstanceTracker.get(WildflyHibernate5Extension.PERSISTENCE_UNIT_SERVICE);
    final Set<PhaseOnePersistenceUnitServiceImpl> phaseOneServices = (Set<PhaseOnePersistenceUnitServiceImpl>) InstanceTracker.get(WildflyHibernate5Extension.PERSISTENCE_PHASE_ONE_SERVICE);
    // we need to update this index
    try {
        WritableServiceBasedNamingStore.pushOwner(CurrentServiceContainer.getServiceContainer());
        try {
            for (PersistenceUnitServiceImpl puService : puServices) {
                try {
                    // make sure the service is started before stopping
                    if (puService.getExecutorInjector().getOptionalValue() != null) {
                        doServiceStop(puService);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            for (PhaseOnePersistenceUnitServiceImpl puService : phaseOneServices) {
                try {
                    if (puService.getExecutorInjector().getOptionalValue() != null) {
                        doServiceStop(puService);
                        doServiceStart(puService);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            for (PersistenceUnitServiceImpl puService : puServices) {
                try {
                    // make sure the service is started before stopping
                    if (puService.getExecutorInjector().getOptionalValue() != null) {
                        doServiceStart(puService);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        } finally {
            WritableServiceBasedNamingStore.popOwner();
        }
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}
Also used : Entity(javax.persistence.Entity) PersistenceUnitServiceImpl(org.jboss.as.jpa.service.PersistenceUnitServiceImpl) PhaseOnePersistenceUnitServiceImpl(org.jboss.as.jpa.service.PhaseOnePersistenceUnitServiceImpl) Set(java.util.Set) ChangedClass(org.fakereplace.api.ChangedClass) PhaseOnePersistenceUnitServiceImpl(org.jboss.as.jpa.service.PhaseOnePersistenceUnitServiceImpl) StartException(org.jboss.msc.service.StartException)

Example 5 with ChangedClass

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

the class WeldClassChangeAware method afterChange.

@Override
public void afterChange(List<ChangedClass> changed, List<NewClassData> added) {
    ClassLoader oldCl = null;
    WeldProxyClassLoadingDelegate.beginProxyRegeneration();
    try {
        final Set<ChangedClass> changedClasses = new HashSet<>(changed);
        // Hack to re-generate the weld client proxies
        for (final Object instance : proxyFactories.values()) {
            try {
                Class cp = instance.getClass();
                while (!cp.getName().equals(WeldClassTransformer.ORG_JBOSS_WELD_BEAN_PROXY_PROXY_FACTORY)) {
                    cp = cp.getSuperclass();
                }
                Field beanField = cp.getDeclaredField("bean");
                beanField.setAccessible(true);
                Method getProxy = instance.getClass().getMethod("getProxyClass");
                getProxy.setAccessible(true);
                final Bean<?> bean = (Bean<?>) beanField.get(instance);
                for (final ChangedClass clazz : changedClasses) {
                    if (bean.getTypes().contains(clazz.getChangedClass())) {
                        Thread.currentThread().setContextClassLoader(bean.getBeanClass().getClassLoader());
                        getProxy.invoke(instance);
                    }
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    } finally {
        WeldProxyClassLoadingDelegate.endProxyRegeneration();
        Thread.currentThread().setContextClassLoader(oldCl);
    }
}
Also used : Field(java.lang.reflect.Field) ChangedClass(org.fakereplace.api.ChangedClass) Method(java.lang.reflect.Method) ChangedClass(org.fakereplace.api.ChangedClass) HashSet(java.util.HashSet) Bean(javax.enterprise.inject.spi.Bean)

Aggregations

ChangedClass (org.fakereplace.api.ChangedClass)5 HashSet (java.util.HashSet)3 Field (java.lang.reflect.Field)2 Set (java.util.Set)2 ByteArrayInputStream (java.io.ByteArrayInputStream)1 ByteArrayOutputStream (java.io.ByteArrayOutputStream)1 DataInputStream (java.io.DataInputStream)1 DataOutputStream (java.io.DataOutputStream)1 File (java.io.File)1 FileOutputStream (java.io.FileOutputStream)1 IOException (java.io.IOException)1 IllegalClassFormatException (java.lang.instrument.IllegalClassFormatException)1 UnmodifiableClassException (java.lang.instrument.UnmodifiableClassException)1 Method (java.lang.reflect.Method)1 ClassPool (javassist.ClassPool)1 LoaderClassPath (javassist.LoaderClassPath)1 NotFoundException (javassist.NotFoundException)1 AnnotationsAttribute (javassist.bytecode.AnnotationsAttribute)1 BadBytecode (javassist.bytecode.BadBytecode)1 Bytecode (javassist.bytecode.Bytecode)1