BUG-865: migrate to Optional<>
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / impl / util / YangSourceContext.java
1 /*
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
6  */
7 package org.opendaylight.yangtools.yang.parser.impl.util;
8
9 import static com.google.common.base.Preconditions.checkNotNull;
10
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;
22 import java.util.Map;
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;
32
33 /**
34  *
35  * Context of YANG model sources
36  *
37  * YANG sources context represent information learned about set of model sources
38  * which could be derived from dependency information only.
39  *
40  * Contains following information:
41  * <ul>
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.
48  *
49  * {@link YangSourceContext} may be associated with {@link SchemaSourceProvider}
50  * (see {@link #getDelegate()}, which was used for retrieval of sources during
51  * context computation.
52  *
53  * {@link YangSourceContext} may be used as schema source provider to retrieve
54  * this sources.
55  *
56  *
57  */
58 // FIXME: for some reason this class is Closeable even though close is never called and no resources are leaked
59 @ThreadSafe
60 public class YangSourceContext implements AdvancedSchemaSourceProvider<InputStream>, Closeable,
61         Delegator<AdvancedSchemaSourceProvider<InputStream>> {
62
63     private final ImmutableSet<SourceIdentifier> validSources;
64
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();
69
70     /**
71      * Construct YANG Source Context
72      * 
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.
78      */
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");
87     }
88
89     /**
90      * Returns set of valid source identifiers.
91      *
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}.
96      *
97      * @return Set of valid source identifiers.
98      */
99     public ImmutableSet<SourceIdentifier> getValidSources() {
100         return validSources;
101     }
102
103     /**
104      * Returns set of source identifiers, whom sources was not resolved.
105      *
106      * Source is considered missing if the source was not present
107      * during resolution of {@link YangSourceContext}.
108      *
109      * @return Set of missing sources.
110      */
111     public ImmutableSet<SourceIdentifier> getMissingSources() {
112         return missingSources;
113     }
114
115     /**
116      * Returns a multimap of Source Identifier and imports which had missing
117      * sources.
118      *
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.
122      *
123      *
124      * @return Multi-map of source identifier to it's unresolved dependencies.
125      */
126     public ImmutableMultimap<SourceIdentifier, ModuleImport> getMissingDependencies() {
127         return missingDependencies;
128     }
129
130     @Override
131     public Optional<InputStream> getSchemaSource(final String moduleName, final Optional<String> revision) {
132         return getSchemaSource(SourceIdentifier.create(moduleName, revision));
133     }
134
135     @Override
136     public Optional<InputStream> getSchemaSource(final SourceIdentifier sourceIdentifier) {
137         if (validSources.contains(sourceIdentifier)) {
138             return getDelegateChecked().getSchemaSource(sourceIdentifier);
139         }
140         return Optional.absent();
141     }
142
143     private AdvancedSchemaSourceProvider<InputStream> getDelegateChecked() {
144         assertNotClosed();
145         return sourceProvider;
146     }
147
148     @Override
149     public AdvancedSchemaSourceProvider<InputStream> getDelegate() {
150         assertNotClosed();
151         return sourceProvider;
152     }
153
154     private void assertNotClosed() {
155         if (isClosed.get()) {
156             throw new IllegalStateException("Instance already closed");
157         }
158     }
159
160     @Override
161     public void close() {
162         isClosed.set(true);
163     }
164
165     /**
166      * Creates YANG Source context from supplied capabilities and schema source
167      * provider.
168      *
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.
174      *
175      * @param schemaSourceProvider
176      *            - {@link SchemaSourceProvider} which should be used to resolve
177      *            sources.
178      * @return YANG source context which describes resolution of capabilities
179      *         and their dependencies
180      *         against supplied schema source provider.
181      */
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();
186     }
187
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();
193     }
194
195     /**
196      * Returns a list of valid input streams from YANG Source Context
197      * using supplied schema source provider.
198      *
199      * @return List of input streams.
200      * @deprecated Use {@link #getValidByteSources()}
201      */
202     @Deprecated
203     public List<InputStream> getValidInputStreams() {
204         return getValidInputStreamsInternal();
205     }
206
207     private List<InputStream> getValidInputStreamsInternal() {
208         assertNotClosed();
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);
216             }
217         }
218
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());
223         }
224         return ret.build();
225     }
226
227
228
229     public Collection<ByteSource> getValidByteSources() throws IOException {
230         List<InputStream> yangModelStreams = getValidInputStreamsInternal();
231         return BuilderUtils.streamsToByteSources(yangModelStreams);
232     }
233
234     @Deprecated
235     public static List<InputStream> getValidInputStreams(final YangSourceContext context) {
236         return context.getValidInputStreams();
237     }
238
239 }