From 218d95a041d2afa83e1c643f18d31d1320e62a01 Mon Sep 17 00:00:00 2001 From: Robert Varga Date: Sat, 18 Feb 2017 12:44:17 +0100 Subject: [PATCH] Add generalized FileGenerator interface This patch adds a maven-independent interface for code generators, which captures enough semantics to make mapping usable. We will be implementing this interface in place of the original SPI. JIRA: YANGTOOLS-1146 Change-Id: I3daef73d3fa71e74a9678979fd00417579f60695 Signed-off-by: Robert Varga --- artifacts/pom.xml | 6 ++ docs/pom.xml | 6 +- plugin/plugin-generator-api/pom.xml | 53 +++++++++++ .../api/AbstractFileGeneratorFactory.java | 28 ++++++ .../generator/api/AbstractGeneratedFile.java | 50 +++++++++++ .../api/AbstractGeneratedTextFile.java | 48 ++++++++++ .../api/ByteSourceGeneratedFile.java | 40 +++++++++ .../api/CharSeqGeneratedTextFile.java | 32 +++++++ .../api/CharSourceGeneratedTextFile.java | 40 +++++++++ .../plugin/generator/api/FileGenerator.java | 71 +++++++++++++++ .../generator/api/FileGeneratorException.java | 29 ++++++ .../generator/api/FileGeneratorFactory.java | 41 +++++++++ .../plugin/generator/api/GeneratedFile.java | 79 +++++++++++++++++ .../generator/api/GeneratedFileLifecycle.java | 30 +++++++ .../generator/api/GeneratedFilePath.java | 70 +++++++++++++++ .../generator/api/GeneratedFileType.java | 88 +++++++++++++++++++ .../generator/api/ModuleResourceResolver.java | 37 ++++++++ .../plugin/generator/api/package-info.java | 17 ++++ plugin/pom.xml | 39 ++++++++ pom.xml | 2 + yang/pom.xml | 8 +- yang/yang-maven-plugin-spi/pom.xml | 4 + .../yang2sources/spi/BasicCodeGenerator.java | 21 ++++- .../spi/ModuleResourceResolver.java | 19 +--- 24 files changed, 837 insertions(+), 21 deletions(-) create mode 100644 plugin/plugin-generator-api/pom.xml create mode 100644 plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/AbstractFileGeneratorFactory.java create mode 100644 plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/AbstractGeneratedFile.java create mode 100644 plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/AbstractGeneratedTextFile.java create mode 100644 plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/ByteSourceGeneratedFile.java create mode 100644 plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/CharSeqGeneratedTextFile.java create mode 100644 plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/CharSourceGeneratedTextFile.java create mode 100644 plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/FileGenerator.java create mode 100644 plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/FileGeneratorException.java create mode 100644 plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/FileGeneratorFactory.java create mode 100644 plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/GeneratedFile.java create mode 100644 plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/GeneratedFileLifecycle.java create mode 100644 plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/GeneratedFilePath.java create mode 100644 plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/GeneratedFileType.java create mode 100644 plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/ModuleResourceResolver.java create mode 100644 plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/package-info.java create mode 100644 plugin/pom.xml diff --git a/artifacts/pom.xml b/artifacts/pom.xml index 6fc96bfd8e..776a6f0e88 100644 --- a/artifacts/pom.xml +++ b/artifacts/pom.xml @@ -130,6 +130,12 @@ 6.0.1-SNAPSHOT test + + + org.opendaylight.yangtools + plugin-generator-api + 6.0.1-SNAPSHOT + org.opendaylight.yangtools yang-maven-plugin diff --git a/docs/pom.xml b/docs/pom.xml index d670390035..e480dedb3c 100644 --- a/docs/pom.xml +++ b/docs/pom.xml @@ -30,6 +30,10 @@ org.opendaylight.yangtools concepts + + org.opendaylight.yangtools + plugin-generator-api + org.opendaylight.yangtools yang-common @@ -376,7 +380,7 @@ yang-maven-plugin codegen interface - org.opendaylight.yangtools.yang2sources.spi* + org.opendaylight.yangtools.plugin.generator.api*:org.opendaylight.yangtools.yang2sources.spi* Common YANG parser diff --git a/plugin/plugin-generator-api/pom.xml b/plugin/plugin-generator-api/pom.xml new file mode 100644 index 0000000000..8b8aa37cd6 --- /dev/null +++ b/plugin/plugin-generator-api/pom.xml @@ -0,0 +1,53 @@ + + + + + 4.0.0 + + org.opendaylight.yangtools + bundle-parent + 6.0.1-SNAPSHOT + ../../bundle-parent + + + plugin-generator-api + bundle + ${project.artifactId} + YANG Generator Plugin API + + + + com.google.guava + guava + + + org.opendaylight.yangtools + concepts + + + org.opendaylight.yangtools + yang-model-api + + + + + + + org.apache.felix + maven-bundle-plugin + true + + + org.opendaylight.yangtools.plugin.generator.api + + + + + + diff --git a/plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/AbstractFileGeneratorFactory.java b/plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/AbstractFileGeneratorFactory.java new file mode 100644 index 0000000000..e83ecf7cc3 --- /dev/null +++ b/plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/AbstractFileGeneratorFactory.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2020 PANTHEON.tech, 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.plugin.generator.api; + +import static com.google.common.base.Preconditions.checkArgument; + +import com.google.common.annotations.Beta; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.opendaylight.yangtools.concepts.AbstractIdentifiable; + +/** + * Abstract base class for {@link FileGeneratorFactory} implementations. Its constructor enforces no spaces in + * identifier. + */ +@Beta +@NonNullByDefault +public abstract class AbstractFileGeneratorFactory extends AbstractIdentifiable + implements FileGeneratorFactory { + protected AbstractFileGeneratorFactory(final String identifier) { + super(identifier); + checkArgument(identifier.indexOf(' ') == -1, "Identifier may not contain any spaces"); + } +} diff --git a/plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/AbstractGeneratedFile.java b/plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/AbstractGeneratedFile.java new file mode 100644 index 0000000000..840ad76b15 --- /dev/null +++ b/plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/AbstractGeneratedFile.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2020 PANTHEON.tech, 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.plugin.generator.api; + +import static java.util.Objects.requireNonNull; + +import com.google.common.annotations.Beta; +import com.google.common.base.MoreObjects; +import com.google.common.base.MoreObjects.ToStringHelper; +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * Abstract base class for {@link GeneratedFile}s. This class is suitable for binary files. For text files use + * {@link AbstractGeneratedTextFile}. + * + * @author Robert Varga + */ +@Beta +@NonNullByDefault +public abstract class AbstractGeneratedFile implements GeneratedFile { + private final GeneratedFileLifecycle lifecycle; + + protected AbstractGeneratedFile(final GeneratedFileLifecycle lifecycle) { + this.lifecycle = requireNonNull(lifecycle); + } + + /** + * Return the lifecycle governing this file. + * + * @return Governing lifecycle + */ + @Override + public final GeneratedFileLifecycle getLifecycle() { + return lifecycle; + } + + @Override + public final String toString() { + return addToStringAttributes(MoreObjects.toStringHelper(this).omitNullValues()).toString(); + } + + protected ToStringHelper addToStringAttributes(final ToStringHelper helper) { + return helper.add("lifecycle", lifecycle); + } +} diff --git a/plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/AbstractGeneratedTextFile.java b/plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/AbstractGeneratedTextFile.java new file mode 100644 index 0000000000..b4c38bf9e4 --- /dev/null +++ b/plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/AbstractGeneratedTextFile.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2020 PANTHEON.tech, 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.plugin.generator.api; + +import com.google.common.annotations.Beta; +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.nio.charset.StandardCharsets; +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * The contents of a generated file and its {@link GeneratedFileLifecycle}. This class is suitable for text files, + * for binary files see {@link AbstractGeneratedFile}. Text files are encoded in {@link StandardCharsets#UTF_8}. + * + * @author Robert Varga + */ +@Beta +@NonNullByDefault +public abstract class AbstractGeneratedTextFile extends AbstractGeneratedFile { + protected AbstractGeneratedTextFile(final GeneratedFileLifecycle lifecycle) { + super(lifecycle); + } + + @Override + public final void writeBody(final OutputStream output) throws IOException { + try (Writer writer = new OutputStreamWriter(output, StandardCharsets.UTF_8)) { + try (BufferedWriter buffered = new BufferedWriter(writer)) { + writeBody(buffered); + } + } + } + + /** + * Write the body of this file into specified {@link Writer}. + * + * @param output writer where to write the output + * @throws IOException when the stream reports an IOException + */ + protected abstract void writeBody(Writer output) throws IOException; +} diff --git a/plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/ByteSourceGeneratedFile.java b/plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/ByteSourceGeneratedFile.java new file mode 100644 index 0000000000..bb5352d455 --- /dev/null +++ b/plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/ByteSourceGeneratedFile.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2020 PANTHEON.tech, 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.plugin.generator.api; + +import static java.util.Objects.requireNonNull; + +import com.google.common.base.MoreObjects.ToStringHelper; +import com.google.common.io.ByteSource; +import java.io.IOException; +import java.io.OutputStream; +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * A generated file with a body is available as a {@link ByteSource}. + */ +@NonNullByDefault +final class ByteSourceGeneratedFile extends AbstractGeneratedFile { + private final ByteSource body; + + ByteSourceGeneratedFile(final GeneratedFileLifecycle lifecycle, final ByteSource body) { + super(lifecycle); + this.body = requireNonNull(body); + } + + @Override + public void writeBody(final @NonNull OutputStream output) throws IOException { + body.copyTo(output); + } + + @Override + protected ToStringHelper addToStringAttributes(final ToStringHelper helper) { + return helper.add("body", body); + } +} diff --git a/plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/CharSeqGeneratedTextFile.java b/plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/CharSeqGeneratedTextFile.java new file mode 100644 index 0000000000..617e8a303c --- /dev/null +++ b/plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/CharSeqGeneratedTextFile.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2020 PANTHEON.tech, 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.plugin.generator.api; + +import static java.util.Objects.requireNonNull; + +import java.io.IOException; +import java.io.Writer; +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * A generated text file with a body is available as a {@link CharSequence}. + */ +@NonNullByDefault +final class CharSeqGeneratedTextFile extends AbstractGeneratedTextFile { + private final CharSequence body; + + CharSeqGeneratedTextFile(final GeneratedFileLifecycle lifecycle, final CharSequence body) { + super(lifecycle); + this.body = requireNonNull(body); + } + + @Override + protected void writeBody(final Writer output) throws IOException { + output.append(body); + } +} diff --git a/plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/CharSourceGeneratedTextFile.java b/plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/CharSourceGeneratedTextFile.java new file mode 100644 index 0000000000..8f44502dd5 --- /dev/null +++ b/plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/CharSourceGeneratedTextFile.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2020 PANTHEON.tech, 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.plugin.generator.api; + +import static java.util.Objects.requireNonNull; + +import com.google.common.base.MoreObjects.ToStringHelper; +import com.google.common.io.ByteSource; +import com.google.common.io.CharSource; +import java.io.IOException; +import java.io.Writer; +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * A generated file with a body is available as a {@link ByteSource}. + */ +@NonNullByDefault +final class CharSourceGeneratedTextFile extends AbstractGeneratedTextFile { + private final CharSource body; + + CharSourceGeneratedTextFile(final GeneratedFileLifecycle lifecycle, final CharSource body) { + super(lifecycle); + this.body = requireNonNull(body); + } + + @Override + protected void writeBody(final Writer output) throws IOException { + body.copyTo(output); + } + + @Override + protected ToStringHelper addToStringAttributes(final ToStringHelper helper) { + return helper.add("body", body); + } +} diff --git a/plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/FileGenerator.java b/plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/FileGenerator.java new file mode 100644 index 0000000000..200b7c2d73 --- /dev/null +++ b/plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/FileGenerator.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2020 PANTHEON.tech, 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.plugin.generator.api; + +import com.google.common.annotations.Beta; +import com.google.common.collect.Table; +import java.util.Set; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext; +import org.opendaylight.yangtools.yang.model.api.Module; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; + +/** + * Interface implemented by plugins which can generate files from a {@link EffectiveModelContext}. + * + * @author Robert Varga + */ +@Beta +@NonNullByDefault +public interface FileGenerator { + /** + * Indicate import resolution mode this code generator requires. Default implementation indicates + * {@link ImportResolutionMode#REVISION_EXACT_OR_LATEST}. + * + * @return Required import resolution mode, null if the code generator does not care. + */ + default ImportResolutionMode importResolutionMode() { + return ImportResolutionMode.REVISION_EXACT_OR_LATEST; + } + + /** + * Generate files from a {@link SchemaContext}, being aware the that specific modules are local to the current + * project being processed. + * + *

+ * Implementations of this interface must not interact with project directory directly, but rather supply the files + * generated as a set of {@link GeneratedFile}s. The caller of this method will use these to integrate with build + * management to ensure proper dependency tracking is performed. + * + * @param context SchemaContext to examine + * @param localModules Modules local to the project + * @param moduleResourcePathResolver Module-to-resource path resolver + * @return The set of generated files. + * @throws FileGeneratorException if anything bad happens + */ + Table generateFiles(EffectiveModelContext context, + Set localModules, ModuleResourceResolver moduleResourcePathResolver) throws FileGeneratorException; + + /** + * {@link EffectiveModelContext} can be assembled in multiple ways, we hold known modes here. + */ + @Beta + enum ImportResolutionMode { + /** + * Standard, RFC6020 and RFC7950 compliant mode. Imports are satisfied by exact revision match (if specified), + * or by latest available revision. + */ + REVISION_EXACT_OR_LATEST, + /** + * Semantic version based mode. Imports which specify a semantic version (via the OpenConfig extension) will + * be satisfied by module which exports the latest compatible revision. Imports which do not specify semantic + * version will be resolved just as they would be via {@link #REVISION_EXACT_OR_LATEST}. + */ + SEMVER_LATEST, + } +} diff --git a/plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/FileGeneratorException.java b/plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/FileGeneratorException.java new file mode 100644 index 0000000000..18c32e97ba --- /dev/null +++ b/plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/FileGeneratorException.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2020 PANTHEON.tech, 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.plugin.generator.api; + +import static java.util.Objects.requireNonNull; + +import com.google.common.annotations.Beta; + +/** + * An exception reporting a problem with file generation. This exception should be reported when exception chaining + * occurs. + */ +@Beta +public class FileGeneratorException extends Exception { + private static final long serialVersionUID = 1L; + + public FileGeneratorException(final String message) { + super(requireNonNull(message)); + } + + public FileGeneratorException(final String message, final Throwable cause) { + super(requireNonNull(message), cause); + } +} diff --git a/plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/FileGeneratorFactory.java b/plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/FileGeneratorFactory.java new file mode 100644 index 0000000000..4b4deb6a8a --- /dev/null +++ b/plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/FileGeneratorFactory.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2020 PANTHEON.tech, 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.plugin.generator.api; + +import com.google.common.annotations.Beta; +import java.util.Map; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.opendaylight.yangtools.concepts.Identifiable; + +/** + * A {@link java.util.ServiceLoader} factory for instantiating {@link FileGenerator} instances. + * + * @author Robert Varga + */ +@Beta +@NonNullByDefault +public interface FileGeneratorFactory extends Identifiable { + /** + * {@inheritDoc} + * + *

+ * This identifier must be a simple string without any whitespace, such as produced by + * {@link Class#getSimpleName()}. + */ + @Override + String getIdentifier(); + + /** + * Create a new {@link FileGenerator}. + * + * @param configuration Configuration properties + * @return a new FileGenerator + * @throws FileGeneratorException if the configuration is not acceptable, or any other issue occurs. + */ + FileGenerator newFileGenerator(Map configuration) throws FileGeneratorException; +} diff --git a/plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/GeneratedFile.java b/plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/GeneratedFile.java new file mode 100644 index 0000000000..df2a8be1c6 --- /dev/null +++ b/plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/GeneratedFile.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2020 PANTHEON.tech, 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.plugin.generator.api; + +import com.google.common.annotations.Beta; +import com.google.common.io.ByteSource; +import com.google.common.io.CharSource; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.opendaylight.yangtools.concepts.Immutable; + +/** + * The contents of a generated file and its {@link GeneratedFileLifecycle}. + * + * @author Robert Varga + */ +@Beta +@NonNullByDefault +public interface GeneratedFile extends Immutable { + /** + * Return the lifecycle governing this file. + * + * @return Governing lifecycle + */ + GeneratedFileLifecycle getLifecycle(); + + /** + * Write the body of this file into specified {@link OutputStream}. + * + * @param output stream where to write the output + * @throws IOException when the stream reports an IOException + */ + void writeBody(OutputStream output) throws IOException; + + /** + * Create a new {@link GeneratedFile} with the specified {@link CharSequence} body. The body will be encoded in + * {@link StandardCharsets#UTF_8}. + * + * @param lifecycle File lifecycle + * @param body File body + * @return A GeneratedFile. + * @throws NullPointerException if any argument is null + */ + static GeneratedFile of(final GeneratedFileLifecycle lifecycle, final CharSequence body) { + return new CharSeqGeneratedTextFile(lifecycle, body); + } + + /** + * Create a new {@link GeneratedFile} with the specified {@link CharSource} body. The body will be encoded in + * {@link StandardCharsets#UTF_8}. + * + * @param lifecycle File lifecycle + * @param body File body + * @return A GeneratedFile. + * @throws NullPointerException if any argument is null + */ + static GeneratedFile of(final GeneratedFileLifecycle lifecycle, final CharSource body) { + return new CharSourceGeneratedTextFile(lifecycle, body); + } + + /** + * Create a new {@link GeneratedFile} with the specified {@link ByteSource} body. The body will be written as is. + * + * @param lifecycle File lifecycle + * @param body File body + * @return A GeneratedFile. + * @throws NullPointerException if any argument is null + */ + static GeneratedFile of(final GeneratedFileLifecycle lifecycle, final ByteSource body) { + return new ByteSourceGeneratedFile(lifecycle, body); + } +} diff --git a/plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/GeneratedFileLifecycle.java b/plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/GeneratedFileLifecycle.java new file mode 100644 index 0000000000..17664fc033 --- /dev/null +++ b/plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/GeneratedFileLifecycle.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2020 PANTHEON.tech, 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.plugin.generator.api; + +import com.google.common.annotations.Beta; +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * Lifecycle policy of a generated file. This governs how existing files interact with newly-generated bodies. + * + * @author Robert Varga + */ +@Beta +@NonNullByDefault +public enum GeneratedFileLifecycle { + /** + * Generated file should be transient and is not expected to be further modified. + */ + TRANSIENT, + /** + * Generated file should be persistent and potentially customized. It should not be overwritten if it already + * exists. + */ + PERSISTENT, +} diff --git a/plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/GeneratedFilePath.java b/plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/GeneratedFilePath.java new file mode 100644 index 0000000000..8c74906ee7 --- /dev/null +++ b/plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/GeneratedFilePath.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2020 PANTHEON.tech, 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.plugin.generator.api; + +import static com.google.common.base.Preconditions.checkArgument; +import static java.util.Objects.requireNonNull; + +import com.google.common.annotations.Beta; +import com.google.common.base.CharMatcher; +import com.google.common.base.MoreObjects; +import java.io.File; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; + +/** + * A relative path to a generated file. + * + * @author Robert Varga + */ +@Beta +@NonNullByDefault +public final class GeneratedFilePath { + public static final char SEPARATOR = '/'; + public static final String SEPARATOR_STR = "/"; + + private static final CharMatcher FS_MATCHER = CharMatcher.is(File.separatorChar); + + private final String path; + + private GeneratedFilePath(final String path) { + this.path = requireNonNull(path); + checkArgument(!path.isEmpty()); + } + + public static GeneratedFilePath ofPath(final String path) { + return new GeneratedFilePath(path); + } + + public static GeneratedFilePath ofFile(final File file) { + return ofFilePath(file.getPath()); + } + + public static GeneratedFilePath ofFilePath(final String filePath) { + return ofPath(FS_MATCHER.replaceFrom(filePath, SEPARATOR)); + } + + public String getPath() { + return path; + } + + @Override + public int hashCode() { + return path.hashCode(); + } + + @Override + public boolean equals(final @Nullable Object obj) { + return this == obj || obj instanceof GeneratedFilePath && path.equals(((GeneratedFilePath) obj).path); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this).add("path", path).toString(); + } +} diff --git a/plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/GeneratedFileType.java b/plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/GeneratedFileType.java new file mode 100644 index 0000000000..0c53ac55c9 --- /dev/null +++ b/plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/GeneratedFileType.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2020 PANTHEON.tech, 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.plugin.generator.api; + +import static com.google.common.base.Preconditions.checkArgument; +import static java.util.Objects.requireNonNull; + +import com.google.common.annotations.Beta; +import com.google.common.base.MoreObjects; +import com.google.common.collect.ImmutableMap; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; + +/** + * Type of generated file. Four most common kinds are captured in {@link #RESOURCE}, {@link #SOURCE}, + * {@link #TEST_RESOURCE} and {@link #TEST_SOURCE}, but others may be externally defined. + * + *

+ * Users of {@link FileGenerator} are expected to provide sensible mapping of {@link GeneratedFileType} to their + * output structures. Notably they must handle pre-defined types, allow end users to specify mapping of custom types. + * They need to deal with runtime mismatches involving between FileGenerators and user's expectations, for example by + * issuing warnings when a mismatch is detected. + * + * @author Robert Varga + */ +@Beta +@NonNullByDefault +public final class GeneratedFileType { + /** + * A generated resource file. This file should be part of artifact's resources. + */ + public static final GeneratedFileType RESOURCE = new GeneratedFileType("resource"); + + /** + * A generated source file. This file should be part of main compilation unit. + */ + public static final GeneratedFileType SOURCE = new GeneratedFileType("source"); + + /** + * A generated test resource file. This file should be part of test resources. + */ + public static final GeneratedFileType TEST_RESOURCE = new GeneratedFileType("test-resource"); + + /** + * A generated test source file. This file should be part of test sources. + */ + public static final GeneratedFileType TEST_SOURCE = new GeneratedFileType("test-source"); + + private static final ImmutableMap WELL_KNOWN = ImmutableMap.of( + RESOURCE.name(), RESOURCE, TEST_RESOURCE.name(), TEST_RESOURCE, + SOURCE.name(), SOURCE, TEST_SOURCE.name(), TEST_SOURCE); + + private final String name; + + private GeneratedFileType(final String name) { + this.name = requireNonNull(name); + } + + public static GeneratedFileType of(final String name) { + checkArgument(!name.isEmpty()); + final @Nullable GeneratedFileType wellKnown = WELL_KNOWN.get(name); + return wellKnown != null ? wellKnown : new GeneratedFileType(name); + } + + public String name() { + return name; + } + + @Override + public int hashCode() { + return name.hashCode(); + } + + @Override + public boolean equals(final @Nullable Object obj) { + return this == obj || obj instanceof GeneratedFileType && name.equals(((GeneratedFileType) obj).name); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this).add("name", name).toString(); + } +} diff --git a/plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/ModuleResourceResolver.java b/plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/ModuleResourceResolver.java new file mode 100644 index 0000000000..c97d03e31f --- /dev/null +++ b/plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/ModuleResourceResolver.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 PANTHEON.tech, 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.plugin.generator.api; + +import com.google.common.annotations.Beta; +import java.util.Optional; +import org.opendaylight.yangtools.yang.model.api.ModuleLike; +import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceRepresentation; +import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource; + +/** + * An SPI-level interface to find the schema source for a particular YANG module, as packaged in the final artifact. + * The module must be part of the current resolution context. + */ +@Beta +public interface ModuleResourceResolver { + /** + * Find the path of the packaged resource which corresponds to the specified module in the specified representation. + * + * @param module Requested module + * @param representation Requested representation + * @return Path to packaged resource + * @throws NullPointerException if any argument is null + * @throws IllegalArgumentException if the requested representation is not supported by this resolver + */ + Optional findModuleResourcePath(ModuleLike module, + Class representation); + + default Optional findModuleYangTextResourcePath(final ModuleLike module) { + return findModuleResourcePath(module, YangTextSchemaSource.class); + } +} diff --git a/plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/package-info.java b/plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/package-info.java new file mode 100644 index 0000000000..1e0177d2a7 --- /dev/null +++ b/plugin/plugin-generator-api/src/main/java/org/opendaylight/yangtools/plugin/generator/api/package-info.java @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2020 PANTHEON.tech, 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 + */ +/** + * API exposed by generator plugins, i.e. pluggable pieces of code which want to create code (and other) files from an + * {@link org.opendaylight.yangtools.yang.model.api.EffectiveModelContext}. + * + *

+ * The primary entry point is {@link org.opendaylight.yangtools.plugin.generator.api.FileGeneratorFactory}, which needs + * to be implemented for bootstrapping a particular generator. Such implementations are discovered using normal + * discovery methods, for example they should always be published as {@link java.util.ServiceLoader} services. + */ +package org.opendaylight.yangtools.plugin.generator.api; \ No newline at end of file diff --git a/plugin/pom.xml b/plugin/pom.xml new file mode 100644 index 0000000000..39a70400e4 --- /dev/null +++ b/plugin/pom.xml @@ -0,0 +1,39 @@ + + + + + + + org.opendaylight.odlparent + odlparent-lite + 8.0.0 + + + + 4.0.0 + org.opendaylight.yangtools + plugin-aggregator + 6.0.1-SNAPSHOT + pom + + + plugin-generator-api + + + + + + true + true + + diff --git a/pom.xml b/pom.xml index c5115eca86..15c385644b 100644 --- a/pom.xml +++ b/pom.xml @@ -41,6 +41,8 @@ common docs features + plugin + yang yang-validation-tool diff --git a/yang/pom.xml b/yang/pom.xml index 5dee24ea01..e77b5e4eb8 100644 --- a/yang/pom.xml +++ b/yang/pom.xml @@ -34,14 +34,16 @@ yang-data-codec-binfmt yang-data-codec-gson yang-data-codec-xml - yang-maven-plugin - yang-maven-plugin-it - yang-maven-plugin-spi yang-model-api yang-model-export yang-model-util yang-model-util-ut + + yang-maven-plugin + yang-maven-plugin-spi + yang-maven-plugin-it + yang-xpath-api yang-xpath-antlr diff --git a/yang/yang-maven-plugin-spi/pom.xml b/yang/yang-maven-plugin-spi/pom.xml index 76e7a3d86d..7bb01a62e1 100644 --- a/yang/yang-maven-plugin-spi/pom.xml +++ b/yang/yang-maven-plugin-spi/pom.xml @@ -40,6 +40,10 @@ org.opendaylight.yangtools yang-model-api + + org.opendaylight.yangtools + plugin-generator-api + org.apache.maven diff --git a/yang/yang-maven-plugin-spi/src/main/java/org/opendaylight/yangtools/yang2sources/spi/BasicCodeGenerator.java b/yang/yang-maven-plugin-spi/src/main/java/org/opendaylight/yangtools/yang2sources/spi/BasicCodeGenerator.java index cac397db4d..8f621ddb11 100644 --- a/yang/yang-maven-plugin-spi/src/main/java/org/opendaylight/yangtools/yang2sources/spi/BasicCodeGenerator.java +++ b/yang/yang-maven-plugin-spi/src/main/java/org/opendaylight/yangtools/yang2sources/spi/BasicCodeGenerator.java @@ -12,6 +12,8 @@ import java.io.IOException; import java.util.Collection; import java.util.Map; import java.util.Set; +import org.eclipse.jdt.annotation.NonNull; +import org.opendaylight.yangtools.plugin.generator.api.FileGenerator; import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext; import org.opendaylight.yangtools.yang.model.api.Module; @@ -24,13 +26,28 @@ public interface BasicCodeGenerator { * Standard, RFC6020 and RFC7950 compliant mode. Imports are satisfied by exact revision match (if specified), * or by latest available revision. */ - REVISION_EXACT_OR_LATEST, + REVISION_EXACT_OR_LATEST(FileGenerator.ImportResolutionMode.REVISION_EXACT_OR_LATEST), /** * Semantic version based mode. Imports which specify a semantic version (via the OpenConfig extension) will * be satisfied by module which exports the latest compatible revision. Imports which do not specify semantic * version will be resolved just as they would be via {@link #REVISION_EXACT_OR_LATEST}. */ - SEMVER_LATEST, + SEMVER_LATEST(FileGenerator.ImportResolutionMode.SEMVER_LATEST); + + private final FileGenerator.@NonNull ImportResolutionMode fileGeneratorMode; + + ImportResolutionMode(final FileGenerator.@NonNull ImportResolutionMode fileGeneratorMode) { + this.fileGeneratorMode = fileGeneratorMode; + } + + /** + * Return {@link FileGenerator.ImportResolutionMode} equivalent of this mode. + * + * @return {@link FileGenerator.ImportResolutionMode} equivalent of this mode + */ + public final FileGenerator.@NonNull ImportResolutionMode toFileGeneratorMode() { + return fileGeneratorMode; + } } /** diff --git a/yang/yang-maven-plugin-spi/src/main/java/org/opendaylight/yangtools/yang2sources/spi/ModuleResourceResolver.java b/yang/yang-maven-plugin-spi/src/main/java/org/opendaylight/yangtools/yang2sources/spi/ModuleResourceResolver.java index d1e0c5b82f..62af2042b5 100644 --- a/yang/yang-maven-plugin-spi/src/main/java/org/opendaylight/yangtools/yang2sources/spi/ModuleResourceResolver.java +++ b/yang/yang-maven-plugin-spi/src/main/java/org/opendaylight/yangtools/yang2sources/spi/ModuleResourceResolver.java @@ -8,9 +8,7 @@ package org.opendaylight.yangtools.yang2sources.spi; import com.google.common.annotations.Beta; -import java.util.Optional; -import org.opendaylight.yangtools.yang.model.api.ModuleLike; -import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceRepresentation; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; /** * An SPI-level interface to find the schema source for a particular YANG module, as packaged in the final artifact. @@ -18,16 +16,7 @@ import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceRepresentation */ @Beta @FunctionalInterface -public interface ModuleResourceResolver { - /** - * Find the path of the packaged resource which corresponds to the specified module in the specified representation. - * - * @param module Requested module - * @param representation Requested representation - * @return Path to packaged resource - * @throws NullPointerException if any argument is null - * @throws IllegalArgumentException if the requested representation is not supported by this resolver - */ - Optional findModuleResourcePath(ModuleLike module, - Class representation); +@SuppressFBWarnings(value = "NM_SAME_SIMPLE_NAME_AS_INTERFACE", justification = "Migration to new place") +public interface ModuleResourceResolver extends org.opendaylight.yangtools.plugin.generator.api.ModuleResourceResolver { + } -- 2.36.6