Move dependency bookkeeping out of BundleRevisionImpl to try to clean
up design. (FELIX-2950)
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1102831 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 88bfd9d..4ed25da 100644
--- a/framework/src/main/java/org/apache/felix/framework/BundleImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/BundleImpl.java
@@ -96,6 +96,7 @@
return m_archive;
}
+// Only called when the framework is stopping. Don't need to clean up dependencies.
synchronized void close()
{
closeRevisions();
@@ -112,6 +113,9 @@
}
}
+// Called when install fails, when stopping framework with uninstalled bundles,
+// and when refreshing an uninstalled bundle. Only need to clear up dependencies
+// for last case.
synchronized void closeAndDelete() throws Exception
{
// Mark the bundle as stale, since it is being deleted.
@@ -122,6 +126,7 @@
m_archive.closeAndDelete();
}
+// Called from BundleImpl.close(), BundleImpl.closeAndDelete(), and BundleImpl.refresh()
private void closeRevisions()
{
// Remove the bundle's associated revisions from the resolver state
@@ -136,6 +141,7 @@
}
}
+// Called when refreshing a bundle. Must clean up dependencies beforehand.
synchronized void refresh() throws Exception
{
if (isExtension() && (getFramework().getState() != Bundle.STOPPING))
@@ -1048,35 +1054,6 @@
return m_revisions.get(m_revisions.size() - 1);
}
- synchronized boolean isUsed()
- {
- boolean unresolved = true;
- for (int i = 0; unresolved && (i < m_revisions.size()); i++)
- {
- if (m_revisions.get(i).getWiring() != null)
- {
- unresolved = false;
- }
- }
- boolean used = false;
- for (int i = 0; !unresolved && !used && (i < m_revisions.size()); i++)
- {
- if (m_revisions.get(i).getWiring() != null)
- {
- List<BundleRevision> dependents =
- ((BundleRevisionImpl) m_revisions.get(i)).getDependents();
- for (int j = 0; (dependents != null) && (j < dependents.size()) && !used; j++)
- {
- if (dependents.get(j) != m_revisions.get(i))
- {
- used = true;
- }
- }
- }
- }
- return used;
- }
-
synchronized void revise(String location, InputStream is)
throws Exception
{
diff --git a/framework/src/main/java/org/apache/felix/framework/BundleRevisionDependencies.java b/framework/src/main/java/org/apache/felix/framework/BundleRevisionDependencies.java
new file mode 100644
index 0000000..72c28ad
--- /dev/null
+++ b/framework/src/main/java/org/apache/felix/framework/BundleRevisionDependencies.java
@@ -0,0 +1,271 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.framework;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import org.apache.felix.framework.util.Util;
+import org.apache.felix.framework.wiring.BundleCapabilityImpl;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.wiring.BundleCapability;
+import org.osgi.framework.wiring.BundleRevision;
+import org.osgi.framework.wiring.BundleWire;
+import org.osgi.framework.wiring.BundleWiring;
+
+class BundleRevisionDependencies
+{
+ private final Map<BundleRevision, Map<BundleCapability, Set<BundleRevision>>>
+ m_dependentsMap = new HashMap<BundleRevision, Map<BundleCapability, Set<BundleRevision>>>();
+
+ public synchronized void addDependent(BundleRevision provider, BundleCapability cap, BundleRevision requirer)
+ {
+ Map<BundleCapability, Set<BundleRevision>> caps = m_dependentsMap.get(provider);
+ if (caps == null)
+ {
+ caps = new HashMap<BundleCapability, Set<BundleRevision>>();
+ m_dependentsMap.put(provider, caps);
+ }
+ Set<BundleRevision> dependents = caps.get(cap);
+ if (dependents == null)
+ {
+ dependents = new HashSet<BundleRevision>();
+ caps.put(cap, dependents);
+ }
+ dependents.add(requirer);
+ }
+
+ public synchronized void removeDependent(
+ BundleRevision provider, BundleCapability cap, BundleRevision requirer)
+ {
+ Map<BundleCapability, Set<BundleRevision>> caps = m_dependentsMap.get(provider);
+ if (caps != null)
+ {
+ Set<BundleRevision> dependents = caps.get(cap);
+ if (dependents == null)
+ {
+ dependents.remove(requirer);
+ if (dependents.isEmpty())
+ {
+ caps.remove(cap);
+ if (caps.isEmpty())
+ {
+ m_dependentsMap.remove(provider);
+ }
+ }
+ }
+ }
+ }
+
+ public synchronized void removeDependents(BundleRevision provider)
+ {
+ m_dependentsMap.remove(provider);
+ }
+
+ public synchronized Map<BundleCapability, Set<BundleRevision>>
+ getDependents(BundleRevision provider)
+ {
+ return m_dependentsMap.get(provider);
+ }
+
+ public synchronized boolean hasDependents(BundleImpl bundle)
+ {
+ List<BundleRevision> revisions = bundle.getRevisions();
+ for (BundleRevision revision : revisions)
+ {
+ if (m_dependentsMap.containsKey(revision))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public synchronized Set<Bundle> getDependentBundles(BundleImpl bundle)
+ {
+ Set<Bundle> result = new HashSet<Bundle>();
+
+ List<BundleRevision> revisions = bundle.getRevisions();
+ for (BundleRevision revision : revisions)
+ {
+// TODO: OSGi R4.3 - This is sort of a hack. We need to special case fragments,
+// since their dependents are their hosts.
+ if (Util.isFragment(revision))
+ {
+ if (revision.getWiring() != null)
+ {
+ for (BundleWire wire : revision.getWiring().getRequiredWires(null))
+ {
+ result.add(wire.getProviderWiring().getBundle());
+ }
+ }
+ }
+ else
+ {
+ Map<BundleCapability, Set<BundleRevision>> caps =
+ m_dependentsMap.get(revision);
+ if (caps != null)
+ {
+ for (Entry<BundleCapability, Set<BundleRevision>> entry : caps.entrySet())
+ {
+ for (BundleRevision rev : entry.getValue())
+ {
+ result.add(rev.getBundle());
+ }
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+
+ public synchronized Set<Bundle> getImportingBundles(
+ BundleImpl exporter, BundleCapability exportCap)
+ {
+ // Create set for storing importing bundles.
+ Set<Bundle> result = new HashSet<Bundle>();
+
+ // Get exported package name.
+ String pkgName = (String)
+ exportCap.getAttributes().get(BundleCapabilityImpl.PACKAGE_ATTR);
+
+ // Get all importers and requirers for all revisions of the bundle.
+ // The spec says that require-bundle should be returned with importers.
+ for (BundleRevision revision : exporter.getRevisions())
+ {
+ Map<BundleCapability, Set<BundleRevision>>
+ caps = m_dependentsMap.get(revision);
+ if (caps != null)
+ {
+ for (Entry<BundleCapability, Set<BundleRevision>> entry : caps.entrySet())
+ {
+ BundleCapability cap = entry.getKey();
+ if ((cap.getNamespace().equals(BundleCapabilityImpl.PACKAGE_NAMESPACE)
+ && cap.getAttributes().get(BundleCapabilityImpl.PACKAGE_ATTR)
+ .equals(pkgName))
+ || cap.getNamespace().equals(BundleCapabilityImpl.BUNDLE_NAMESPACE))
+ {
+ for (BundleRevision dependent : entry.getValue())
+ {
+ result.add(dependent.getBundle());
+ }
+ }
+ }
+ }
+ }
+
+ // Return the results.
+ return result;
+ }
+
+ public synchronized Set<Bundle> getRequiringBundles(BundleImpl bundle)
+ {
+ // Create set for storing requiring bundles.
+ Set<Bundle> result = new HashSet<Bundle>();
+
+ // Get all requirers for all revisions of the bundle.
+ for (BundleRevision revision : bundle.getRevisions())
+ {
+ Map<BundleCapability, Set<BundleRevision>>
+ caps = m_dependentsMap.get(revision);
+ if (caps != null)
+ {
+ for (Entry<BundleCapability, Set<BundleRevision>> entry : caps.entrySet())
+ {
+ if (entry.getKey().getNamespace()
+ .equals(BundleCapabilityImpl.BUNDLE_NAMESPACE))
+ {
+ for (BundleRevision dependent : entry.getValue())
+ {
+ result.add(dependent.getBundle());
+ }
+ }
+ }
+ }
+ }
+
+ // Return the results.
+ return result;
+ }
+
+ public synchronized void removeDependencies(BundleImpl bundle)
+ {
+ List<BundleRevision> revs = bundle.getRevisions();
+ for (BundleRevision rev : revs)
+ {
+ BundleWiring wiring = rev.getWiring();
+ if (wiring != null)
+ {
+ for (BundleWire wire : wiring.getRequiredWires(null))
+ {
+ // The provider wiring may already be null if the framework
+ // is shutting down, so don't worry about updating dependencies
+ // in that case.
+ if (wire.getProviderWiring() != null)
+ {
+ Map<BundleCapability, Set<BundleRevision>> caps =
+ m_dependentsMap.get(wire.getProviderWiring().getRevision());
+ if (caps != null)
+ {
+ List<BundleCapability> gc = new ArrayList<BundleCapability>();
+ for (Entry<BundleCapability, Set<BundleRevision>> entry
+ : caps.entrySet())
+ {
+ entry.getValue().remove(rev);
+ if (entry.getValue().isEmpty())
+ {
+ gc.add(entry.getKey());
+ }
+ }
+ for (BundleCapability cap : gc)
+ {
+ caps.remove(cap);
+ }
+ if (caps.isEmpty())
+ {
+ m_dependentsMap.remove(wire.getProviderWiring().getRevision());
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ public synchronized void dump()
+ {
+/*
+System.out.println("DEPENDENTS:");
+ for (Entry<BundleRevision, Map<BundleCapability, Set<BundleRevision>>> entry
+ : m_dependentsMap.entrySet())
+ {
+ System.out.println("Revision " + entry.getKey() + " DEPS:");
+ for (Entry<BundleCapability, Set<BundleRevision>> capEntry : entry.getValue().entrySet())
+ {
+ System.out.println(" " + capEntry.getKey() + " <-- " + capEntry.getValue());
+ }
+ }
+*/
+ }
+}
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/BundleRevisionImpl.java b/framework/src/main/java/org/apache/felix/framework/BundleRevisionImpl.java
index 1813617..33ecf5e 100644
--- a/framework/src/main/java/org/apache/felix/framework/BundleRevisionImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/BundleRevisionImpl.java
@@ -20,52 +20,29 @@
import java.io.IOException;
import java.io.InputStream;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLStreamHandler;
-import java.security.AccessController;
-import java.security.PrivilegedActionException;
-import java.security.PrivilegedExceptionAction;
import java.security.ProtectionDomain;
-import java.security.SecureClassLoader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
import java.util.List;
import java.util.Map;
-import java.util.Set;
-import java.util.SortedMap;
-import java.util.TreeMap;
import org.apache.felix.framework.Felix.StatefulResolver;
-import org.apache.felix.framework.cache.JarContent;
import org.apache.felix.framework.resolver.Content;
-import org.apache.felix.framework.resolver.ResolveException;
-import org.apache.felix.framework.resolver.ResolverWire;
-import org.apache.felix.framework.resolver.ResourceNotFoundException;
-import org.apache.felix.framework.util.CompoundEnumeration;
import org.apache.felix.framework.util.FelixConstants;
import org.apache.felix.framework.util.SecureAction;
import org.apache.felix.framework.util.SecurityManagerEx;
-import org.apache.felix.framework.util.Util;
import org.apache.felix.framework.util.manifestparser.ManifestParser;
import org.apache.felix.framework.util.manifestparser.R4Library;
-import org.apache.felix.framework.wiring.BundleCapabilityImpl;
-import org.apache.felix.framework.wiring.BundleRequirementImpl;
-import org.apache.felix.framework.wiring.BundleWireImpl;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleException;
-import org.osgi.framework.BundleReference;
import org.osgi.framework.Constants;
import org.osgi.framework.Version;
import org.osgi.framework.wiring.BundleCapability;
import org.osgi.framework.wiring.BundleRequirement;
import org.osgi.framework.wiring.BundleRevision;
-import org.osgi.framework.wiring.BundleWire;
import org.osgi.framework.wiring.BundleWiring;
public class BundleRevisionImpl implements BundleRevision
@@ -96,9 +73,6 @@
private final Bundle m_bundle;
- private List<BundleRevision> m_dependentImporters = new ArrayList<BundleRevision>(0);
- private List<BundleRevision> m_dependentRequirers = new ArrayList<BundleRevision>(0);
-
private Content[] m_contentPath;
private boolean m_isActivationTriggered = false;
private ProtectionDomain m_protectionDomain = null;
@@ -362,28 +336,17 @@
return m_id;
}
- public synchronized void resolve(
- List<BundleRevision> fragments,
- List<ResolverWire> rws,
- Map<ResolverWire, Set<String>> requiredPkgWires)
- throws Exception
+ public synchronized void resolve(BundleWiringImpl wiring)
{
- // This not only sets the wires for the module, but it also records
- // the dependencies this module has on other modules (i.e., the provider
- // end of the wire) to simplify bookkeeping.
-
- // If there is an existing wiring, then dispose of it, which will
- // remove any dependencies on other wirings.
if (m_wiring != null)
{
m_wiring.dispose();
m_wiring = null;
}
- if (rws != null)
+ if (wiring != null)
{
- m_wiring = new BundleWiringImpl(
- m_logger, m_configMap, m_resolver, this, fragments, rws, requiredPkgWires);
+ m_wiring = wiring;
}
}
@@ -684,70 +647,11 @@
return null;
}
- public synchronized List<BundleRevision> getDependentImporters()
- {
- return m_dependentImporters;
- }
-
- public synchronized void addDependentImporter(BundleRevision br)
- {
- if (!m_dependentImporters.contains(br))
- {
- m_dependentImporters.add(br);
- }
- }
-
- public synchronized void removeDependentImporter(BundleRevision br)
- {
- m_dependentImporters.remove(br);
- }
-
- public synchronized List<BundleRevision> getDependentRequirers()
- {
- return m_dependentRequirers;
- }
-
- public synchronized void addDependentRequirer(BundleRevision br)
- {
- if (!m_dependentRequirers.contains(br))
- {
- m_dependentRequirers.add(br);
- }
- }
-
- public synchronized void removeDependentRequirer(BundleRevision br)
- {
- m_dependentRequirers.remove(br);
- }
-
- public synchronized List<BundleRevision> getDependents()
- {
- List<BundleRevision> dependents;
- if (Util.isFragment(this))
- {
- dependents = new ArrayList<BundleRevision>();
- List<BundleWire> wires = (m_wiring == null)
- ? null : m_wiring.getRequiredWires(null);
- for (int i = 0; (wires != null) && (i < wires.size()); i++)
- {
- dependents.add(wires.get(i).getProviderWiring().getRevision());
- }
- }
- else
- {
- dependents = new ArrayList<BundleRevision>
- (m_dependentImporters.size() + m_dependentRequirers.size());
- dependents.addAll(m_dependentImporters);
- dependents.addAll(m_dependentRequirers);
- }
- return dependents;
- }
-
- public synchronized void close()
+ synchronized void close()
{
try
{
- resolve(null, null, null);
+ resolve(null);
}
catch (Exception ex)
{
@@ -783,4 +687,4 @@
}
return url;
}
-}
+}
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java b/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java
index db4c8cd..5b193e3 100644
--- a/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java
@@ -45,7 +45,6 @@
import org.apache.felix.framework.resolver.HostedCapability;
import org.apache.felix.framework.resolver.HostedRequirement;
import org.apache.felix.framework.resolver.ResolveException;
-import org.apache.felix.framework.resolver.ResolverWire;
import org.apache.felix.framework.resolver.ResourceNotFoundException;
import org.apache.felix.framework.util.CompoundEnumeration;
import org.apache.felix.framework.util.FelixConstants;
@@ -139,76 +138,18 @@
BundleWiringImpl(
Logger logger, Map configMap, StatefulResolver resolver,
BundleRevisionImpl revision, List<BundleRevision> fragments,
- List<ResolverWire> resolverWires,
- Map<ResolverWire, Set<String>> requiredPkgWires)
+ List<BundleWire> wires,
+ Map<String, BundleRevision> importedPkgs,
+ Map<String, List<BundleRevision>> requiredPkgs)
throws Exception
{
m_logger = logger;
m_configMap = configMap;
m_resolver = resolver;
m_revision = revision;
-
- List<BundleWire> wires = new ArrayList<BundleWire>(resolverWires.size());
- Map<String, BundleRevision> importedPkgs =
- new HashMap<String, BundleRevision>();
- Map<String, List<BundleRevision>> requiredPkgs =
- new HashMap<String, List<BundleRevision>>();
-
- for (ResolverWire rw : resolverWires)
- {
- wires.add(
- new BundleWireImpl(
- rw.getRequirer(),
- rw.getRequirement(),
- rw.getProvider(),
- rw.getCapability()));
-
- if (Util.isFragment(m_revision))
- {
- m_logger.log(
- Logger.LOG_DEBUG,
- "FRAGMENT WIRE: "
- + this + " -> hosted by -> " + rw.getProvider());
- }
- else
- {
- m_logger.log(Logger.LOG_DEBUG, "WIRE: " + rw);
-
- if (rw.getCapability().getNamespace()
- .equals(BundleCapabilityImpl.PACKAGE_NAMESPACE))
- {
- ((BundleRevisionImpl) rw.getProvider()).addDependentImporter(m_revision);
-
- importedPkgs.put(
- (String) rw.getCapability().getAttributes()
- .get(BundleCapabilityImpl.PACKAGE_ATTR),
- rw.getProvider());
- }
- else if (rw.getCapability().getNamespace()
- .equals(BundleCapabilityImpl.BUNDLE_NAMESPACE))
- {
- ((BundleRevisionImpl) rw.getProvider()).addDependentRequirer(m_revision);
-
- for (String pkgName : requiredPkgWires.get(rw))
- {
- List<BundleRevision> revs = requiredPkgs.get(pkgName);
- if (revs != null)
- {
- revs.add(rw.getProvider());
- }
- else
- {
- revs = new ArrayList<BundleRevision>();
- revs.add(rw.getProvider());
- requiredPkgs.put(pkgName, revs);
- }
- }
- }
- }
- }
- m_wires = wires;
- m_requiredPkgs = requiredPkgs;
m_importedPkgs = importedPkgs;
+ m_requiredPkgs = requiredPkgs;
+ m_wires = wires;
// We need to sort the fragments and add ourself as a dependent of each one.
// We also need to create an array of fragment contents to attach to our
@@ -367,28 +308,6 @@
public void dispose()
{
- if (!Util.isFragment(m_revision) && (m_wires != null))
- {
- for (BundleWire bw : m_wires)
- {
- if (bw.getProviderWiring() != null)
- {
- if (bw.getCapability().getNamespace()
- .equals(BundleCapabilityImpl.PACKAGE_NAMESPACE))
- {
- ((BundleRevisionImpl) bw.getProviderWiring().getRevision())
- .removeDependentImporter(m_revision);
- }
- else if (bw.getCapability().getNamespace()
- .equals(BundleCapabilityImpl.BUNDLE_NAMESPACE))
- {
- ((BundleRevisionImpl) bw.getProviderWiring().getRevision())
- .removeDependentRequirer(m_revision);
- }
- }
- }
- }
-
for (int i = 0; (m_contentPath != null) && (i < m_contentPath.length); i++)
{
m_contentPath[i].close();
@@ -579,21 +498,12 @@
return m_wires;
}
- public synchronized void addDynamicWire(ResolverWire rw)
+ public synchronized void addDynamicWire(BundleWireImpl wire)
{
- // This not only sets the wires for the module, but it also records
- // the dependencies this module has on other modules (i.e., the provider
- // end of the wire) to simplify bookkeeping.
-
- BundleWire wire = new BundleWireImpl(
- rw.getRequirer(),
- rw.getRequirement(),
- rw.getProvider(),
- rw.getCapability());
m_wires.add(wire);
m_importedPkgs.put(
(String) wire.getCapability().getAttributes().get(BundleCapabilityImpl.PACKAGE_ATTR),
- rw.getProvider());
+ wire.getProviderWiring().getRevision());
}
public BundleRevision getRevision()
diff --git a/framework/src/main/java/org/apache/felix/framework/EntryFilterEnumeration.java b/framework/src/main/java/org/apache/felix/framework/EntryFilterEnumeration.java
index 7e039c7..5fee892 100644
--- a/framework/src/main/java/org/apache/felix/framework/EntryFilterEnumeration.java
+++ b/framework/src/main/java/org/apache/felix/framework/EntryFilterEnumeration.java
@@ -43,11 +43,13 @@
{
m_bundle = bundle;
BundleRevision br = m_bundle.getCurrentRevision();
- List<BundleRevision> fragments = ((BundleWiringImpl) br.getWiring()).getFragments();
- if (includeFragments && (fragments != null))
+ if (includeFragments
+ && (br.getWiring() != null)
+ && (((BundleWiringImpl) br.getWiring()).getFragments() != null))
{
- m_revisions = new ArrayList(fragments.size() + 1);
- m_revisions.addAll(fragments);
+ m_revisions = new ArrayList(
+ ((BundleWiringImpl) br.getWiring()).getFragments().size() + 1);
+ m_revisions.addAll(((BundleWiringImpl) br.getWiring()).getFragments());
}
else
{
diff --git a/framework/src/main/java/org/apache/felix/framework/ExportedPackageImpl.java b/framework/src/main/java/org/apache/felix/framework/ExportedPackageImpl.java
index 0275069..01fab7a 100644
--- a/framework/src/main/java/org/apache/felix/framework/ExportedPackageImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/ExportedPackageImpl.java
@@ -18,7 +18,7 @@
*/
package org.apache.felix.framework;
-import java.util.List;
+import java.util.Set;
import org.apache.felix.framework.wiring.BundleCapabilityImpl;
import org.osgi.framework.Bundle;
import org.osgi.framework.Version;
@@ -65,8 +65,8 @@
{
return null;
}
- List<Bundle> list = m_felix.getImportingBundles(this);
- return list.toArray(new Bundle[list.size()]);
+ Set<Bundle> set = m_felix.getImportingBundles(m_exportingBundle, m_export);
+ return set.toArray(new Bundle[set.size()]);
}
public String getName()
diff --git a/framework/src/main/java/org/apache/felix/framework/ExtensionManager.java b/framework/src/main/java/org/apache/felix/framework/ExtensionManager.java
index be07bbc..cdae317 100644
--- a/framework/src/main/java/org/apache/felix/framework/ExtensionManager.java
+++ b/framework/src/main/java/org/apache/felix/framework/ExtensionManager.java
@@ -56,6 +56,7 @@
import org.osgi.framework.Version;
import org.osgi.framework.wiring.BundleCapability;
import org.osgi.framework.wiring.BundleRevision;
+import org.osgi.framework.wiring.BundleWire;
import org.osgi.framework.wiring.BundleWiring;
/**
@@ -720,12 +721,17 @@
}
@Override
- public void resolve(
- List<BundleRevision> fragments, List<ResolverWire> rws,
- Map<ResolverWire, Set<String>> requiredPkgWires) throws Exception
+ public void resolve(BundleWiringImpl wire)
{
- m_wiring = new ExtensionManagerWiring(
- m_logger, m_configMap, null, this, fragments, rws, requiredPkgWires);
+ try
+ {
+ m_wiring = new ExtensionManagerWiring(
+ m_logger, m_configMap, this);
+ }
+ catch (Exception ex)
+ {
+ // This should never happen.
+ }
}
@Override
@@ -738,14 +744,11 @@
class ExtensionManagerWiring extends BundleWiringImpl
{
ExtensionManagerWiring(
- Logger logger, Map configMap, StatefulResolver resolver,
- BundleRevisionImpl revision, List<BundleRevision> fragments,
- List<ResolverWire> resolverWires,
- Map<ResolverWire, Set<String>> requiredPkgWires)
+ Logger logger, Map configMap, BundleRevisionImpl revision)
throws Exception
{
- super(logger, configMap, resolver, revision,
- fragments, resolverWires, requiredPkgWires);
+ super(logger, configMap, null, revision,
+ null, Collections.EMPTY_LIST, null, null);
}
@Override
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 4889fa5..079c1e9 100644
--- a/framework/src/main/java/org/apache/felix/framework/Felix.java
+++ b/framework/src/main/java/org/apache/felix/framework/Felix.java
@@ -46,6 +46,7 @@
import org.apache.felix.framework.util.manifestparser.R4LibraryClause;
import org.apache.felix.framework.wiring.BundleCapabilityImpl;
import org.apache.felix.framework.wiring.BundleRequirementImpl;
+import org.apache.felix.framework.wiring.BundleWireImpl;
import org.osgi.framework.AdminPermission;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleActivator;
@@ -125,6 +126,9 @@
// CONCURRENCY: Access guarded by the global lock for writes,
// but no lock for reads since it is copy on write.
private volatile List<BundleImpl> m_uninstalledBundles;
+ // Object to keep track of dependencies among bundle revisions.
+ private final BundleRevisionDependencies m_dependencies =
+ new BundleRevisionDependencies();
// Framework's active start level.
private volatile int m_activeStartLevel = FelixConstants.FRAMEWORK_INACTIVE_STARTLEVEL;
@@ -2146,7 +2150,8 @@
{
try
{
- if (!bundle.isUsed() && !bundle.isExtension())
+ if (!m_dependencies.hasDependents(bundle)
+ && !bundle.isExtension())
{
try
{
@@ -2486,7 +2491,7 @@
{
// If the bundle is not used by anyone, then garbage
// collect it now.
- if (!bundle.isUsed())
+ if (!m_dependencies.hasDependents(bundle))
{
try
{
@@ -3462,72 +3467,16 @@
}
}
- List<Bundle> getDependentBundles(BundleImpl exporter)
+ // Needed by ExportedPackageImpl.
+ Set<Bundle> getImportingBundles(BundleImpl exporter, BundleCapability cap)
{
- // Create list for storing importing bundles.
- List<Bundle> list = new ArrayList();
-
- // Get all dependent revisions from all exporter revisions.
- List<BundleRevision> revisions = exporter.getRevisions();
- for (int revIdx = 0; revIdx < revisions.size(); revIdx++)
- {
- List<BundleRevision> dependents =
- ((BundleRevisionImpl) revisions.get(revIdx)).getDependents();
- for (int depIdx = 0;
- (dependents != null) && (depIdx < dependents.size());
- depIdx++)
- {
- list.add(dependents.get(depIdx).getBundle());
- }
- }
-
- return list;
+ return m_dependencies.getImportingBundles(exporter, cap);
}
- List<Bundle> getImportingBundles(ExportedPackage ep)
+ // Needed by RequiredBundleImpl.
+ Set<Bundle> getRequiringBundles(BundleImpl bundle)
{
- // Create list for storing importing bundles.
- List<Bundle> list = new ArrayList();
-
- // Get exporting bundle information.
- BundleImpl exporter = (BundleImpl) ep.getExportingBundle();
-
- // Get all importers and requirers for all revisions of the bundle.
- // The spec says that require-bundle should be returned with importers.
- List<BundleRevision> expRevisions = exporter.getRevisions();
- for (int expIdx = 0; (expRevisions != null) && (expIdx < expRevisions.size()); expIdx++)
- {
- // Include any importers that have wires to the specific
- // exported package.
- if (expRevisions.get(expIdx).getWiring() != null)
- {
- List<BundleRevision> dependents = ((BundleRevisionImpl)
- expRevisions.get(expIdx)).getDependentImporters();
- for (int depIdx = 0; (dependents != null) && (depIdx < dependents.size()); depIdx++)
- {
- if (dependents.get(depIdx).getWiring() != null)
- {
- BundleRevision providerRevision =
- ((BundleWiringImpl) dependents.get(depIdx).getWiring())
- .getImportedPackageSource(ep.getName());
- if ((providerRevision != null)
- && (providerRevision == expRevisions.get(expIdx)))
- {
- list.add(dependents.get(depIdx).getBundle());
- }
- }
- }
- dependents = ((BundleRevisionImpl)
- expRevisions.get(expIdx)).getDependentRequirers();
- for (int depIdx = 0; (dependents != null) && (depIdx < dependents.size()); depIdx++)
- {
- list.add(dependents.get(depIdx).getBundle());
- }
- }
- }
-
- // Return the results.
- return list;
+ return m_dependencies.getRequiringBundles(bundle);
}
boolean resolveBundles(Bundle[] targets)
@@ -3671,18 +3620,18 @@
{
// Create map of bundles that import the packages
// from the target bundles.
- Map map = new HashMap();
+ Set<Bundle> set = new HashSet<Bundle>();
for (int targetIdx = 0; targetIdx < newTargets.length; targetIdx++)
{
// Add the current target bundle to the map of
// bundles to be refreshed.
BundleImpl target = (BundleImpl) newTargets[targetIdx];
- map.put(target, target);
+ set.add(target);
// Add all importing bundles to map.
- populateDependentGraph(target, map);
+ populateDependentGraph(target, set);
}
- bundles = (BundleImpl[]) map.values().toArray(new BundleImpl[map.size()]);
+ bundles = (BundleImpl[]) set.toArray(new BundleImpl[set.size()]);
}
// Now refresh each bundle.
@@ -3776,23 +3725,23 @@
fireFrameworkEvent(FrameworkEvent.PACKAGES_REFRESHED, this, null);
}
- private void populateDependentGraph(BundleImpl exporter, Map map)
+ private void populateDependentGraph(BundleImpl exporter, Set<Bundle> set)
{
// Get all dependent bundles of this bundle.
- List<Bundle> dependents = getDependentBundles(exporter);
+ Set<Bundle> dependents = m_dependencies.getDependentBundles(exporter);
- for (int depIdx = 0;
- (dependents != null) && (depIdx < dependents.size());
- depIdx++)
+ if (dependents != null)
{
- // Avoid cycles if the bundle is already in map.
- if (!map.containsKey(dependents.get(depIdx)))
+ for (Bundle b : dependents)
{
- // Add each importing bundle to map.
- map.put(dependents.get(depIdx), dependents.get(depIdx));
- // Now recurse into each bundle to get its importers.
- populateDependentGraph(
- (BundleImpl) dependents.get(depIdx), map);
+ // Avoid cycles if the bundle is already in set.
+ if (!set.contains(b))
+ {
+ // Add each dependent bundle to set.
+ set.add(b);
+ // Now recurse into each bundle to get its dependents.
+ populateDependentGraph((BundleImpl) b, set);
+ }
}
}
}
@@ -3879,6 +3828,8 @@
{
// See if we need to fire UNRESOLVED event.
boolean fire = (bundle.getState() != Bundle.INSTALLED);
+ // Remove dependencies.
+ m_dependencies.removeDependencies(bundle);
// Reset the bundle object.
((BundleImpl) bundle).refresh();
// Fire UNRESOLVED event if necessary
@@ -4256,8 +4207,19 @@
// Dynamically add new wire to importing revision.
if (dynamicWire != null)
{
+ m_dependencies.addDependent(
+ dynamicWire.getProvider(),
+ dynamicWire.getCapability(),
+ revision);
+
((BundleWiringImpl) revision.getWiring())
- .addDynamicWire(dynamicWire);
+ .addDynamicWire(
+ new BundleWireImpl(
+ dynamicWire.getRequirer(),
+ dynamicWire.getRequirement(),
+ dynamicWire.getProvider(),
+ dynamicWire.getCapability()));
+
m_logger.log(
Logger.LOG_DEBUG,
"DYNAMIC WIRE: " + dynamicWire);
@@ -4369,50 +4331,109 @@
}
}
- // Second pass: Loop through the wire map to set wires and attach
- // fragments, if any.
+ // Second pass: Loop through the wire map to do three things:
+ // 1) convert resolver wires to bundle wires 2) create wiring
+ // objects for revisions and 3) record dependencies among
+ // revisions. We don't actually set the wirings here because
+ // that indicates that a revision is resolved and we don't want
+ // to mark anything as resolved unless we succussfully create
+ // all wirings.
+ Map<BundleRevision, BundleWiringImpl> wirings =
+ new HashMap<BundleRevision, BundleWiringImpl>(wireMap.size());
for (Entry<BundleRevision, List<ResolverWire>> entry : wireMap.entrySet())
{
BundleRevision revision = entry.getKey();
List<ResolverWire> resolverWires = entry.getValue();
- Map<ResolverWire, Set<String>> requiredPkgWires =
- new HashMap<ResolverWire, Set<String>>();
+ List<BundleWire> bundleWires =
+ new ArrayList<BundleWire>(resolverWires.size());
+
+ // Loop through resolver wires to calculate the package
+ // space implied by the wires as well as to record the
+ // dependencies.
+ Map<String, BundleRevision> importedPkgs =
+ new HashMap<String, BundleRevision>();
+ Map<String, List<BundleRevision>> requiredPkgs =
+ new HashMap<String, List<BundleRevision>>();
for (ResolverWire rw : resolverWires)
{
- if (rw.getCapability().getNamespace()
- .equals(BundleCapabilityImpl.BUNDLE_NAMESPACE))
+ bundleWires.add(
+ new BundleWireImpl(
+ rw.getRequirer(),
+ rw.getRequirement(),
+ rw.getProvider(),
+ rw.getCapability()));
+
+ m_dependencies.addDependent(
+ rw.getProvider(), rw.getCapability(), rw.getRequirer());
+
+ if (Util.isFragment(revision))
{
- Set<String> pkgs =
- calculateExportedAndReexportedPackages(
- rw.getProvider(),
- wireMap,
- new HashSet<String>(),
- new HashSet<BundleRevision>());
- requiredPkgWires.put(rw, pkgs);
+ m_logger.log(
+ Logger.LOG_DEBUG,
+ "FRAGMENT WIRE: "
+ + this + " -> hosted by -> " + rw.getProvider());
+ }
+ else
+ {
+ m_logger.log(Logger.LOG_DEBUG, "WIRE: " + rw);
+
+ if (rw.getCapability().getNamespace()
+ .equals(BundleCapabilityImpl.PACKAGE_NAMESPACE))
+ {
+ importedPkgs.put(
+ (String) rw.getCapability().getAttributes()
+ .get(BundleCapabilityImpl.PACKAGE_ATTR),
+ rw.getProvider());
+ }
+ else if (rw.getCapability().getNamespace()
+ .equals(BundleCapabilityImpl.BUNDLE_NAMESPACE))
+ {
+ Set<String> pkgs = calculateExportedAndReexportedPackages(
+ rw.getProvider(),
+ wireMap,
+ new HashSet<String>(),
+ new HashSet<BundleRevision>());
+ for (String pkg : pkgs)
+ {
+ List<BundleRevision> revs = requiredPkgs.get(pkg);
+ if (revs == null)
+ {
+ revs = new ArrayList<BundleRevision>();
+ requiredPkgs.put(pkg, revs);
+ }
+ revs.add(rw.getProvider());
+ }
+ }
}
}
List<BundleRevision> fragments = hosts.get(revision);
try
{
-// TODO: OSGi R4.3 - Technically, this is where the revision becomes resolved,
-// but we used to wait and mark it as resolved in the third phase below.
- ((BundleRevisionImpl) revision).resolve(
- fragments, resolverWires, requiredPkgWires);
+ wirings.put(
+ revision,
+ new BundleWiringImpl(
+ m_logger,
+ m_configMap,
+ this,
+ (BundleRevisionImpl) revision,
+ fragments,
+ bundleWires,
+ importedPkgs,
+ requiredPkgs));
}
catch (Exception ex)
{
// This is a fatal error, so undo everything and
// throw an exception.
- for (Entry<BundleRevision, List<ResolverWire>> reentry : wireMap.entrySet())
+ for (Entry<BundleRevision, BundleWiringImpl> wiringEntry
+ : wirings.entrySet())
{
- revision = reentry.getKey();
-
- // Undo wires.
+ // Dispose of wiring.
try
{
- ((BundleRevisionImpl) revision).resolve(null, null, null);
+ wiringEntry.getValue().dispose();
}
catch (Exception ex2)
{
@@ -4438,24 +4459,28 @@
re.getMessage(), ex);
throw re;
}
-
- // Reindex host with attached fragments.
- m_resolverState.addRevision(revision);
}
// Third pass: Loop through the wire map to mark revision as resolved
// and update the resolver state.
- for (Entry<BundleRevision, List<ResolverWire>> entry : wireMap.entrySet())
+ for (Entry<BundleRevision, BundleWiringImpl> entry : wirings.entrySet())
{
- BundleRevision revision = entry.getKey();
+ BundleRevisionImpl revision = (BundleRevisionImpl) entry.getKey();
+
// Mark revision as resolved.
-// TODO: OSGi R4.3 - See message above when we call BundleRevisionImpl.resolve().
-// ((BundleRevisionImpl) revision).setResolved();
+ revision.resolve(entry.getValue());
+
// Update resolver state to remove substituted capabilities.
if (!Util.isFragment(revision))
{
+ // Update resolver state by reindexing host with attached
+ // fragments and removing any substituted exports.
+// TODO: OSGi R4.3 - We could avoid reindexing for fragments if we check it
+// the revision has fragments or not.
+ m_resolverState.addRevision(revision);
m_resolverState.removeSubstitutedCapabilities(revision);
}
+
// Update the state of the revision's bundle to resolved as well.
markBundleResolved(revision);
}
@@ -4551,15 +4576,20 @@
// visibility, since we need to include those packages too.
if (br.getWiring() == null)
{
+System.out.println("+++ br.getWiring() = " + br.getWiring());
for (ResolverWire rw : wireMap.get(br))
{
+System.out.println("+++ rw.getCapability() = " + rw.getCapability());
+System.out.println("+++ rw.getRequirement() = " + rw.getRequirement());
if (rw.getCapability().getNamespace().equals(
BundleCapabilityImpl.BUNDLE_NAMESPACE))
{
String dir = rw.getRequirement()
.getDirectives().get(Constants.VISIBILITY_DIRECTIVE);
+System.out.println("+++ dir = " + dir);
if ((dir != null) && (dir.equals(Constants.VISIBILITY_REEXPORT)))
{
+System.out.println("+++ rw.getProvider() = " + rw.getProvider());
calculateExportedAndReexportedPackages(
rw.getProvider(),
wireMap,
@@ -4782,6 +4812,8 @@
// current state.
if (m_bundle.getState() == Bundle.UNINSTALLED)
{
+ // Remove dependencies.
+ m_dependencies.removeDependencies(m_bundle);
m_bundle.closeAndDelete();
m_bundle = null;
}
diff --git a/framework/src/main/java/org/apache/felix/framework/RequiredBundleImpl.java b/framework/src/main/java/org/apache/felix/framework/RequiredBundleImpl.java
index 0518172..1cea004 100644
--- a/framework/src/main/java/org/apache/felix/framework/RequiredBundleImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/RequiredBundleImpl.java
@@ -51,34 +51,13 @@
public Bundle[] getRequiringBundles()
{
- // Spec says to return null for stale bundles.
+ // If the package is stale, then return null per the spec.
if (m_bundle.isStale())
{
return null;
}
-
- // We need to find all revisions that require any of the revisions
- // associated with this bundle and save the associated bundle
- // of the dependent revisions.
- Set bundleSet = new HashSet();
- // Loop through all of this bundle's revisions.
- List<BundleRevision> revisions = m_bundle.getRevisions();
- for (int modIdx = 0; (revisions != null) && (modIdx < revisions.size()); modIdx++)
- {
- // For each of this bundle's revisions, loop through all of the
- // revisions that require it and add them to the dependents list.
- List<BundleRevision> dependents =
- ((BundleRevisionImpl) revisions.get(modIdx)).getDependentRequirers();
- for (int depIdx = 0; (dependents != null) && (depIdx < dependents.size()); depIdx++)
- {
- if (dependents.get(depIdx).getBundle() != null)
- {
- bundleSet.add(dependents.get(depIdx).getBundle());
- }
- }
- }
- // Convert to an array.
- return (Bundle[]) bundleSet.toArray(new Bundle[bundleSet.size()]);
+ Set<Bundle> set = m_felix.getRequiringBundles(m_bundle);
+ return set.toArray(new Bundle[set.size()]);
}
public Version getVersion()
diff --git a/framework/src/main/java/org/apache/felix/framework/ResolverStateImpl.java b/framework/src/main/java/org/apache/felix/framework/ResolverStateImpl.java
index bdb4ade..3272b82 100644
--- a/framework/src/main/java/org/apache/felix/framework/ResolverStateImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/ResolverStateImpl.java
@@ -23,6 +23,7 @@
import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Set;
import java.util.SortedSet;
import java.util.StringTokenizer;
@@ -56,6 +57,16 @@
// Parsed framework environments
private final Set<String> m_fwkExecEnvSet;
+// void dump()
+// {
+// for (Entry<String, CapabilitySet> entry : m_capSets.entrySet())
+// {
+// System.out.println("+++ START CAPSET " + entry.getKey());
+// entry.getValue().dump();
+// System.out.println("+++ END CAPSET " + entry.getKey());
+// }
+// }
+
ResolverStateImpl(Logger logger, String fwkExecEnvStr)
{
m_logger = logger;
@@ -135,7 +146,7 @@
}
// TODO: OSGi R4.3 - This will need to be changed once BundleWiring.getCapabilities()
-// is correctly implemented, since they already has to remove substituted caps.
+// is correctly implemented, since it already has to remove substituted caps.
synchronized void removeSubstitutedCapabilities(BundleRevision br)
{
if (br.getWiring() != null)
diff --git a/framework/src/main/java/org/apache/felix/framework/URLHandlersBundleURLConnection.java b/framework/src/main/java/org/apache/felix/framework/URLHandlersBundleURLConnection.java
index 6092980..1be90ea 100644
--- a/framework/src/main/java/org/apache/felix/framework/URLHandlersBundleURLConnection.java
+++ b/framework/src/main/java/org/apache/felix/framework/URLHandlersBundleURLConnection.java
@@ -123,6 +123,7 @@
{
m_classPathIdx = 0;
}
+// TODO: OSGi R4.3 - This is messed up. We need to fix resource lookup.
if (!((BundleRevisionImpl) m_targetRevision)
.hasInputStream(m_classPathIdx, url.getPath()))
{
diff --git a/framework/src/main/java/org/apache/felix/framework/capabilityset/CapabilitySet.java b/framework/src/main/java/org/apache/felix/framework/capabilityset/CapabilitySet.java
index 1dfe525..7d2bd16 100644
--- a/framework/src/main/java/org/apache/felix/framework/capabilityset/CapabilitySet.java
+++ b/framework/src/main/java/org/apache/felix/framework/capabilityset/CapabilitySet.java
@@ -41,6 +41,35 @@
private final Set<BundleCapability> m_capSet = new HashSet<BundleCapability>();
private final static SecureAction m_secureAction = new SecureAction();
+public void dump()
+{
+ for (Entry<String, Map<Object, Set<BundleCapability>>> entry : m_indices.entrySet())
+ {
+ boolean header1 = false;
+ for (Entry<Object, Set<BundleCapability>> entry2 : entry.getValue().entrySet())
+ {
+ boolean header2 = false;
+ for (BundleCapability cap : entry2.getValue())
+ {
+ if (cap.getRevision().getBundle().getBundleId() != 0)
+ {
+ if (!header1)
+ {
+ System.out.println(entry.getKey() + ":");
+ header1 = true;
+ }
+ if (!header2)
+ {
+ System.out.println(" " + entry2.getKey());
+ header2 = true;
+ }
+ System.out.println(" " + cap);
+ }
+ }
+ }
+ }
+}
+
public CapabilitySet(List<String> indexProps, boolean caseSensitive)
{
m_indices = (caseSensitive)
diff --git a/framework/src/main/java/org/apache/felix/framework/resolver/ResolverImpl.java b/framework/src/main/java/org/apache/felix/framework/resolver/ResolverImpl.java
index 3110261..2721387 100644
--- a/framework/src/main/java/org/apache/felix/framework/resolver/ResolverImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/resolver/ResolverImpl.java
@@ -28,7 +28,6 @@
import java.util.Map.Entry;
import java.util.Set;
import java.util.SortedSet;
-import org.apache.felix.framework.BundleRevisionImpl;
import org.apache.felix.framework.BundleWiringImpl;
import org.apache.felix.framework.Logger;
import org.apache.felix.framework.capabilityset.CapabilitySet;