| /* |
| * 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(BundleRevision revision) |
| { |
| // We have to special case fragments, since their dependencies |
| // are actually reversed (i.e., they require a host, but then |
| // the host ends up dependent on them at run time). |
| if (Util.isFragment(revision) |
| && (revision.getWiring() != null) |
| && !revision.getWiring().getRequiredWires(null).isEmpty()) |
| { |
| return true; |
| } |
| else if (m_dependentsMap.containsKey(revision)) |
| { |
| return true; |
| } |
| return false; |
| } |
| |
| public synchronized boolean hasDependents(BundleImpl bundle) |
| { |
| List<BundleRevision> revisions = bundle.getRevisions(); |
| for (BundleRevision revision : revisions) |
| { |
| if (hasDependents(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(BundleRevision.PACKAGE_NAMESPACE); |
| |
| // 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(BundleRevision.PACKAGE_NAMESPACE) |
| && cap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE) |
| .equals(pkgName)) |
| || cap.getNamespace().equals(BundleRevision.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(BundleRevision.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()); |
| } |
| } |
| */ |
| } |
| } |