package org.eclipse.osgi.internal.url;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandlerFactory;
import java.util.Hashtable;
import org.eclipse.osgi.framework.log.FrameworkLogEntry;
import org.eclipse.osgi.internal.framework.EquinoxContainer;
import org.osgi.framework.BundleContext;
public class EquinoxFactoryManager {
private final EquinoxContainer container;
private volatile URLStreamHandlerFactoryImpl urlStreamHandlerFactory;
private volatile ContentHandlerFactoryImpl contentHandlerFactory;
public EquinoxFactoryManager(EquinoxContainer container) {
this.container = container;
}
public void installHandlerFactories(BundleContext context) {
installURLStreamHandlerFactory(context);
installContentHandlerFactory(context);
}
private void installURLStreamHandlerFactory(BundleContext context) {
URLStreamHandlerFactoryImpl shf = new URLStreamHandlerFactoryImpl(context, container);
try {
URL.setURLStreamHandlerFactory(shf);
} catch (Error err) {
try {
forceURLStreamHandlerFactory(shf);
} catch (Throwable ex) {
container.getLogServices().log(EquinoxContainer.NAME, FrameworkLogEntry.ERROR, ex.getMessage(), ex);
urlStreamHandlerFactory = null;
return;
}
}
urlStreamHandlerFactory = shf;
}
private static void forceURLStreamHandlerFactory(URLStreamHandlerFactoryImpl shf) throws Exception {
Field factoryField = getField(URL.class, URLStreamHandlerFactory.class, false);
if (factoryField == null)
throw new Exception("Could not find URLStreamHandlerFactory field");
Object lock = getURLStreamHandlerFactoryLock();
synchronized (lock) {
URLStreamHandlerFactory factory = (URLStreamHandlerFactory) factoryField.get(null);
if (factory != null) {
try {
factory.getClass().getMethod("isMultiplexing", (Class[]) null);
Method register = factory.getClass().getMethod("register", new Class[] {Object.class});
register.invoke(factory, new Object[] {shf});
} catch (NoSuchMethodException e) {
shf.setParentFactory(factory);
factory = shf;
}
}
factoryField.set(null, null);
resetURLStreamHandlers();
URL.setURLStreamHandlerFactory(factory);
}
}
private static void resetURLStreamHandlers() throws IllegalAccessException {
Field handlersField = getField(URL.class, Hashtable.class, false);
if (handlersField != null) {
@SuppressWarnings("rawtypes")
Hashtable<?, ?> handlers = (Hashtable) handlersField.get(null);
if (handlers != null)
handlers.clear();
}
}
private static Object getURLStreamHandlerFactoryLock() throws IllegalAccessException {
Object lock;
try {
Field streamHandlerLockField = URL.class.getDeclaredField("streamHandlerLock");
MultiplexingFactory.setAccessible(streamHandlerLockField);
lock = streamHandlerLockField.get(null);
} catch (NoSuchFieldException noField) {
lock = URL.class;
}
return lock;
}
private void installContentHandlerFactory(BundleContext context) {
ContentHandlerFactoryImpl chf = new ContentHandlerFactoryImpl(context, container);
try {
URLConnection.setContentHandlerFactory(chf);
} catch (Error err) {
try {
forceContentHandlerFactory(chf);
} catch (Throwable ex) {
container.getLogServices().log(EquinoxContainer.NAME, FrameworkLogEntry.ERROR, ex.getMessage(), ex);
contentHandlerFactory = null;
return;
}
}
contentHandlerFactory = chf;
}
private static void forceContentHandlerFactory(ContentHandlerFactoryImpl chf) throws Exception {
Field factoryField = getField(URLConnection.class, java.net.ContentHandlerFactory.class, false);
if (factoryField == null)
throw new Exception("Could not find ContentHandlerFactory field");
synchronized (URLConnection.class) {
java.net.ContentHandlerFactory factory = (java.net.ContentHandlerFactory) factoryField.get(null);
if (factory != null) {
try {
factory.getClass().getMethod("isMultiplexing", (Class[]) null);
Method register = factory.getClass().getMethod("register", new Class[] {Object.class});
register.invoke(factory, new Object[] {chf});
} catch (NoSuchMethodException e) {
chf.setParentFactory(factory);
factory = chf;
}
}
factoryField.set(null, null);
resetContentHandlers();
URLConnection.setContentHandlerFactory(factory);
}
}
private static void resetContentHandlers() throws IllegalAccessException {
Field handlersField = getField(URLConnection.class, Hashtable.class, false);
if (handlersField != null) {
@SuppressWarnings("rawtypes")
Hashtable<?, ?> handlers = (Hashtable) handlersField.get(null);
if (handlers != null)
handlers.clear();
}
}
public void uninstallHandlerFactories() {
uninstallURLStreamHandlerFactory();
uninstallContentHandlerFactory();
}
private void uninstallURLStreamHandlerFactory() {
if (urlStreamHandlerFactory == null) {
return;
}
try {
Field factoryField = getField(URL.class, URLStreamHandlerFactory.class, false);
if (factoryField == null)
return;
Object lock = getURLStreamHandlerFactoryLock();
synchronized (lock) {
URLStreamHandlerFactory factory = (URLStreamHandlerFactory) factoryField.get(null);
if (factory == urlStreamHandlerFactory) {
factory = (URLStreamHandlerFactory) urlStreamHandlerFactory.designateSuccessor();
} else {
Method unregister = factory.getClass().getMethod("unregister", new Class[] {Object.class});
unregister.invoke(factory, new Object[] {urlStreamHandlerFactory});
}
factoryField.set(null, null);
resetURLStreamHandlers();
if (factory != null)
URL.setURLStreamHandlerFactory(factory);
}
} catch (Throwable e) {
}
}
private void uninstallContentHandlerFactory() {
if (contentHandlerFactory == null) {
return;
}
try {
Field factoryField = getField(URLConnection.class, java.net.ContentHandlerFactory.class, false);
if (factoryField == null)
return;
synchronized (URLConnection.class) {
java.net.ContentHandlerFactory factory = (java.net.ContentHandlerFactory) factoryField.get(null);
if (factory == contentHandlerFactory) {
factory = (java.net.ContentHandlerFactory) contentHandlerFactory.designateSuccessor();
} else {
Method unregister = factory.getClass().getMethod("unregister", new Class[] {Object.class});
unregister.invoke(factory, new Object[] {contentHandlerFactory});
}
factoryField.set(null, null);
resetContentHandlers();
if (factory != null)
URLConnection.setContentHandlerFactory(factory);
}
} catch (Throwable e) {
}
}
public static Field getField(Class<?> clazz, Class<?> type, boolean instance) {
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
boolean isStatic = Modifier.isStatic(field.getModifiers());
if (instance != isStatic && field.getType().equals(type)) {
MultiplexingFactory.setAccessible(field);
return field;
}
}
return null;
}
}