Bug 560788 - Improve runtime exceptions out of the framework

Improve exception methods to include information about the bundle
related to the exception.  This is not an exhaustive change, but it does
improve many of the common error that can happen when a bundle is
uninstalled or a bundle context is invalid or a service is unregistered.

Change-Id: I983a1fb4750f24259df71f73b4646134c3f1cc26
Signed-off-by: Thomas Watson <tjwatson@us.ibm.com>
diff --git a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/BundleTests.java b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/BundleTests.java
index 0b497d5..e955a5c 100644
--- a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/BundleTests.java
+++ b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/BundleTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2006, 2018 IBM Corporation and others.
+ * Copyright (c) 2006, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -19,6 +19,7 @@
 public class BundleTests {
 	public static Test suite() {
 		TestSuite suite = new TestSuite(BundleTests.class.getName());
+		suite.addTest(ExceptionMessageTest.suite());
 		suite.addTest(ImportJavaSEPackagesTests.suite());
 		suite.addTest(MultiReleaseJarTests.suite());
 		suite.addTest(URLHandlerTests.suite());
diff --git a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/ExceptionMessageTest.java b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/ExceptionMessageTest.java
new file mode 100644
index 0000000..0c5a4cf
--- /dev/null
+++ b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/ExceptionMessageTest.java
@@ -0,0 +1,148 @@
+/*******************************************************************************
+ * Copyright (c) 2020 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.tests.bundles;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+import org.eclipse.osgi.container.Module;
+import org.eclipse.osgi.tests.OSGiTestsActivator;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.framework.startlevel.BundleStartLevel;
+
+public class ExceptionMessageTest extends AbstractBundleTests {
+	public static Test suite() {
+		return new TestSuite(ExceptionMessageTest.class);
+	}
+
+	public void testTrasientStartLevelError() throws BundleException {
+		Bundle b = installer.installBundle("test");
+		b.adapt(BundleStartLevel.class).setStartLevel(500);
+		try {
+			b.start(Bundle.START_TRANSIENT);
+			fail();
+		} catch (BundleException e) {
+			assertTrue("Wrong message: " + e.getMessage(), e.getMessage().endsWith(b.adapt(Module.class).toString()));
+		}
+	}
+
+	public void testUninstallModuleError() throws BundleException {
+		Bundle b = installer.installBundle("test");
+		BundleStartLevel bsl = b.adapt(BundleStartLevel.class);
+		b.uninstall();
+		try {
+			bsl.getStartLevel();
+			fail();
+		} catch (IllegalStateException e) {
+			assertTrue("Wrong message: " + e.getMessage(), e.getMessage().endsWith(b.adapt(Module.class).toString()));
+		}
+	}
+
+	public void testUninstallContextError() throws BundleException, InvalidSyntaxException {
+		Bundle b = installer.installBundle("test");
+		b.start();
+		BundleContext context = b.getBundleContext();
+		b.uninstall();
+		try {
+			context.createFilter("(a=b)");
+			fail();
+		} catch (IllegalStateException e) {
+			assertTrue("Wrong message: " + e.getMessage(), e.getMessage().endsWith(b.toString()));
+		}
+	}
+
+	public void testStartFragmentError() throws BundleException, IOException {
+		Map<String, String> headers = new HashMap<>();
+		headers.put(Constants.BUNDLE_SYMBOLICNAME, "fragment");
+		headers.put(Constants.FRAGMENT_HOST, "host");
+		File bundles = OSGiTestsActivator.getContext().getDataFile("/"); // $NON-NLS-1$
+		File bundleFile = SystemBundleTests.createBundle(bundles, getName(), headers);
+		Bundle b = OSGiTestsActivator.getContext().installBundle(bundleFile.toURI().toString());
+		try {
+			b.start();
+			fail();
+		} catch (BundleException e) {
+			assertTrue("Wrong message: " + e.getMessage(), e.getMessage().endsWith(b.adapt(Module.class).toString()));
+		} finally {
+			b.uninstall();
+		}
+	}
+
+	public void testLoadActivatorError() throws IOException, BundleException {
+		Map<String, String> headers = new HashMap<>();
+		headers.put(Constants.BUNDLE_ACTIVATOR, "does.not.Exist");
+		headers.put(Constants.BUNDLE_SYMBOLICNAME, "no.activator");
+		File bundles = OSGiTestsActivator.getContext().getDataFile("/"); // $NON-NLS-1$
+		File bundleFile = SystemBundleTests.createBundle(bundles, getName(), headers);
+		Bundle b = OSGiTestsActivator.getContext().installBundle(bundleFile.toURI().toString());
+		try {
+			b.start();
+			fail();
+		} catch (BundleException e) {
+			assertTrue("Wrong message: " + e.getMessage(), e.getMessage().endsWith(b.toString()));
+		} finally {
+			b.uninstall();
+		}
+	}
+
+	public void testUnregisterSetPropsError() throws BundleException {
+		Bundle b = installer.installBundle("test");
+		b.start();
+		BundleContext context = b.getBundleContext();
+		ServiceRegistration<Object> reg = context.registerService(Object.class, new Object(),
+				new Hashtable<>(Collections.singletonMap("k1", "v1")));
+		reg.unregister();
+
+		try {
+			reg.setProperties(new Hashtable<>(Collections.singletonMap("k2", "v2")));
+			fail();
+		} catch (IllegalStateException e) {
+			assertTrue("Wrong message: " + e.getMessage(), e.getMessage().endsWith(reg.toString()));
+		}
+
+		try {
+			reg.unregister();
+			fail();
+		} catch (IllegalStateException e) {
+			assertTrue("Wrong message: " + e.getMessage(), e.getMessage().endsWith(reg.toString()));
+		}
+
+		try {
+			reg.getReference();
+			fail();
+		} catch (IllegalStateException e) {
+			assertTrue("Wrong message: " + e.getMessage(), e.getMessage().endsWith(reg.toString()));
+		}
+	}
+
+	public void testUnregisterTwiceError() throws BundleException {
+		Bundle b = installer.installBundle("test");
+		b.start();
+		BundleContext context = b.getBundleContext();
+		ServiceRegistration<Object> reg = context.registerService(Object.class, new Object(),
+				new Hashtable<>(Collections.singletonMap("k1", "v1")));
+		reg.unregister();
+
+	}
+}
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/Module.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/Module.java
index 8f92194..64cda18 100644
--- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/Module.java
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/Module.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2012, 2016 IBM Corporation and others.
+ * Copyright (c) 2012, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -350,7 +350,7 @@
 			throw new BundleException(Msg.Module_LockError + exceptonInfo, BundleException.STATECHANGE_ERROR, cause);
 		} catch (InterruptedException e) {
 			Thread.currentThread().interrupt();
-			throw new BundleException(Msg.Module_LockError + toString() + " " + transitionEvent, BundleException.STATECHANGE_ERROR, e); //$NON-NLS-1$
+			throw new BundleException(Msg.Module_LockError + toString() + ' ' + transitionEvent, BundleException.STATECHANGE_ERROR, e);
 		} finally {
 			if (previousInterruption) {
 				Thread.currentThread().interrupt();
@@ -428,7 +428,8 @@
 			if (getStartLevel() > container.getStartLevel()) {
 				if (StartOptions.TRANSIENT.isContained(options)) {
 					// it is an error to attempt to transient start a bundle without its start level met
-					throw new BundleException(Msg.Module_Transient_StartError, BundleException.START_TRANSIENT_ERROR);
+					throw new BundleException(Msg.Module_Transient_StartError + ' ' + this,
+							BundleException.START_TRANSIENT_ERROR);
 				}
 				// Do nothing; start level is not met
 				return;
@@ -539,7 +540,8 @@
 	private void checkFragment() throws BundleException {
 		ModuleRevision current = getCurrentRevision();
 		if ((current.getTypes() & BundleRevision.TYPE_FRAGMENT) != 0) {
-			throw new BundleException(Msg.Module_Fragment_InvalidOperation, BundleException.INVALID_OPERATION);
+			throw new BundleException(Msg.Module_Fragment_InvalidOperation + ' ' + this,
+					BundleException.INVALID_OPERATION);
 		}
 	}
 
@@ -555,7 +557,7 @@
 
 	final void checkValid() {
 		if (getState().equals(State.UNINSTALLED))
-			throw new IllegalStateException(Msg.Module_UninstalledError);
+			throw new IllegalStateException(Msg.Module_UninstalledError + ' ' + this);
 	}
 
 	private ModuleEvent doStart(StartOptions... options) throws BundleException {
@@ -609,7 +611,7 @@
 			publishEvent(ModuleEvent.STOPPING);
 			if (t instanceof BundleException)
 				throw (BundleException) t;
-			throw new BundleException(Msg.Module_StartError, BundleException.ACTIVATOR_ERROR, t);
+			throw new BundleException(Msg.Module_StartError + ' ' + this, BundleException.ACTIVATOR_ERROR, t);
 		}
 	}
 
@@ -660,7 +662,7 @@
 		} catch (Throwable t) {
 			if (t instanceof BundleException)
 				throw (BundleException) t;
-			throw new BundleException(Msg.Module_StopError, BundleException.ACTIVATOR_ERROR, t);
+			throw new BundleException(Msg.Module_StopError + ' ' + this, BundleException.ACTIVATOR_ERROR, t);
 		} finally {
 			// must always set the state to stopped
 			setState(State.RESOLVED);
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleContainer.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleContainer.java
index a45fafd..4a4836d 100644
--- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleContainer.java
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleContainer.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2012, 2018 IBM Corporation and others.
+ * Copyright (c) 2012, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -348,7 +348,8 @@
 			// Attempt to lock the name
 			try {
 				if (name != null && !(nameLocked = nameLocks.tryLock(name, 5, TimeUnit.SECONDS))) {
-					throw new BundleException("Failed to obtain id locks for installation.", BundleException.STATECHANGE_ERROR, new ThreadInfoReport(nameLocks.getLockInfo(name))); //$NON-NLS-1$
+					throw new BundleException("Failed to obtain id locks for installation: " + name, //$NON-NLS-1$
+							BundleException.STATECHANGE_ERROR, new ThreadInfoReport(nameLocks.getLockInfo(name)));
 				}
 			} catch (InterruptedException e) {
 				Thread.currentThread().interrupt();
@@ -1503,7 +1504,7 @@
 					for (Bundle bundle : bundles) {
 						Module module = bundle.adapt(Module.class);
 						if (module == null)
-							throw new IllegalStateException("Could not adapt a bundle to a module."); //$NON-NLS-1$
+							throw new IllegalStateException("Could not adapt a bundle to a module. " + bundle); //$NON-NLS-1$
 						result.add(module);
 					}
 					return result;
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleRevisionBuilder.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleRevisionBuilder.java
index ca895ae..0d9b6f3 100644
--- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleRevisionBuilder.java
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleRevisionBuilder.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2012, 2017 IBM Corporation and others.
+ * Copyright (c) 2012, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -279,7 +279,8 @@
 							if (systemNames.contains(hostName)) {
 								Bundle b = module.getBundle();
 								if (b != null && !b.hasPermission(new AllPermission())) {
-									SecurityException se = new SecurityException("Must have AllPermission granted to install an extension bundle"); //$NON-NLS-1$
+									SecurityException se = new SecurityException(
+											"Must have AllPermission granted to install an extension bundle: " + b); //$NON-NLS-1$
 									// TODO this is such a hack: making the cause a bundle exception so we can throw the right one later
 									BundleException be = new BundleException(se.getMessage(), BundleException.SECURITY_ERROR, se);
 									se.initCause(be);
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleRevisions.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleRevisions.java
index 2570138..f298dec 100644
--- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleRevisions.java
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleRevisions.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2012, 2016 IBM Corporation and others.
+ * Copyright (c) 2012, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -121,7 +121,7 @@
 			uninstalled = true;
 			// save off the current revision
 			if (revisions.isEmpty()) {
-				throw new IllegalStateException("Revisions is empty on uninstall!"); //$NON-NLS-1$
+				throw new IllegalStateException("Revisions is empty on uninstall! " + module); //$NON-NLS-1$
 			}
 			uninstalledCurrent = revisions.get(0);
 		}
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/container/LockSet.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/container/LockSet.java
index 67dd60b..b118a35 100644
--- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/container/LockSet.java
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/container/LockSet.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2012, 2018 IBM Corporation and others.
+ * Copyright (c) 2012, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -98,7 +98,7 @@
 		synchronized (locks) {
 			LockHolder lock = locks.get(t);
 			if (lock == null)
-				throw new IllegalStateException("No lock found."); //$NON-NLS-1$
+				throw new IllegalStateException("No lock found: " + t); //$NON-NLS-1$
 			lock.unlock();
 			// If, after unlocking, no other thread is using the lock, discard it.
 			if (lock.decremementUseCount() == 0) {
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/framework/BundleContextImpl.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/framework/BundleContextImpl.java
index 29b20c0..0f059c8 100644
--- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/framework/BundleContextImpl.java
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/framework/BundleContextImpl.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2003, 2017 IBM Corporation and others.
+ * Copyright (c) 2003, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -783,7 +783,8 @@
 			if (e instanceof RuntimeException) {
 				throw (RuntimeException) e;
 			}
-			throw new BundleException(Msg.BundleContextImpl_LoadActivatorError, BundleException.ACTIVATOR_ERROR, e);
+			throw new BundleException(Msg.BundleContextImpl_LoadActivatorError + ' ' + bundle,
+					BundleException.ACTIVATOR_ERROR, e);
 		}
 
 		if (activator != null) {
@@ -1052,7 +1053,7 @@
 	 */
 	public void checkValid() {
 		if (!isValid()) {
-			throw new IllegalStateException(Msg.BUNDLE_CONTEXT_INVALID_EXCEPTION);
+			throw new IllegalStateException(Msg.BUNDLE_CONTEXT_INVALID_EXCEPTION + ' ' + bundle);
 		}
 	}
 
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/framework/EquinoxBundle.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/framework/EquinoxBundle.java
index 684d805..ad6fb1a 100644
--- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/framework/EquinoxBundle.java
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/framework/EquinoxBundle.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2012, 2017 IBM Corporation and others.
+ * Copyright (c) 2012, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -287,14 +287,14 @@
 		}
 
 		void addInitFrameworkListeners() {
-			BundleContext context = createBundleContext(false);
+			BundleContext context = createBundleContext();
 			for (FrameworkListener initListener : initListeners) {
 				context.addFrameworkListener(initListener);
 			}
 		}
 
 		void removeInitListeners() {
-			BundleContext context = createBundleContext(false);
+			BundleContext context = createBundleContext();
 			for (FrameworkListener initListener : initListeners) {
 				context.removeFrameworkListener(initListener);
 			}
@@ -721,10 +721,10 @@
 	@Override
 	public BundleContext getBundleContext() {
 		equinoxContainer.checkAdminPermission(this, AdminPermission.CONTEXT);
-		return createBundleContext(true);
+		return createBundleContext();
 	}
 
-	BundleContextImpl createBundleContext(boolean checkPermission) {
+	BundleContextImpl createBundleContext() {
 		if (isFragment()) {
 			// fragments cannot have contexts
 			return null;
@@ -999,7 +999,7 @@
 
 	private final void checkValid() {
 		if (module.getState().equals(State.UNINSTALLED))
-			throw new IllegalStateException("Module has been uninstalled."); //$NON-NLS-1$
+			throw new IllegalStateException("Bundle has been uninstalled: " + this); //$NON-NLS-1$
 	}
 
 	public boolean isFragment() {
@@ -1007,9 +1007,9 @@
 	}
 
 	void startWorker0() throws BundleException {
-		BundleContextImpl current = createBundleContext(false);
+		BundleContextImpl current = createBundleContext();
 		if (current == null) {
-			throw new BundleException("Unable to create bundle context!"); //$NON-NLS-1$
+			throw new BundleException("Unable to create bundle context! " + this); //$NON-NLS-1$
 		}
 		try {
 			current.start();
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/serviceregistry/ServiceRegistrationImpl.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/serviceregistry/ServiceRegistrationImpl.java
index 09a0c82..c81a64b 100644
--- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/serviceregistry/ServiceRegistrationImpl.java
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/serviceregistry/ServiceRegistrationImpl.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2003, 2017 IBM Corporation and others.
+ * Copyright (c) 2003, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -14,12 +14,23 @@
 
 package org.eclipse.osgi.internal.serviceregistry;
 
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.List;
+import java.util.Map;
 import org.eclipse.osgi.internal.debug.Debug;
 import org.eclipse.osgi.internal.framework.BundleContextImpl;
 import org.eclipse.osgi.internal.loader.sources.PackageSource;
 import org.eclipse.osgi.internal.messages.Msg;
-import org.osgi.framework.*;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+import org.osgi.framework.FrameworkEvent;
+import org.osgi.framework.PrototypeServiceFactory;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceException;
+import org.osgi.framework.ServiceFactory;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
 
 /**
  * A registered service.
@@ -159,7 +170,7 @@
 		synchronized (registry) {
 			synchronized (registrationLock) {
 				if (state != REGISTERED) { /* in the process of unregisterING */
-					throw new IllegalStateException(Msg.SERVICE_ALREADY_UNREGISTERED_EXCEPTION);
+					throw new IllegalStateException(Msg.SERVICE_ALREADY_UNREGISTERED_EXCEPTION + ' ' + this);
 				}
 
 				ref = reference; /* used to publish event outside sync */
@@ -208,7 +219,7 @@
 		synchronized (registry) {
 			synchronized (registrationLock) {
 				if (state != REGISTERED) { /* in the process of unregisterING */
-					throw new IllegalStateException(Msg.SERVICE_ALREADY_UNREGISTERED_EXCEPTION);
+					throw new IllegalStateException(Msg.SERVICE_ALREADY_UNREGISTERED_EXCEPTION + ' ' + this);
 				}
 
 				/* remove this object from the service registry */
@@ -288,7 +299,7 @@
 		 */
 		synchronized (registrationLock) {
 			if (reference == null) {
-				throw new IllegalStateException(Msg.SERVICE_ALREADY_UNREGISTERED_EXCEPTION);
+				throw new IllegalStateException(Msg.SERVICE_ALREADY_UNREGISTERED_EXCEPTION + ' ' + this);
 			}
 
 			return reference;
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/FrameworkExtensionInstaller.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/FrameworkExtensionInstaller.java
index 5737b0c..3013700 100644
--- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/FrameworkExtensionInstaller.java
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/FrameworkExtensionInstaller.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2013, 2017 IBM Corporation and others.
+ * Copyright (c) 2013, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -152,7 +152,7 @@
 						callAddFilePathMethod(file);
 					}
 				} catch (InvocationTargetException | MalformedURLException e) {
-					throw new BundleException("Error adding extension content.", e); //$NON-NLS-1$
+					throw new BundleException("Error adding extension content. " + revision, e); //$NON-NLS-1$
 				}
 			}
 		}
@@ -268,7 +268,8 @@
 		} catch (Throwable e) {
 			BundleException eventException;
 			if (activator == null) {
-				eventException = new BundleException(Msg.BundleContextImpl_LoadActivatorError, BundleException.ACTIVATOR_ERROR, e);
+				eventException = new BundleException(Msg.BundleContextImpl_LoadActivatorError + ' ' + extensionRevision,
+						BundleException.ACTIVATOR_ERROR, e);
 			} else {
 				eventException = new BundleException(NLS.bind(Msg.BUNDLE_ACTIVATOR_EXCEPTION, new Object[] {activator.getClass(), "start", extensionRevision.getSymbolicName()}), BundleException.ACTIVATOR_ERROR, e); //$NON-NLS-1$
 			}