/*
* 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;
}
}