/* * Licensed 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.aries.subsystem.core.internal; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import org.apache.aries.subsystem.core.archive.PreferredProviderHeader; import org.osgi.framework.hooks.resolver.ResolverHook; import org.osgi.framework.wiring.BundleCapability; import org.osgi.framework.wiring.BundleRequirement; import org.osgi.framework.wiring.BundleRevision; import org.osgi.resource.Resource; import org.osgi.service.subsystem.Subsystem; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class SubsystemResolverHook implements ResolverHook { private static final Logger LOGGER = LoggerFactory.getLogger(SubsystemResolverHook.class); private final Subsystems subsystems; public SubsystemResolverHook(Subsystems subsystems) { if (subsystems == null) throw new NullPointerException("Missing required parameter: subsystems"); this.subsystems = subsystems; } public void end() { // noop } public void filterMatches(BundleRequirement requirement, Collection<BundleCapability> candidates) { // Filter out candidates that don't come from preferred providers when // there is at least one preferred provider. // (1) Find the subsystem(s) containing requirement.getResource() as a // constituent. Collection<BasicSubsystem> requirers = subsystems.getSubsystemsReferencing(requirement.getResource()); // (2) For each candidate, ask each subsystem if the candidate or any of // the candidate's containing subsystems is a preferred provider. If at // least one preferred provider exists, filter out all other candidates // that are not also preferred providers. Collection<BundleCapability> preferredProviders = new ArrayList<BundleCapability>(candidates.size()); for (BundleCapability candidate : candidates) for (BasicSubsystem subsystem : requirers) { PreferredProviderHeader header = subsystem.getSubsystemManifest().getPreferredProviderHeader(); if (header != null && (header.contains(candidate.getResource()) || isResourceConstituentOfPreferredSubsystem(candidate.getResource(), subsystem))) preferredProviders.add(candidate); } if (!preferredProviders.isEmpty()) candidates.retainAll(preferredProviders); } public void filterResolvable(Collection<BundleRevision> candidates) { try { for (Iterator<BundleRevision> iterator = candidates.iterator(); iterator.hasNext();) { BundleRevision revision = iterator.next(); if (revision.equals(ThreadLocalBundleRevision.get())) { // The candidate is a bundle whose INSTALLED event is // currently being processed on this thread. iterator.remove(); continue; } if (revision.getSymbolicName().startsWith(Constants.RegionContextBundleSymbolicNamePrefix)) // Don't want to filter out the region context bundle. continue; Collection<BasicSubsystem> subsystems = this.subsystems.getSubsystemsReferencing(revision); if (subsystems.isEmpty() && ThreadLocalSubsystem.get() != null) { // This is the revision of a bundle being installed as part of a subsystem installation // before it has been added as a reference or constituent. iterator.remove(); continue; } for (BasicSubsystem subsystem : subsystems) { if (subsystem.isFeature()) { // Feature subsystems require no isolation. continue; } // Otherwise, the candidate is part of an application or composite subsystem requiring isolation. // But only when in the INSTALLING state. if (Subsystem.State.INSTALLING.equals(subsystem.getState())) { iterator.remove(); } } } } catch (RuntimeException e) { // This try/catch block is in place because exceptions occurring here are not showing up in the console during testing. LOGGER.debug("Unexpected exception while filtering resolution candidates: " + candidates, e); } } public void filterSingletonCollisions(BundleCapability singleton, Collection<BundleCapability> collisionCandidates) { // noop } private boolean isResourceConstituentOfPreferredSubsystem(Resource resource, BasicSubsystem preferer) { Collection<BasicSubsystem> subsystems = this.subsystems.getSubsystemsReferencing(resource); for (BasicSubsystem subsystem : subsystems) if (preferer.getSubsystemManifest().getPreferredProviderHeader().contains(subsystem)) return true; return false; } }