001/*
002 * SPDX-FileCopyrightText: none
003 * SPDX-License-Identifier: CC0-1.0
004 */
005
006package dev.metaschema.schemagen;
007
008import java.io.IOException;
009import java.io.Writer;
010import java.nio.charset.StandardCharsets;
011import java.nio.file.Files;
012import java.nio.file.Path;
013import java.nio.file.StandardOpenOption;
014
015import dev.metaschema.core.configuration.IConfiguration;
016import dev.metaschema.core.model.IModule;
017import dev.metaschema.schemagen.json.JsonSchemaGenerator;
018import dev.metaschema.schemagen.xml.XmlSchemaGenerator;
019import edu.umd.cs.findbugs.annotations.NonNull;
020
021/**
022 * Provides the capability to generate a schema from a Metaschema module.
023 */
024@FunctionalInterface
025public interface ISchemaGenerator {
026  /**
027   * Generate and write a schema for the provided {@code metaschema} to the
028   * {@link Writer} provided by {@code writer} using the provided
029   * {@code configuration}.
030   *
031   * @param metaschema
032   *          the Module to generate the schema for
033   * @param writer
034   *          the writer to use to write the schema
035   * @param configuration
036   *          the schema generation configuration
037   * @throws SchemaGenerationException
038   *           if an error occurred while writing the schema
039   */
040  void generateFromModule(
041      @NonNull IModule metaschema,
042      @NonNull Writer writer,
043      @NonNull IConfiguration<SchemaGenerationFeature<?>> configuration);
044
045  /**
046   * Generate a schema for the provided module and write it to the specified file
047   * path.
048   *
049   * @param module
050   *          the Metaschema module to generate the schema for
051   * @param destination
052   *          the file path to write the schema to
053   * @param asFormat
054   *          the schema format to generate
055   * @param configuration
056   *          the schema generation configuration
057   * @throws IOException
058   *           if an I/O error occurs while writing the schema
059   */
060  static void generateSchema(
061      @NonNull IModule module,
062      @NonNull Path destination,
063      @NonNull SchemaFormat asFormat,
064      @NonNull IConfiguration<SchemaGenerationFeature<?>> configuration)
065      throws IOException {
066    ISchemaGenerator schemaGenerator = asFormat.getSchemaGenerator();
067
068    try (Writer writer = Files.newBufferedWriter(
069        destination,
070        StandardCharsets.UTF_8,
071        StandardOpenOption.CREATE,
072        StandardOpenOption.WRITE,
073        StandardOpenOption.TRUNCATE_EXISTING)) {
074      assert writer != null;
075      schemaGenerator.generateFromModule(module, writer, configuration);
076      writer.flush();
077    }
078  }
079
080  /**
081   * Generate a schema for the provided module and write it to the specified
082   * writer.
083   * <p>
084   * The writer is not closed by this method, as the caller is responsible for
085   * managing its lifecycle.
086   *
087   * @param module
088   *          the Metaschema module to generate the schema for
089   * @param writer
090   *          the writer to output the schema to
091   * @param asFormat
092   *          the schema format to generate
093   * @param configuration
094   *          the schema generation configuration
095   * @throws IOException
096   *           if an I/O error occurs while writing the schema
097   */
098  static void generateSchema(
099      @NonNull IModule module,
100      @NonNull Writer writer,
101      @NonNull SchemaFormat asFormat,
102      @NonNull IConfiguration<SchemaGenerationFeature<?>> configuration)
103      throws IOException {
104    ISchemaGenerator schemaGenerator = asFormat.getSchemaGenerator();
105
106    schemaGenerator.generateFromModule(module, writer, configuration);
107    writer.flush();
108    // we don't want to close os, since we do not own it
109  }
110
111  /**
112   * Identifies the supported schema generation formats.
113   */
114  enum SchemaFormat {
115    /**
116     * a JSON Schema.
117     */
118    JSON(new JsonSchemaGenerator()),
119    /**
120     * an XML Schema.
121     */
122    XML(new XmlSchemaGenerator());
123
124    @NonNull
125    private final ISchemaGenerator schemaGenerator;
126
127    SchemaFormat(@NonNull ISchemaGenerator schemaGenerator) {
128      this.schemaGenerator = schemaGenerator;
129    }
130
131    /**
132     * Get the schema generator implementation for this format.
133     *
134     * @return the schema generator
135     */
136    @NonNull
137    public ISchemaGenerator getSchemaGenerator() {
138      return schemaGenerator;
139    }
140  }
141}