2 * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
5 * and is available at http://www.eclipse.org/legal/eplv10.html
7 package org.opendaylight.yangtools.yang.parser.impl.util;
9 import static com.google.common.base.Preconditions.checkNotNull;
11 import com.google.common.base.Optional;
12 import com.google.common.collect.ImmutableList;
13 import com.google.common.collect.ImmutableMultimap;
14 import com.google.common.collect.ImmutableSet;
15 import com.google.common.io.ByteSource;
16 import java.io.Closeable;
17 import java.io.IOException;
18 import java.io.InputStream;
19 import java.util.Collection;
20 import java.util.HashSet;
21 import java.util.List;
23 import java.util.concurrent.atomic.AtomicBoolean;
24 import javax.annotation.concurrent.ThreadSafe;
25 import org.opendaylight.yangtools.concepts.Delegator;
26 import org.opendaylight.yangtools.yang.common.QName;
27 import org.opendaylight.yangtools.yang.model.api.ModuleImport;
28 import org.opendaylight.yangtools.yang.model.util.repo.AdvancedSchemaSourceProvider;
29 import org.opendaylight.yangtools.yang.model.util.repo.SchemaSourceProvider;
30 import org.opendaylight.yangtools.yang.model.util.repo.SourceIdentifier;
31 import org.opendaylight.yangtools.yang.parser.builder.impl.BuilderUtils;
35 * Context of YANG model sources
37 * YANG sources context represent information learned about set of model sources
38 * which could be derived from dependency information only.
40 * Contains following information:
42 * <li>{@link #getValidSources()} - set of {@link SourceIdentifier} which have
43 * their dependencies present and are safe to be used by full blown parser.
44 * <li>{@link #getMissingSources()} - set of {@link SourceIdentifier} which have
45 * been referenced by other YANG sources, but source code for them is missing.
46 * <li>{@link #getMissingDependencies()} - map of {@link SourceIdentifier} and
47 * their imports for which source codes was not available.
49 * {@link YangSourceContext} may be associated with {@link SchemaSourceProvider}
50 * (see {@link #getDelegate()}, which was used for retrieval of sources during
51 * context computation.
53 * {@link YangSourceContext} may be used as schema source provider to retrieve
58 // FIXME: for some reason this class is Closeable even though close is never called and no resources are leaked
60 public class YangSourceContext implements AdvancedSchemaSourceProvider<InputStream>, Closeable,
61 Delegator<AdvancedSchemaSourceProvider<InputStream>> {
63 private final ImmutableSet<SourceIdentifier> validSources;
65 private final ImmutableSet<SourceIdentifier> missingSources;
66 private final ImmutableMultimap<SourceIdentifier, ModuleImport> missingDependencies;
67 private final AdvancedSchemaSourceProvider<InputStream> sourceProvider;
68 private final AtomicBoolean isClosed = new AtomicBoolean();
71 * Construct YANG Source Context
73 * @param validSourcesSet Set of identifiers of valid sources
74 * @param missingSourcesSet Set of identifiers of missing sources
75 * @param missingDependenciesMap Map of identifiers of resolved sources and their missing imports.
76 * @param sourceProvider Source provider which was used for context resolution or
77 * null if provider was not used.
79 YangSourceContext(final ImmutableSet<SourceIdentifier> validSourcesSet,
80 final ImmutableSet<SourceIdentifier> missingSourcesSet,
81 final ImmutableMultimap<SourceIdentifier, ModuleImport> missingDependenciesMap,
82 final AdvancedSchemaSourceProvider<InputStream> sourceProvider) {
83 validSources = checkNotNull(validSourcesSet, "Valid source set must not be null");
84 missingSources = checkNotNull(missingSourcesSet, "Missing sources set must not be null");
85 missingDependencies = checkNotNull(missingDependenciesMap, "Missing dependencies map must not be null");
86 this.sourceProvider = checkNotNull(sourceProvider, "Missing sourceProvider");
90 * Returns set of valid source identifiers.
92 * Source identifier is considered valid if it's source
93 * was present during resolution and sources
94 * for all known dependencies was present at the time of creation
95 * of {@link YangSourceContext}.
97 * @return Set of valid source identifiers.
99 public ImmutableSet<SourceIdentifier> getValidSources() {
104 * Returns set of source identifiers, whom sources was not resolved.
106 * Source is considered missing if the source was not present
107 * during resolution of {@link YangSourceContext}.
109 * @return Set of missing sources.
111 public ImmutableSet<SourceIdentifier> getMissingSources() {
112 return missingSources;
116 * Returns a multimap of Source Identifier and imports which had missing
119 * Maps a source identifier to its imports, which was not resolved
120 * during resolution of this context, so it is unable to fully
121 * processed source identifier.
124 * @return Multi-map of source identifier to it's unresolved dependencies.
126 public ImmutableMultimap<SourceIdentifier, ModuleImport> getMissingDependencies() {
127 return missingDependencies;
131 public Optional<InputStream> getSchemaSource(final String moduleName, final Optional<String> revision) {
132 return getSchemaSource(SourceIdentifier.create(moduleName, revision));
136 public Optional<InputStream> getSchemaSource(final SourceIdentifier sourceIdentifier) {
137 if (validSources.contains(sourceIdentifier)) {
138 return getDelegateChecked().getSchemaSource(sourceIdentifier);
140 return Optional.absent();
143 private AdvancedSchemaSourceProvider<InputStream> getDelegateChecked() {
145 return sourceProvider;
149 public AdvancedSchemaSourceProvider<InputStream> getDelegate() {
151 return sourceProvider;
154 private void assertNotClosed() {
155 if (isClosed.get()) {
156 throw new IllegalStateException("Instance already closed");
161 public void close() {
166 * Creates YANG Source context from supplied capabilities and schema source
169 * @param capabilities
170 * Set of QName representing module capabilities,
171 * {@link QName#getLocalName()} represents
172 * source name and {@link QName#getRevision()} represents
173 * revision of source.
175 * @param schemaSourceProvider
176 * - {@link SchemaSourceProvider} which should be used to resolve
178 * @return YANG source context which describes resolution of capabilities
179 * and their dependencies
180 * against supplied schema source provider.
182 public static YangSourceContext createFrom(final Iterable<QName> capabilities,
183 final SchemaSourceProvider<InputStream> schemaSourceProvider) {
184 YangSourceContextResolver resolver = new YangSourceFromCapabilitiesResolver(capabilities, schemaSourceProvider);
185 return resolver.resolveContext();
188 public static YangSourceContext createFrom(final Map<SourceIdentifier, YangModelDependencyInfo> moduleDependencies,
189 AdvancedSchemaSourceProvider<InputStream> sourceProvider) {
190 YangSourceFromDependencyInfoResolver resolver = new YangSourceFromDependencyInfoResolver(
191 moduleDependencies, sourceProvider);
192 return resolver.resolveContext();
196 * Returns a list of valid input streams from YANG Source Context
197 * using supplied schema source provider.
199 * @return List of input streams.
200 * @deprecated Use {@link #getValidByteSources()}
203 public List<InputStream> getValidInputStreams() {
204 return getValidInputStreamsInternal();
207 private List<InputStream> getValidInputStreamsInternal() {
209 final HashSet<SourceIdentifier> sourcesToLoad = new HashSet<>();
210 sourcesToLoad.addAll(this.getValidSources());
211 for (SourceIdentifier source : this.getValidSources()) {
212 if (source.getRevision() != null) {
213 SourceIdentifier sourceWithoutRevision = SourceIdentifier.create(source.getName(),
214 Optional.<String> absent());
215 sourcesToLoad.remove(sourceWithoutRevision);
219 ImmutableList.Builder<InputStream> ret = ImmutableList.<InputStream>builder();
220 for (SourceIdentifier sourceIdentifier : sourcesToLoad) {
221 Optional<InputStream> source = sourceProvider.getSchemaSource(sourceIdentifier);
222 ret.add(source.get());
229 public Collection<ByteSource> getValidByteSources() throws IOException {
230 List<InputStream> yangModelStreams = getValidInputStreamsInternal();
231 return BuilderUtils.streamsToByteSources(yangModelStreams);
235 public static List<InputStream> getValidInputStreams(final YangSourceContext context) {
236 return context.getValidInputStreams();