/* * 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.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.aries.subsystem.core.capabilityset.CapabilitySetRepository; import org.osgi.framework.Constants; import org.osgi.framework.namespace.ExecutionEnvironmentNamespace; import org.osgi.framework.namespace.IdentityNamespace; import org.osgi.framework.namespace.NativeNamespace; import org.osgi.resource.Capability; import org.osgi.resource.Requirement; import org.osgi.resource.Resource; import org.osgi.resource.Wire; import org.osgi.resource.Wiring; import org.osgi.service.resolver.HostedCapability; import org.osgi.service.resolver.ResolutionException; import org.osgi.service.resolver.Resolver; public class DependencyCalculator { private static class ResolveContext extends org.osgi.service.resolver.ResolveContext { private final CapabilitySetRepository repository = new CapabilitySetRepository(); private final Collection<Resource> resources; public ResolveContext(Collection<Resource> resources) { this.resources = resources; for (Resource resource : resources) { repository.addResource(resource); } } @Override public List<Capability> findProviders(Requirement requirement) { String namespace = requirement.getNamespace(); // never check local resources for osgi.ee or osgi.native capabilities if (ExecutionEnvironmentNamespace.EXECUTION_ENVIRONMENT_NAMESPACE.equals(namespace) || NativeNamespace.NATIVE_NAMESPACE.equals(namespace)) { return Collections.<Capability>singletonList(new MissingCapability(requirement)); } Map<Requirement, Collection<Capability>> map = repository.findProviders(Collections.singleton(requirement)); Collection<Capability> capabilities = map.get(requirement); if (!capabilities.isEmpty()) { return new ArrayList<Capability>(capabilities); } return Collections.<Capability>singletonList(new MissingCapability(requirement)); } @Override public boolean isEffective(Requirement requirement) { return true; } @Override public Collection<Resource> getMandatoryResources() { return resources; } @Override public Map<Resource, Wiring> getWirings() { return Collections.emptyMap(); } @Override public int insertHostedCapability(List<Capability> capabilities, HostedCapability hostedCapability) { int sz = capabilities.size(); capabilities.add(sz, hostedCapability); return sz; } } static class MissingCapability extends AbstractCapability { private static class Resource implements org.osgi.resource.Resource { public static final Resource INSTANCE = new Resource(); private final Capability identity; public Resource() { Map<String, Object> attributes = new HashMap<String, Object>(); attributes.put(IdentityNamespace.IDENTITY_NAMESPACE, org.apache.aries.subsystem.core.internal.Constants.ResourceTypeSynthesized); attributes.put(IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE, org.apache.aries.subsystem.core.internal.Constants.ResourceTypeSynthesized); identity = new BasicCapability(IdentityNamespace.IDENTITY_NAMESPACE, attributes, null, this); } @Override public List<Capability> getCapabilities(String namespace) { return Collections.singletonList(identity); } @Override public List<Requirement> getRequirements(String namespace) { return Collections.emptyList(); } } private final Map<String, Object> attributes = new HashMap<String, Object>(); private final Requirement requirement; public MissingCapability(Requirement requirement) { this.requirement = requirement; initializeAttributes(); } @Override public Map<String, Object> getAttributes() { return Collections.unmodifiableMap(attributes); } @Override public Map<String, String> getDirectives() { return Collections.emptyMap(); } @Override public String getNamespace() { return requirement.getNamespace(); } @Override public Resource getResource() { return Resource.INSTANCE; } private void initializeAttributes() { String filter = requirement.getDirectives().get(Constants.FILTER_DIRECTIVE); if (filter == null) return; Pattern pattern = Pattern.compile("\\(([^<>~(=]+)(?:=|<=|>=|~=)([^)]+)\\)"); Matcher matcher = pattern.matcher(filter); while (matcher.find()) attributes.put(matcher.group(1), matcher.group(2)); } } private final ResolveContext context; public DependencyCalculator(Collection<Resource> resources) { context = new ResolveContext(resources); } public List<Requirement> calculateDependencies() throws ResolutionException { ArrayList<Requirement> result = new ArrayList<Requirement>(); Resolver resolver = Activator.getInstance().getResolver(); Map<Resource, List<Wire>> resolution = resolver.resolve(context); for (List<Wire> wires : resolution.values()) for (Wire wire : wires) if (wire.getCapability() instanceof MissingCapability) result.add(wire.getRequirement()); result.trimToSize(); return result; } }