From 6ca20588f7c4f5763fbe5ef97625a9aa017260ea Mon Sep 17 00:00:00 2001 From: Robert Varga Date: Wed, 8 Nov 2017 14:36:20 +0100 Subject: [PATCH] Populate yang-parser-api This adds a simpistic API to access a pre-configured YANG inference engine, so its complexities are hidden from users. Both a ServiceLoader and OSGi loading interface is provided. Change-Id: Iab444bd1698273c30ac37b8d3ea577ae35db71e7 Signed-off-by: Robert Varga --- .../yang/validator/SystemTestUtils.java | 65 ++++---- .../yang/model/parser/api/YangParser.java | 150 ++++++++++++++++++ .../model/parser/api/YangParserException.java | 31 ++++ .../model/parser/api/YangParserFactory.java | 46 ++++++ .../parser/api/YangSyntaxErrorException.java | 6 +- yang/yang-parser-impl/pom.xml | 24 +-- .../yang/parser/impl/DefaultReactors.java | 14 +- .../parser/impl/YangParserFactoryImpl.java | 62 ++++++++ .../yang/parser/impl/YangParserImpl.java | 134 ++++++++++++++++ .../yang/parser/impl/osgi/Activator.java | 37 +++++ .../yang/parser/impl/osgi/package-info.java | 11 ++ .../parser/repo/SharedSchemaRepository.java | 2 + ...tools.yang.model.repo.api.SchemaRepository | 1 - ...tomCrossSourceStatementReactorBuilder.java | 3 +- .../yang/test/util/YangParserTestUtils.java | 130 ++++----------- 15 files changed, 566 insertions(+), 150 deletions(-) create mode 100644 yang/yang-parser-api/src/main/java/org/opendaylight/yangtools/yang/model/parser/api/YangParser.java create mode 100644 yang/yang-parser-api/src/main/java/org/opendaylight/yangtools/yang/model/parser/api/YangParserException.java create mode 100644 yang/yang-parser-api/src/main/java/org/opendaylight/yangtools/yang/model/parser/api/YangParserFactory.java create mode 100644 yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangParserFactoryImpl.java create mode 100644 yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangParserImpl.java create mode 100644 yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/osgi/Activator.java create mode 100644 yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/osgi/package-info.java delete mode 100644 yang/yang-parser-impl/src/main/resources/META-INF/services/org.opendaylight.yangtools.yang.model.repo.api.SchemaRepository diff --git a/yang/yang-model-validator/src/main/java/org/opendaylight/yangtools/yang/validator/SystemTestUtils.java b/yang/yang-model-validator/src/main/java/org/opendaylight/yangtools/yang/validator/SystemTestUtils.java index e4eba0bdf4..b0280fad76 100644 --- a/yang/yang-model-validator/src/main/java/org/opendaylight/yangtools/yang/validator/SystemTestUtils.java +++ b/yang/yang-model-validator/src/main/java/org/opendaylight/yangtools/yang/validator/SystemTestUtils.java @@ -19,25 +19,34 @@ import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Iterator; import java.util.List; +import java.util.ServiceLoader; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.eclipse.jdt.annotation.NonNull; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.common.YangConstants; import org.opendaylight.yangtools.yang.model.api.SchemaContext; -import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException; +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.repo.api.YangTextSchemaSource; -import org.opendaylight.yangtools.yang.parser.impl.DefaultReactors; -import org.opendaylight.yangtools.yang.parser.rfc7950.repo.YangStatementStreamSource; -import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException; -import org.opendaylight.yangtools.yang.parser.spi.source.StatementStreamSource; -import org.opendaylight.yangtools.yang.parser.stmt.reactor.CrossSourceStatementReactor.BuildAction; final class SystemTestUtils { private static final Pattern MODULE_PATTERN = Pattern.compile("module(.*?)\\{"); private static final Pattern WHITESPACES = Pattern.compile("\\s+"); + private static final @NonNull YangParserFactory PARSER_FACTORY; + + static { + final Iterator<@NonNull YangParserFactory> it = ServiceLoader.load(YangParserFactory.class).iterator(); + if (!it.hasNext()) { + throw new IllegalStateException("No YangParserFactory found"); + } + PARSER_FACTORY = it.next(); + } private SystemTestUtils() { throw new UnsupportedOperationException(); @@ -49,8 +58,7 @@ final class SystemTestUtils { }; static SchemaContext parseYangSources(final List yangLibDirs, final List yangTestFiles, - final Set supportedFeatures, final boolean recursiveSearch) - throws ReactorException, IOException, YangSyntaxErrorException { + final Set supportedFeatures, final boolean recursiveSearch) throws IOException, YangParserException { /* * Current dir "." should be always present implicitly in the list of * directories where dependencies are searched for @@ -77,24 +85,22 @@ final class SystemTestUtils { } static SchemaContext parseYangSources(final Set supportedFeatures, final List testFiles, - final List libFiles) throws ReactorException, IOException, YangSyntaxErrorException { - final List testSources = getYangStatementSources(testFiles); - final List libSources = getYangStatementSources(libFiles); - return parseYangSources(testSources, libSources, supportedFeatures); - } - - static SchemaContext parseYangSources(final List testSources, - final List libSources, final Set supportedFeatures) throws ReactorException { - Preconditions.checkArgument(testSources != null && !testSources.isEmpty(), "No yang sources"); - - final BuildAction reactor = DefaultReactors.defaultReactor().newBuild() - .addLibSources(libSources).addSources(testSources); + final List libFiles) throws IOException, YangParserException { + Preconditions.checkArgument(!testFiles.isEmpty(), "No yang sources"); + final YangParser parser = PARSER_FACTORY.createParser(); if (supportedFeatures != null) { - reactor.setSupportedFeatures(supportedFeatures); + parser.setSupportedFeatures(supportedFeatures); } - return reactor.buildEffective(); + for (File file : testFiles) { + parser.addSource(YangTextSchemaSource.forFile(file)); + } + for (File file : libFiles) { + parser.addLibSource(YangTextSchemaSource.forFile(file)); + } + + return parser.buildSchemaContext(); } private static File findInFiles(final List libFiles, final String yangTestFile) throws IOException { @@ -109,26 +115,13 @@ final class SystemTestUtils { private static String getModelNameFromFile(final File file) throws IOException { final String fileAsString = readFile(file.getAbsolutePath()); final Matcher matcher = MODULE_PATTERN.matcher(fileAsString); - if (matcher.find()) { - return matcher.group(1); - } else { - return ""; - } + return matcher.find() ? matcher.group(1) : ""; } private static String readFile(final String path) throws IOException { return new String(Files.readAllBytes(Paths.get(path)), StandardCharsets.UTF_8); } - private static List getYangStatementSources(final List yangFiles) - throws IOException, YangSyntaxErrorException { - final List yangSources = new ArrayList<>(yangFiles.size()); - for (final File file : yangFiles) { - yangSources.add(YangStatementStreamSource.create(YangTextSchemaSource.forFile(file))); - } - return yangSources; - } - private static Collection getYangFiles(final String yangSourcesDirectoryPath, final boolean recursiveSearch) throws FileNotFoundException { final File testSourcesDir = new File(yangSourcesDirectoryPath); diff --git a/yang/yang-parser-api/src/main/java/org/opendaylight/yangtools/yang/model/parser/api/YangParser.java b/yang/yang-parser-api/src/main/java/org/opendaylight/yangtools/yang/model/parser/api/YangParser.java new file mode 100644 index 0000000000..ab287e41b7 --- /dev/null +++ b/yang/yang-parser-api/src/main/java/org/opendaylight/yangtools/yang/model/parser/api/YangParser.java @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2017 Pantheon Technologies, s.r.o. 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/epl-v10.html + */ +package org.opendaylight.yangtools.yang.model.parser.api; + +import com.google.common.annotations.Beta; +import java.io.IOException; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; +import javax.annotation.Nonnull; +import javax.annotation.concurrent.NotThreadSafe; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.QNameModule; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement; +import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceRepresentation; + +/** + * Configurable single-use YANG parser. Each instance can be configured to use a different set of models after + * which it is built. Models once added cannot be removed. + * + * @author Robert Varga + */ +@Beta +@NotThreadSafe +public interface YangParser { + /** + * Return enumeration of concrete types of {@link SchemaSourceRepresentation} parsers created from this factory + * support. Users can use this + * + * @return Enumeration of supported schema source representations. + */ + Collection> supportedSourceRepresentations(); + + /** + * Return the set of all YANG statements semantically supported by this parser instance. + * + * @return Set of all YANG statements semantically supported by this parser instance. + */ + Set supportedStatements(); + + /** + * Add main source. All main sources are present in resulting SchemaContext. + * + * @param source + * which should be added into main sources + * @throws YangSyntaxErrorException when one of the sources fails syntactic analysis + * @throws IOException when an IO error occurs + * @throws IllegalArgumentException if the representation is not supported + */ + YangParser addSource(final SchemaSourceRepresentation source) throws IOException, YangSyntaxErrorException; + + /** + * Add main sources. All main sources are present in resulting SchemaContext. + * + * @param sources + * which should be added into main sources + * @throws YangSyntaxErrorException when one of the sources fails syntactic analysis + * @throws IOException when an IO error occurs + * @throws IllegalArgumentException if the representation is not supported + */ + default YangParser addSources(final SchemaSourceRepresentation... sources) throws IOException, + YangSyntaxErrorException { + for (SchemaSourceRepresentation source : sources) { + addSource(source); + } + return this; + } + + default YangParser addSources(final Collection sources) throws IOException, + YangSyntaxErrorException { + for (SchemaSourceRepresentation source : sources) { + addSource(source); + } + return this; + } + + YangParser addLibSource(SchemaSourceRepresentation source) throws IOException, YangSyntaxErrorException; + + /** + * Add library sources. Only library sources required by main sources are present in resulting SchemaContext. + * Any other library sources are ignored and this also applies to error reporting. + * + *

+ * Note: Library sources are not supported in semantic version mode currently. + * + * @param sources + * YANG sources which should be added into library sources + * @throws YangSyntaxErrorException when one of the sources fails syntactic analysis + * @throws IOException when an IO error occurs + * @throws IllegalArgumentException if the representation is not supported + */ + default YangParser addLibSources(final SchemaSourceRepresentation... sources) throws IOException, + YangSyntaxErrorException { + for (SchemaSourceRepresentation source : sources) { + addLibSource(source); + } + return this; + } + + default YangParser addLibSources(final Collection sources) throws IOException, + YangSyntaxErrorException { + for (SchemaSourceRepresentation source : sources) { + addLibSource(source); + } + return this; + } + + /** + * Set supported features based on which all if-feature statements in the + * parsed YANG modules will be resolved. If this method is not invoked, all features will be supported. + * + * @param supportedFeatures + * Set of supported features in the final SchemaContext. + * If the set is empty, no features encountered will be supported. + */ + YangParser setSupportedFeatures(@Nonnull final Set supportedFeatures); + + /** + * Set YANG modules which can be deviated by specified modules during the parsing process. + * Map key (QNameModule) denotes a module which can be deviated by the modules in the Map value. + * + * @param modulesDeviatedByModules + * Map of YANG modules (Map key) which can be deviated by specified modules (Map value) in the final + * SchemaContext. If the map is empty, no deviations encountered will be supported. + */ + YangParser setModulesWithSupportedDeviations( + @Nonnull Map> modulesDeviatedByModules); + + /** + * Build the declared view of a combined view of declared statements. + * + * @return Ordered collection of declared statements from requested sources. + */ + List> buildDeclaredModel() throws YangParserException; + + /** + * Build effective {@link SchemaContext} + * + * @return An effective schema context comprised of configured models. + * @throws YangSyntaxErrorException When a syntactic error is encountered. + */ + SchemaContext buildSchemaContext() throws YangParserException; +} diff --git a/yang/yang-parser-api/src/main/java/org/opendaylight/yangtools/yang/model/parser/api/YangParserException.java b/yang/yang-parser-api/src/main/java/org/opendaylight/yangtools/yang/model/parser/api/YangParserException.java new file mode 100644 index 0000000000..96e4793658 --- /dev/null +++ b/yang/yang-parser-api/src/main/java/org/opendaylight/yangtools/yang/model/parser/api/YangParserException.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2017 Pantheon Technologies, s.r.o. 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/epl-v10.html + */ +package org.opendaylight.yangtools.yang.model.parser.api; + +import static java.util.Objects.requireNonNull; + +import com.google.common.annotations.Beta; + +/** + * Base exception reported by {@link YangParser}. This is used as an exception of last resort, semantic reporting + * of individual errors is performed via subclasses, like {@link YangSyntaxErrorException}. + * + * @author Robert Varga + */ +@Beta +public class YangParserException extends Exception { + private static final long serialVersionUID = 1L; + + public YangParserException(final String message) { + super(requireNonNull(message)); + } + + public YangParserException(final String message, final Throwable cause) { + super(requireNonNull(message), cause); + } +} diff --git a/yang/yang-parser-api/src/main/java/org/opendaylight/yangtools/yang/model/parser/api/YangParserFactory.java b/yang/yang-parser-api/src/main/java/org/opendaylight/yangtools/yang/model/parser/api/YangParserFactory.java new file mode 100644 index 0000000000..94c3074008 --- /dev/null +++ b/yang/yang-parser-api/src/main/java/org/opendaylight/yangtools/yang/model/parser/api/YangParserFactory.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2017 Pantheon Technologies, s.r.o. 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/epl-v10.html + */ +package org.opendaylight.yangtools.yang.model.parser.api; + +import com.google.common.annotations.Beta; +import java.util.Collection; +import org.opendaylight.yangtools.yang.model.repo.api.StatementParserMode; + +/** + * Basic entry point into a YANG parser implementation. + * + * @author Robert Varga + */ +@Beta +public interface YangParserFactory { + /** + * Return enumeration of {@link StatementParserMode}s supported by this factory. + * + * @return Enumeration of supported schema source representations. + */ + Collection supportedParserModes(); + + /** + * Create a {@link YangParser} instance operating in default import resolution mode. + * + * @return A new {@link YangParser} instance + */ + default YangParser createParser() { + return createParser(StatementParserMode.DEFAULT_MODE); + } + + /** + * Create a {@link YangParser} instance operating in specified import resolution mode. + * + * @param parserMode Requested parser mode, may not be null. + * @return A new {@link YangParser} instance + * @throws NullPointerException if parser mode is null + * @throws IllegalArgumentException if specified parser mode is not supported + */ + YangParser createParser(StatementParserMode parserMode); +} diff --git a/yang/yang-parser-api/src/main/java/org/opendaylight/yangtools/yang/model/parser/api/YangSyntaxErrorException.java b/yang/yang-parser-api/src/main/java/org/opendaylight/yangtools/yang/model/parser/api/YangSyntaxErrorException.java index c2da1bdbd7..5731e18eb7 100644 --- a/yang/yang-parser-api/src/main/java/org/opendaylight/yangtools/yang/model/parser/api/YangSyntaxErrorException.java +++ b/yang/yang-parser-api/src/main/java/org/opendaylight/yangtools/yang/model/parser/api/YangSyntaxErrorException.java @@ -7,13 +7,11 @@ */ package org.opendaylight.yangtools.yang.model.parser.api; -import static java.util.Objects.requireNonNull; - import java.util.Optional; import javax.annotation.Nullable; import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier; -public class YangSyntaxErrorException extends Exception { +public class YangSyntaxErrorException extends YangParserException { private static final long serialVersionUID = 2L; private final SourceIdentifier source; @@ -27,7 +25,7 @@ public class YangSyntaxErrorException extends Exception { public YangSyntaxErrorException(@Nullable final SourceIdentifier source, final int line, final int charPositionInLine, final String message, @Nullable final Throwable cause) { - super(requireNonNull(message), cause); + super(message, cause); this.source = source; this.line = line; this.charPositionInLine = charPositionInLine; diff --git a/yang/yang-parser-impl/pom.xml b/yang/yang-parser-impl/pom.xml index 260ef3d901..73dd50c0a5 100644 --- a/yang/yang-parser-impl/pom.xml +++ b/yang/yang-parser-impl/pom.xml @@ -37,6 +37,10 @@ + + ${project.groupId} + concepts + ${project.groupId} yang-common @@ -110,6 +114,15 @@ rfc8040-parser-support + + org.kohsuke.metainf-services + metainf-services + + + org.osgi + org.osgi.core + + org.mockito mockito-core @@ -128,10 +141,6 @@ logback-classic test - - ${project.groupId} - concepts - @@ -153,11 +162,8 @@ true - - {local-packages}, - org.opendaylight.yangtools.yang.parser.impl.*, - ;-split-package:=error - + {META-INF/services=${project.build.directory}/classes/META-INF/services} + org.opendaylight.yangtools.yang.parser.impl.osgi.Activator diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/DefaultReactors.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/DefaultReactors.java index 03f56aea98..03fc317681 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/DefaultReactors.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/DefaultReactors.java @@ -8,6 +8,7 @@ package org.opendaylight.yangtools.yang.parser.impl; import com.google.common.annotations.Beta; +import org.eclipse.jdt.annotation.NonNull; import org.opendaylight.yangtools.odlext.parser.AnyxmlSchemaLocationNamespace; import org.opendaylight.yangtools.odlext.parser.AnyxmlSchemaLocationStatementSupport; import org.opendaylight.yangtools.odlext.parser.AnyxmlStatementSupportOverride; @@ -30,7 +31,7 @@ import org.opendaylight.yangtools.yang.parser.stmt.reactor.CrossSourceStatementR */ @Beta public final class DefaultReactors { - private static final CrossSourceStatementReactor DEFAULT_REACTOR = defaultReactorBuilder().build(); + private static final @NonNull CrossSourceStatementReactor DEFAULT_REACTOR = defaultReactorBuilder().build(); private DefaultReactors() { throw new UnsupportedOperationException(); @@ -38,11 +39,18 @@ public final class DefaultReactors { /** * Get a shared default-configured reactor instance. This instance is configured to handle both RFC6020 and RFC7950, - * as well as RFC8040's yang-data extension. + * as well as + *

    + *
  • RFC6536's default-deny-{all,write} extensions
  • + *
  • RFC7952's annotation extension
  • + *
  • RFC8040's yang-data extension
  • + *
  • OpenConfig extensions
  • + *
  • OpenDaylight extensions
  • + *
* * @return a shared default-configured reactor instance. */ - public static CrossSourceStatementReactor defaultReactor() { + public static @NonNull CrossSourceStatementReactor defaultReactor() { return DEFAULT_REACTOR; } diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangParserFactoryImpl.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangParserFactoryImpl.java new file mode 100644 index 0000000000..10872fb1aa --- /dev/null +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangParserFactoryImpl.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2017 Pantheon Technologies, s.r.o. 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/epl-v10.html + */ +package org.opendaylight.yangtools.yang.parser.impl; + +import static java.util.Objects.requireNonNull; + +import com.google.common.annotations.Beta; +import com.google.common.collect.ImmutableList; +import java.util.Collection; +import javax.annotation.concurrent.ThreadSafe; +import org.eclipse.jdt.annotation.NonNull; +import org.kohsuke.MetaInfServices; +import org.opendaylight.yangtools.yang.model.parser.api.YangParser; +import org.opendaylight.yangtools.yang.model.parser.api.YangParserFactory; +import org.opendaylight.yangtools.yang.model.repo.api.StatementParserMode; +import org.opendaylight.yangtools.yang.parser.stmt.reactor.CrossSourceStatementReactor; + +/** + * Reference {@link YangParserFactory} implementation. + * + * @author Robert Varga + */ +@Beta +@ThreadSafe +@MetaInfServices +public final class YangParserFactoryImpl implements YangParserFactory { + private static final Collection SUPPORTED_MODES = ImmutableList.of( + StatementParserMode.DEFAULT_MODE, StatementParserMode.SEMVER_MODE); + + private final CrossSourceStatementReactor reactor; + + /** + * Construct a new {@link YangParserFactory} backed by {@link DefaultReactors#defaultReactor()}. + */ + public YangParserFactoryImpl() { + this(DefaultReactors.defaultReactor()); + } + + /** + * Construct a new {@link YangParserFactory} backed by specified reactor. + * + * @param reactor Backing reactor + */ + public YangParserFactoryImpl(@NonNull final CrossSourceStatementReactor reactor) { + this.reactor = requireNonNull(reactor); + } + + @Override + public Collection supportedParserModes() { + return SUPPORTED_MODES; + } + + @Override + public YangParser createParser(final StatementParserMode parserMode) { + return new YangParserImpl(reactor.newBuild(parserMode)); + } +} diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangParserImpl.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangParserImpl.java new file mode 100644 index 0000000000..17741879d8 --- /dev/null +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangParserImpl.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2017 Pantheon Technologies, s.r.o. 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/epl-v10.html + */ +package org.opendaylight.yangtools.yang.parser.impl; + +import static java.util.Objects.requireNonNull; + +import com.google.common.collect.ImmutableList; +import java.io.IOException; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; +import javax.xml.transform.TransformerException; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.QNameModule; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement; +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.YangSyntaxErrorException; +import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceRepresentation; +import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource; +import org.opendaylight.yangtools.yang.model.repo.api.YinDomSchemaSource; +import org.opendaylight.yangtools.yang.model.repo.api.YinTextSchemaSource; +import org.opendaylight.yangtools.yang.model.repo.api.YinXmlSchemaSource; +import org.opendaylight.yangtools.yang.parser.rfc7950.repo.YangStatementStreamSource; +import org.opendaylight.yangtools.yang.parser.rfc7950.repo.YinStatementStreamSource; +import org.opendaylight.yangtools.yang.parser.rfc7950.repo.YinTextToDomTransformer; +import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException; +import org.opendaylight.yangtools.yang.parser.spi.source.StatementStreamSource; +import org.opendaylight.yangtools.yang.parser.stmt.reactor.CrossSourceStatementReactor.BuildAction; +import org.xml.sax.SAXException; + +final class YangParserImpl implements YangParser { + private static final Collection> REPRESENTATIONS = ImmutableList.of( + YangTextSchemaSource.class, YinDomSchemaSource.class, YinXmlSchemaSource.class, YinTextSchemaSource.class); + + private final BuildAction buildAction; + + YangParserImpl(final BuildAction buildAction) { + this.buildAction = requireNonNull(buildAction); + } + + @Override + public Collection> supportedSourceRepresentations() { + return REPRESENTATIONS; + } + + @Override + public Set supportedStatements() { + // TODO Auto-generated method stub + return null; + } + + @Override + public YangParser addSource(final SchemaSourceRepresentation source) throws IOException, YangSyntaxErrorException { + buildAction.addSources(sourceToStatementStream(source)); + return null; + } + + @Override + public YangParser addLibSource(final SchemaSourceRepresentation source) throws IOException, + YangSyntaxErrorException { + buildAction.addLibSources(sourceToStatementStream(source)); + return null; + } + + @Override + public YangParser setSupportedFeatures(final Set supportedFeatures) { + buildAction.setSupportedFeatures(supportedFeatures); + return this; + } + + @Override + public YangParser setModulesWithSupportedDeviations( + final Map> modulesDeviatedByModules) { + buildAction.setModulesWithSupportedDeviations(modulesDeviatedByModules); + return this; + } + + @Override + public List> buildDeclaredModel() throws YangParserException { + try { + return buildAction.build().getRootStatements(); + } catch (ReactorException e) { + throw decodeReactorException(e); + } + } + + @Override + public SchemaContext buildSchemaContext() throws YangParserException { + try { + return buildAction.buildEffective(); + } catch (ReactorException e) { + throw decodeReactorException(e); + } + } + + private static YangParserException decodeReactorException(final ReactorException reported) { + // FIXME: map exception in some reasonable manner + return new YangParserException("Failed to assemble sources", reported); + } + + private static StatementStreamSource sourceToStatementStream(final SchemaSourceRepresentation source) + throws IOException, YangSyntaxErrorException { + requireNonNull(source); + if (source instanceof YangTextSchemaSource) { + return YangStatementStreamSource.create((YangTextSchemaSource) source); + } else if (source instanceof YinDomSchemaSource) { + return YinStatementStreamSource.create((YinDomSchemaSource) source); + } else if (source instanceof YinTextSchemaSource) { + try { + return YinStatementStreamSource.create(YinTextToDomTransformer.transformSource( + (YinTextSchemaSource) source)); + } catch (SAXException e) { + throw new YangSyntaxErrorException(source.getIdentifier(), 0, 0, "Failed to parse XML text", e); + } + } else if (source instanceof YinXmlSchemaSource) { + try { + return YinStatementStreamSource.create((YinXmlSchemaSource) source); + } catch (TransformerException e) { + throw new YangSyntaxErrorException(source.getIdentifier(), 0, 0, + "Failed to assemble in-memory representation", e); + } + } else { + throw new IllegalArgumentException("Unsupported source " + source); + } + } +} diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/osgi/Activator.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/osgi/Activator.java new file mode 100644 index 0000000000..c42d0b3b87 --- /dev/null +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/osgi/Activator.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2017 Pantheon Technologies, s.r.o. 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/epl-v10.html + */ +package org.opendaylight.yangtools.yang.parser.impl.osgi; + +import org.eclipse.jdt.annotation.NonNull; +import org.opendaylight.yangtools.yang.model.parser.api.YangParserFactory; +import org.opendaylight.yangtools.yang.parser.impl.YangParserFactoryImpl; +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceRegistration; + +/** + * YANG parser implementation activator. Publishes a {@link YangParserFactory} implementation on bundle start. + * + * @author Robert Varga + */ +public final class Activator implements BundleActivator { + private ServiceRegistration<@NonNull YangParserFactory> registration; + + @Override + public void start(final BundleContext context) throws Exception { + registration = context.registerService(YangParserFactory.class, new YangParserFactoryImpl(), null); + } + + @Override + public void stop(final BundleContext context) throws Exception { + if (registration != null) { + registration.unregister(); + registration = null; + } + } +} diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/osgi/package-info.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/osgi/package-info.java new file mode 100644 index 0000000000..f052302e2b --- /dev/null +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/osgi/package-info.java @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2017 Pantheon Technologies, s.r.o. 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/epl-v10.html + */ +/** + * OSGi-specific YANG parser code. Contains activators and similar. + */ +package org.opendaylight.yangtools.yang.parser.impl.osgi; \ No newline at end of file diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/SharedSchemaRepository.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/SharedSchemaRepository.java index 6c615b58a9..3682b1014f 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/SharedSchemaRepository.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/SharedSchemaRepository.java @@ -13,6 +13,7 @@ import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import javax.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.repo.api.SchemaContextFactory; @@ -28,6 +29,7 @@ import org.opendaylight.yangtools.yang.model.repo.util.AbstractSchemaRepository; * Note: for current implementation, "same" means the same filter and the same set of {@link SourceIdentifier}s. */ @Beta +@MetaInfServices(value = SchemaRepository.class) public final class SharedSchemaRepository extends AbstractSchemaRepository implements Identifiable { private final LoadingCache cache = CacheBuilder.newBuilder().softValues().build(new CacheLoader() { diff --git a/yang/yang-parser-impl/src/main/resources/META-INF/services/org.opendaylight.yangtools.yang.model.repo.api.SchemaRepository b/yang/yang-parser-impl/src/main/resources/META-INF/services/org.opendaylight.yangtools.yang.model.repo.api.SchemaRepository deleted file mode 100644 index 44871af165..0000000000 --- a/yang/yang-parser-impl/src/main/resources/META-INF/services/org.opendaylight.yangtools.yang.model.repo.api.SchemaRepository +++ /dev/null @@ -1 +0,0 @@ -org.opendaylight.yangtools.yang.parser.repo.SharedSchemaRepository diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/reactor/CustomCrossSourceStatementReactorBuilder.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/reactor/CustomCrossSourceStatementReactorBuilder.java index d2838568a5..4f63e37e54 100644 --- a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/reactor/CustomCrossSourceStatementReactorBuilder.java +++ b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/reactor/CustomCrossSourceStatementReactorBuilder.java @@ -16,6 +16,7 @@ import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import org.eclipse.jdt.annotation.NonNull; import org.opendaylight.yangtools.concepts.Builder; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.common.YangVersion; @@ -109,7 +110,7 @@ public class CustomCrossSourceStatementReactorBuilder implements Builder it = ServiceLoader.load(YangParserFactory.class).iterator(); + if (!it.hasNext()) { + throw new IllegalStateException("No YangParserFactory found"); + } + PARSER_FACTORY = it.next(); + } + private YangParserTestUtils() { throw new UnsupportedOperationException("Utility class should not be instantiated."); } @@ -186,7 +197,7 @@ public final class YangParserTestUtils { */ public static SchemaContext parseYangFiles(final Set supportedFeatures, final StatementParserMode parserMode, final Collection files) { - return parseYangSources(supportedFeatures, parserMode, + return parseSources(parserMode, supportedFeatures, files.stream().map(YangTextSchemaSource::forFile).collect(Collectors.toList())); } @@ -264,7 +275,7 @@ public final class YangParserTestUtils { for (final String r : resources) { sources.add(YangTextSchemaSource.forResource(clazz, r)); } - return parseYangSources(null, StatementParserMode.DEFAULT_MODE, sources); + return parseSources(StatementParserMode.DEFAULT_MODE, null, sources); } /** @@ -326,101 +337,28 @@ public final class YangParserTestUtils { public static SchemaContext parseYangSources(final StatementParserMode parserMode, final Set supportedFeatures, final YangTextSchemaSource... sources) { - return parseYangSources(supportedFeatures, parserMode, Arrays.asList(sources)); + return parseSources(parserMode, supportedFeatures, Arrays.asList(sources)); } - public static SchemaContext parseYangSources(final Set supportedFeatures, - final StatementParserMode parserMode, final Collection sources) { - final Collection streams = new ArrayList<>(sources.size()); - for (YangTextSchemaSource source : sources) { - try { - streams.add(YangStatementStreamSource.create(source)); - } catch (IOException e) { - throw new IllegalArgumentException("Failed to read source " + source, e); - } catch (YangSyntaxErrorException e) { - throw new IllegalArgumentException("Malformed source " + source, e); - } + public static SchemaContext parseSources(final StatementParserMode parserMode, final Set supportedFeatures, + final Collection sources) { + final YangParser parser = PARSER_FACTORY.createParser(parserMode); + if (supportedFeatures != null) { + parser.setSupportedFeatures(supportedFeatures); } - return parseSources(supportedFeatures, parserMode, streams); - } - - /** - * Creates a new effective schema context containing the specified YIN sources. Statement parser mode is set to - * default mode and all YANG features are supported. - * - * @param sources YIN sources to be parsed - * @return effective schema context - */ - public static SchemaContext parseYinSources(final YinStatementStreamSource... sources) { - return parseYinSources(StatementParserMode.DEFAULT_MODE, sources); - } - - /** - * Creates a new effective schema context containing the specified YIN sources. Statement parser mode is set to - * default mode. - * - * @param supportedFeatures set of supported features based on which all if-feature statements in the parsed YIN - * models are resolved - * @param sources YIN sources to be parsed - * - * @return effective schema context - * @throws ReactorException if there is an error in one of the parsed YIN sources - */ - public static SchemaContext parseYinSources(final Set supportedFeatures, - final YinStatementStreamSource... sources) throws ReactorException { - return parseSources(supportedFeatures, StatementParserMode.DEFAULT_MODE, sources); - } - - /** - * Creates a new effective schema context containing the specified YIN sources. All YANG features are supported. - * - * @param statementParserMode mode of statement parser - * @param sources YIN sources to be parsed - * @return effective schema context - */ - public static SchemaContext parseYinSources(final StatementParserMode statementParserMode, - final YinStatementStreamSource... sources) { - return parseSources(null, statementParserMode, sources); - } - - /** - * Creates a new effective schema context containing the specified YANG sources. - * - * @param supportedFeatures set of supported features based on which all if-feature statements in the parsed YANG - * models are resolved - * @param parserMode mode of statement parser - * @param sources sources to be parsed - * - * @return effective schema context - */ - public static SchemaContext parseSources(final Set supportedFeatures, - final StatementParserMode parserMode, final StatementStreamSource... sources) { - return parseSources(supportedFeatures, parserMode, Arrays.asList(sources)); - } - - /** - * Creates a new effective schema context containing the specified YANG sources. - * - * @param supportedFeatures set of supported features based on which all if-feature statements in the parsed YANG - * models are resolved - * @param statementParserMode mode of statement parser - * @param sources sources to be parsed - * - * @return effective schema context - */ - public static SchemaContext parseSources(final Set supportedFeatures, - final StatementParserMode statementParserMode, final Collection sources) { - final BuildAction reactor = DefaultReactors.defaultReactor().newBuild(statementParserMode); - if (supportedFeatures != null) { - reactor.setSupportedFeatures(supportedFeatures); + try { + parser.addSources(sources); + } catch (YangSyntaxErrorException e) { + throw new IllegalArgumentException("Malformed source", e); + } catch (IOException e) { + throw new IllegalArgumentException("Failed to read a source", e); } - reactor.addSources(sources); try { - return reactor.buildEffective(); - } catch (ReactorException e) { - throw new IllegalStateException(e); + return parser.buildSchemaContext(); + } catch (YangParserException e) { + throw new IllegalStateException("Failed to assemble SchemaContext", e); } } -- 2.36.6