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.Optional;
11 import com.google.common.base.Preconditions;
12 import com.google.common.collect.ArrayListMultimap;
13 import com.google.common.collect.ImmutableMultimap;
14 import com.google.common.collect.Multimap;
16 import java.util.ArrayList;
17 import java.util.Collection;
18 import java.util.Collections;
19 import java.util.Iterator;
22 import org.opendaylight.yangtools.yang.model.api.ModuleImport;
23 import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
24 import org.opendaylight.yangtools.yang.parser.impl.util.YangModelDependencyInfo;
25 import org.slf4j.Logger;
26 import org.slf4j.LoggerFactory;
29 * Inter-module dependency resolved. Given a set of schema source identifiers and their
30 * corresponding dependency information, the {@link #create(Map)} method creates a
31 * a view of how consistent the dependencies are. In particular, this detects whether
32 * any imports are unsatisfied.
34 * FIXME: improve this class to track and expose how wildcard imports were resolved.
35 * That information will allow us to track "damage" to dependency resolution
36 * as new models are added to a schema context.
38 final class DependencyResolver {
39 private static final Logger LOG = LoggerFactory.getLogger(DependencyResolver.class);
40 private final Collection<SourceIdentifier> resolvedSources;
41 private final Collection<SourceIdentifier> unresolvedSources;
42 private final Multimap<SourceIdentifier, ModuleImport> unsatisfiedImports;
44 public DependencyResolver(final Collection<SourceIdentifier> resolvedSources,
45 final Collection<SourceIdentifier> unresolvedSources, final Multimap<SourceIdentifier, ModuleImport> unsatisfiedImports) {
46 this.resolvedSources = Preconditions.checkNotNull(resolvedSources);
47 this.unresolvedSources = Preconditions.checkNotNull(unresolvedSources);
48 this.unsatisfiedImports = Preconditions.checkNotNull(unsatisfiedImports);
51 private static SourceIdentifier findWildcard(final Iterable<SourceIdentifier> haystack, final String needle) {
52 for (SourceIdentifier r : haystack) {
53 if (r.getName().equals(needle)) {
61 private static boolean isKnown(final Collection<SourceIdentifier> haystack, final ModuleImport mi) {
62 final String rev = mi.getRevision() != null ? mi.getRevision().toString() : null;
63 final SourceIdentifier msi = SourceIdentifier.create(mi.getModuleName(), Optional.fromNullable(rev));
66 if (haystack.contains(msi)) {
70 // Slow revision-less walk
71 return rev == null && findWildcard(haystack, mi.getModuleName()) != null;
74 public static final DependencyResolver create(final Map<SourceIdentifier, YangModelDependencyInfo> depInfo) {
75 final Collection<SourceIdentifier> resolved = new ArrayList<>(depInfo.size());
76 final Collection<SourceIdentifier> pending = new ArrayList<>(depInfo.keySet());
82 final Iterator<SourceIdentifier> it = pending.iterator();
83 while (it.hasNext()) {
84 final SourceIdentifier id = it.next();
85 final YangModelDependencyInfo dep = depInfo.get(id);
88 for (ModuleImport mi : dep.getDependencies()) {
89 if (!isKnown(resolved, mi)) {
90 LOG.debug("Source {} is missing import {}", id, mi);
97 LOG.debug("Resolved source {}", id);
105 if (!pending.isEmpty()) {
106 final Multimap<SourceIdentifier, ModuleImport> imports = ArrayListMultimap.create();
107 for (SourceIdentifier id : pending) {
108 final YangModelDependencyInfo dep = depInfo.get(id);
109 for (ModuleImport mi : dep.getDependencies()) {
110 if (!isKnown(pending, mi) && !isKnown(resolved, mi)) {
116 return new DependencyResolver(resolved, pending, imports);
118 return new DependencyResolver(resolved, Collections.<SourceIdentifier>emptyList(), ImmutableMultimap.<SourceIdentifier, ModuleImport>of());
123 * Collection of sources which have been resolved.
127 Collection<SourceIdentifier> getResolvedSources() {
128 return resolvedSources;
132 * Collection of sources which have not been resolved due to missing dependencies.
136 Collection<SourceIdentifier> getUnresolvedSources() {
137 return unresolvedSources;
141 * Detailed information about which imports were missing. The key in the map
142 * is the source identifier of module which was issuing an import, the values
143 * are imports which were unsatisfied.
145 * Note that this map contains only imports which are missing from the reactor,
146 * not transitive failures.
150 * If A imports B, B imports C, and both A and B are in the reactor, only B->C
153 * If A imports B and C, B imports C, and both A and B are in the reactor,
154 * A->C and B->C will be reported.
158 Multimap<SourceIdentifier, ModuleImport> getUnsatisfiedImports() {
159 return unsatisfiedImports;