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%2FYangTextSchemaContextResolver.java;h=6cdcaac81c57ef724385921f9845e798714468fa;hb=bf702d417b0dec12e8a9a23aa700ddb7c8b0defb;hp=9b5fb1ee916cbd0f9576a58c4c3b81a283084c6b;hpb=e420e37d6545f45c94c1cffbd5e261cad1cb3ead;p=yangtools.git diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/YangTextSchemaContextResolver.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/YangTextSchemaContextResolver.java index 9b5fb1ee91..6cdcaac81c 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/YangTextSchemaContextResolver.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/YangTextSchemaContextResolver.java @@ -8,32 +8,40 @@ package org.opendaylight.yangtools.yang.parser.repo; import static com.google.common.base.Preconditions.checkArgument; -import com.google.common.base.MoreObjects.ToStringHelper; -import com.google.common.base.Optional; -import com.google.common.base.Preconditions; +import static java.util.Objects.requireNonNull; +import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFailedFluentFuture; +import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFluentFuture; + +import com.google.common.annotations.Beta; +import com.google.common.base.Verify; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Multimap; -import com.google.common.util.concurrent.CheckedFuture; -import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.FluentFuture; +import com.google.common.util.concurrent.ListenableFuture; import java.io.IOException; -import java.io.InputStream; import java.net.URL; import java.util.Collection; +import java.util.Optional; import java.util.Set; import java.util.concurrent.ConcurrentLinkedDeque; +import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; -import javax.annotation.Nonnull; -import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.eclipse.jdt.annotation.NonNull; +import org.opendaylight.yangtools.yang.common.Revision; +import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext; +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.MissingSchemaSourceException; -import org.opendaylight.yangtools.yang.model.repo.api.SchemaContextFactory; +import org.opendaylight.yangtools.yang.model.repo.api.RevisionSourceIdentifier; +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.SchemaSourceException; -import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceFilter; import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier; +import org.opendaylight.yangtools.yang.model.repo.api.StatementParserMode; import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource; import org.opendaylight.yangtools.yang.model.repo.spi.PotentialSchemaSource; import org.opendaylight.yangtools.yang.model.repo.spi.PotentialSchemaSource.Costs; @@ -42,8 +50,8 @@ import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceProvider; import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistration; import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistry; import org.opendaylight.yangtools.yang.model.repo.util.InMemorySchemaSourceCache; -import org.opendaylight.yangtools.yang.parser.util.ASTSchemaSource; -import org.opendaylight.yangtools.yang.parser.util.TextToASTTransformer; +import org.opendaylight.yangtools.yang.parser.rfc7950.ir.IRSchemaSource; +import org.opendaylight.yangtools.yang.parser.rfc7950.repo.TextToIRTransformer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -53,9 +61,9 @@ public final class YangTextSchemaContextResolver implements AutoCloseable, Schem private final Collection requiredSources = new ConcurrentLinkedDeque<>(); private final Multimap texts = ArrayListMultimap.create(); - private final AtomicReference> currentSchemaContext = - new AtomicReference<>(Optional.absent()); - private final InMemorySchemaSourceCache cache; + private final AtomicReference> currentSchemaContext = + new AtomicReference<>(Optional.empty()); + private final InMemorySchemaSourceCache cache; private final SchemaListenerRegistration transReg; private final SchemaSourceRegistry registry; private final SchemaRepository repository; @@ -63,35 +71,40 @@ public final class YangTextSchemaContextResolver implements AutoCloseable, Schem private volatile Object contextVersion = version; private YangTextSchemaContextResolver(final SchemaRepository repository, final SchemaSourceRegistry registry) { - this.repository = Preconditions.checkNotNull(repository); - this.registry = Preconditions.checkNotNull(registry); + this.repository = requireNonNull(repository); + this.registry = requireNonNull(registry); - final TextToASTTransformer t = TextToASTTransformer.create(repository, registry); + final TextToIRTransformer t = TextToIRTransformer.create(repository, registry); transReg = registry.registerSchemaSourceListener(t); - cache = InMemorySchemaSourceCache.createSoftCache(registry, ASTSchemaSource.class, SOURCE_LIFETIME_SECONDS, + cache = InMemorySchemaSourceCache.createSoftCache(registry, IRSchemaSource.class, SOURCE_LIFETIME_SECONDS, TimeUnit.SECONDS); } - public static YangTextSchemaContextResolver create(final String name) { + public static @NonNull YangTextSchemaContextResolver create(final String name) { final SharedSchemaRepository sharedRepo = new SharedSchemaRepository(name); return new YangTextSchemaContextResolver(sharedRepo, sharedRepo); } + public static @NonNull YangTextSchemaContextResolver create(final String name, final YangParserFactory factory) { + final SharedSchemaRepository sharedRepo = new SharedSchemaRepository(name, factory); + return new YangTextSchemaContextResolver(sharedRepo, sharedRepo); + } + /** * Register a {@link YangTextSchemaSource}. * * @param source YANG text source + * @return a YangTextSchemaSourceRegistration * @throws YangSyntaxErrorException When the YANG file is syntactically invalid * @throws IOException when the URL is not readable * @throws SchemaSourceException When parsing encounters general error - * @return a YangTextSchemaSourceRegistration */ - public YangTextSchemaSourceRegistration registerSource(@Nonnull final YangTextSchemaSource source) + public @NonNull YangTextSchemaSourceRegistration registerSource(final @NonNull YangTextSchemaSource source) throws SchemaSourceException, IOException, YangSyntaxErrorException { checkArgument(source != null); - final ASTSchemaSource ast = TextToASTTransformer.TRANSFORMATION.apply(source).checkedGet(); + final IRSchemaSource ast = TextToIRTransformer.transformText(source); LOG.trace("Resolved source {} to source {}", source, ast); // AST carries an accurate identifier, check if it matches the one supplied by the source. If it @@ -101,12 +114,12 @@ public final class YangTextSchemaContextResolver implements AutoCloseable, Schem final YangTextSchemaSource text; if (!parsedId.equals(providedId)) { if (!parsedId.getName().equals(providedId.getName())) { - LOG.info("Provided module name {} does not match actual text {}, corrected", providedId.toYangFilename(), - parsedId.toYangFilename()); + LOG.info("Provided module name {} does not match actual text {}, corrected", + providedId.toYangFilename(), parsedId.toYangFilename()); } else { - final String sourceRev = providedId.getRevision(); - final String astRev = parsedId.getRevision(); - if (sourceRev != null) { + final Optional sourceRev = providedId.getRevision(); + final Optional astRev = parsedId.getRevision(); + if (sourceRev.isPresent()) { if (!sourceRev.equals(astRev)) { LOG.info("Provided module revision {} does not match actual text {}, corrected", providedId.toYangFilename(), parsedId.toYangFilename()); @@ -151,37 +164,52 @@ public final class YangTextSchemaContextResolver implements AutoCloseable, Schem * Register a URL containing a YANG text. * * @param url YANG text source URL + * @return a YangTextSchemaSourceRegistration for this URL * @throws YangSyntaxErrorException When the YANG file is syntactically invalid * @throws IOException when the URL is not readable * @throws SchemaSourceException When parsing encounters general error - * @return a YangTextSchemaSourceRegistration for this URL */ - public YangTextSchemaSourceRegistration registerSource(@Nonnull final URL url) throws SchemaSourceException, IOException, YangSyntaxErrorException { + public @NonNull YangTextSchemaSourceRegistration registerSource(final @NonNull URL url) + throws SchemaSourceException, IOException, YangSyntaxErrorException { checkArgument(url != null, "Supplied URL must not be null"); - final SourceIdentifier guessedId = new SourceIdentifier(url.getFile(), Optional.absent()); - return registerSource(new YangTextSchemaSource(guessedId) { - @Override - public InputStream openStream() throws IOException { - return url.openStream(); - } + final String path = url.getPath(); + final String fileName = path.substring(path.lastIndexOf('/') + 1); + return registerSource(YangTextSchemaSource.forURL(url, guessSourceIdentifier(fileName))); + } - @Override - protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) { - return toStringHelper.add("url", url); - } - }); + private static SourceIdentifier guessSourceIdentifier(final @NonNull String fileName) { + try { + return YangTextSchemaSource.identifierFromFilename(fileName); + } catch (final IllegalArgumentException e) { + LOG.warn("Invalid file name format in '{}'", fileName, e); + return RevisionSourceIdentifier.create(fileName); + } } /** * Try to parse all currently available yang files and build new schema context. + * * @return new schema context iif there is at least 1 yang file registered and * new schema context was successfully built. */ - public Optional getSchemaContext() { - final SchemaContextFactory factory = repository.createSchemaContextFactory(SchemaSourceFilter.ALWAYS_ACCEPT); - Optional sc; - Object v; + public Optional getEffectiveModelContext() { + return getEffectiveModelContext(StatementParserMode.DEFAULT_MODE); + } + + /** + * Try to parse all currently available yang files and build new schema context depending on specified parsing mode. + * + * @param statementParserMode mode of statement parser + * @return new schema context iif there is at least 1 yang file registered and + * new schema context was successfully built. + */ + public Optional getEffectiveModelContext( + final StatementParserMode statementParserMode) { + final EffectiveModelContextFactory factory = repository.createEffectiveModelContextFactory( + config(statementParserMode)); + Optional sc; + Object ver; do { // Spin get stable context version Object cv; @@ -196,18 +224,22 @@ public final class YangTextSchemaContextResolver implements AutoCloseable, Schem // Version has been updated Collection sources; do { - v = version; + ver = version; sources = ImmutableSet.copyOf(requiredSources); - } while (v != version); + } while (ver != version); while (true) { - final CheckedFuture f = factory.createSchemaContext(sources); + final ListenableFuture f = factory.createEffectiveModelContext(sources); try { - sc = Optional.of(f.checkedGet()); + sc = Optional.of(f.get()); break; - } catch (SchemaResolutionException e) { + } catch (final InterruptedException e) { + throw new IllegalStateException("Interrupted while assembling schema context", e); + } catch (final ExecutionException e) { LOG.info("Failed to fully assemble schema context for {}", sources, e); - sources = e.getResolvedSources(); + final Throwable cause = e.getCause(); + Verify.verify(cause instanceof SchemaResolutionException); + sources = ((SchemaResolutionException) cause).getResolvedSources(); } } @@ -216,25 +248,26 @@ public final class YangTextSchemaContextResolver implements AutoCloseable, Schem synchronized (this) { if (contextVersion == cv) { currentSchemaContext.set(sc); - contextVersion = v; + contextVersion = ver; } } - } while (version == v); + } while (version == ver); return sc; } @Override - public synchronized CheckedFuture getSource(final SourceIdentifier sourceIdentifier) { + public synchronized @NonNull FluentFuture getSource( + final SourceIdentifier sourceIdentifier) { final Collection ret = texts.get(sourceIdentifier); LOG.debug("Lookup {} result {}", sourceIdentifier, ret); if (ret.isEmpty()) { - return Futures.immediateFailedCheckedFuture( - new MissingSchemaSourceException("URL for " + sourceIdentifier + " not registered", sourceIdentifier)); + return immediateFailedFluentFuture(new MissingSchemaSourceException("URL for " + sourceIdentifier + + " not registered", sourceIdentifier)); } - return Futures.immediateCheckedFuture(ret.iterator().next()); + return immediateFluentFuture(ret.iterator().next()); } /** @@ -246,8 +279,44 @@ public final class YangTextSchemaContextResolver implements AutoCloseable, Schem return ImmutableSet.copyOf(texts.keySet()); } + @Beta + public synchronized Collection getSourceTexts(final SourceIdentifier sourceIdentifier) { + return ImmutableSet.copyOf(texts.get(sourceIdentifier)); + } + + @Beta + public EffectiveModelContext trySchemaContext() throws SchemaResolutionException { + return trySchemaContext(StatementParserMode.DEFAULT_MODE); + } + + @Beta + @SuppressWarnings("checkstyle:avoidHidingCauseException") + public EffectiveModelContext trySchemaContext(final StatementParserMode statementParserMode) + throws SchemaResolutionException { + final ListenableFuture future = repository + .createEffectiveModelContextFactory(config(statementParserMode)) + .createEffectiveModelContext(ImmutableSet.copyOf(requiredSources)); + + try { + return future.get(); + } catch (final InterruptedException e) { + throw new IllegalStateException("Interrupted while waiting for SchemaContext assembly", e); + } catch (final ExecutionException e) { + final Throwable cause = e.getCause(); + if (cause instanceof SchemaResolutionException) { + throw (SchemaResolutionException) cause; + } + + throw new SchemaResolutionException("Failed to assemble SchemaContext", e); + } + } + @Override public void close() { transReg.close(); } + + private static SchemaContextFactoryConfiguration config(final StatementParserMode statementParserMode) { + return SchemaContextFactoryConfiguration.builder().setStatementParserMode(statementParserMode).build(); + } }