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);
}
}
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();
}
}
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);
}
}
}
}
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);
}
}
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);
}
}
Aggregations