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=e9a4fc6d842f55158ae155a19327b69881e30f84;hb=43657f12c39e61d51d178e99075e5b0e3eea4b24;hp=2a9af3d1f81dda64cf5f71b0312c451871bc7839;hpb=dbfcee6d57a103531a6043ffd1740cd939bc4373;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 2a9af3d1f8..e9a4fc6d84 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 @@ -7,8 +7,10 @@ */ package org.opendaylight.yangtools.yang.parser.repo; +import static java.util.Objects.requireNonNull; +import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFluentFuture; + import com.google.common.base.Function; -import com.google.common.base.Preconditions; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.google.common.collect.Collections2; @@ -16,10 +18,13 @@ 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.FluentFuture; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; +import com.google.common.util.concurrent.SettableFuture; +import java.io.IOException; import java.util.Collection; import java.util.LinkedHashMap; import java.util.LinkedHashSet; @@ -27,82 +32,66 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; -import javax.annotation.Nonnull; -import org.antlr.v4.runtime.ParserRuleContext; -import org.opendaylight.yangtools.antlrv4.code.gen.YangStatementParser.StatementContext; -import org.opendaylight.yangtools.yang.common.QName; -import org.opendaylight.yangtools.yang.model.api.SchemaContext; -import org.opendaylight.yangtools.yang.model.repo.api.SchemaContextFactory; +import java.util.concurrent.ExecutionException; +import org.eclipse.jdt.annotation.NonNull; +import org.gaul.modernizer_maven_annotations.SuppressModernizer; +import org.opendaylight.yangtools.concepts.SemVer; +import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext; +import org.opendaylight.yangtools.yang.model.parser.api.YangParser; +import org.opendaylight.yangtools.yang.model.parser.api.YangParserException; +import org.opendaylight.yangtools.yang.model.parser.api.YangParserFactory; +import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException; +import org.opendaylight.yangtools.yang.model.repo.api.EffectiveModelContextFactory; import org.opendaylight.yangtools.yang.model.repo.api.SchemaContextFactoryConfiguration; -import org.opendaylight.yangtools.yang.model.repo.api.SchemaRepository; 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.SemVerSourceIdentifier; import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier; import org.opendaylight.yangtools.yang.model.repo.api.StatementParserMode; -import org.opendaylight.yangtools.yang.parser.impl.DefaultReactors; -import org.opendaylight.yangtools.yang.parser.rfc7950.repo.ASTSchemaSource; +import org.opendaylight.yangtools.yang.parser.rfc7950.ir.IRSchemaSource; import org.opendaylight.yangtools.yang.parser.rfc7950.repo.YangModelDependencyInfo; -import org.opendaylight.yangtools.yang.parser.rfc7950.repo.YangStatementStreamSource; import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException; -import org.opendaylight.yangtools.yang.parser.stmt.reactor.CrossSourceStatementReactor.BuildAction; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -final class SharedSchemaContextFactory implements SchemaContextFactory { +final class SharedSchemaContextFactory implements EffectiveModelContextFactory { private static final Logger LOG = LoggerFactory.getLogger(SharedSchemaContextFactory.class); - private final Cache, SchemaContext> revisionCache = CacheBuilder.newBuilder() + private final Cache, EffectiveModelContext> revisionCache = CacheBuilder.newBuilder() .weakValues().build(); - private final Cache, SchemaContext> semVerCache = CacheBuilder.newBuilder() + private final Cache, EffectiveModelContext> semVerCache = CacheBuilder.newBuilder() .weakValues().build(); - private final SchemaRepository repository; - private final SchemaContextFactoryConfiguration config; - - // FIXME SchemaRepository should be the type for repository parameter instead of SharedSchemaRepository - // (final implementation) - @Deprecated - SharedSchemaContextFactory(final SharedSchemaRepository repository, final SchemaSourceFilter filter) { - this.repository = Preconditions.checkNotNull(repository); - this.config = SchemaContextFactoryConfiguration.builder().setFilter(filter).build(); - } - - SharedSchemaContextFactory(final SchemaRepository repository, final SchemaContextFactoryConfiguration config) { - this.repository = Preconditions.checkNotNull(repository); - this.config = Preconditions.checkNotNull(config); - } + private final @NonNull SharedSchemaRepository repository; + private final @NonNull SchemaContextFactoryConfiguration config; - @Override - @Deprecated - public ListenableFuture createSchemaContext(final Collection requiredSources, - final StatementParserMode statementParserMode, final Set supportedFeatures) { - return createSchemaContext(requiredSources, - statementParserMode == StatementParserMode.SEMVER_MODE ? semVerCache : revisionCache, - new AssembleSources(SchemaContextFactoryConfiguration.builder() - .setFilter(config.getSchemaSourceFilter()).setStatementParserMode(statementParserMode) - .setSupportedFeatures(supportedFeatures).build())); + SharedSchemaContextFactory(final @NonNull SharedSchemaRepository repository, + final @NonNull SchemaContextFactoryConfiguration config) { + this.repository = requireNonNull(repository); + this.config = requireNonNull(config); } @Override - public ListenableFuture createSchemaContext(final Collection requiredSources) { + public @NonNull ListenableFuture createEffectiveModelContext( + final @NonNull Collection requiredSources) { return createSchemaContext(requiredSources, config.getStatementParserMode() == StatementParserMode.SEMVER_MODE ? semVerCache : revisionCache, - new AssembleSources(config)); + new AssembleSources(repository.factory(), config)); } - private ListenableFuture createSchemaContext(final Collection requiredSources, - final Cache, SchemaContext> cache, - final AsyncFunction, SchemaContext> assembleSources) { + private @NonNull ListenableFuture createSchemaContext( + final Collection requiredSources, + final Cache, EffectiveModelContext> cache, + final AsyncFunction, EffectiveModelContext> assembleSources) { // Make sources unique final List uniqueSourceIdentifiers = deDuplicateSources(requiredSources); - final SchemaContext existing = cache.getIfPresent(uniqueSourceIdentifiers); + final EffectiveModelContext existing = cache.getIfPresent(uniqueSourceIdentifiers); if (existing != null) { LOG.debug("Returning cached context {}", existing); - return Futures.immediateFuture(existing); + return immediateFluentFuture(existing); } // Request all sources be loaded - ListenableFuture> sf = Futures.allAsList(Collections2.transform(uniqueSourceIdentifiers, + ListenableFuture> sf = Futures.allAsList(Collections2.transform(uniqueSourceIdentifiers, this::requestSource)); // Detect mismatch between requested Source IDs and IDs that are extracted from parsed source @@ -112,27 +101,38 @@ final class SharedSchemaContextFactory implements SchemaContextFactory { MoreExecutors.directExecutor()); // Assemble sources into a schema context - final ListenableFuture cf = Futures.transformAsync(sf, assembleSources, + final ListenableFuture cf = Futures.transformAsync(sf, assembleSources, MoreExecutors.directExecutor()); - // Populate cache when successful - Futures.addCallback(cf, new FutureCallback() { + final SettableFuture rf = SettableFuture.create(); + Futures.addCallback(cf, new FutureCallback() { @Override - public void onSuccess(final SchemaContext result) { - cache.put(uniqueSourceIdentifiers, result); + public void onSuccess(final EffectiveModelContext result) { + // Deduplicate concurrent loads + final EffectiveModelContext existing; + try { + existing = cache.get(uniqueSourceIdentifiers, () -> result); + } catch (ExecutionException e) { + LOG.warn("Failed to recheck result with cache, will use computed value", e); + rf.set(result); + return; + } + + rf.set(existing); } @Override - public void onFailure(@Nonnull final Throwable cause) { + public void onFailure(final Throwable cause) { LOG.debug("Failed to assemble sources", cause); + rf.setException(cause); } }, MoreExecutors.directExecutor()); - return cf; + return rf; } - private ListenableFuture requestSource(final SourceIdentifier identifier) { - return repository.getSchemaSource(identifier, ASTSchemaSource.class); + private ListenableFuture requestSource(final @NonNull SourceIdentifier identifier) { + return repository.getSchemaSource(identifier, IRSchemaSource.class); } /** @@ -152,23 +152,24 @@ final class SharedSchemaContextFactory implements SchemaContextFactory { return ImmutableList.copyOf(uniqueSourceIdentifiers); } - private static final class SourceIdMismatchDetector implements Function, - List> { + @SuppressModernizer + private static final class SourceIdMismatchDetector implements Function, + List> { private final List sourceIdentifiers; SourceIdMismatchDetector(final List sourceIdentifiers) { - this.sourceIdentifiers = Preconditions.checkNotNull(sourceIdentifiers); + this.sourceIdentifiers = requireNonNull(sourceIdentifiers); } @Override - public List apply(final List input) { - final Map filtered = new LinkedHashMap<>(); + 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(); + final IRSchemaSource irSchemaSource = input.get(i); + final SourceIdentifier realSId = irSchemaSource.getIdentifier(); if (!expectedSId.equals(realSId)) { LOG.warn("Source identifier mismatch for module \"{}\", requested as {} but actually is {}. " @@ -179,35 +180,37 @@ final class SharedSchemaContextFactory implements SchemaContextFactory { LOG.warn("Duplicate source for module {} detected in reactor", realSId); } - filtered.put(realSId, astSchemaSource); + filtered.put(realSId, irSchemaSource); } return ImmutableList.copyOf(filtered.values()); } } - private static final class AssembleSources implements AsyncFunction, SchemaContext> { + private static final class AssembleSources implements AsyncFunction, EffectiveModelContext> { + private final @NonNull YangParserFactory parserFactory; + private final @NonNull SchemaContextFactoryConfiguration config; + private final @NonNull Function getIdentifier; - private final SchemaContextFactoryConfiguration config; - private final Function getIdentifier; - - private AssembleSources(@Nonnull final SchemaContextFactoryConfiguration config) { + private AssembleSources(final @NonNull YangParserFactory parserFactory, + final @NonNull SchemaContextFactoryConfiguration config) { + this.parserFactory = parserFactory; this.config = config; switch (config.getStatementParserMode()) { case SEMVER_MODE: - this.getIdentifier = ASTSchemaSource::getSemVerIdentifier; + this.getIdentifier = AssembleSources::getSemVerIdentifier; break; default: - this.getIdentifier = ASTSchemaSource::getIdentifier; + this.getIdentifier = IRSchemaSource::getIdentifier; } } @Override - public ListenableFuture apply(@Nonnull final List sources) + public FluentFuture apply(final List sources) throws SchemaResolutionException, ReactorException { - final Map srcs = Maps.uniqueIndex(sources, getIdentifier); + final Map srcs = Maps.uniqueIndex(sources, getIdentifier); final Map deps = - Maps.transformValues(srcs, ASTSchemaSource::getDependencyInformation); + Maps.transformValues(srcs, YangModelDependencyInfo::forIR); LOG.debug("Resolving dependency reactor {}", deps); @@ -221,28 +224,36 @@ final class SharedSchemaContextFactory implements SchemaContextFactory { res.getResolvedSources(), res.getUnsatisfiedImports()); } - final BuildAction reactor = DefaultReactors.defaultReactor().newBuild(statementParserMode); - config.getSupportedFeatures().ifPresent(reactor::setSupportedFeatures); - config.getModulesDeviatedByModules().ifPresent(reactor::setModulesWithSupportedDeviations); - - for (final Entry e : srcs.entrySet()) { - final ASTSchemaSource ast = e.getValue(); - final ParserRuleContext parserRuleCtx = ast.getAST(); - Preconditions.checkArgument(parserRuleCtx instanceof StatementContext, - "Unsupported context class %s for source %s", parserRuleCtx.getClass(), e.getKey()); + final YangParser parser = parserFactory.createParser(statementParserMode); + config.getSupportedFeatures().ifPresent(parser::setSupportedFeatures); + config.getModulesDeviatedByModules().ifPresent(parser::setModulesWithSupportedDeviations); - reactor.addSource(YangStatementStreamSource.create(e.getKey(), (StatementContext) parserRuleCtx, - ast.getSymbolicName().orElse(null))); + for (final Entry entry : srcs.entrySet()) { + try { + parser.addSource(entry.getValue()); + } catch (YangSyntaxErrorException | IOException e) { + throw new SchemaResolutionException("Failed to add source " + entry.getKey(), e); + } } - final SchemaContext schemaContext; + final EffectiveModelContext schemaContext; try { - schemaContext = reactor.buildEffective(); - } catch (final ReactorException ex) { - throw new SchemaResolutionException("Failed to resolve required models", ex.getSourceIdentifier(), ex); + schemaContext = parser.buildEffectiveModel(); + } catch (final YangParserException e) { + throw new SchemaResolutionException("Failed to resolve required models", e); + } + + return immediateFluentFuture(schemaContext); + } + + private static SemVerSourceIdentifier getSemVerIdentifier(final IRSchemaSource source) { + final SourceIdentifier identifier = source.getIdentifier(); + final SemVer semver = YangModelDependencyInfo.findSemanticVersion(source.getRootStatement(), identifier); + if (identifier instanceof SemVerSourceIdentifier && semver == null) { + return (SemVerSourceIdentifier) identifier; } - return Futures.immediateFuture(schemaContext); + return SemVerSourceIdentifier.create(identifier.getName(), identifier.getRevision(), semver); } } }