1 package org.opendaylight.yangtools.yang.parser.impl.util;
3 import java.io.InputStream;
4 import java.util.Collections;
5 import java.util.HashMap;
6 import java.util.HashSet;
11 import org.opendaylight.yangtools.yang.common.QName;
12 import org.opendaylight.yangtools.yang.model.api.Module;
13 import org.opendaylight.yangtools.yang.model.api.ModuleImport;
14 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
15 import org.opendaylight.yangtools.yang.model.util.repo.SchemaSourceProvider;
16 import org.opendaylight.yangtools.yang.model.util.repo.SourceIdentifier;
17 import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
18 import org.slf4j.Logger;
19 import org.slf4j.LoggerFactory;
21 import com.google.common.base.Optional;
22 import com.google.common.base.Preconditions;
23 import com.google.common.collect.ImmutableList;
24 import com.google.common.collect.ImmutableMap;
25 import com.google.common.collect.ImmutableMultimap;
26 import com.google.common.collect.ImmutableSet;
27 import com.google.common.collect.ImmutableSet.Builder;
29 public class YangSourceContext implements SchemaSourceProvider<InputStream>,AutoCloseable {
31 private final ImmutableSet<SourceIdentifier> validSources;
34 private final ImmutableSet<SourceIdentifier> missingSources;
35 private final ImmutableMultimap<SourceIdentifier, ModuleImport> missingDependencies;
36 private SchemaSourceProvider<InputStream> sourceProvider;
38 private YangSourceContext(ImmutableSet<SourceIdentifier> validSourcesSet,
39 ImmutableSet<SourceIdentifier> missingSourcesSet,
40 ImmutableMultimap<SourceIdentifier, ModuleImport> missingDependenciesMap, SchemaSourceProvider<InputStream> sourceProvicer) {
41 validSources = validSourcesSet;
42 missingSources = missingSourcesSet;
43 missingDependencies = missingDependenciesMap;
44 sourceProvider = sourceProvicer;
47 public ImmutableSet<SourceIdentifier> getValidSources() {
51 public ImmutableSet<SourceIdentifier> getMissingSources() {
52 return missingSources;
55 public ImmutableMultimap<SourceIdentifier, ModuleImport> getMissingDependencies() {
56 return missingDependencies;
60 public Optional<InputStream> getSchemaSource(String moduleName, Optional<String> revision) {
61 return getSchemaSource(SourceIdentifier.create(moduleName,revision));
65 public Optional<InputStream> getSchemaSource(SourceIdentifier sourceIdentifier) {
66 if(validSources.contains(sourceIdentifier)) {
67 return getDelegateChecked().getSchemaSource(sourceIdentifier);
69 return Optional.absent();
72 private SchemaSourceProvider<InputStream> getDelegateChecked() {
73 Preconditions.checkState(sourceProvider != null,"Instance is already closed.");
74 return sourceProvider;
79 if(sourceProvider != null) {
80 sourceProvider = null;
84 public static final YangSourceContext createFrom(Iterable<QName> capabilities,
85 SchemaSourceProvider<InputStream> schemaSourceProvider) {
86 YangSourceContextResolver resolver = new YangSourceFromCapabilitiesResolver(capabilities, schemaSourceProvider);
87 return resolver.resolveContext();
90 public static final SchemaContext toSchemaContext(YangSourceContext context) {
91 List<InputStream> inputStreams = getValidInputStreams(context);
92 YangParserImpl parser = new YangParserImpl();
93 Set<Module> models = parser.parseYangModelsFromStreams(inputStreams);
94 return parser.resolveSchemaContext(models);
97 public static List<InputStream> getValidInputStreams(YangSourceContext context) {
98 return getValidInputStreams(context, context.sourceProvider);
101 public static List<InputStream> getValidInputStreams(YangSourceContext context, SchemaSourceProvider<InputStream> provider) {
102 // TODO Auto-generated method stub
103 final HashSet<SourceIdentifier> sourcesToLoad = new HashSet<>();
104 sourcesToLoad.addAll(context.getValidSources());
105 for(SourceIdentifier source : context.getValidSources()) {
106 if(source.getRevision() != null) {
107 SourceIdentifier sourceWithoutRevision = SourceIdentifier.create(source.getName(), Optional.<String>absent());
108 sourcesToLoad.removeAll(Collections.singleton(sourceWithoutRevision));
112 ImmutableList.Builder<InputStream> ret = ImmutableList.<InputStream>builder();
113 for(SourceIdentifier sourceIdentifier : sourcesToLoad) {
114 Optional<InputStream> source = provider.getSchemaSource(sourceIdentifier);
115 ret.add(source.get());
121 public static abstract class YangSourceContextResolver {
123 private static final Logger LOG = LoggerFactory.getLogger(YangSourceContextResolver.class);
125 private SchemaSourceProvider<InputStream> sourceProvicer;
127 private HashMap<SourceIdentifier, ResolutionState> alreadyProcessed = new HashMap<>();
129 private ImmutableSet.Builder<SourceIdentifier> missingSources = ImmutableSet.builder();
131 private ImmutableMultimap.Builder<SourceIdentifier, ModuleImport> missingDependencies = ImmutableMultimap
134 private ImmutableSet.Builder<SourceIdentifier> validSources = ImmutableSet.builder();
136 public YangSourceContextResolver(SchemaSourceProvider<InputStream> schemaSourceProvider) {
137 sourceProvicer = schemaSourceProvider;
140 public abstract YangSourceContext resolveContext();
142 public ResolutionState resolveSource(String name, Optional<String> formattedRevision) {
143 return resolveSource(new SourceIdentifier(name, formattedRevision));
146 private ResolutionState resolveSource(SourceIdentifier identifier) {
148 if (alreadyProcessed.containsKey(identifier)) {
149 return alreadyProcessed.get(identifier);
151 LOG.info("Resolving source: {}",identifier);
152 ResolutionState potentialState = ResolutionState.EVERYTHING_OK;
154 Optional<InputStream> source = getSchemaSource(identifier);
155 if (source.isPresent()) {
157 YangModelDependencyInfo info = YangModelDependencyInfo.fromInputStream(source.get());
159 checkValidSource(identifier,info);
161 for (ModuleImport dependency : info.getDependencies()) {
162 LOG.debug("Source: {} Resolving dependency: {}",identifier,dependency);
163 ResolutionState dependencyState = resolveDependency(dependency);
164 if (dependencyState == ResolutionState.MISSING_SOURCE) {
165 potentialState = ResolutionState.MISSING_DEPENDENCY;
166 missingDependencies.put(identifier, dependency);
170 missingSources.add(identifier);
171 return ResolutionState.MISSING_SOURCE;
173 } catch (Exception e) {
174 potentialState = ResolutionState.OTHER_ERROR;
176 updateResolutionState(identifier, potentialState);
177 return potentialState;
180 private boolean checkValidSource(SourceIdentifier identifier, YangModelDependencyInfo info) {
181 if(!identifier.getName().equals(info.getName())) {
182 LOG.warn("Incorrect model returned. Identifier name was: {}, source contained: {}", identifier.getName(),info.getName());
183 throw new IllegalStateException("Incorrect source was returned");
188 private void updateResolutionState(SourceIdentifier identifier, ResolutionState potentialState) {
189 alreadyProcessed.put(identifier, potentialState);
190 switch (potentialState) {
192 missingSources.add(identifier);
195 validSources.add(identifier);
202 private ResolutionState resolveDependency(ModuleImport dependency) {
203 String name = dependency.getModuleName();
204 Optional<String> formattedRevision = Optional
205 .fromNullable(QName.formattedRevision(dependency.getRevision()));
206 return resolveSource(new SourceIdentifier(name, formattedRevision));
209 private Optional<InputStream> getSchemaSource(SourceIdentifier identifier) {
210 return sourceProvicer
211 .getSchemaSource(identifier.getName(), Optional.fromNullable(identifier.getRevision()));
214 protected YangSourceContext createSourceContext() {
216 ImmutableSet<SourceIdentifier> missingSourcesSet = missingSources.build();
217 ImmutableMultimap<SourceIdentifier, ModuleImport> missingDependenciesMap = missingDependencies.build();
218 ImmutableSet<SourceIdentifier> validSourcesSet = validSources.build();
221 return new YangSourceContext(validSourcesSet,missingSourcesSet,missingDependenciesMap,sourceProvicer);
226 private enum ResolutionState {
227 MISSING_SOURCE, MISSING_DEPENDENCY, OTHER_ERROR, EVERYTHING_OK
230 public static final class YangSourceFromCapabilitiesResolver extends YangSourceContextResolver {
232 private Iterable<QName> capabilities;
234 public YangSourceFromCapabilitiesResolver(Iterable<QName> capabilities,
235 SchemaSourceProvider<InputStream> schemaSourceProvider) {
236 super(schemaSourceProvider);
237 this.capabilities = capabilities;
241 public YangSourceContext resolveContext() {
242 for (QName capability : capabilities) {
243 resolveCapability(capability);
245 return createSourceContext();
248 private void resolveCapability(QName capability) {
249 super.resolveSource(capability.getLocalName(), Optional.fromNullable(capability.getFormattedRevision()));