/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
- *
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/eplv10.html
*/
package org.opendaylight.yangtools.yang.parser.impl.util;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMultimap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.io.ByteSource;
+import java.io.Closeable;
+import java.io.IOException;
import java.io.InputStream;
-import java.util.Collections;
-import java.util.HashMap;
+import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-
+import java.util.concurrent.atomic.AtomicBoolean;
+import javax.annotation.concurrent.ThreadSafe;
+import org.opendaylight.yangtools.concepts.Delegator;
import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.model.api.Module;
import org.opendaylight.yangtools.yang.model.api.ModuleImport;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.opendaylight.yangtools.yang.model.util.repo.AdvancedSchemaSourceProvider;
import org.opendaylight.yangtools.yang.model.util.repo.SchemaSourceProvider;
-import org.opendaylight.yangtools.yang.model.util.repo.SchemaSourceProviders;
import org.opendaylight.yangtools.yang.model.util.repo.SourceIdentifier;
-import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableMultimap;
-import com.google.common.collect.ImmutableSet;
+import org.opendaylight.yangtools.yang.parser.builder.impl.BuilderUtils;
-public class YangSourceContext implements AdvancedSchemaSourceProvider<InputStream>, AutoCloseable {
+/**
+ *
+ * Context of YANG model sources
+ *
+ * YANG sources context represent information learned about set of model sources
+ * which could be derived from dependency information only.
+ *
+ * Contains following information:
+ * <ul>
+ * <li>{@link #getValidSources()} - set of {@link SourceIdentifier} which have
+ * their dependencies present and are safe to be used by full blown parser.
+ * <li>{@link #getMissingSources()} - set of {@link SourceIdentifier} which have
+ * been referenced by other YANG sources, but source code for them is missing.
+ * <li>{@link #getMissingDependencies()} - map of {@link SourceIdentifier} and
+ * their imports for which source codes was not available.
+ *
+ * {@link YangSourceContext} may be associated with {@link SchemaSourceProvider}
+ * (see {@link #getDelegate()}, which was used for retrieval of sources during
+ * context computation.
+ *
+ * {@link YangSourceContext} may be used as schema source provider to retrieve
+ * this sources.
+ *
+ *
+ */
+// FIXME: for some reason this class is Closeable even though close is never called and no resources are leaked
+@ThreadSafe
+public class YangSourceContext implements AdvancedSchemaSourceProvider<InputStream>, Closeable,
+ Delegator<AdvancedSchemaSourceProvider<InputStream>> {
private final ImmutableSet<SourceIdentifier> validSources;
private final ImmutableSet<SourceIdentifier> missingSources;
private final ImmutableMultimap<SourceIdentifier, ModuleImport> missingDependencies;
- private AdvancedSchemaSourceProvider<InputStream> sourceProvider;
-
- private YangSourceContext(ImmutableSet<SourceIdentifier> validSourcesSet,
- ImmutableSet<SourceIdentifier> missingSourcesSet,
- ImmutableMultimap<SourceIdentifier, ModuleImport> missingDependenciesMap,
- AdvancedSchemaSourceProvider<InputStream> sourceProvicer) {
- validSources = validSourcesSet;
- missingSources = missingSourcesSet;
- missingDependencies = missingDependenciesMap;
- sourceProvider = sourceProvicer;
- }
-
+ private final AdvancedSchemaSourceProvider<InputStream> sourceProvider;
+ private final AtomicBoolean isClosed = new AtomicBoolean();
+
+ /**
+ * Construct YANG Source Context
+ *
+ * @param validSourcesSet Set of identifiers of valid sources
+ * @param missingSourcesSet Set of identifiers of missing sources
+ * @param missingDependenciesMap Map of identifiers of resolved sources and their missing imports.
+ * @param sourceProvider Source provider which was used for context resolution or
+ * null if provider was not used.
+ */
+ YangSourceContext(final ImmutableSet<SourceIdentifier> validSourcesSet,
+ final ImmutableSet<SourceIdentifier> missingSourcesSet,
+ final ImmutableMultimap<SourceIdentifier, ModuleImport> missingDependenciesMap,
+ final AdvancedSchemaSourceProvider<InputStream> sourceProvider) {
+ validSources = checkNotNull(validSourcesSet, "Valid source set must not be null");
+ missingSources = checkNotNull(missingSourcesSet, "Missing sources set must not be null");
+ missingDependencies = checkNotNull(missingDependenciesMap, "Missing dependencies map must not be null");
+ this.sourceProvider = checkNotNull(sourceProvider, "Missing sourceProvider");
+ }
+
+ /**
+ * Returns set of valid source identifiers.
+ *
+ * Source identifier is considered valid if it's source
+ * was present during resolution and sources
+ * for all known dependencies was present at the time of creation
+ * of {@link YangSourceContext}.
+ *
+ * @return Set of valid source identifiers.
+ */
public ImmutableSet<SourceIdentifier> getValidSources() {
return validSources;
}
+ /**
+ * Returns set of source identifiers, whom sources was not resolved.
+ *
+ * Source is considered missing if the source was not present
+ * during resolution of {@link YangSourceContext}.
+ *
+ * @return Set of missing sources.
+ */
public ImmutableSet<SourceIdentifier> getMissingSources() {
return missingSources;
}
+ /**
+ * Returns a multimap of Source Identifier and imports which had missing
+ * sources.
+ *
+ * Maps a source identifier to its imports, which was not resolved
+ * during resolution of this context, so it is unable to fully
+ * processed source identifier.
+ *
+ *
+ * @return Multi-map of source identifier to it's unresolved dependencies.
+ */
public ImmutableMultimap<SourceIdentifier, ModuleImport> getMissingDependencies() {
return missingDependencies;
}
@Override
- public Optional<InputStream> getSchemaSource(String moduleName, Optional<String> revision) {
+ public Optional<InputStream> getSchemaSource(final String moduleName, final Optional<String> revision) {
return getSchemaSource(SourceIdentifier.create(moduleName, revision));
}
@Override
- public Optional<InputStream> getSchemaSource(SourceIdentifier sourceIdentifier) {
+ public Optional<InputStream> getSchemaSource(final SourceIdentifier sourceIdentifier) {
if (validSources.contains(sourceIdentifier)) {
return getDelegateChecked().getSchemaSource(sourceIdentifier);
}
}
private AdvancedSchemaSourceProvider<InputStream> getDelegateChecked() {
- Preconditions.checkState(sourceProvider != null, "Instance is already closed.");
+ assertNotClosed();
return sourceProvider;
}
@Override
- public void close() {
- if (sourceProvider != null) {
- sourceProvider = null;
+ public AdvancedSchemaSourceProvider<InputStream> getDelegate() {
+ assertNotClosed();
+ return sourceProvider;
+ }
+
+ private void assertNotClosed() {
+ if (isClosed.get()) {
+ throw new IllegalStateException("Instance already closed");
}
}
- public static final YangSourceContext createFrom(Iterable<QName> capabilities,
- SchemaSourceProvider<InputStream> schemaSourceProvider) {
+ @Override
+ public void close() {
+ isClosed.set(true);
+ }
+
+ /**
+ * Creates YANG Source context from supplied capabilities and schema source
+ * provider.
+ *
+ * @param capabilities
+ * Set of QName representing module capabilities,
+ * {@link QName#getLocalName()} represents
+ * source name and {@link QName#getRevision()} represents
+ * revision of source.
+ *
+ * @param schemaSourceProvider
+ * - {@link SchemaSourceProvider} which should be used to resolve
+ * sources.
+ * @return YANG source context which describes resolution of capabilities
+ * and their dependencies
+ * against supplied schema source provider.
+ */
+ public static YangSourceContext createFrom(final Iterable<QName> capabilities,
+ final SchemaSourceProvider<InputStream> schemaSourceProvider) {
YangSourceContextResolver resolver = new YangSourceFromCapabilitiesResolver(capabilities, schemaSourceProvider);
return resolver.resolveContext();
}
- public static final YangSourceContext createFrom(Map<SourceIdentifier, YangModelDependencyInfo> moduleDependencies) {
- YangSourceContextResolver resolver = new YangSourceFromDependencyInfoResolver(moduleDependencies);
+ public static YangSourceContext createFrom(final Map<SourceIdentifier, YangModelDependencyInfo> moduleDependencies,
+ AdvancedSchemaSourceProvider<InputStream> sourceProvider) {
+ YangSourceFromDependencyInfoResolver resolver = new YangSourceFromDependencyInfoResolver(
+ moduleDependencies, sourceProvider);
return resolver.resolveContext();
}
- public static final SchemaContext toSchemaContext(YangSourceContext context) {
- List<InputStream> inputStreams = getValidInputStreams(context);
- YangParserImpl parser = new YangParserImpl();
- Set<Module> models = parser.parseYangModelsFromStreams(inputStreams);
- return parser.resolveSchemaContext(models);
+ /**
+ * Returns a list of valid input streams from YANG Source Context
+ * using supplied schema source provider.
+ *
+ * @return List of input streams.
+ * @deprecated Use {@link #getValidByteSources()}
+ */
+ @Deprecated
+ public List<InputStream> getValidInputStreams() {
+ return getValidInputStreamsInternal();
}
- public static List<InputStream> getValidInputStreams(YangSourceContext context) {
- return getValidInputStreams(context, context.sourceProvider);
- }
-
- public static List<InputStream> getValidInputStreams(YangSourceContext context,
- AdvancedSchemaSourceProvider<InputStream> provider) {
+ private List<InputStream> getValidInputStreamsInternal() {
+ assertNotClosed();
final HashSet<SourceIdentifier> sourcesToLoad = new HashSet<>();
- sourcesToLoad.addAll(context.getValidSources());
- for (SourceIdentifier source : context.getValidSources()) {
+ sourcesToLoad.addAll(this.getValidSources());
+ for (SourceIdentifier source : this.getValidSources()) {
if (source.getRevision() != null) {
SourceIdentifier sourceWithoutRevision = SourceIdentifier.create(source.getName(),
Optional.<String> absent());
- sourcesToLoad.removeAll(Collections.singleton(sourceWithoutRevision));
+ sourcesToLoad.remove(sourceWithoutRevision);
}
}
- ImmutableList.Builder<InputStream> ret = ImmutableList.<InputStream> builder();
+ ImmutableList.Builder<InputStream> ret = ImmutableList.<InputStream>builder();
for (SourceIdentifier sourceIdentifier : sourcesToLoad) {
- Optional<InputStream> source = provider.getSchemaSource(sourceIdentifier);
+ Optional<InputStream> source = sourceProvider.getSchemaSource(sourceIdentifier);
ret.add(source.get());
}
return ret.build();
}
- public static abstract class YangSourceContextResolver {
-
- private static final Logger LOG = LoggerFactory.getLogger(YangSourceContextResolver.class);
-
- private final AdvancedSchemaSourceProvider<InputStream> sourceProvider;
-
- public AdvancedSchemaSourceProvider<InputStream> getSourceProvider() {
- return sourceProvider;
- }
-
- private final HashMap<SourceIdentifier, ResolutionState> alreadyProcessed = new HashMap<>();
-
- private final ImmutableSet.Builder<SourceIdentifier> missingSources = ImmutableSet.builder();
-
- private ImmutableMultimap.Builder<SourceIdentifier, ModuleImport> missingDependencies = ImmutableMultimap
- .builder();
-
- private final ImmutableSet.Builder<SourceIdentifier> validSources = ImmutableSet.builder();
-
- public YangSourceContextResolver() {
- sourceProvider = null;
- }
-
- public YangSourceContextResolver(AdvancedSchemaSourceProvider<InputStream> sourceProvicer) {
- super();
- this.sourceProvider = sourceProvicer;
- }
-
- public abstract YangSourceContext resolveContext();
-
- public ResolutionState resolveSource(String name, Optional<String> formattedRevision) {
- return resolveSource(new SourceIdentifier(name, formattedRevision));
- }
-
- public ResolutionState resolveSource(SourceIdentifier identifier) {
-
- if (alreadyProcessed.containsKey(identifier)) {
- return alreadyProcessed.get(identifier);
- }
- LOG.trace("Resolving source: {}", identifier);
- ResolutionState potentialState = ResolutionState.EVERYTHING_OK;
- try {
- Optional<YangModelDependencyInfo> potentialInfo = getDependencyInfo(identifier);
- if (potentialInfo.isPresent()) {
- YangModelDependencyInfo info = potentialInfo.get();
- checkValidSource(identifier, info);
- for (ModuleImport dependency : info.getDependencies()) {
- LOG.trace("Source: {} Resolving dependency: {}", identifier, dependency);
- ResolutionState dependencyState = resolveDependency(dependency);
- if (dependencyState != ResolutionState.EVERYTHING_OK) {
- potentialState = ResolutionState.MISSING_DEPENDENCY;
- missingDependencies.put(identifier, dependency);
- }
- }
- } else {
- missingSources.add(identifier);
- return ResolutionState.MISSING_SOURCE;
- }
- } catch (Exception e) {
- potentialState = ResolutionState.OTHER_ERROR;
- }
- updateResolutionState(identifier, potentialState);
- return potentialState;
- }
-
- public abstract Optional<YangModelDependencyInfo> getDependencyInfo(SourceIdentifier identifier);
-
- private boolean checkValidSource(SourceIdentifier identifier, YangModelDependencyInfo info) {
- if (!identifier.getName().equals(info.getName())) {
- LOG.warn("Incorrect model returned. Identifier name was: {}, source contained: {}",
- identifier.getName(), info.getName());
- throw new IllegalStateException("Incorrect source was returned");
- }
- return true;
- }
-
- private void updateResolutionState(SourceIdentifier identifier, ResolutionState potentialState) {
- alreadyProcessed.put(identifier, potentialState);
- switch (potentialState) {
- case MISSING_SOURCE:
- missingSources.add(identifier);
- break;
- case EVERYTHING_OK:
- validSources.add(identifier);
- break;
- default:
- break;
- }
- }
-
- private ResolutionState resolveDependency(ModuleImport dependency) {
- String name = dependency.getModuleName();
- Optional<String> formattedRevision = Optional
- .fromNullable(QName.formattedRevision(dependency.getRevision()));
- return resolveSource(new SourceIdentifier(name, formattedRevision));
- }
-
- protected YangSourceContext createSourceContext() {
-
- ImmutableSet<SourceIdentifier> missingSourcesSet = missingSources.build();
- ImmutableMultimap<SourceIdentifier, ModuleImport> missingDependenciesMap = missingDependencies.build();
- ImmutableSet<SourceIdentifier> validSourcesSet = validSources.build();
-
- return new YangSourceContext(validSourcesSet, missingSourcesSet, missingDependenciesMap, sourceProvider);
-
- }
- }
-
- private enum ResolutionState {
- MISSING_SOURCE, MISSING_DEPENDENCY, OTHER_ERROR, EVERYTHING_OK
- }
-
- public static final class YangSourceFromCapabilitiesResolver extends YangSourceContextResolver {
- private Iterable<QName> capabilities;
-
- public YangSourceFromCapabilitiesResolver(Iterable<QName> capabilities,
- SchemaSourceProvider<InputStream> schemaSourceProvider) {
- super(SchemaSourceProviders.toAdvancedSchemaSourceProvider(schemaSourceProvider));
- this.capabilities = capabilities;
- }
-
- @Override
- public YangSourceContext resolveContext() {
- for (QName capability : capabilities) {
- resolveCapability(capability);
- }
- return createSourceContext();
- }
-
- private void resolveCapability(QName capability) {
- super.resolveSource(capability.getLocalName(), Optional.fromNullable(capability.getFormattedRevision()));
- }
-
- @Override
- public Optional<YangModelDependencyInfo> getDependencyInfo(SourceIdentifier identifier) {
- Optional<InputStream> source = getSchemaSource(identifier);
- if (source.isPresent()) {
- return Optional.of(YangModelDependencyInfo.fromInputStream(source.get()));
- }
- return Optional.absent();
- }
-
- private Optional<InputStream> getSchemaSource(SourceIdentifier identifier) {
- return getSourceProvider().getSchemaSource(identifier.getName(),
- Optional.fromNullable(identifier.getRevision()));
- }
+ public Collection<ByteSource> getValidByteSources() throws IOException {
+ List<InputStream> yangModelStreams = getValidInputStreamsInternal();
+ return BuilderUtils.streamsToByteSources(yangModelStreams);
}
- public static final class YangSourceFromDependencyInfoResolver extends YangSourceContextResolver {
-
- private final Map<SourceIdentifier, YangModelDependencyInfo> dependencyInfo;
-
- public YangSourceFromDependencyInfoResolver(Map<SourceIdentifier, YangModelDependencyInfo> moduleDependencies) {
- dependencyInfo = ImmutableMap.copyOf(moduleDependencies);
- }
-
- @Override
- public Optional<YangModelDependencyInfo> getDependencyInfo(SourceIdentifier identifier) {
- if (identifier.getRevision() != null) {
- return Optional.fromNullable(dependencyInfo.get(identifier));
- }
- YangModelDependencyInfo potential = dependencyInfo.get(identifier);
- if (potential == null) {
- for (Entry<SourceIdentifier, YangModelDependencyInfo> newPotential : dependencyInfo.entrySet()) {
- String newPotentialName = newPotential.getKey().getName();
-
- if (newPotentialName.equals(identifier.getName())) {
- String newPotentialRevision = newPotential.getKey().getRevision();
- if (potential == null || 1 == newPotentialRevision.compareTo(potential.getFormattedRevision())) {
- potential = newPotential.getValue();
- }
- }
- }
- }
- return Optional.fromNullable(potential);
- }
-
- @Override
- public YangSourceContext resolveContext() {
- for (SourceIdentifier source : dependencyInfo.keySet()) {
- resolveSource(source);
- }
- return createSourceContext();
- }
+ @Deprecated
+ public static List<InputStream> getValidInputStreams(final YangSourceContext context) {
+ return context.getValidInputStreams();
}
}