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.base.MoreObjects;
11 import com.google.common.collect.ArrayListMultimap;
12 import com.google.common.collect.ImmutableList;
13 import com.google.common.collect.ImmutableMultimap;
14 import com.google.common.collect.Multimap;
15 import java.util.ArrayList;
16 import java.util.Collection;
17 import java.util.HashMap;
18 import java.util.Iterator;
20 import java.util.Map.Entry;
21 import java.util.Optional;
23 import org.opendaylight.yangtools.concepts.SemVer;
24 import org.opendaylight.yangtools.yang.common.Revision;
25 import org.opendaylight.yangtools.yang.model.api.ModuleImport;
26 import org.opendaylight.yangtools.yang.model.api.stmt.ImportEffectiveStatement;
27 import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
28 import org.opendaylight.yangtools.yang.parser.api.YangParserConfiguration;
29 import org.opendaylight.yangtools.yang.parser.rfc7950.repo.YangModelDependencyInfo;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
34 * Inter-module dependency resolved. Given a set of schema source identifiers and their
35 * corresponding dependency information, the {@link #create(Map)} method creates a
36 * a view of how consistent the dependencies are. In particular, this detects whether
37 * any imports are unsatisfied.
39 // FIXME: improve this class to track and expose how wildcard imports were resolved.
40 // That information will allow us to track "damage" to dependency resolution
41 // as new models are added to a schema context.
42 abstract class DependencyResolver {
43 private static final Logger LOG = LoggerFactory.getLogger(DependencyResolver.class);
44 private final ImmutableList<SourceIdentifier> resolvedSources;
45 private final ImmutableList<SourceIdentifier> unresolvedSources;
46 private final ImmutableMultimap<SourceIdentifier, ModuleImport> unsatisfiedImports;
48 protected DependencyResolver(final Map<SourceIdentifier, YangModelDependencyInfo> depInfo) {
49 final Collection<SourceIdentifier> resolved = new ArrayList<>(depInfo.size());
50 final Collection<SourceIdentifier> pending = new ArrayList<>(depInfo.keySet());
51 final Map<SourceIdentifier, BelongsToDependency> submodules = new HashMap<>();
57 final Iterator<SourceIdentifier> it = pending.iterator();
58 while (it.hasNext()) {
59 final SourceIdentifier id = it.next();
60 final YangModelDependencyInfo dep = depInfo.get(id);
64 final Set<ModuleImport> dependencies = dep.getDependencies();
66 // in case of submodule, remember belongs to
67 if (dep instanceof YangModelDependencyInfo.SubmoduleDependencyInfo) {
68 final String parent = ((YangModelDependencyInfo.SubmoduleDependencyInfo) dep).getParentModule();
69 submodules.put(id, new BelongsToDependency(parent));
72 for (final ModuleImport mi : dependencies) {
73 if (!isKnown(resolved, mi)) {
74 LOG.debug("Source {} is missing import {}", id, mi);
81 LOG.debug("Resolved source {}", id);
89 /// Additional check only for belongs-to statement
90 for (final Entry<SourceIdentifier, BelongsToDependency> submodule : submodules.entrySet()) {
91 final BelongsToDependency belongs = submodule.getValue();
92 final SourceIdentifier sourceIdentifier = submodule.getKey();
93 if (!isKnown(resolved, belongs)) {
94 LOG.debug("Source {} is missing parent {}", sourceIdentifier, belongs);
95 pending.add(sourceIdentifier);
96 resolved.remove(sourceIdentifier);
100 final Multimap<SourceIdentifier, ModuleImport> imports = ArrayListMultimap.create();
101 for (final SourceIdentifier id : pending) {
102 final YangModelDependencyInfo dep = depInfo.get(id);
103 for (final ModuleImport mi : dep.getDependencies()) {
104 if (!isKnown(pending, mi) && !isKnown(resolved, mi)) {
110 this.resolvedSources = ImmutableList.copyOf(resolved);
111 this.unresolvedSources = ImmutableList.copyOf(pending);
112 this.unsatisfiedImports = ImmutableMultimap.copyOf(imports);
115 protected abstract boolean isKnown(Collection<SourceIdentifier> haystack, ModuleImport mi);
117 abstract YangParserConfiguration parserConfig();
120 * Collection of sources which have been resolved.
122 Collection<SourceIdentifier> getResolvedSources() {
123 return resolvedSources;
127 * Collection of sources which have not been resolved due to missing dependencies.
129 Collection<SourceIdentifier> getUnresolvedSources() {
130 return unresolvedSources;
134 * Detailed information about which imports were missing. The key in the map
135 * is the source identifier of module which was issuing an import, the values
136 * are imports which were unsatisfied.
139 * Note that this map contains only imports which are missing from the reactor,
140 * not transitive failures.
145 * If A imports B, B imports C, and both A and B are in the reactor, only B->C
148 * If A imports B and C, B imports C, and both A and B are in the reactor,
149 * A->C and B->C will be reported.
152 Multimap<SourceIdentifier, ModuleImport> getUnsatisfiedImports() {
153 return unsatisfiedImports;
156 private static class BelongsToDependency implements ModuleImport {
157 private final String parent;
159 BelongsToDependency(final String parent) {
160 this.parent = parent;
164 public String getModuleName() {
169 public Optional<Revision> getRevision() {
170 return Optional.empty();
174 public Optional<String> getDescription() {
175 return Optional.empty();
179 public Optional<String> getReference() {
180 return Optional.empty();
184 public String getPrefix() {
189 public Optional<SemVer> getSemanticVersion() {
190 return Optional.empty();
194 public String toString() {
195 return MoreObjects.toStringHelper(this).add("parent", parent).toString();
199 public ImportEffectiveStatement asEffectiveStatement() {
200 throw new UnsupportedOperationException();