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/eplv10.html
8 package org.opendaylight.yangtools.yang.parser.impl.util;
10 import java.io.InputStream;
11 import java.util.Collections;
12 import java.util.HashMap;
13 import java.util.HashSet;
14 import java.util.List;
17 import org.opendaylight.yangtools.yang.common.QName;
18 import org.opendaylight.yangtools.yang.model.api.Module;
19 import org.opendaylight.yangtools.yang.model.api.ModuleImport;
20 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
21 import org.opendaylight.yangtools.yang.model.util.repo.AdvancedSchemaSourceProvider;
22 import org.opendaylight.yangtools.yang.model.util.repo.SchemaSourceProvider;
23 import org.opendaylight.yangtools.yang.model.util.repo.SchemaSourceProviders;
24 import org.opendaylight.yangtools.yang.model.util.repo.SourceIdentifier;
25 import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
29 import com.google.common.base.Optional;
30 import com.google.common.base.Preconditions;
31 import com.google.common.collect.ImmutableList;
32 import com.google.common.collect.ImmutableMultimap;
33 import com.google.common.collect.ImmutableSet;
35 public class YangSourceContext implements AdvancedSchemaSourceProvider<InputStream>,AutoCloseable {
37 private final ImmutableSet<SourceIdentifier> validSources;
40 private final ImmutableSet<SourceIdentifier> missingSources;
41 private final ImmutableMultimap<SourceIdentifier, ModuleImport> missingDependencies;
42 private AdvancedSchemaSourceProvider<InputStream> sourceProvider;
44 private YangSourceContext(ImmutableSet<SourceIdentifier> validSourcesSet,
45 ImmutableSet<SourceIdentifier> missingSourcesSet,
46 ImmutableMultimap<SourceIdentifier, ModuleImport> missingDependenciesMap, AdvancedSchemaSourceProvider<InputStream> sourceProvicer) {
47 validSources = validSourcesSet;
48 missingSources = missingSourcesSet;
49 missingDependencies = missingDependenciesMap;
50 sourceProvider = sourceProvicer;
53 public ImmutableSet<SourceIdentifier> getValidSources() {
57 public ImmutableSet<SourceIdentifier> getMissingSources() {
58 return missingSources;
61 public ImmutableMultimap<SourceIdentifier, ModuleImport> getMissingDependencies() {
62 return missingDependencies;
66 public Optional<InputStream> getSchemaSource(String moduleName, Optional<String> revision) {
67 return getSchemaSource(SourceIdentifier.create(moduleName,revision));
71 public Optional<InputStream> getSchemaSource(SourceIdentifier sourceIdentifier) {
72 if(validSources.contains(sourceIdentifier)) {
73 return getDelegateChecked().getSchemaSource(sourceIdentifier);
75 return Optional.absent();
78 private AdvancedSchemaSourceProvider<InputStream> getDelegateChecked() {
79 Preconditions.checkState(sourceProvider != null,"Instance is already closed.");
80 return sourceProvider;
85 if(sourceProvider != null) {
86 sourceProvider = null;
90 public static final YangSourceContext createFrom(Iterable<QName> capabilities,
91 SchemaSourceProvider<InputStream> schemaSourceProvider) {
92 YangSourceContextResolver resolver = new YangSourceFromCapabilitiesResolver(capabilities, schemaSourceProvider);
93 return resolver.resolveContext();
96 public static final SchemaContext toSchemaContext(YangSourceContext context) {
97 List<InputStream> inputStreams = getValidInputStreams(context);
98 YangParserImpl parser = new YangParserImpl();
99 Set<Module> models = parser.parseYangModelsFromStreams(inputStreams);
100 return parser.resolveSchemaContext(models);
103 public static List<InputStream> getValidInputStreams(YangSourceContext context) {
104 return getValidInputStreams(context, context.sourceProvider);
107 public static List<InputStream> getValidInputStreams(YangSourceContext context, AdvancedSchemaSourceProvider<InputStream> provider) {
108 final HashSet<SourceIdentifier> sourcesToLoad = new HashSet<>();
109 sourcesToLoad.addAll(context.getValidSources());
110 for(SourceIdentifier source : context.getValidSources()) {
111 if(source.getRevision() != null) {
112 SourceIdentifier sourceWithoutRevision = SourceIdentifier.create(source.getName(), Optional.<String>absent());
113 sourcesToLoad.removeAll(Collections.singleton(sourceWithoutRevision));
117 ImmutableList.Builder<InputStream> ret = ImmutableList.<InputStream>builder();
118 for(SourceIdentifier sourceIdentifier : sourcesToLoad) {
119 Optional<InputStream> source = provider.getSchemaSource(sourceIdentifier);
120 ret.add(source.get());
126 public static abstract class YangSourceContextResolver {
128 private static final Logger LOG = LoggerFactory.getLogger(YangSourceContextResolver.class);
130 private AdvancedSchemaSourceProvider<InputStream> sourceProvicer;
132 private HashMap<SourceIdentifier, ResolutionState> alreadyProcessed = new HashMap<>();
134 private ImmutableSet.Builder<SourceIdentifier> missingSources = ImmutableSet.builder();
136 private ImmutableMultimap.Builder<SourceIdentifier, ModuleImport> missingDependencies = ImmutableMultimap
139 private ImmutableSet.Builder<SourceIdentifier> validSources = ImmutableSet.builder();
141 public YangSourceContextResolver(AdvancedSchemaSourceProvider<InputStream> schemaSourceProvider) {
142 sourceProvicer = schemaSourceProvider;
145 public abstract YangSourceContext resolveContext();
147 public ResolutionState resolveSource(String name, Optional<String> formattedRevision) {
148 return resolveSource(new SourceIdentifier(name, formattedRevision));
151 private ResolutionState resolveSource(SourceIdentifier identifier) {
153 if (alreadyProcessed.containsKey(identifier)) {
154 return alreadyProcessed.get(identifier);
156 LOG.info("Resolving source: {}",identifier);
157 ResolutionState potentialState = ResolutionState.EVERYTHING_OK;
159 Optional<InputStream> source = getSchemaSource(identifier);
160 if (source.isPresent()) {
162 YangModelDependencyInfo info = YangModelDependencyInfo.fromInputStream(source.get());
164 checkValidSource(identifier,info);
166 for (ModuleImport dependency : info.getDependencies()) {
167 LOG.debug("Source: {} Resolving dependency: {}",identifier,dependency);
168 ResolutionState dependencyState = resolveDependency(dependency);
169 if (dependencyState == ResolutionState.MISSING_SOURCE) {
170 potentialState = ResolutionState.MISSING_DEPENDENCY;
171 missingDependencies.put(identifier, dependency);
175 missingSources.add(identifier);
176 return ResolutionState.MISSING_SOURCE;
178 } catch (Exception e) {
179 potentialState = ResolutionState.OTHER_ERROR;
181 updateResolutionState(identifier, potentialState);
182 return potentialState;
185 private boolean checkValidSource(SourceIdentifier identifier, YangModelDependencyInfo info) {
186 if(!identifier.getName().equals(info.getName())) {
187 LOG.warn("Incorrect model returned. Identifier name was: {}, source contained: {}", identifier.getName(),info.getName());
188 throw new IllegalStateException("Incorrect source was returned");
193 private void updateResolutionState(SourceIdentifier identifier, ResolutionState potentialState) {
194 alreadyProcessed.put(identifier, potentialState);
195 switch (potentialState) {
197 missingSources.add(identifier);
200 validSources.add(identifier);
207 private ResolutionState resolveDependency(ModuleImport dependency) {
208 String name = dependency.getModuleName();
209 Optional<String> formattedRevision = Optional
210 .fromNullable(QName.formattedRevision(dependency.getRevision()));
211 return resolveSource(new SourceIdentifier(name, formattedRevision));
214 private Optional<InputStream> getSchemaSource(SourceIdentifier identifier) {
215 return sourceProvicer
216 .getSchemaSource(identifier.getName(), Optional.fromNullable(identifier.getRevision()));
219 protected YangSourceContext createSourceContext() {
221 ImmutableSet<SourceIdentifier> missingSourcesSet = missingSources.build();
222 ImmutableMultimap<SourceIdentifier, ModuleImport> missingDependenciesMap = missingDependencies.build();
223 ImmutableSet<SourceIdentifier> validSourcesSet = validSources.build();
226 return new YangSourceContext(validSourcesSet,missingSourcesSet,missingDependenciesMap,sourceProvicer);
231 private enum ResolutionState {
232 MISSING_SOURCE, MISSING_DEPENDENCY, OTHER_ERROR, EVERYTHING_OK
235 public static final class YangSourceFromCapabilitiesResolver extends YangSourceContextResolver {
237 private Iterable<QName> capabilities;
239 public YangSourceFromCapabilitiesResolver(Iterable<QName> capabilities,
240 SchemaSourceProvider<InputStream> schemaSourceProvider) {
241 super(SchemaSourceProviders.toAdvancedSchemaSourceProvider(schemaSourceProvider));
242 this.capabilities = capabilities;
246 public YangSourceContext resolveContext() {
247 for (QName capability : capabilities) {
248 resolveCapability(capability);
250 return createSourceContext();
253 private void resolveCapability(QName capability) {
254 super.resolveSource(capability.getLocalName(), Optional.fromNullable(capability.getFormattedRevision()));