2 * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.yangtools.yang.parser.repo;
10 import com.google.common.collect.ImmutableList;
11 import com.google.common.collect.ImmutableMultimap;
12 import com.google.common.collect.Sets;
13 import java.util.Collection;
14 import java.util.HashMap;
16 import org.opendaylight.yangtools.yang.model.api.source.SourceDependency;
17 import org.opendaylight.yangtools.yang.model.api.source.SourceIdentifier;
18 import org.opendaylight.yangtools.yang.model.spi.source.SourceInfo;
19 import org.opendaylight.yangtools.yang.model.spi.source.SourceInfo.Submodule;
20 import org.opendaylight.yangtools.yang.parser.api.YangParserConfiguration;
21 import org.slf4j.Logger;
22 import org.slf4j.LoggerFactory;
25 * Inter-module dependency resolved. Given a set of schema source identifiers and their
26 * corresponding dependency information, the {@link #create(Map)} method creates a
27 * a view of how consistent the dependencies are. In particular, this detects whether
28 * any imports are unsatisfied.
30 // FIXME: improve this class to track and expose how wildcard imports were resolved.
31 // That information will allow us to track "damage" to dependency resolution
32 // as new models are added to a schema context.
33 abstract class DependencyResolver {
34 private static final Logger LOG = LoggerFactory.getLogger(DependencyResolver.class);
36 private final ImmutableList<SourceIdentifier> resolvedSources;
37 private final ImmutableList<SourceIdentifier> unresolvedSources;
38 private final ImmutableMultimap<SourceIdentifier, SourceDependency> unsatisfiedImports;
40 protected DependencyResolver(final Map<SourceIdentifier, SourceInfo> depInfo) {
41 final var resolved = Sets.<SourceIdentifier>newHashSetWithExpectedSize(depInfo.size());
42 final var pending = new HashMap<>(depInfo);
48 final var it = pending.values().iterator();
49 while (it.hasNext()) {
50 final var dep = it.next();
51 if (tryResolve(resolved, dep)) {
52 final var sourceId = dep.sourceId();
53 LOG.debug("Resolved source {}", sourceId);
54 resolved.add(sourceId);
61 resolvedSources = ImmutableList.copyOf(resolved);
62 unresolvedSources = ImmutableList.copyOf(pending.keySet());
64 final var unstatisfied = ImmutableMultimap.<SourceIdentifier, SourceDependency>builder();
65 for (var info : pending.values()) {
66 for (var dep : info.imports()) {
67 if (!isKnown(depInfo.keySet(), dep)) {
68 unstatisfied.put(info.sourceId(), dep);
71 for (var dep : info.includes()) {
72 if (!isKnown(depInfo.keySet(), dep)) {
73 unstatisfied.put(info.sourceId(), dep);
76 if (info instanceof Submodule submodule) {
77 final var dep = submodule.belongsTo();
78 if (!isKnown(depInfo.keySet(), dep)) {
79 unstatisfied.put(info.sourceId(), dep);
83 unsatisfiedImports = unstatisfied.build();
87 * Collection of sources which have been resolved.
89 final ImmutableList<SourceIdentifier> resolvedSources() {
90 return resolvedSources;
94 * Collection of sources which have not been resolved due to missing dependencies.
96 final ImmutableList<SourceIdentifier> unresolvedSources() {
97 return unresolvedSources;
101 * Detailed information about which imports were missing. The key in the map is the source identifier of module
102 * which was issuing an import, the values are imports which were unsatisfied.
105 * Note that this map contains only imports which are missing from the reactor, not transitive failures. Examples:
107 * <li>if A imports B, B imports C, and both A and B are in the reactor, only B->C will be reported</li>
108 * <li>if A imports B and C, B imports C, and both A and B are in the reactor, A->C and B->C will be reported</li>
111 final ImmutableMultimap<SourceIdentifier, SourceDependency> unsatisfiedImports() {
112 return unsatisfiedImports;
115 private boolean tryResolve(final Collection<SourceIdentifier> resolved, final SourceInfo info) {
116 for (var dep : info.imports()) {
117 if (!isKnown(resolved, dep)) {
118 LOG.debug("Source {} is missing import {}", info.sourceId(), dep);
122 for (var dep : info.includes()) {
123 if (!isKnown(resolved, dep)) {
124 LOG.debug("Source {} is missing include {}", info.sourceId(), dep);
128 if (info instanceof Submodule submodule) {
129 final var dep = submodule.belongsTo();
130 if (!isKnown(resolved, dep)) {
131 LOG.debug("Source {} is missing belongs-to {}", info.sourceId(), dep);
138 abstract boolean isKnown(Collection<SourceIdentifier> haystack, SourceDependency dependency);
140 abstract YangParserConfiguration parserConfig();