1   /*
2    * SPDX-FileCopyrightText: none
3    * SPDX-License-Identifier: CC0-1.0
4    */
5   
6   package dev.metaschema.schemagen;
7   
8   import java.io.IOException;
9   import java.io.Writer;
10  import java.nio.charset.StandardCharsets;
11  import java.nio.file.Files;
12  import java.nio.file.Path;
13  import java.nio.file.StandardOpenOption;
14  
15  import dev.metaschema.core.configuration.IConfiguration;
16  import dev.metaschema.core.model.IModule;
17  import dev.metaschema.schemagen.json.JsonSchemaGenerator;
18  import dev.metaschema.schemagen.xml.XmlSchemaGenerator;
19  import edu.umd.cs.findbugs.annotations.NonNull;
20  
21  /**
22   * Provides the capability to generate a schema from a Metaschema module.
23   */
24  @FunctionalInterface
25  public interface ISchemaGenerator {
26    /**
27     * Generate and write a schema for the provided {@code metaschema} to the
28     * {@link Writer} provided by {@code writer} using the provided
29     * {@code configuration}.
30     *
31     * @param metaschema
32     *          the Module to generate the schema for
33     * @param writer
34     *          the writer to use to write the schema
35     * @param configuration
36     *          the schema generation configuration
37     * @throws SchemaGenerationException
38     *           if an error occurred while writing the schema
39     */
40    void generateFromModule(
41        @NonNull IModule metaschema,
42        @NonNull Writer writer,
43        @NonNull IConfiguration<SchemaGenerationFeature<?>> configuration);
44  
45    /**
46     * Generate a schema for the provided module and write it to the specified file
47     * path.
48     *
49     * @param module
50     *          the Metaschema module to generate the schema for
51     * @param destination
52     *          the file path to write the schema to
53     * @param asFormat
54     *          the schema format to generate
55     * @param configuration
56     *          the schema generation configuration
57     * @throws IOException
58     *           if an I/O error occurs while writing the schema
59     */
60    static void generateSchema(
61        @NonNull IModule module,
62        @NonNull Path destination,
63        @NonNull SchemaFormat asFormat,
64        @NonNull IConfiguration<SchemaGenerationFeature<?>> configuration)
65        throws IOException {
66      ISchemaGenerator schemaGenerator = asFormat.getSchemaGenerator();
67  
68      try (Writer writer = Files.newBufferedWriter(
69          destination,
70          StandardCharsets.UTF_8,
71          StandardOpenOption.CREATE,
72          StandardOpenOption.WRITE,
73          StandardOpenOption.TRUNCATE_EXISTING)) {
74        assert writer != null;
75        schemaGenerator.generateFromModule(module, writer, configuration);
76        writer.flush();
77      }
78    }
79  
80    /**
81     * Generate a schema for the provided module and write it to the specified
82     * writer.
83     * <p>
84     * The writer is not closed by this method, as the caller is responsible for
85     * managing its lifecycle.
86     *
87     * @param module
88     *          the Metaschema module to generate the schema for
89     * @param writer
90     *          the writer to output the schema to
91     * @param asFormat
92     *          the schema format to generate
93     * @param configuration
94     *          the schema generation configuration
95     * @throws IOException
96     *           if an I/O error occurs while writing the schema
97     */
98    static void generateSchema(
99        @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 }