The old packages from uninstalled and updated bundles remain available
until refreshPackages() is called per the spec; however, the spec also
states that new bundles should not be wired to these old packages. Felix'
resolving was wiring to the old packages. Related to this, Felix previously
associated "isRemovalPending()" with a bundle as a whole, but to fix the
resolver to wire only to new packages the "isRemovalPending()" must be
associated with the modules underlying bundles.
Thus, for example, if a bundle is updated, the module associated with the
old version is marked for removal (and thus its exported packages are
marked for removal), but the module associated with its new version is
not marked for removal. As a result, the resolver is able to correctly
avoid wiring new bundles to old packages.
git-svn-id: https://svn.apache.org/repos/asf/incubator/felix/trunk@423428 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/BundleInfo.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/BundleInfo.java
index 42e00b4..0bbd8ed 100644
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/BundleInfo.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/BundleInfo.java
@@ -19,14 +19,12 @@
import java.util.Map;
import org.apache.felix.framework.cache.BundleArchive;
+import org.apache.felix.framework.searchpolicy.R4SearchPolicy;
import org.apache.felix.moduleloader.IModule;
import org.osgi.framework.*;
class BundleInfo
{
- private static final int REMOVAL_PENDING_FLAG = 1;
- private static final int STALE_FLAG = 2;
-
private Logger m_logger = null;
private BundleArchive m_archive = null;
private IModule[] m_modules = null;
@@ -34,11 +32,9 @@
private long m_modified = 0;
private BundleActivator m_activator = null;
private BundleContext m_context = null;
- // Indicates that the bundle was either updated or
- // uninstalled and is waiting to be removed or refreshed,
- // or whether the bundle is stale because it was already
- // refreshed.
- private int m_removalState = 0;
+ // Indicates whether the bundle is stale, meaning that it has
+ // been refreshed and completely removed from the framework.
+ private boolean m_stale = false;
// Used for bundle locking.
private int m_lockCount = 0;
@@ -52,7 +48,7 @@
m_modules = (module == null) ? new IModule[0] : new IModule[] { module };
m_state = Bundle.INSTALLED;
- m_removalState = 0;
+ m_stale = false;
m_activator = null;
m_context = null;
}
@@ -305,24 +301,14 @@
m_activator = activator;
}
- public boolean isRemovalPending()
- {
- return (m_removalState & REMOVAL_PENDING_FLAG) != 0;
- }
-
- public void setRemovalPending()
- {
- m_removalState = (m_removalState | REMOVAL_PENDING_FLAG);
- }
-
public boolean isStale()
{
- return (m_removalState & STALE_FLAG) != 0;
+ return m_stale;
}
public void setStale()
{
- m_removalState = (m_removalState | STALE_FLAG | REMOVAL_PENDING_FLAG);
+ m_stale = true;
}
//
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/ExportedPackageImpl.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/ExportedPackageImpl.java
index 87a5146..0a24187 100644
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/ExportedPackageImpl.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/ExportedPackageImpl.java
@@ -16,6 +16,9 @@
*/
package org.apache.felix.framework;
+import org.apache.felix.framework.searchpolicy.IR4SearchPolicy;
+import org.apache.felix.framework.searchpolicy.R4Export;
+import org.apache.felix.moduleloader.IModule;
import org.osgi.framework.Bundle;
import org.osgi.framework.Version;
import org.osgi.service.packageadmin.ExportedPackage;
@@ -23,35 +26,35 @@
class ExportedPackageImpl implements ExportedPackage
{
private Felix m_felix = null;
- private BundleImpl m_exporter = null;
- private String m_name = null;
- private Version m_version = null;
+ private BundleImpl m_exportingBundle = null;
+ private IModule m_exportingModule = null;
+ private R4Export m_export = null;
private String m_toString = null;
private String m_versionString = null;
public ExportedPackageImpl(
- Felix felix, BundleImpl exporter, String name, Version version)
+ Felix felix, BundleImpl exporter, IModule module, R4Export export)
{
m_felix = felix;
- m_exporter = exporter;
- m_name = name;
- m_version = (version == null) ? Version.emptyVersion : version;
+ m_exportingBundle = exporter;
+ m_exportingModule = module;
+ m_export = export;
}
public Bundle getExportingBundle()
{
// If the package is stale, then return null per the spec.
- if (m_exporter.getInfo().isStale())
+ if (m_exportingBundle.getInfo().isStale())
{
return null;
}
- return m_exporter;
+ return m_exportingBundle;
}
public Bundle[] getImportingBundles()
{
// If the package is stale, then return null per the spec.
- if (m_exporter.getInfo().isStale())
+ if (m_exportingBundle.getInfo().isStale())
{
return null;
}
@@ -60,33 +63,38 @@
public String getName()
{
- return m_name;
+ return m_export.getName();
}
public String getSpecificationVersion()
{
if (m_versionString == null)
{
- m_versionString = m_version.toString();
+ m_versionString = (m_export.getVersion() == null)
+ ? Version.emptyVersion.toString()
+ : m_export.getVersion().toString();
}
return m_versionString;
}
public Version getVersion()
{
- return m_version;
+ return (m_export.getVersion() == null)
+ ? Version.emptyVersion
+ : m_export.getVersion();
}
public boolean isRemovalPending()
{
- return m_exporter.getInfo().isRemovalPending();
+ return ((IR4SearchPolicy)
+ m_exportingModule.getContentLoader().getSearchPolicy()).isRemovalPending();
}
public String toString()
{
if (m_toString == null)
{
- m_toString = m_name
+ m_toString = m_export.getName()
+ "; version=" + getSpecificationVersion();
}
return m_toString;
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/Felix.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/Felix.java
index 6a56bc8..aa0391b 100644
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/Felix.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/Felix.java
@@ -541,12 +541,17 @@
m_logger.log(Logger.LOG_ERROR, "Error stopping system bundle.", ex);
}
- // Loop through all bundles and update any updated bundles.
+ // Since they may be updated and uninstalled bundles that
+ // have not been refreshed, we will take care of refreshing
+ // them during shutdown.
+
+ // First loop through all bundled and purge old revisions
+ // from updated bundles.
Bundle[] bundles = getBundles();
for (int i = 0; i < bundles.length; i++)
{
BundleImpl bundle = (BundleImpl) bundles[i];
- if (bundle.getInfo().isRemovalPending())
+ if (bundle.getInfo().getArchive().getRevisionCount() > 1)
{
try
{
@@ -561,7 +566,7 @@
}
}
- // Remove any uninstalled bundles.
+ // Next garbage collection any uninstalled bundles.
for (int i = 0;
(m_uninstalledBundles != null) && (i < m_uninstalledBundles.length);
i++)
@@ -1534,12 +1539,14 @@
info.setState(Bundle.INSTALLED);
info.setLastModified(System.currentTimeMillis());
- // Mark as needing a refresh.
- info.setRemovalPending();
-
// Fire updated event if successful.
if (rethrow == null)
{
+ // Mark previous the bundle's old module for removal since
+ // it can no longer be used to resolve other modules per the spec.
+ IModule module = info.getModules()[info.getModules().length - 2];
+ m_policyCore.setRemovalPending(module, true);
+
fireBundleEvent(BundleEvent.UPDATED, bundle);
}
@@ -1761,8 +1768,9 @@
// Set the bundle's persistent state to uninstalled.
target.getInfo().setPersistentStateUninstalled();
- // Mark bundle for removal.
- target.getInfo().setRemovalPending();
+ // Mark current module for removal since it can no longer
+ // be used to resolve other modules per the spec.
+ m_policyCore.setRemovalPending(target.getInfo().getCurrentModule(), true);
// Put bundle in uninstalled bundle array.
rememberUninstalledBundle(bundle);
@@ -2519,7 +2527,7 @@
{
pkgs[pkgIdx] =
new ExportedPackageImpl(
- this, bundle, name, export.getVersion());
+ this, bundle, modules[modIdx], export);
}
}
}
@@ -2615,8 +2623,7 @@
if (inUseModules[i] == modules[modIdx])
{
list.add(new ExportedPackageImpl(
- this, bundle, exports[expIdx].getName(),
- exports[expIdx].getVersion()));
+ this, bundle, modules[modIdx], exports[expIdx]));
}
}
}
@@ -3979,7 +3986,7 @@
while (iter.hasNext())
{
BundleImpl bundle = (BundleImpl) iter.next();
- if (bundle.getInfo().isRemovalPending())
+ if (bundle.getInfo().getArchive().getRevisionCount() > 1)
{
list.add(bundle);
}
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/IR4SearchPolicy.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/IR4SearchPolicy.java
index 0a36b98..08ac520 100644
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/IR4SearchPolicy.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/IR4SearchPolicy.java
@@ -50,6 +50,9 @@
public void setResolved(boolean resolved);
public void resolve() throws ResolveException;
+ public boolean isRemovalPending();
+ public void setRemovalPending(boolean removePending);
+
public void addResolverListener(ResolveListener l);
public void removeResolverListener(ResolveListener l);
}
\ No newline at end of file
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4SearchPolicy.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4SearchPolicy.java
index ef6bfef..972c542 100644
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4SearchPolicy.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4SearchPolicy.java
@@ -118,6 +118,16 @@
m_policyCore.resolve(m_module);
}
+ public boolean isRemovalPending()
+ {
+ return m_policyCore.isRemovalPending(m_module);
+ }
+
+ public void setRemovalPending(boolean removalPending)
+ {
+ m_policyCore.setRemovalPending(m_module, removalPending);
+ }
+
public void addResolverListener(ResolveListener l)
{
m_policyCore.addResolverListener(l);
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4SearchPolicyCore.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4SearchPolicyCore.java
index 51bf370..30020d3 100755
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4SearchPolicyCore.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4SearchPolicyCore.java
@@ -254,6 +254,23 @@
data.m_resolved = resolved;
}
+ public synchronized boolean isRemovalPending(IModule module)
+ {
+ ModuleData data = (ModuleData) m_moduleDataMap.get(module);
+ return (data == null) ? false : data.m_removalPending;
+ }
+
+ public synchronized void setRemovalPending(IModule module, boolean removalPending)
+ {
+ ModuleData data = (ModuleData) m_moduleDataMap.get(module);
+ if (data == null)
+ {
+ data = new ModuleData(module);
+ m_moduleDataMap.put(module, data);
+ }
+ data.m_removalPending = removalPending;
+ }
+
public Object[] definePackage(IModule module, String pkgName)
{
R4Package pkg = Util.getExportPackage(module, pkgName);
@@ -541,7 +558,7 @@
// First check already resolved exports for a match.
IModule[] candidates = getCompatibleExporters(
- (IModule[]) m_inUsePkgMap.get(impMatch.getName()), impMatch);
+ (IModule[]) m_inUsePkgMap.get(impMatch.getName()), impMatch, false);
// If there is an "in use" candidate, just take the first one.
if (candidates.length > 0)
{
@@ -553,7 +570,7 @@
if (candidate == null)
{
candidates = getCompatibleExporters(
- (IModule[]) m_availPkgMap.get(impMatch.getName()), impMatch);
+ (IModule[]) m_availPkgMap.get(impMatch.getName()), impMatch, false);
for (int candIdx = 0;
(candidate == null) && (candIdx < candidates.length);
candIdx++)
@@ -674,7 +691,7 @@
synchronized (m_factory)
{
return getCompatibleExporters(
- (IModule[]) m_availPkgMap.get(pkg.getName()), pkg);
+ (IModule[]) m_availPkgMap.get(pkg.getName()), pkg, false);
}
}
@@ -685,7 +702,7 @@
synchronized (m_factory)
{
return getCompatibleExporters(
- (IModule[]) m_inUsePkgMap.get(pkg.getName()), pkg);
+ (IModule[]) m_inUsePkgMap.get(pkg.getName()), pkg, true);
}
}
@@ -796,10 +813,10 @@
// at the front of the list of candidates.
IModule[] inuse = getCompatibleExporters(
(IModule[]) m_inUsePkgMap.get(
- imports[impIdx].getName()), imports[impIdx]);
+ imports[impIdx].getName()), imports[impIdx], false);
IModule[] available = getCompatibleExporters(
(IModule[]) m_availPkgMap.get(
- imports[impIdx].getName()), imports[impIdx]);
+ imports[impIdx].getName()), imports[impIdx], false);
IModule[] candidates = new IModule[inuse.length + available.length];
System.arraycopy(inuse, 0, candidates, 0, inuse.length);
System.arraycopy(available, 0, candidates, inuse.length, available.length);
@@ -873,11 +890,14 @@
for (Iterator i = m_availPkgMap.entrySet().iterator(); i.hasNext(); )
{
Map.Entry entry = (Map.Entry) i.next();
- System.out.println(" " + entry.getKey());
IModule[] modules = (IModule[]) entry.getValue();
- for (int j = 0; j < modules.length; j++)
+ if ((modules != null) && (modules.length > 0))
{
- System.out.println(" " + modules[j]);
+ System.out.println(" " + entry.getKey());
+ for (int j = 0; j < modules.length; j++)
+ {
+ System.out.println(" " + modules[j]);
+ }
}
}
}
@@ -891,28 +911,38 @@
for (Iterator i = m_inUsePkgMap.entrySet().iterator(); i.hasNext(); )
{
Map.Entry entry = (Map.Entry) i.next();
- System.out.println(" " + entry.getKey());
IModule[] modules = (IModule[]) entry.getValue();
- for (int j = 0; j < modules.length; j++)
+ if ((modules != null) && (modules.length > 0))
{
- System.out.println(" " + modules[j]);
+ System.out.println(" " + entry.getKey());
+ for (int j = 0; j < modules.length; j++)
+ {
+ System.out.println(" " + modules[j]);
+ }
}
}
}
}
- private IModule[] getCompatibleExporters(IModule[] modules, R4Import target)
+ private IModule[] getCompatibleExporters(
+ IModule[] modules, R4Import target, boolean includeRemovalPending)
{
// Create list of compatible exporters.
IModule[] candidates = null;
for (int modIdx = 0; (modules != null) && (modIdx < modules.length); modIdx++)
{
- // Get the modules export package for the target package.
- R4Export export = Util.getExportPackage(modules[modIdx], target.getName());
- // If compatible, then add the candidate to the list.
- if ((export != null) && (target.isSatisfied(export)))
+ // The spec says that we cannot consider modules that
+ // are pending removal, so ignore them.
+ if (includeRemovalPending || !isRemovalPending(modules[modIdx]))
{
- candidates = addModuleToArray(candidates, modules[modIdx]);
+ // Get the modules export package for the target package.
+ R4Export export = Util.getExportPackage(
+ modules[modIdx], target.getName());
+ // If compatible, then add the candidate to the list.
+ if ((export != null) && (target.isSatisfied(export)))
+ {
+ candidates = addModuleToArray(candidates, modules[modIdx]);
+ }
}
}
if (candidates == null)
@@ -1583,6 +1613,7 @@
public R4Library[] m_libraries = null;
public R4Wire[] m_wires = null;
public boolean m_resolved = false;
+ public boolean m_removalPending = false;
public ModuleData(IModule module)
{
m_module = module;