package org.eclipse.osgi.internal.weaving;
import java.util.*;
import org.eclipse.osgi.internal.framework.EquinoxContainer;
import org.eclipse.osgi.internal.hookregistry.ClassLoaderHook;
import org.eclipse.osgi.internal.loader.BundleLoader;
import org.eclipse.osgi.internal.loader.ModuleClassLoader;
import org.eclipse.osgi.internal.loader.classpath.ClasspathEntry;
import org.eclipse.osgi.internal.loader.classpath.ClasspathManager;
import org.eclipse.osgi.internal.serviceregistry.ServiceRegistry;
import org.eclipse.osgi.storage.bundlefile.BundleEntry;
import org.osgi.framework.*;
public class WeavingHookConfigurator extends ClassLoaderHook {
static class WovenClassContext {
List<WovenClassImpl> wovenClassStack = new ArrayList<>(6);
List<String> processClassNameStack = new ArrayList<>(6);
}
private final Map<ServiceRegistration<?>, Boolean> blackList = Collections.synchronizedMap(new WeakHashMap<ServiceRegistration<?>, Boolean>());
private final ThreadLocal<WovenClassContext> wovenClassContext = new ThreadLocal<>();
private final EquinoxContainer container;
public WeavingHookConfigurator(EquinoxContainer container) {
this.container = container;
}
private ServiceRegistry getRegistry() {
return container.getServiceRegistry();
}
@Override
public byte[] processClass(String name, byte[] classbytes, ClasspathEntry classpathEntry, BundleEntry entry, ClasspathManager manager) {
ServiceRegistry registry = getRegistry();
if (registry == null)
return null;
ModuleClassLoader classLoader = manager.getClassLoader();
BundleLoader loader = classLoader.getBundleLoader();
WovenClassImpl wovenClass = new WovenClassImpl(name, classbytes, entry, classpathEntry, loader, container, blackList);
WovenClassContext context = wovenClassContext.get();
if (context == null) {
context = new WovenClassContext();
wovenClassContext.set(context);
}
context.wovenClassStack.add(wovenClass);
if (!context.processClassNameStack.contains(name)) {
context.processClassNameStack.add(name);
try {
return wovenClass.callHooks();
} catch (Throwable t) {
ServiceRegistration<?> errorHook = wovenClass.getErrorHook();
Bundle errorBundle = errorHook != null ? errorHook.getReference().getBundle() : manager.getGeneration().getRevision().getBundle();
container.getEventPublisher().publishFrameworkEvent(FrameworkEvent.ERROR, errorBundle, t);
ClassFormatError error = new ClassFormatError("Unexpected error from weaving hook.");
error.initCause(t);
throw error;
} finally {
context.processClassNameStack.remove(name);
}
}
return null;
}
@Override
public void recordClassDefine(String name, Class<?> clazz, byte[] classbytes, ClasspathEntry classpathEntry, BundleEntry entry, ClasspathManager manager) {
WovenClassContext context = wovenClassContext.get();
if (context == null || context.wovenClassStack.size() == 0)
return;
WovenClassImpl wovenClass = context.wovenClassStack.remove(context.wovenClassStack.size() - 1);
wovenClass.setWeavingCompleted(clazz);
}
@Override
public boolean isProcessClassRecursionSupported() {
return true;
}
}