If a fragment bundle is uninstalled, it must be unmerged from any unresolved
hosts to avoid causing an exception.
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@904631 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/framework/src/main/java/org/apache/felix/framework/BundleImpl.java b/framework/src/main/java/org/apache/felix/framework/BundleImpl.java
index 587098b..9226422 100644
--- a/framework/src/main/java/org/apache/felix/framework/BundleImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/BundleImpl.java
@@ -134,6 +134,21 @@
}
}
+ /**
+ * This is sort of a hacky method called after uninstalling a bundle.
+ * If the bundle is a fragment, this will unmerge it from any unresolved
+ * hosts. This is necessary since fragments are pre-merged into unresolved
+ * hosts. If uninstalled fragments are not unmerged from unresolved hosts,
+ * any attempts to subsequently resolve the host will result in an exception.
+ */
+ synchronized void cleanAfterUninstall()
+ {
+ for (int i = 0; i < m_modules.length; i++)
+ {
+ getFramework().getResolverState().unmergeFragment(m_modules[i]);
+ }
+ }
+
synchronized void refresh() throws Exception
{
if (isExtension() && (getFramework().getState() != Bundle.STOPPING))
diff --git a/framework/src/main/java/org/apache/felix/framework/Felix.java b/framework/src/main/java/org/apache/felix/framework/Felix.java
index b1e3b92..7db8b23 100644
--- a/framework/src/main/java/org/apache/felix/framework/Felix.java
+++ b/framework/src/main/java/org/apache/felix/framework/Felix.java
@@ -2261,6 +2261,10 @@
// Set state to uninstalled.
setBundleStateAndNotify(bundle, Bundle.UNINSTALLED);
bundle.setLastModified(System.currentTimeMillis());
+
+ // If this bundle is a fragment, unmerge it from any
+ // unresolved hosts.
+ bundle.cleanAfterUninstall();
}
finally
{
diff --git a/framework/src/main/java/org/apache/felix/framework/FelixResolverState.java b/framework/src/main/java/org/apache/felix/framework/FelixResolverState.java
index 367ef0c..8f89e6e 100644
--- a/framework/src/main/java/org/apache/felix/framework/FelixResolverState.java
+++ b/framework/src/main/java/org/apache/felix/framework/FelixResolverState.java
@@ -288,6 +288,101 @@
}
}
+ public void unmergeFragment(IModule module)
+ {
+ if (!Util.isFragment(module))
+ {
+ return;
+ }
+
+ // Get fragment list, which may be null for system bundle fragments.
+ List fragList = (List) m_fragmentMap.get(module.getSymbolicName());
+ if (fragList != null)
+ {
+ // Remove from fragment map.
+ fragList.remove(module);
+ if (fragList.size() == 0)
+ {
+ m_fragmentMap.remove(module.getSymbolicName());
+ }
+
+ // If we have any matching hosts, then remove fragment while
+ // removing any older version of the new fragment. Also remove host's
+ // existing capabilities from the package index and reindex its new
+ // ones after attaching the fragment.
+ List matchingHosts = getMatchingHosts(module);
+ for (int hostIdx = 0; hostIdx < matchingHosts.size(); hostIdx++)
+ {
+ IModule host = ((ICapability) matchingHosts.get(hostIdx)).getModule();
+ // Find any unresolved hosts into which the fragment is merged
+ // and unmerge it.
+ IModule[] fragments = ((ModuleImpl) host).getFragments();
+ for (int fragIdx = 0;
+ !host.isResolved() && (fragments != null) && (fragIdx < fragments.length);
+ fragIdx++)
+ {
+ if (!fragments[fragIdx].equals(module))
+ {
+ List fragmentList = getMatchingFragments(host);
+
+ // Remove host's existing exported packages from index.
+ ICapability[] caps = host.getCapabilities();
+ for (int i = 0; (caps != null) && (i < caps.length); i++)
+ {
+ if (caps[i].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
+ {
+ // Get package name.
+ String pkgName = (String)
+ caps[i].getProperties().get(ICapability.PACKAGE_PROPERTY);
+ // Remove from "unresolved" package map.
+ List capList = (List) m_unresolvedPkgIndex.get(pkgName);
+ if (capList != null)
+ {
+ capList.remove(caps[i]);
+ }
+ }
+ }
+
+ // Check if fragment conflicts with existing metadata.
+ checkForConflicts(host, fragmentList);
+
+ // Attach the fragments to the host.
+ fragments = (fragmentList.size() == 0)
+ ? null
+ : (IModule[]) fragmentList.toArray(new IModule[fragmentList.size()]);
+ try
+ {
+ ((ModuleImpl) host).attachFragments(fragments);
+ }
+ catch (Exception ex)
+ {
+ // Try to clean up by removing all fragments.
+ try
+ {
+ ((ModuleImpl) host).attachFragments(null);
+ }
+ catch (Exception ex2)
+ {
+ }
+ m_logger.log(Logger.LOG_ERROR,
+ "Serious error attaching fragments.", ex);
+ }
+
+ // Reindex the host's exported packages.
+ caps = host.getCapabilities();
+ for (int i = 0; (caps != null) && (i < caps.length); i++)
+ {
+ if (caps[i].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
+ {
+ indexPackageCapability(m_unresolvedPkgIndex, caps[i]);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
private List getMatchingHosts(IModule fragment)
{
// Find the fragment's host requirement.