All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.osgi.internal.url.EquinoxFactoryManager Maven / Gradle / Ivy

Go to download

AspectJ tools most notably contains the AspectJ compiler (AJC). AJC applies aspects to Java classes during compilation, fully replacing Javac for plain Java classes and also compiling native AspectJ or annotation-based @AspectJ syntax. Furthermore, AJC can weave aspects into existing class files in a post-compile binary weaving step. This library is a superset of AspectJ weaver and hence also of AspectJ runtime.

There is a newer version: 1.9.22.1
Show newest version
/*******************************************************************************
 * Copyright (c) 2012 IBM Corporation and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
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.Collections;
import java.util.Hashtable;
import org.eclipse.osgi.framework.log.FrameworkLogEntry;
import org.eclipse.osgi.internal.framework.EquinoxContainer;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;

public class EquinoxFactoryManager {
	private final EquinoxContainer container;
	// we need to hold these so that we can unregister them at shutdown
	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 {
			// first try the standard way
			URL.setURLStreamHandlerFactory(shf);
		} catch (Error err) {
			try {
				// ok we failed now use more drastic means to set the factory
				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 {
		// force our FrameworkUtil to initialize before we register to avoid calling
		// getBundle before we register this as a multiplexing handler
		FrameworkUtil.asDictionary(Collections.emptyMap());
		Field factoryField = getField(URL.class, URLStreamHandlerFactory.class, false);
		if (factoryField == null)
			throw new Exception("Could not find URLStreamHandlerFactory field"); //$NON-NLS-1$
		// look for a lock to synchronize on
		Object lock = getURLStreamHandlerFactoryLock();
		synchronized (lock) {
			URLStreamHandlerFactory factory = (URLStreamHandlerFactory) factoryField.get(null);
			// doing a null check here just in case, but it would be really strange if it was null,
			// because we failed to set the factory normally!!
			if (factory != null) {
				try {
					factory.getClass().getMethod("isMultiplexing", (Class[]) null); //$NON-NLS-1$
					Method register = factory.getClass().getMethod("register", new Class[] {Object.class}); //$NON-NLS-1$
					register.invoke(factory, new Object[] {shf});
				} catch (NoSuchMethodException e) {
					// current factory does not support multiplexing, ok we'll wrap it
					shf.setParentFactory(factory);
					factory = shf;
				}
			}
			factoryField.set(null, null);
			// always attempt to clear the handlers cache
			// This allows an optimization for the single framework use-case
			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"); //$NON-NLS-1$
			MultiplexingFactory.setAccessible(streamHandlerLockField);
			lock = streamHandlerLockField.get(null);
		} catch (NoSuchFieldException noField) {
			// could not find the lock, lets sync on the class object
			lock = URL.class;
		}
		return lock;
	}

	private void installContentHandlerFactory(BundleContext context) {
		ContentHandlerFactoryImpl chf = new ContentHandlerFactoryImpl(context, container);
		try {
			// first try the standard way
			URLConnection.setContentHandlerFactory(chf);
		} catch (Error err) {
			// ok we failed now use more drastic means to set the factory
			try {
				forceContentHandlerFactory(chf);
			} catch (Throwable ex) {
				// this is unexpected, log the exception and throw the original error
				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"); //$NON-NLS-1$
		synchronized (URLConnection.class) {
			java.net.ContentHandlerFactory factory = (java.net.ContentHandlerFactory) factoryField.get(null);
			// doing a null check here just in case, but it would be really strange if it was null,
			// because we failed to set the factory normally!!

			if (factory != null) {
				try {
					factory.getClass().getMethod("isMultiplexing", (Class[]) null); //$NON-NLS-1$
					Method register = factory.getClass().getMethod("register", new Class[] {Object.class}); //$NON-NLS-1$
					register.invoke(factory, new Object[] {chf});
				} catch (NoSuchMethodException e) {
					// current factory does not support multiplexing, ok we'll wrap it
					chf.setParentFactory(factory);
					factory = chf;
				}
			}
			// null out the field so that we can successfully call setContentHandlerFactory
			factoryField.set(null, null);
			// always attempt to clear the handlers cache
			// This allows an optimization for the single framework use-case
			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; // didn't succeed in setting the factory at launch
		}
		try {
			Field factoryField = getField(URL.class, URLStreamHandlerFactory.class, false);
			if (factoryField == null)
				return; // oh well, we tried
			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}); //$NON-NLS-1$
					unregister.invoke(factory, new Object[] {urlStreamHandlerFactory});
				}
				factoryField.set(null, null);
				// always attempt to clear the handlers cache
				// This allows an optimization for the single framework use-case
				// Note that the call to setURLStreamHandlerFactory below may clear this cache
				// but we want to be sure to clear it here just in case the parent is null.
				// In this case the call below would not occur.
				resetURLStreamHandlers();
				if (factory != null)
					URL.setURLStreamHandlerFactory(factory);
			}
		} catch (Throwable e) {
			// ignore and continue closing the framework
		}
	}

	private void uninstallContentHandlerFactory() {
		if (contentHandlerFactory == null) {
			return; // didn't succeed in setting the factory at launch
		}
		try {
			Field factoryField = getField(URLConnection.class, java.net.ContentHandlerFactory.class, false);
			if (factoryField == null)
				return; // oh well, we tried.
			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}); //$NON-NLS-1$
					unregister.invoke(factory, new Object[] {contentHandlerFactory});
				}
				// null out the field so that we can successfully call setContentHandlerFactory
				factoryField.set(null, null);
				// always attempt to clear the handlers cache
				// This allows an optomization for the single framework use-case
				// Note that the call to setContentHandlerFactory below may clear this cache
				// but we want to be sure to clear it here just incase the parent is null.
				// In this case the call below would not occur.
				// Also it appears most java libraries actually do not clear the cache
				// when setContentHandlerFactory is called, go figure!!
				resetContentHandlers();
				if (factory != null)
					URLConnection.setContentHandlerFactory(factory);
			}
		} catch (Throwable e) {
			// ignore and continue closing the framework
		}
	}

	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;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy