blob: eecb7a4dc2733b77ff4a206a28bb8c05f0599e5c [file] [log] [blame]
/*
* 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.karaf.features.internal.region;
import java.io.BufferedReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.apache.felix.resolver.Logger;
import org.apache.felix.resolver.ResolverImpl;
import org.apache.felix.utils.repository.BaseRepository;
import org.apache.felix.utils.resource.RequirementImpl;
import org.apache.felix.utils.resource.ResourceBuilder;
import org.apache.felix.utils.resource.ResourceImpl;
import org.apache.felix.utils.resource.SimpleFilter;
import org.apache.karaf.util.json.JsonReader;
import org.osgi.framework.BundleException;
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.repository.Repository;
import org.osgi.service.resolver.HostedCapability;
import org.osgi.service.resolver.ResolveContext;
import org.osgi.service.resolver.Resolver;
import static org.osgi.framework.Constants.RESOLUTION_DIRECTIVE;
import static org.osgi.framework.Constants.RESOLUTION_OPTIONAL;
import static org.osgi.framework.namespace.IdentityNamespace.IDENTITY_NAMESPACE;
public class OfflineResolver {
public static void main(String[] args) throws Exception {
if (args == null || args.length != 1) {
throw new IllegalArgumentException("File path expected");
}
resolve(args[0]);
}
public static void resolve(String resolutionFile) throws Exception {
Map<String, Object> resolution;
try (BufferedReader reader = Files.newBufferedReader(Paths.get(resolutionFile), StandardCharsets.UTF_8)) {
resolution = (Map<String, Object>) JsonReader.read(reader);
}
final Repository globalRepository;
if (resolution.containsKey("globalRepository")) {
globalRepository = readRepository(resolution.get("globalRepository"));
} else {
globalRepository = null;
}
final Repository repository = readRepository(resolution.get("repository"));
Resolver resolver = new ResolverImpl(new Logger(Logger.LOG_ERROR));
Map<Resource, List<Wire>> wiring = resolver.resolve(new ResolveContext() {
private final CandidateComparator candidateComparator = new CandidateComparator(r -> 0);
@Override
public Collection<Resource> getMandatoryResources() {
List<Resource> resources = new ArrayList<>();
Requirement req = new RequirementImpl(
null,
IDENTITY_NAMESPACE,
Collections.emptyMap(),
Collections.emptyMap(),
SimpleFilter.parse("(" + IDENTITY_NAMESPACE + "=root)"));
Collection<Capability> identities = repository.findProviders(Collections.singleton(req)).get(req);
for (Capability identity : identities) {
resources.add(identity.getResource());
}
return resources;
}
@Override
public List<Capability> findProviders(Requirement requirement) {
List<Capability> caps = new ArrayList<>();
Map<Requirement, Collection<Capability>> resMap =
repository.findProviders(Collections.singleton(requirement));
Collection<Capability> res = resMap != null ? resMap.get(requirement) : null;
if (res != null && !res.isEmpty()) {
caps.addAll(res);
} else if (globalRepository != null) {
// Only bring in external resources for non optional requirements
if (!RESOLUTION_OPTIONAL.equals(requirement.getDirectives().get(RESOLUTION_DIRECTIVE))) {
resMap = globalRepository.findProviders(Collections.singleton(requirement));
res = resMap != null ? resMap.get(requirement) : null;
if (res != null && !res.isEmpty()) {
caps.addAll(res);
}
}
}
// Sort caps
Collections.sort(caps, candidateComparator);
return caps;
}
@Override
public int insertHostedCapability(List<Capability> capabilities, HostedCapability hostedCapability) {
int idx = Collections.binarySearch(capabilities, hostedCapability, candidateComparator);
if (idx < 0) {
idx = Math.abs(idx + 1);
}
capabilities.add(idx, hostedCapability);
return idx;
}
@Override
public boolean isEffective(Requirement requirement) {
return true;
}
@Override
public Map<Resource, Wiring> getWirings() {
return Collections.emptyMap();
}
});
}
private static Repository readRepository(Object repository) throws BundleException {
List<Resource> resources = new ArrayList<>();
Collection<Map<String, List<String>>> metadatas;
if (repository instanceof Map) {
metadatas = ((Map<String, Map<String, List<String>>>) repository).values();
} else {
metadatas = (Collection<Map<String, List<String>>>) repository;
}
for (Map<String, List<String>> metadata : metadatas) {
ResourceImpl res = new ResourceImpl();
for (String cap : metadata.get("capabilities")) {
res.addCapabilities(ResourceBuilder.parseCapability(res, cap));
}
if (metadata.containsKey("requirements")) {
for (String req : metadata.get("requirements")) {
res.addRequirements(ResourceBuilder.parseRequirement(res, req));
}
}
resources.add(res);
}
return new BaseRepository(resources);
}
}