X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=yang%2Fyang-parser-impl%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fyangtools%2Fyang%2Fparser%2Frepo%2FSharedSchemaContextFactory.java;h=ab146fcfc6d732196966f3697c36cee12aad0c3d;hb=34f9631ab5302045214340d9ff91a9e3a16beca2;hp=d40b726a140b4ded60170a4bb3dccd6fc24883e8;hpb=85a9a2f03fba2912e6824d546c7b250c442b201a;p=yangtools.git diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/SharedSchemaContextFactory.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/SharedSchemaContextFactory.java index d40b726a14..ab146fcfc6 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/SharedSchemaContextFactory.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/SharedSchemaContextFactory.java @@ -8,40 +8,42 @@ package org.opendaylight.yangtools.yang.parser.repo; import com.google.common.base.Function; -import com.google.common.base.Optional; import com.google.common.base.Preconditions; +import com.google.common.base.Predicate; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.google.common.collect.Collections2; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; import com.google.common.collect.Maps; import com.google.common.util.concurrent.AsyncFunction; import com.google.common.util.concurrent.CheckedFuture; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; -import java.net.URI; import java.util.Collection; -import java.util.Date; import java.util.LinkedHashMap; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; -import java.util.TreeMap; +import java.util.Set; +import javax.annotation.Nullable; import org.antlr.v4.runtime.ParserRuleContext; -import org.antlr.v4.runtime.tree.ParseTreeWalker; +import org.opendaylight.yangtools.antlrv4.code.gen.YangStatementParser.StatementContext; import org.opendaylight.yangtools.util.concurrent.ExceptionMapper; import org.opendaylight.yangtools.util.concurrent.ReflectiveExceptionMapper; -import org.opendaylight.yangtools.yang.model.api.Module; import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.opendaylight.yangtools.yang.model.repo.api.SchemaContextFactory; import org.opendaylight.yangtools.yang.model.repo.api.SchemaResolutionException; import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceFilter; import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier; -import org.opendaylight.yangtools.yang.parser.builder.impl.BuilderUtils; -import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder; -import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl; -import org.opendaylight.yangtools.yang.parser.impl.YangParserListenerImpl; import org.opendaylight.yangtools.yang.parser.impl.util.YangModelDependencyInfo; +import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException; +import org.opendaylight.yangtools.yang.parser.spi.source.SourceException; +import org.opendaylight.yangtools.yang.parser.stmt.reactor.CrossSourceStatementReactor; +import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangInferencePipeline; +import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangStatementSourceImpl; import org.opendaylight.yangtools.yang.parser.util.ASTSchemaSource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -56,11 +58,11 @@ final class SharedSchemaContextFactory implements SchemaContextFactory { return repository.getSchemaSource(input, ASTSchemaSource.class); } }; - private final Cache, SchemaContext> cache = CacheBuilder.newBuilder().softValues().build(); + private final Cache, SchemaContext> cache = CacheBuilder.newBuilder().weakValues().build(); private final AsyncFunction, SchemaContext> assembleSources = new AsyncFunction, SchemaContext>() { @Override - public ListenableFuture apply(final List sources) throws SchemaResolutionException { + public ListenableFuture apply(final List sources) throws SchemaResolutionException, SourceException, ReactorException { final Map srcs = Maps.uniqueIndex(sources, ASTSchemaSource.GET_IDENTIFIER); final Map deps = @@ -71,34 +73,24 @@ final class SharedSchemaContextFactory implements SchemaContextFactory { final DependencyResolver res = DependencyResolver.create(deps); if (!res.getUnresolvedSources().isEmpty()) { LOG.debug("Omitting models {} due to unsatisfied imports {}", res.getUnresolvedSources(), res.getUnsatisfiedImports()); - - // FIXME: push into DependencyResolver - throw new SchemaResolutionException("Failed to resolve required models", res.getResolvedSources(), res.getUnsatisfiedImports()); } - final Map asts = - Maps.transformValues(srcs, ASTSchemaSource.GET_AST); - final Map> namespaceContext = BuilderUtils.createYangNamespaceContext( - asts.values(), Optional. absent()); - - final ParseTreeWalker walker = new ParseTreeWalker(); - final Map sourceToBuilder = new LinkedHashMap<>(); + final Map asts = Maps.transformValues(srcs, ASTSchemaSource.GET_AST); + final CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild(); - for (Entry entry : asts.entrySet()) { - ModuleBuilder moduleBuilder = YangParserListenerImpl.create(namespaceContext, entry.getKey().getName(), - walker, entry.getValue()).getModuleBuilder(); + for (final Entry e : asts.entrySet()) { + final ParserRuleContext parserRuleCtx = e.getValue(); + Preconditions.checkArgument(parserRuleCtx instanceof StatementContext, + "Unsupported context class %s for source %s", parserRuleCtx.getClass(), e.getKey()); - moduleBuilder.setSource(srcs.get(entry.getKey()).getYangText()); - sourceToBuilder.put(entry.getKey(), moduleBuilder); + reactor.addSource(new YangStatementSourceImpl(e.getKey(), (StatementContext) parserRuleCtx)); } - LOG.debug("Modules ready for integration"); - final YangParserImpl parser = YangParserImpl.getInstance(); - final Collection modules = parser.buildModules(sourceToBuilder.values()); - LOG.debug("Integrated cross-references modules"); - return Futures.immediateCheckedFuture(parser.assembleContext(modules)); + SchemaContext schemaContext = reactor.buildEffective(); + + return Futures.immediateCheckedFuture(schemaContext); } }; @@ -106,6 +98,7 @@ final class SharedSchemaContextFactory implements SchemaContextFactory { // FIXME: ignored right now private final SchemaSourceFilter filter; + // FIXME SchemaRepository should be the type for repository parameter instead of SharedSchemaRepository (final implementation) public SharedSchemaContextFactory(final SharedSchemaRepository repository, final SchemaSourceFilter filter) { this.repository = Preconditions.checkNotNull(repository); this.filter = Preconditions.checkNotNull(filter); @@ -113,31 +106,92 @@ final class SharedSchemaContextFactory implements SchemaContextFactory { @Override public CheckedFuture createSchemaContext(final Collection requiredSources) { - final SchemaContext existing = cache.getIfPresent(requiredSources); + // Make sources unique + final List uniqueSourceIdentifiers = deDuplicateSources(requiredSources); + + final SchemaContext existing = cache.getIfPresent(uniqueSourceIdentifiers); if (existing != null) { LOG.debug("Returning cached context {}", existing); return Futures.immediateCheckedFuture(existing); } // Request all sources be loaded - final ListenableFuture> sf = Futures.allAsList(Collections2.transform(requiredSources, requestSources)); + ListenableFuture> sf = Futures.allAsList(Collections2.transform(uniqueSourceIdentifiers, requestSources)); + + // Detect mismatch between requested Source IDs and IDs that are extracted from parsed source + // Also remove duplicates if present + // We are relying on preserved order of uniqueSourceIdentifiers as well as sf + sf = Futures.transform(sf, new SourceIdMismatchDetector(uniqueSourceIdentifiers)); - // Assemble sources into a schemacontext + // Assemble sources into a schema context final ListenableFuture cf = Futures.transform(sf, assembleSources); // Populate cache when successful Futures.addCallback(cf, new FutureCallback() { @Override public void onSuccess(final SchemaContext result) { - cache.put(requiredSources, result); + cache.put(uniqueSourceIdentifiers, result); } @Override public void onFailure(final Throwable t) { - LOG.info("Failed to assemble sources", t); + LOG.debug("Failed to assemble sources", t); } }); return Futures.makeChecked(cf, MAPPER); } -} \ No newline at end of file + + /** + * @return set (preserving ordering) from the input collection + */ + private static List deDuplicateSources(final Collection requiredSources) { + final Set uniqueSourceIdentifiers = new LinkedHashSet<>(requiredSources); + if (uniqueSourceIdentifiers.size() == requiredSources.size()) { + // Can potentially reuse input + return ImmutableList.copyOf(requiredSources); + } + + LOG.warn("Duplicate sources requested for schema context, removed duplicate sources: {}", + Collections2.filter(uniqueSourceIdentifiers, new Predicate() { + @Override + public boolean apply(@Nullable final SourceIdentifier input) { + return Iterables.frequency(requiredSources, input) > 1; + } + })); + return ImmutableList.copyOf(uniqueSourceIdentifiers); + } + + private static final class SourceIdMismatchDetector implements Function, List> { + private final List sourceIdentifiers; + + public SourceIdMismatchDetector(final List sourceIdentifiers) { + this.sourceIdentifiers = Preconditions.checkNotNull(sourceIdentifiers); + } + + @Override + public List apply(final List input) { + final Map filtered = new LinkedHashMap<>(); + + for (int i = 0; i < input.size(); i++) { + + final SourceIdentifier expectedSId = sourceIdentifiers.get(i); + final ASTSchemaSource astSchemaSource = input.get(i); + final SourceIdentifier realSId = astSchemaSource.getIdentifier(); + + if (!expectedSId.equals(realSId)) { + LOG.warn("Source identifier mismatch for module \"{}\", requested as {} but actually is {}. Using actual id", + expectedSId.getName(), expectedSId, realSId); + } + + if (filtered.containsKey(realSId)) { + LOG.warn("Duplicate source for module {} detected in reactor", realSId); + } + + filtered.put(realSId, astSchemaSource); + + } + return ImmutableList.copyOf(filtered.values()); + } + } +}