Bug 87775 - Overcoming classloading issues with third party libraries
diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleLoader.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleLoader.java
index 160de23..cbbdcfa 100644
--- a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleLoader.java
+++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleLoader.java
@@ -37,6 +37,7 @@
 	public final static byte FLAG_HASDYNAMICIMPORTS = 0x02;
 	public final static byte FLAG_HASDYNAMICEIMPORTALL = 0x04;
 	public final static byte FLAG_CLOSED = 0x08;
+
 	public final static ClassContext CLASS_CONTEXT = (ClassContext) AccessController.doPrivileged(new PrivilegedAction() {
 		public Object run() {
 			return new ClassContext();
@@ -69,6 +70,8 @@
 	/* loader flags */
 	byte loaderFlags = 0;
 
+	private PolicyHandler policy;
+
 	/**
 	 * Returns the package name from the specified class name.
 	 * The returned package is dot seperated.
@@ -176,6 +179,15 @@
 		for (int i = 0; i < fragments.length; i++)
 			if (fragments[i].isResolved() && fragments[i].hasDynamicImports())
 				addDynamicImportPackage(fragments[i].getImportPackages());
+
+		//Initialize the policy handler
+		try {
+			String buddyList = null;
+			if ((buddyList = (String) bundle.getBundleData().getManifest().get(Constants.BUDDY_LOADER)) != null)
+				policy = new PolicyHandler(this, buddyList);
+		} catch (BundleException e) {
+			//ignore
+		}
 	}
 
 	private synchronized void addImportedPackages(ExportPackageDescription[] packages) {
@@ -243,6 +255,10 @@
 			return;
 		if (classloader != null)
 			classloader.close();
+		if (policy != null) {
+			policy.close();
+			policy = null;
+		}
 		loaderFlags |= FLAG_CLOSED; /* This indicates the BundleLoader is destroyed */
 	}
 
@@ -377,8 +393,12 @@
 		source = findDynamicSource(pkgName);
 		if (source != null)
 			result = source.loadClass(name);
+		// do buddy policy loading
+		if (result == null && policy != null)
+			result = policy.doBuddyClassLoading(name);
+		// last resort; do class context trick to work around VM bugs
 		if (result == null && findParentResource(name))
-			return parent.loadClass(name);
+			result = parent.loadClass(name);
 		if (result == null)
 			throw new ClassNotFoundException(name);
 		return result;
@@ -466,8 +486,12 @@
 		source = findDynamicSource(pkgName);
 		if (source != null)
 			result = source.getResource(name);
+		// do buddy policy loading
+		if (result == null && policy != null)
+			return policy.doBuddyResourceLoading(name);
+		// last resort; do class context trick to work around VM bugs
 		if (result == null && findParentResource(name))
-			return parent.getResource(name);
+			result = parent.getResource(name);
 		return result;
 	}
 
@@ -511,6 +535,8 @@
 		source = findDynamicSource(pkgName);
 		if (source != null)
 			result = source.getResources(name);
+		if (result == null && policy != null)
+			result = policy.doBuddyResourcesLoading(name);
 		return result;
 	}
 
@@ -709,8 +735,8 @@
 		if (packages == null)
 			return;
 
-		loaderFlags |= FLAG_HASDYNAMICIMPORTS;
 		// make sure importedPackages is not null;
+		loaderFlags |= FLAG_HASDYNAMICIMPORTS;
 		if (importedSources == null) {
 			importedSources = new KeyedHashSet(10, false);
 		}
diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/Constants.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/Constants.java
index 54d91e8..2a6cb23 100644
--- a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/Constants.java
+++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/Constants.java
@@ -227,4 +227,10 @@
 	 */
 	public final static String REQUIRE_PACKAGES_ATTRIBUTE = "require-packages"; //$NON-NLS-1$
 
+	 /**
+	 * The key used to designate the buddy loader associated with a given bundle.
+	 */
+	 public final static String BUDDY_LOADER = "Eclipse-BuddyPolicy"; //$NON-NLS-1$
+
+	 public final static String REGISTERED_POLICY = "Eclipse-RegisterBuddy";  //$NON-NLS-1$
 }
diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/DependentPolicy.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/DependentPolicy.java
new file mode 100644
index 0000000..95ce26a
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/DependentPolicy.java
@@ -0,0 +1,117 @@
+/*******************************************************************************
+ * Copyright (c) 2005 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.osgi.framework.internal.core;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.*;
+import org.eclipse.osgi.service.resolver.BundleDescription;
+
+/**
+ * DependentPolicy is an implementation of a buddy policy. 
+ * It is responsible for looking up a class in the dependents of the bundle
+ * to which this policy is attached to.
+ */
+public class DependentPolicy implements IBuddyPolicy {
+	BundleLoader buddyRequester;
+	int lastDependentOfAdded = -1; //remember the index of the bundle for which we last added the dependent
+	List allDependents = null; //the list of all dependents known so far
+
+	public DependentPolicy(BundleLoader requester) {
+		buddyRequester = requester;
+
+		//Initialize with the first level of dependent the list
+		allDependents = new ArrayList();
+		basicAddImmediateDependents(buddyRequester.getBundle().getBundleDescription());
+		//If there is no dependent, reset to null
+		if (allDependents.size() == 0)
+			allDependents = null;
+	}
+
+	public Class loadClass(String name) {
+		if (allDependents == null)
+			return null;
+
+		Class result = null;
+		for (int i = 0; i < allDependents.size() && result == null; i++) {
+			BundleDescription searchedBundle = (BundleDescription) allDependents.get(i);
+			try {
+				BundleLoaderProxy proxy = buddyRequester.getLoaderProxy(searchedBundle);
+				if (proxy == null)
+					continue;
+				result = proxy.getBundleLoader().findClass(name, true);
+			} catch (ClassNotFoundException e) {
+				if (result == null)
+					addDependent(i, searchedBundle);
+			}
+		}
+		return result;
+	}
+
+	private synchronized void addDependent(int i, BundleDescription searchedBundle) {
+		if (i > lastDependentOfAdded) {
+			lastDependentOfAdded = i;
+			basicAddImmediateDependents(searchedBundle);
+		}
+	}
+
+	public URL loadResource(String name) {
+		if (allDependents == null)
+			return null;
+		
+		URL result = null;
+		for (int i = 0; i < allDependents.size() && result == null; i++) {
+			BundleDescription searchedBundle = (BundleDescription) allDependents.get(i);
+			BundleLoaderProxy proxy = buddyRequester.getLoaderProxy(searchedBundle);
+			if (proxy == null)
+				continue;
+			result = proxy.getBundleLoader().findResource(name, true);
+			if (result == null) {
+				addDependent(i, searchedBundle);
+			}
+		}
+		return result;
+	}
+
+	public Enumeration loadResources(String name) {
+		if (allDependents == null)
+			return null;
+		
+		Enumeration result = null;
+		for (int i = 0; i < allDependents.size() && result == null; i++) {
+			BundleDescription searchedBundle = (BundleDescription) allDependents.get(i);
+			try {
+				BundleLoaderProxy proxy = buddyRequester.getLoaderProxy(searchedBundle);
+				if (proxy == null)
+					continue;
+				result = proxy.getBundleLoader().findResources(name);
+			} catch (IOException e) {
+				//Ignore and keep looking
+				continue;
+			}
+			if (result == null) {
+				addDependent(i, searchedBundle);
+			}
+		}
+		return result;
+	}
+
+	private void basicAddImmediateDependents(BundleDescription root) {
+		BundleDescription[] dependents = root.getDependents();
+		for (int i = 0; i < dependents.length; i++) {
+			BundleDescription toAdd = dependents[i];
+			if (toAdd.getHost() == null && !allDependents.contains(toAdd)) {
+				allDependents.add(toAdd);
+			}
+		}
+	}
+}
diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/GlobalPolicy.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/GlobalPolicy.java
new file mode 100644
index 0000000..6ecd9c0
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/GlobalPolicy.java
@@ -0,0 +1,61 @@
+/*******************************************************************************
+ * Copyright (c) 2005 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.osgi.framework.internal.core;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.Enumeration;
+import org.osgi.service.packageadmin.ExportedPackage;
+import org.osgi.service.packageadmin.PackageAdmin;
+
+/**
+ * Global policy is an implementation of a buddy policy. It is responsible
+ * for looking up a class within the global set of exported classes. If multiple
+ * version of the same package are exported in the system, the exported package
+ * with the highest version will be returned.
+ */
+public class GlobalPolicy implements IBuddyPolicy {
+	private PackageAdmin admin;
+
+	public GlobalPolicy( PackageAdmin admin) {
+		this.admin = admin;
+	}
+
+	public Class loadClass(String name) {
+		ExportedPackage pkg = admin.getExportedPackage(BundleLoader.getPackageName(name));
+		if (pkg == null)
+			return null;
+		try {
+			return pkg.getExportingBundle().loadClass(name);
+		} catch (ClassNotFoundException e) {
+			return null;
+		}
+	}
+
+	public URL loadResource(String name) {
+		ExportedPackage pkg = admin.getExportedPackage(BundleLoader.getPackageName(name));
+		if (pkg == null)
+			return null;
+		return pkg.getExportingBundle().getResource(name);
+	}
+
+	public Enumeration loadResources(String name) {
+		ExportedPackage pkg = admin.getExportedPackage(BundleLoader.getPackageName(name));
+		if (pkg == null)
+			return null;
+		try {
+			return pkg.getExportingBundle().getResources(name);
+		} catch (IOException e) {
+			return null;
+		}
+	}
+
+}
diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/IBuddyPolicy.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/IBuddyPolicy.java
new file mode 100644
index 0000000..24abbf2
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/IBuddyPolicy.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright (c) 2005 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.osgi.framework.internal.core;
+
+import java.net.URL;
+import java.util.Enumeration;
+
+public interface IBuddyPolicy {
+	public Class loadClass(String name);
+
+	public URL loadResource(String name);
+
+	public Enumeration loadResources(String name);
+}
diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/ParentPolicy.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/ParentPolicy.java
new file mode 100644
index 0000000..7d6e55b
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/ParentPolicy.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2005 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.osgi.framework.internal.core;
+
+import java.net.URL;
+import java.util.Enumeration;
+
+public class ParentPolicy implements IBuddyPolicy {
+
+	public Class loadClass(String name) {
+		// TODO Auto-generated method stub
+		return null;
+	}
+
+	public URL loadResource(String name) {
+		// TODO Auto-generated method stub
+		return null;
+	}
+
+	public Enumeration loadResources(String name) {
+		// TODO Auto-generated method stub
+		return null;
+	}
+
+}
diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/PolicyHandler.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/PolicyHandler.java
new file mode 100644
index 0000000..fc16a89
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/PolicyHandler.java
@@ -0,0 +1,192 @@
+/*******************************************************************************
+ * Copyright (c) 2005 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.osgi.framework.internal.core;
+
+import java.net.URL;
+import java.util.*;
+import org.osgi.framework.*;
+
+public class PolicyHandler {
+	//Key for the framework buddies
+	private final static String DEPENDENT_POLICY = "dependent"; //$NON-NLS-1$
+	private final static String GLOBAL_POLICY = "global"; //$NON-NLS-1$
+	private final static String REGISTERED_POLICY = "registered"; //$NON-NLS-1$
+	private final static String APP_POLICY = "app"; //$NON-NLS-1$
+	private final static String EXT_POLICY = "ext"; //$NON-NLS-1$
+	private final static String BOOT_POLICY = "boot"; //$NON-NLS-1$
+	private final static String PARENT_POLICY = "parent"; //$NON-NLS-1$
+	
+	//The loader to which this policy is attached.
+	BundleLoader policedLoader;
+	//List of the policies as well as cache for the one that have been created. The size of this array never changes over time. This is why the synchronization is not done when iterating over it.
+	Object[] policies = null;
+
+	//Support to cut class / resource loading cycles in the context of one thread. The contained object is a set of classname
+	private ThreadLocal beingLoaded;
+
+	private BundleListener listener = new BundleListener() {
+		public void bundleChanged(BundleEvent event) {
+			if (event.getType() == BundleEvent.STARTED || event.getType() == BundleEvent.STOPPED)
+				return;
+			try {
+				String list = (String) policedLoader.getBundle().getBundleData().getManifest().get(Constants.BUDDY_LOADER);
+				synchronized (this) {
+					policies = getArrayFromList(list);
+				}
+			} catch (BundleException e) {
+				//Ignore
+			}
+		}
+	};
+
+	public PolicyHandler(BundleLoader loader, String buddyList) {
+		policedLoader = loader;
+		policies = getArrayFromList(buddyList);
+		beingLoaded = new ThreadLocal();
+		policedLoader.bundle.framework.systemBundle.context.addBundleListener(listener);
+	}
+
+	static Object[] getArrayFromList(String stringList) {
+		if (stringList == null || stringList.trim().equals("")) //$NON-NLS-1$
+			return null;
+		Vector list = new Vector();
+		StringTokenizer tokens = new StringTokenizer(stringList, ","); //$NON-NLS-1$
+		while (tokens.hasMoreTokens()) {
+			String token = tokens.nextToken().trim();
+			if (!token.equals("")) //$NON-NLS-1$
+				list.addElement(token);
+		}
+		return list.isEmpty() ? new Object[0] : (Object[]) list.toArray(new Object[list.size()]);
+	}
+
+	private synchronized IBuddyPolicy getPolicyImplementation(int policyOrder) {
+		if (policies[policyOrder] instanceof String) {
+			String buddyName = (String) policies[policyOrder];
+
+			if (REGISTERED_POLICY.equals(buddyName)) {
+				policies[policyOrder] = new RegisteredPolicy(policedLoader);
+				return (IBuddyPolicy) policies[policyOrder];
+			}
+			if (BOOT_POLICY.equals(buddyName)) {
+				policies[policyOrder] = SystemPolicy.getInstance(SystemPolicy.BOOT);
+				return (IBuddyPolicy) policies[policyOrder];
+			}
+			if (APP_POLICY.equals(buddyName)) {
+				policies[policyOrder] = SystemPolicy.getInstance(SystemPolicy.APP);
+				return (IBuddyPolicy) policies[policyOrder];
+			}
+			if (EXT_POLICY.equals(buddyName)) {
+				policies[policyOrder] = SystemPolicy.getInstance(SystemPolicy.EXT);
+				return (IBuddyPolicy) policies[policyOrder];
+			}
+			if (DEPENDENT_POLICY.equals(buddyName)) {
+				policies[policyOrder] = new DependentPolicy(policedLoader);
+				return (IBuddyPolicy) policies[policyOrder];
+			}
+			if (GLOBAL_POLICY.equals(buddyName)) {
+				policies[policyOrder] = new GlobalPolicy(policedLoader.bundle.framework.packageAdmin);
+				return (IBuddyPolicy) policies[policyOrder];
+			}
+			if (PARENT_POLICY.equals(buddyName)) {
+				policies[policyOrder] = new SystemPolicy(policedLoader.parent);
+				return (IBuddyPolicy) policies[policyOrder];
+			}
+			
+			//			//Buddy policy can be provided by service implementations
+			//			BundleContext fwkCtx = policedLoader.bundle.framework.systemBundle.context;
+			//			ServiceReference[] matchingBuddies = null;
+			//			try {
+			//				matchingBuddies = fwkCtx.getAllServiceReferences(IBuddyPolicy.class.getName(), "buddyName=" + buddyName);
+			//			} catch (InvalidSyntaxException e) {
+			//				//The filter is valid
+			//			}
+			//			if (matchingBuddies == null)
+			//				return new IBuddyPolicy() {
+			//					public Class loadClass(String name) {
+			//						return null;
+			//					}
+			//
+			//					public URL loadResource(String name) {
+			//						return null;
+			//					}
+			//
+			//					public Enumeration loadResources(String name) {
+			//						return null;
+			//					}
+			//				};
+			//
+			//			//The policies loaded through service are not cached
+			//			return ((IBuddyPolicy) fwkCtx.getService(matchingBuddies[0]));
+		}
+		return (IBuddyPolicy) policies[policyOrder];
+	}
+
+	public Class doBuddyClassLoading(String name) {
+		if (startLoading(name) == false)
+			return null;
+
+		Class result = null;
+		for (int i = 0; i < policies.length && result == null; i++) {
+			result = getPolicyImplementation(i).loadClass(name);
+		}
+		stopLoading(name);
+		return result;
+	}
+
+	public URL doBuddyResourceLoading(String name) {
+		if (startLoading(name) == false)
+			return null;
+
+		if (policies == null)
+			return null;
+		URL result = null;
+		for (int i = 0; i < policies.length && result == null; i++) {
+			result = getPolicyImplementation(i).loadResource(name);
+		}
+		stopLoading(name);
+		return result;
+	}
+
+	public Enumeration doBuddyResourcesLoading(String name) {
+		if (startLoading(name) == false)
+			return null;
+
+		if (policies == null)
+			return null;
+		Enumeration result = null;
+		for (int i = 0; i < policies.length && result == null; i++) {
+			result = getPolicyImplementation(i).loadResources(name);
+		}
+		stopLoading(name);
+		return result;
+	}
+
+	private boolean startLoading(String name) {
+		Set classesAndResources = (Set) beingLoaded.get();
+		if (classesAndResources != null && classesAndResources.contains(name))
+			return false;
+
+		if (classesAndResources == null) {
+			classesAndResources = new HashSet(3);
+			beingLoaded.set(classesAndResources);
+		}
+		classesAndResources.add(name);
+		return true;
+	}
+
+	private void stopLoading(String name) {
+		((Set) beingLoaded.get()).remove(name);
+	}
+
+	public void close() {
+		policedLoader.bundle.framework.systemBundle.context.removeBundleListener(listener);
+	}
+}
diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/RegisteredPolicy.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/RegisteredPolicy.java
new file mode 100644
index 0000000..c1ace21
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/RegisteredPolicy.java
@@ -0,0 +1,113 @@
+/*******************************************************************************
+ * Copyright (c) 2005 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.osgi.framework.internal.core;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.*;
+import org.eclipse.osgi.service.resolver.BundleDescription;
+import org.eclipse.osgi.util.ManifestElement;
+import org.osgi.framework.BundleException;
+
+/**
+ *Registered policy is an implementation of a buddy policy. 
+ * It is responsible for looking up a class in the bundles (registrant) that declare interest in the bundle that require the buddy loading.
+ * Note that the registrants must have a direct dependency on the bundle needing buddy.
+ */
+public class RegisteredPolicy extends DependentPolicy {
+
+	public RegisteredPolicy(BundleLoader requester) {
+		super(requester);
+
+		//Filter the dependents;
+		if (allDependents == null)
+			return;
+
+		for (Iterator iter = allDependents.iterator(); iter.hasNext();) {
+			BundleLoaderProxy proxy = buddyRequester.getLoaderProxy((BundleDescription) iter.next());			
+			if (proxy == null)
+				iter.remove();
+
+			try {
+				String[] allContributions = ManifestElement.getArrayFromList((String) ((AbstractBundle) proxy.getBundle()).getBundleData().getManifest().get(Constants.REGISTERED_POLICY));
+				if (allContributions == null) {
+					iter.remove();
+					continue;
+				}
+				boolean contributes = false;
+				for (int j = 0; j < allContributions.length && contributes == false; j++) {
+					if (allContributions[j].equals(buddyRequester.bundle.getSymbolicName()))
+						contributes = true;
+				}
+				if (!contributes)
+					iter.remove();
+				
+			} catch (BundleException e) {
+				iter.remove();
+			}
+		}
+
+		//After the filtering, if nothing is left then null out the variable for optimization
+		if (allDependents.size() == 0)
+			allDependents = null;
+	}
+
+	public Class loadClass(String name) {
+		if (allDependents == null)
+			return null;
+
+		Class result = null;
+		for (int i = 0; i < allDependents.size() && result == null; i++) {
+			try {
+				BundleLoaderProxy proxy = buddyRequester.getLoaderProxy((BundleDescription) allDependents.get(i));
+				if (proxy == null)
+					continue;
+				result = proxy.getBundleLoader().findClass(name, true);
+			} catch (ClassNotFoundException e) {
+				//Nothing to do, just keep looking
+				continue;
+			}
+		}
+		return result;
+	}
+
+	public URL loadResource(String name) {
+		if (allDependents == null)
+			return null;
+
+		URL result = null;
+		for (int i = 0; i < allDependents.size() && result == null; i++) {
+			BundleLoaderProxy proxy = buddyRequester.getLoaderProxy((BundleDescription) allDependents.get(i));
+			if (proxy == null)
+				continue;
+			result = proxy.getBundleLoader().findResource(name, true);
+		}
+		return result;
+	}
+
+	public Enumeration loadResources(String name) {
+		if (allDependents == null)
+			return null;
+
+		Enumeration result = null;
+		for (int i = 0; i < allDependents.size() && result == null; i++) {
+			try {
+				BundleLoaderProxy proxy = buddyRequester.getLoaderProxy((BundleDescription) allDependents.get(i));
+				if (proxy == null)
+					continue;
+				result = proxy.getBundleLoader().findResources(name);
+			} catch (IOException e) {
+				//Ignore and keep looking
+			}
+		}
+		return result;
+	}
+}
diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/SystemPolicy.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/SystemPolicy.java
new file mode 100644
index 0000000..b9f5d99
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/SystemPolicy.java
@@ -0,0 +1,93 @@
+/*******************************************************************************
+ * Copyright (c) 2005 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.osgi.framework.internal.core;
+
+import java.io.IOException;
+import java.net.URL;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Enumeration;
+
+public class SystemPolicy implements IBuddyPolicy {
+
+	private static class ParentClassLoader extends ClassLoader {
+		protected ParentClassLoader() {
+			super(null);
+		}
+	}
+
+	public static final byte BOOT = 0;
+	public static final byte EXT = 1;
+	public static final byte APP = 2;
+
+	private static SystemPolicy[] instances = new SystemPolicy[3];
+
+	private ClassLoader classLoader;
+
+	public static SystemPolicy getInstance(final byte type) {
+		if (instances[type] == null) {
+			instances[type] = new SystemPolicy();
+			instances[type].classLoader = (ClassLoader) AccessController.doPrivileged(new PrivilegedAction() {
+				public Object run() {
+					return createClassLoader(type);
+				}
+			});
+		}
+		return instances[type];
+	}
+
+	public SystemPolicy() {
+		//Nothing to do
+	}
+	
+	public SystemPolicy(ClassLoader parent) {
+		classLoader = parent;
+	}
+	
+	static ClassLoader createClassLoader(byte type) {
+		switch (type) {
+			case APP :
+				if (ClassLoader.getSystemClassLoader() != null)
+					return ClassLoader.getSystemClassLoader();
+				return new ParentClassLoader();
+
+			case BOOT :
+				return new ParentClassLoader();
+
+			case EXT :
+				if (ClassLoader.getSystemClassLoader() != null)
+					return ClassLoader.getSystemClassLoader().getParent();
+				return new ParentClassLoader();
+		}
+		return null;
+	}
+
+	public Class loadClass(String name) {
+		try {
+			return classLoader.loadClass(name);
+		} catch (ClassNotFoundException e) {
+			return null;
+		}
+	}
+
+	public URL loadResource(String name) {
+		return classLoader.getResource(name);
+	}
+
+	public Enumeration loadResources(String name) {
+		try {
+			return classLoader.getResources(name);
+		} catch (IOException e) {
+			return null;
+		}
+	}
+
+}
diff --git a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/CachedManifest.java b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/CachedManifest.java
index ffe694f..12945ba 100644
--- a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/CachedManifest.java
+++ b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/CachedManifest.java
@@ -14,6 +14,7 @@
 import java.util.Enumeration;
 import org.eclipse.osgi.framework.adaptor.BundleData;
 import org.eclipse.osgi.framework.adaptor.FrameworkAdaptor;
+import org.eclipse.osgi.framework.internal.core.Constants;
 import org.eclipse.osgi.framework.log.FrameworkLogEntry;
 import org.eclipse.osgi.util.NLS;
 import org.osgi.framework.*;
@@ -75,6 +76,12 @@
 				return bundledata.getSymbolicName();
 			return bundledata.getSymbolicName() + ';' + Constants.SINGLETON_DIRECTIVE + ":=true"; //$NON-NLS-1$
 		}
+		if (Constants.BUDDY_LOADER.equalsIgnoreCase(keyString)) {
+			return bundledata.buddyList == null ? null : bundledata.buddyList;
+		}
+		if (Constants.REGISTERED_POLICY.equalsIgnoreCase(keyString)) {
+			return bundledata.registeredBuddyList == null ? null : bundledata.registeredBuddyList;
+		}
 		Dictionary result = getManifest();
 		return result == null ? null : result.get(key);
 	}
diff --git a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/ContextFinder.java b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/ContextFinder.java
new file mode 100644
index 0000000..8520ed4
--- /dev/null
+++ b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/ContextFinder.java
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * Copyright (c) 2005 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.core.runtime.adaptor;
+
+import java.io.IOException;
+import java.net.URL;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Enumeration;
+
+public class ContextFinder extends ClassLoader {
+	 
+	private static final class Finder extends SecurityManager {
+		public Class[] getClassContext() {
+			return super.getClassContext();
+		}
+	}
+
+	static final Finder contextFinder = (Finder) AccessController.doPrivileged(new PrivilegedAction() {
+		public Object run() {
+			return new Finder();	
+		}
+	});
+
+	public ContextFinder(ClassLoader contextClassLoader) {
+		super(contextClassLoader);
+	}
+
+	ClassLoader basicFindClassLoader() {
+		Class[] stack = contextFinder.getClassContext();
+		for (int i = 1; i < stack.length; i++) {
+			if (stack[i] != ContextFinder.class && stack[i] != ClassLoader.class)
+				return stack[i].getClassLoader();
+		}
+		return null;
+	}
+	
+	private ClassLoader findClassLoader() {
+		if (System.getSecurityManager() == null) {
+			return basicFindClassLoader();
+		}
+		
+		return (ClassLoader) AccessController.doPrivileged(new PrivilegedAction() {
+			public Object run() {
+				return basicFindClassLoader();
+			}
+		});
+	}
+
+	protected synchronized Class loadClass(String arg0, boolean arg1) throws ClassNotFoundException {
+		Class result = null;
+		try {
+			result = super.loadClass(arg0, arg1);
+		} catch (ClassNotFoundException e) {
+			//Ignore
+		}
+		if (result == null) {
+			ClassLoader toConsult = findClassLoader();
+			if (toConsult != null && toConsult != getParent())
+				result = findClassLoader().loadClass(arg0);
+		}
+		return result;
+	}
+
+	protected URL findResource(String arg0) {
+		URL result = super.findResource(arg0);
+		if (result == null) {
+			ClassLoader toConsult = findClassLoader();
+			if (toConsult != null && toConsult != getParent())
+				result = findClassLoader().getResource(arg0);
+		}
+		return result;
+	}
+
+	protected Enumeration findResources(String arg0) {
+		try {
+			Enumeration result = super.findResources(arg0);
+			if (result == null) {
+				ClassLoader toConsult = findClassLoader();
+				if (toConsult != null && toConsult != getParent())
+					result = toConsult.getResources(arg0);
+			}
+			return result;
+		} catch (IOException e) {
+			return null;
+		}
+	}
+}
diff --git a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/EclipseAdaptor.java b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/EclipseAdaptor.java
index 1fa1085..c0eb973 100644
--- a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/EclipseAdaptor.java
+++ b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/EclipseAdaptor.java
@@ -69,7 +69,7 @@
 
 	private static final String OPTION_LOCATION = RUNTIME_ADAPTOR + "/debug/location"; //$NON-NLS-1$	
 
-	public static final byte BUNDLEDATA_VERSION = 14;
+	public static final byte BUNDLEDATA_VERSION = 15;
 
 	public static final byte NULL = 0;
 
@@ -545,6 +545,8 @@
 		for (int i = 0; i < exceptionsCount; i++)
 			autoStartExceptions[i] = in.readUTF();
 		data.setAutoStartExceptions(autoStartExceptions);
+		data.buddyList = readString(in, false);
+		data.registeredBuddyList = readString(in, false);
 		data.setPluginClass(readString(in, false));
 		data.setClassPathString(readString(in, false));
 		data.setNativePaths(readString(in, false));
@@ -609,6 +611,8 @@
 			for (int i = 0; i < autoStartExceptions.length; i++)
 				out.writeUTF(autoStartExceptions[i]);
 		}
+		writeStringOrNull(out, bundleData.buddyList);
+		writeStringOrNull(out, bundleData.registeredBuddyList);
 		writeStringOrNull(out, bundleData.getPluginClass());
 		writeStringOrNull(out, bundleData.getClassPathString());
 		writeStringOrNull(out, bundleData.getNativePathsString());
diff --git a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/EclipseAdaptorMessages.properties b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/EclipseAdaptorMessages.properties
index 95546b2..fad9568 100644
--- a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/EclipseAdaptorMessages.properties
+++ b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/EclipseAdaptorMessages.properties
@@ -74,6 +74,7 @@
 ECLIPSE_CLASSLOADER_ACTIVATION=An error occured while automatically activating bundle {0} ({1}).
 ECLIPSE_CLASSLOADER_GENERATED_EXCEPTION=Generated exception.
 ECLIPSE_CLASSLOADER_ALREADY_STOPPED= The class \"{0}\" cannot be loaded because the system is shutting down and the plug-in \"{1}\" has already been stopped.
+ECLIPSE_CLASSLOADER_CANNOT_SET_CONTEXTFINDER=The context finder has not been installed.
 
 #CachedManifest messages
 ECLIPSE_CACHEDMANIFEST_UNEXPECTED_EXCEPTION=Unexpected exception occurred loading manifest for bundle at the location: {0}.
diff --git a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/EclipseAdaptorMsg.java b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/EclipseAdaptorMsg.java
index 80ecfce..0294077 100644
--- a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/EclipseAdaptorMsg.java
+++ b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/EclipseAdaptorMsg.java
@@ -45,7 +45,8 @@
 	public static String ECLIPSE_CLASSLOADER_ACTIVATION;
 	public static String ECLIPSE_CLASSLOADER_ALREADY_STOPPED;
 	public static String ECLIPSE_CLASSLOADER_GENERATED_EXCEPTION;
-
+	public static String ECLIPSE_CLASSLOADER_CANNOT_SET_CONTEXTFINDER;
+	
 	public static String ECLIPSE_CONSOLE_COMMANDS_HEADER;
 	public static String ECLIPSE_CONSOLE_HELP_DIAG_COMMAND_DESCRIPTION;
 	public static String ECLIPSE_CONSOLE_HELP_ACTIVE_COMMAND_DESCRIPTION;
diff --git a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/EclipseBundleData.java b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/EclipseBundleData.java
index ea75cb0..aaf5d87 100644
--- a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/EclipseBundleData.java
+++ b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/EclipseBundleData.java
@@ -52,6 +52,10 @@
 	// the Eclipse-AutoStart header	
 	private boolean autoStart;
 	private String[] autoStartExceptions;
+	// shortcut to know if a bundle has a buddy
+	protected String buddyList;
+	// shortcut to know if a bundle is a registrant to a registered policy
+	protected String registeredBuddyList;
 
 	private static String[] buildLibraryVariants() {
 		ArrayList result = new ArrayList();
@@ -308,6 +312,8 @@
 			throw new IllegalStateException();
 		pluginClass = (String) manifest.get(EclipseAdaptor.PLUGIN_CLASS);
 		parseAutoStart((String) manifest.get(EclipseAdaptor.ECLIPSE_AUTOSTART));
+		buddyList = (String) manifest.get(Constants.BUDDY_LOADER); 
+		registeredBuddyList = (String) manifest.get(Constants.REGISTERED_POLICY);
 	}
 
 	public String getPluginClass() {
diff --git a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/EclipseStarter.java b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/EclipseStarter.java
index c3f8770..70cafd1 100644
--- a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/EclipseStarter.java
+++ b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/EclipseStarter.java
@@ -11,7 +11,7 @@
 package org.eclipse.core.runtime.adaptor;
 
 import java.io.*;
-import java.lang.reflect.Constructor;
+import java.lang.reflect.*;
 import java.net.*;
 import java.security.CodeSource;
 import java.security.ProtectionDomain;
@@ -251,6 +251,7 @@
 		processCommandLine(args);
 		LocationManager.initializeLocations();
 		log = createFrameworkLog();
+		initializeContextFinder();
 		loadConfigurationInfo();
 		finalizeProperties();
 		if (Profile.PROFILE)
@@ -295,6 +296,29 @@
 			Profile.logExit("EclipseStarter.startup()"); //$NON-NLS-1$
 	}
 
+	private static void initializeContextFinder() {
+		Thread current = Thread.currentThread();
+		try {
+			Method getContextClassLoader = Thread.class.getMethod("getContextClassLoader", null); //$NON-NLS-1$
+			Method setContextClassLoader = Thread.class.getMethod("setContextClassLoader", new Class[] { ClassLoader.class }); //$NON-NLS-1$
+			Object[] params = new Object[] { new ContextFinder((ClassLoader) getContextClassLoader.invoke(current, null)) };
+			setContextClassLoader.invoke(current, params);
+			return;
+		} catch (SecurityException e) {
+			//Ignore
+		} catch (NoSuchMethodException e) {
+			//Ignore
+		} catch (IllegalArgumentException e) {
+			//Ignore
+		} catch (IllegalAccessException e) {
+			//Ignore
+		} catch (InvocationTargetException e) {
+			//Ignore
+		}
+		FrameworkLogEntry entry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, NLS.bind(EclipseAdaptorMsg.ECLIPSE_CLASSLOADER_CANNOT_SET_CONTEXTFINDER, null), 0, null, null);
+		log.log(entry);
+	}
+
 	private static int getStartLevel() {
 		String level = System.getProperty(PROP_INITIAL_STARTLEVEL);
 		if (level != null)