/*
* 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.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
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.ModuleImport;
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.SourceIdentifier;
import org.opendaylight.yangtools.yang.parser.builder.impl.BuilderUtils;
/**
*
* 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:
*
* - {@link #getValidSources()} - set of {@link SourceIdentifier} which have
* their dependencies present and are safe to be used by full blown parser.
*
- {@link #getMissingSources()} - set of {@link SourceIdentifier} which have
* been referenced by other YANG sources, but source code for them is missing.
*
- {@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, Closeable,
Delegator> {
private final ImmutableSet validSources;
private final ImmutableSet missingSources;
private final ImmutableMultimap missingDependencies;
private final AdvancedSchemaSourceProvider 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 validSourcesSet,
final ImmutableSet missingSourcesSet,
final ImmutableMultimap missingDependenciesMap,
final AdvancedSchemaSourceProvider 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 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 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 getMissingDependencies() {
return missingDependencies;
}
@Override
public Optional getSchemaSource(final String moduleName, final Optional revision) {
return getSchemaSource(SourceIdentifier.create(moduleName, revision));
}
@Override
public Optional getSchemaSource(final SourceIdentifier sourceIdentifier) {
if (validSources.contains(sourceIdentifier)) {
return getDelegateChecked().getSchemaSource(sourceIdentifier);
}
return Optional.absent();
}
private AdvancedSchemaSourceProvider getDelegateChecked() {
assertNotClosed();
return sourceProvider;
}
@Override
public AdvancedSchemaSourceProvider getDelegate() {
assertNotClosed();
return sourceProvider;
}
private void assertNotClosed() {
if (isClosed.get()) {
throw new IllegalStateException("Instance already closed");
}
}
@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 capabilities,
final SchemaSourceProvider schemaSourceProvider) {
YangSourceContextResolver resolver = new YangSourceFromCapabilitiesResolver(capabilities, schemaSourceProvider);
return resolver.resolveContext();
}
public static YangSourceContext createFrom(final Map moduleDependencies,
AdvancedSchemaSourceProvider sourceProvider) {
YangSourceFromDependencyInfoResolver resolver = new YangSourceFromDependencyInfoResolver(
moduleDependencies, sourceProvider);
return resolver.resolveContext();
}
/**
* 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 getValidInputStreams() {
return getValidInputStreamsInternal();
}
private List getValidInputStreamsInternal() {
assertNotClosed();
final HashSet sourcesToLoad = new HashSet<>();
sourcesToLoad.addAll(this.getValidSources());
for (SourceIdentifier source : this.getValidSources()) {
if (source.getRevision() != null) {
SourceIdentifier sourceWithoutRevision = SourceIdentifier.create(source.getName(),
Optional. absent());
sourcesToLoad.remove(sourceWithoutRevision);
}
}
ImmutableList.Builder ret = ImmutableList.builder();
for (SourceIdentifier sourceIdentifier : sourcesToLoad) {
Optional source = sourceProvider.getSchemaSource(sourceIdentifier);
ret.add(source.get());
}
return ret.build();
}
public Collection getValidByteSources() throws IOException {
List yangModelStreams = getValidInputStreamsInternal();
return BuilderUtils.streamsToByteSources(yangModelStreams);
}
@Deprecated
public static List getValidInputStreams(final YangSourceContext context) {
return context.getValidInputStreams();
}
}