Copyright (c) 2013, 2016 IBM Corporation and others. This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 which accompanies this distribution, and is available at https://www.eclipse.org/legal/epl-2.0/ SPDX-License-Identifier: EPL-2.0 Contributors: IBM Corporation - initial API and implementation
/******************************************************************************* * Copyright (c) 2013, 2016 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/
package org.eclipse.osgi.container; import java.util.*; import org.eclipse.osgi.internal.framework.FilterImpl; import org.eclipse.osgi.internal.messages.Msg; import org.eclipse.osgi.report.resolution.ResolutionReport; import org.osgi.framework.Constants; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.namespace.*; import org.osgi.framework.wiring.BundleRevision; import org.osgi.resource.*; import org.osgi.service.resolver.ResolutionException;
A resolution report implementation used by the container for resolution operations.
Since:3.10
/** * A resolution report implementation used by the container for resolution operations. * @since 3.10 */
class ModuleResolutionReport implements ResolutionReport { static class Builder { private final Map<Resource, List<Entry>> resourceToEntries = new HashMap<>(); public void addEntry(Resource resource, Entry.Type type, Object data) { List<Entry> entries = resourceToEntries.get(resource); if (entries == null) { entries = new ArrayList<>(); resourceToEntries.put(resource, entries); } entries.add(new EntryImpl(type, data)); } public ModuleResolutionReport build(Map<Resource, List<Wire>> resolutionResult, ResolutionException cause) { return new ModuleResolutionReport(resolutionResult, resourceToEntries, cause); } } static class EntryImpl implements Entry { private final Object data; private final Type type; EntryImpl(Type type, Object data) { this.type = type; this.data = data; } @Override public Object getData() { return data; } @Override public Type getType() { return type; } } private final Map<Resource, List<Entry>> entries; private final ResolutionException resolutionException; private final Map<Resource, List<Wire>> resolutionResult; ModuleResolutionReport(Map<Resource, List<Wire>> resolutionResult, Map<Resource, List<Entry>> entries, ResolutionException cause) { this.entries = entries == null ? Collections.<Resource, List<Entry>> emptyMap() : Collections.unmodifiableMap(new HashMap<>(entries)); this.resolutionResult = resolutionResult == null ? Collections.<Resource, List<Wire>> emptyMap() : Collections.unmodifiableMap(resolutionResult); this.resolutionException = cause; } @Override public Map<Resource, List<Entry>> getEntries() { return entries; } @Override public ResolutionException getResolutionException() { return resolutionException; } Map<Resource, List<Wire>> getResolutionResult() { return resolutionResult; } private static String getResolutionReport0(String prepend, ModuleRevision revision, Map<Resource, List<ResolutionReport.Entry>> reportEntries, Set<BundleRevision> visited) { if (prepend == null) { prepend = ""; //$NON-NLS-1$ } if (visited == null) { visited = new HashSet<>(); } if (visited.contains(revision)) { return ""; //$NON-NLS-1$ } visited.add(revision); StringBuilder result = new StringBuilder(); String id = revision.getRevisions().getModule().getId().toString(); result.append(prepend).append(revision.getSymbolicName()).append(" [").append(id).append("]").append('\n'); //$NON-NLS-1$ //$NON-NLS-2$ List<ResolutionReport.Entry> revisionEntries = reportEntries.get(revision); if (revisionEntries == null) { result.append(prepend).append(" ").append(Msg.ModuleResolutionReport_NoReport); //$NON-NLS-1$ } else { for (ResolutionReport.Entry entry : revisionEntries) { printResolutionEntry(result, prepend + " ", entry, reportEntries, visited); //$NON-NLS-1$ } } return result.toString(); } private static void printResolutionEntry(StringBuilder result, String prepend, ResolutionReport.Entry entry, Map<Resource, List<ResolutionReport.Entry>> reportEntries, Set<BundleRevision> visited) { switch (entry.getType()) { case MISSING_CAPABILITY : result.append(prepend).append(Msg.ModuleResolutionReport_UnresolvedReq).append(printRequirement(entry.getData())).append('\n'); break; case SINGLETON_SELECTION : result.append(prepend).append(Msg.ModuleResolutionReport_AnotherSingleton).append(entry.getData()).append('\n'); break; case UNRESOLVED_PROVIDER : @SuppressWarnings("unchecked") Map<Requirement, Set<Capability>> unresolvedProviders = (Map<Requirement, Set<Capability>>) entry.getData(); for (Map.Entry<Requirement, Set<Capability>> unresolvedRequirement : unresolvedProviders.entrySet()) { // for now only printing the first possible unresolved candidates Set<Capability> unresolvedCapabilities = unresolvedRequirement.getValue(); if (!unresolvedCapabilities.isEmpty()) { Capability unresolvedCapability = unresolvedCapabilities.iterator().next(); // make sure this is not a case of importing and exporting the same package if (!unresolvedRequirement.getKey().getResource().equals(unresolvedCapability.getResource())) { result.append(prepend).append(Msg.ModuleResolutionReport_UnresolvedReq).append(printRequirement(unresolvedRequirement.getKey())).append('\n'); result.append(prepend).append(" -> ").append(printCapability(unresolvedCapability)).append('\n'); //$NON-NLS-1$ result.append(getResolutionReport0(prepend + " ", (ModuleRevision) unresolvedCapability.getResource(), reportEntries, visited)); //$NON-NLS-1$ } } } break; case FILTERED_BY_RESOLVER_HOOK : result.append(Msg.ModuleResolutionReport_FilteredByHook).append('\n'); break; case USES_CONSTRAINT_VIOLATION : result.append(prepend).append(Msg.ModuleResolutionReport_UsesConstraintError).append('\n'); result.append(" ").append(entry.getData()); //$NON-NLS-1$ break; default : result.append(Msg.ModuleResolutionReport_Unknown).append("type=").append(entry.getType()).append(" data=").append(entry.getData()).append('\n'); //$NON-NLS-1$ //$NON-NLS-2$ break; } } private static Object printCapability(Capability cap) { if (PackageNamespace.PACKAGE_NAMESPACE.equals(cap.getNamespace())) { return Constants.EXPORT_PACKAGE + ": " + createOSGiCapability(cap); //$NON-NLS-1$ } else if (BundleNamespace.BUNDLE_NAMESPACE.equals(cap.getNamespace())) { return Constants.BUNDLE_SYMBOLICNAME + ": " + createOSGiCapability(cap); //$NON-NLS-1$ } else if (HostNamespace.HOST_NAMESPACE.equals(cap.getNamespace())) { return Constants.BUNDLE_SYMBOLICNAME + ": " + createOSGiCapability(cap); //$NON-NLS-1$ } return Constants.PROVIDE_CAPABILITY + ": " + cap.toString(); //$NON-NLS-1$ } private static String createOSGiCapability(Capability cap) { Map<String, Object> attributes = new HashMap<>(cap.getAttributes()); Map<String, String> directives = cap.getDirectives(); String name = String.valueOf(attributes.remove(cap.getNamespace())); return name + ModuleRevision.toString(attributes, false, true) + ModuleRevision.toString(directives, true, true); } private static String printRequirement(Object data) { if (!(data instanceof Requirement)) { return String.valueOf(data); } Requirement req = (Requirement) data; if (PackageNamespace.PACKAGE_NAMESPACE.equals(req.getNamespace())) { return Constants.IMPORT_PACKAGE + ": " + createOSGiRequirement(req, PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE, PackageNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE); //$NON-NLS-1$ } else if (BundleNamespace.BUNDLE_NAMESPACE.equals(req.getNamespace())) { return Constants.REQUIRE_BUNDLE + ": " + createOSGiRequirement(req, BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE); //$NON-NLS-1$ } else if (HostNamespace.HOST_NAMESPACE.equals(req.getNamespace())) { return Constants.FRAGMENT_HOST + ": " + createOSGiRequirement(req, HostNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE); //$NON-NLS-1$ } return Constants.REQUIRE_CAPABILITY + ": " + req.toString(); //$NON-NLS-1$ } private static String createOSGiRequirement(Requirement requirement, String... versions) { Map<String, String> directives = new HashMap<>(requirement.getDirectives()); String filter = directives.remove(Namespace.REQUIREMENT_FILTER_DIRECTIVE); if (filter == null) throw new IllegalArgumentException("No filter directive found:" + requirement); //$NON-NLS-1$ FilterImpl filterImpl; try { filterImpl = FilterImpl.newInstance(filter); } catch (InvalidSyntaxException e) { throw new IllegalArgumentException("Invalid filter directive", e); //$NON-NLS-1$ } Map<String, String> matchingAttributes = filterImpl.getStandardOSGiAttributes(versions); String name = matchingAttributes.remove(requirement.getNamespace()); if (name == null) throw new IllegalArgumentException("Invalid requirement: " + requirement); //$NON-NLS-1$ return name + ModuleRevision.toString(matchingAttributes, false, true) + ModuleRevision.toString(directives, true, true); } @Override public String getResolutionReportMessage(Resource resource) { return getResolutionReport0(null, (ModuleRevision) resource, getEntries(), null); } }