Inject YangParserFactory into SharedSchemaRepository 01/88001/2
authorRobert Varga <robert.varga@pantheon.tech>
Sat, 22 Feb 2020 08:21:14 +0000 (09:21 +0100)
committerRobert Varga <robert.varga@pantheon.tech>
Sat, 22 Feb 2020 10:03:24 +0000 (11:03 +0100)
Attempting to access defaultReactor() in OSGi environment trips up
the inability to load XPath parser -- as that only works in single
classloader. Force users to add parser reference, so that we can
go through the proper API.

JIRA: YANGTOOLS-1085
Change-Id: I9c1632f07c782234fd00b6f12a9a497d514557cf
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/SharedSchemaContextFactory.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/SharedSchemaRepository.java
yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/parser/repo/SchemaContextFactoryDeviationsTest.java

index 396bd754b65b1e5206c149e9be27e328780bef57..b5ee5fd53e8180befef594c9a3897ab4826270d2 100644 (file)
@@ -25,6 +25,7 @@ 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;
@@ -37,19 +38,19 @@ import org.antlr.v4.runtime.ParserRuleContext;
 import org.eclipse.jdt.annotation.NonNull;
 import org.gaul.modernizer_maven_annotations.SuppressModernizer;
 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.SourceIdentifier;
 import org.opendaylight.yangtools.yang.model.repo.api.StatementParserMode;
 import org.opendaylight.yangtools.yang.parser.antlr.YangStatementParser.StatementContext;
-import org.opendaylight.yangtools.yang.parser.impl.DefaultReactors;
 import org.opendaylight.yangtools.yang.parser.rfc7950.repo.ASTSchemaSource;
 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;
 
@@ -60,11 +61,11 @@ final class SharedSchemaContextFactory implements EffectiveModelContextFactory {
             .weakValues().build();
     private final Cache<Collection<SourceIdentifier>, EffectiveModelContext> semVerCache = CacheBuilder.newBuilder()
             .weakValues().build();
-    private final @NonNull SchemaRepository repository;
+    private final @NonNull SharedSchemaRepository repository;
     private final @NonNull SchemaContextFactoryConfiguration config;
 
-    SharedSchemaContextFactory(final @NonNull SchemaRepository repository,
-        final @NonNull SchemaContextFactoryConfiguration config) {
+    SharedSchemaContextFactory(final @NonNull SharedSchemaRepository repository,
+            final @NonNull SchemaContextFactoryConfiguration config) {
         this.repository = requireNonNull(repository);
         this.config = requireNonNull(config);
     }
@@ -74,7 +75,7 @@ final class SharedSchemaContextFactory implements EffectiveModelContextFactory {
             final @NonNull Collection<SourceIdentifier> requiredSources) {
         return createSchemaContext(requiredSources,
                 config.getStatementParserMode() == StatementParserMode.SEMVER_MODE ? semVerCache : revisionCache,
-                new AssembleSources(config));
+                new AssembleSources(repository.factory(), config));
     }
 
     private @NonNull ListenableFuture<EffectiveModelContext> createSchemaContext(
@@ -188,10 +189,13 @@ final class SharedSchemaContextFactory implements EffectiveModelContextFactory {
     }
 
     private static final class AssembleSources implements AsyncFunction<List<ASTSchemaSource>, EffectiveModelContext> {
+        private final @NonNull YangParserFactory parserFactory;
         private final @NonNull SchemaContextFactoryConfiguration config;
         private final @NonNull Function<ASTSchemaSource, SourceIdentifier> getIdentifier;
 
-        private AssembleSources(final @NonNull SchemaContextFactoryConfiguration config) {
+        private AssembleSources(final @NonNull YangParserFactory parserFactory,
+                final @NonNull SchemaContextFactoryConfiguration config) {
+            this.parserFactory = parserFactory;
             this.config = config;
             switch (config.getStatementParserMode()) {
                 case SEMVER_MODE:
@@ -221,25 +225,28 @@ final class SharedSchemaContextFactory implements EffectiveModelContextFactory {
                         res.getResolvedSources(), res.getUnsatisfiedImports());
             }
 
-            final BuildAction reactor = DefaultReactors.defaultReactor().newBuild(statementParserMode);
-            config.getSupportedFeatures().ifPresent(reactor::setSupportedFeatures);
-            config.getModulesDeviatedByModules().ifPresent(reactor::setModulesWithSupportedDeviations);
+            final YangParser parser = parserFactory.createParser(statementParserMode);
+            config.getSupportedFeatures().ifPresent(parser::setSupportedFeatures);
+            config.getModulesDeviatedByModules().ifPresent(parser::setModulesWithSupportedDeviations);
 
-            for (final Entry<SourceIdentifier, ASTSchemaSource> e : srcs.entrySet()) {
-                final ASTSchemaSource ast = e.getValue();
+            for (final Entry<SourceIdentifier, ASTSchemaSource> entry : srcs.entrySet()) {
+                final ASTSchemaSource ast = entry.getValue();
                 final ParserRuleContext parserRuleCtx = ast.getAST();
                 checkArgument(parserRuleCtx instanceof StatementContext, "Unsupported context class %s for source %s",
-                    parserRuleCtx.getClass(), e.getKey());
+                    parserRuleCtx.getClass(), entry.getKey());
 
-                reactor.addSource(YangStatementStreamSource.create(e.getKey(), (StatementContext) parserRuleCtx,
-                    ast.getSymbolicName().orElse(null)));
+                try {
+                    parser.addSource(entry.getValue());
+                } catch (YangSyntaxErrorException | IOException e) {
+                    throw new SchemaResolutionException("Failed to add source " + entry.getKey(), e);
+                }
             }
 
             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);
index b25cbeed8890c95b373069eb9de154ccab330c79..de2d89d1b5eff525a8c7e0ed375ddea53da7c5fe 100644 (file)
@@ -17,11 +17,13 @@ import org.eclipse.jdt.annotation.NonNull;
 import org.kohsuke.MetaInfServices;
 import org.opendaylight.yangtools.concepts.Identifiable;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.parser.api.YangParserFactory;
 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.SourceIdentifier;
 import org.opendaylight.yangtools.yang.model.repo.util.AbstractSchemaRepository;
+import org.opendaylight.yangtools.yang.parser.impl.YangParserFactoryImpl;
 
 /**
  * A {@link SchemaRepository} which allows sharing of {@link SchemaContext} as long as their specification is the same.
@@ -42,9 +44,19 @@ public final class SharedSchemaRepository extends AbstractSchemaRepository imple
             });
 
     private final @NonNull String id;
+    private final @NonNull YangParserFactory factory;
+
+    public SharedSchemaRepository() {
+        this("unnamed");
+    }
 
     public SharedSchemaRepository(final String id) {
+        this(id, new YangParserFactoryImpl());
+    }
+
+    public SharedSchemaRepository(final String id, final YangParserFactory factory) {
         this.id = requireNonNull(id);
+        this.factory = requireNonNull(factory);
     }
 
     @Override
@@ -58,6 +70,10 @@ public final class SharedSchemaRepository extends AbstractSchemaRepository imple
         return cacheByConfig.getUnchecked(config);
     }
 
+    @NonNull YangParserFactory factory() {
+        return factory;
+    }
+
     @Override
     public String toString() {
         return "SchemaRepository: " + id;
index 36ed59ae91a9cb758f1fcf5830b6e901e3552850..be8ca50946e1e69aac340398f75eb19c2400d01c 100644 (file)
@@ -7,11 +7,15 @@
  */
 package org.opendaylight.yangtools.yang.parser.repo;
 
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.CoreMatchers.startsWith;
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
 
+import com.google.common.base.Throwables;
 import com.google.common.collect.ImmutableSetMultimap;
 import com.google.common.collect.SetMultimap;
 import com.google.common.util.concurrent.ListenableFuture;
@@ -109,15 +113,12 @@ public class SchemaContextFactoryDeviationsTest {
     public void shouldFailOnAttemptToDeviateTheSameModule2() throws Exception {
         final ListenableFuture<EffectiveModelContext> lf = createSchemaContext(null, BAR_INVALID, BAZ_INVALID);
         assertTrue(lf.isDone());
-        try {
-            lf.get();
-            fail("Deviation that targets the same module as the one it is defined is forbidden.");
-        } catch (final ExecutionException ex) {
-            final Throwable cause = ex.getCause().getCause().getCause();
-            assertTrue(cause instanceof InferenceException);
-            assertTrue(cause.getMessage()
-                    .startsWith("Deviation must not target the same module as the one it is defined in"));
-        }
+
+        final ExecutionException ex = assertThrows(ExecutionException.class, lf::get);
+        final Throwable cause = Throwables.getRootCause(ex);
+        assertThat(cause, instanceOf(InferenceException.class));
+        assertThat(cause.getMessage(),
+            startsWith("Deviation must not target the same module as the one it is defined in"));
     }
 
     private static SettableSchemaProvider<ASTSchemaSource> getImmediateYangSourceProviderFromResource(