1
2
3
4
5
6 package dev.metaschema.maven.plugin;
7
8 import org.apache.maven.plugin.MojoExecutionException;
9 import org.apache.maven.plugins.annotations.LifecyclePhase;
10 import org.apache.maven.plugins.annotations.Mojo;
11 import org.apache.maven.plugins.annotations.Parameter;
12
13 import java.io.File;
14 import java.io.IOException;
15 import java.io.Writer;
16 import java.nio.charset.StandardCharsets;
17 import java.nio.file.Files;
18 import java.nio.file.Path;
19 import java.nio.file.StandardOpenOption;
20 import java.util.EnumSet;
21 import java.util.LinkedList;
22 import java.util.List;
23 import java.util.Locale;
24 import java.util.Set;
25
26 import dev.metaschema.core.configuration.DefaultConfiguration;
27 import dev.metaschema.core.configuration.IConfiguration;
28 import dev.metaschema.core.configuration.IMutableConfiguration;
29 import dev.metaschema.core.model.IModule;
30 import dev.metaschema.core.util.CollectionUtil;
31 import dev.metaschema.core.util.ObjectUtils;
32 import dev.metaschema.schemagen.ISchemaGenerator;
33 import dev.metaschema.schemagen.SchemaGenerationFeature;
34 import dev.metaschema.schemagen.json.JsonSchemaGenerator;
35 import dev.metaschema.schemagen.xml.XmlSchemaGenerator;
36 import edu.umd.cs.findbugs.annotations.NonNull;
37
38
39
40
41
42 @Mojo(name = "generate-schemas", defaultPhase = LifecyclePhase.GENERATE_RESOURCES)
43 public class GenerateSchemaMojo
44 extends AbstractMetaschemaMojo {
45
46
47
48 public enum SchemaFormat {
49
50
51
52 XSD,
53
54
55
56 JSON_SCHEMA;
57 }
58
59 @NonNull
60 private static final String STALE_FILE_NAME = "generateSschemaStaleFile";
61
62 @NonNull
63 private static final XmlSchemaGenerator XML_SCHEMA_GENERATOR = new XmlSchemaGenerator();
64 @NonNull
65 private static final JsonSchemaGenerator JSON_SCHEMA_GENERATOR = new JsonSchemaGenerator();
66
67
68
69
70
71
72
73
74
75
76
77
78
79 @Parameter
80 private List<String> formats;
81
82
83
84
85
86 @Parameter(defaultValue = "true")
87 @SuppressWarnings("PMD.ImmutableField")
88 private boolean inlineDefinitions = true;
89
90
91
92
93
94
95
96 @Parameter(defaultValue = "false")
97 private boolean inlineChoiceDefinitions;
98
99
100
101
102
103
104
105 protected boolean isInlineDefinitions() {
106 return inlineDefinitions;
107 }
108
109
110
111
112
113
114
115 protected boolean isInlineChoiceDefinitions() {
116 return inlineChoiceDefinitions;
117 }
118
119
120
121
122
123
124
125
126
127
128
129 @Override
130 protected String getStaleFileName() {
131 return STALE_FILE_NAME;
132 }
133
134
135
136
137
138
139
140
141
142
143 @Override
144 @NonNull
145 protected List<File> generate(@NonNull Set<IModule> modules) throws MojoExecutionException {
146 IMutableConfiguration<SchemaGenerationFeature<?>> schemaGenerationConfig
147 = new DefaultConfiguration<>();
148
149 if (isInlineDefinitions()) {
150 schemaGenerationConfig.enableFeature(SchemaGenerationFeature.INLINE_DEFINITIONS);
151 } else {
152 schemaGenerationConfig.disableFeature(SchemaGenerationFeature.INLINE_DEFINITIONS);
153 }
154
155 if (isInlineChoiceDefinitions()) {
156 schemaGenerationConfig.enableFeature(SchemaGenerationFeature.INLINE_CHOICE_DEFINITIONS);
157 } else {
158 schemaGenerationConfig.disableFeature(SchemaGenerationFeature.INLINE_CHOICE_DEFINITIONS);
159 }
160
161 Set<SchemaFormat> schemaFormats;
162 if (formats != null) {
163 schemaFormats = ObjectUtils.notNull(EnumSet.noneOf(SchemaFormat.class));
164 for (String format : formats) {
165 switch (format.toLowerCase(Locale.ROOT)) {
166 case "xsd":
167 schemaFormats.add(SchemaFormat.XSD);
168 break;
169 case "json":
170 schemaFormats.add(SchemaFormat.JSON_SCHEMA);
171 break;
172 default:
173 throw new IllegalStateException("Unsupported schema format: " + format);
174 }
175 }
176 } else {
177 schemaFormats = ObjectUtils.notNull(EnumSet.allOf(SchemaFormat.class));
178 }
179
180 Path outputDirectory = ObjectUtils.notNull(getOutputDirectory().toPath());
181 List<File> generatedSchemas = new LinkedList<>();
182 for (IModule module : modules) {
183 if (getLog().isInfoEnabled()) {
184 getLog().info(String.format("Processing metaschema: %s", module.getLocation()));
185 }
186 if (module.getExportedRootAssemblyDefinitions().isEmpty()) {
187 continue;
188 }
189 generatedSchemas.addAll(generateSchemas(module, schemaGenerationConfig, outputDirectory, schemaFormats));
190 }
191 return CollectionUtil.unmodifiableList(generatedSchemas);
192 }
193
194 @SuppressWarnings("PMD.AvoidCatchingGenericException")
195 @NonNull
196 private static List<File> generateSchemas(
197 @NonNull IModule module,
198 @NonNull IConfiguration<SchemaGenerationFeature<?>> schemaGenerationConfig,
199 @NonNull Path outputDirectory,
200 @NonNull Set<SchemaFormat> schemaFormats) throws MojoExecutionException {
201
202 String shortName = module.getShortName();
203
204 List<File> generatedSchemas = new LinkedList<>();
205 if (schemaFormats.contains(SchemaFormat.XSD)) {
206 try {
207 String filename = String.format("%s_schema.xsd", shortName);
208 Path xmlSchema = ObjectUtils.notNull(outputDirectory.resolve(filename));
209 generateSchema(module, schemaGenerationConfig, xmlSchema, XML_SCHEMA_GENERATOR);
210 generatedSchemas.add(xmlSchema.toFile());
211 } catch (Exception ex) {
212 throw new MojoExecutionException("Unable to generate XML schema.", ex);
213 }
214 }
215
216 if (schemaFormats.contains(SchemaFormat.JSON_SCHEMA)) {
217 try {
218 String filename = String.format("%s_schema.json", shortName);
219 Path jsonSchema = ObjectUtils.notNull(outputDirectory.resolve(filename));
220 generateSchema(module, schemaGenerationConfig, jsonSchema, JSON_SCHEMA_GENERATOR);
221 generatedSchemas.add(jsonSchema.toFile());
222 } catch (Exception ex) {
223 throw new MojoExecutionException("Unable to generate JSON schema.", ex);
224 }
225 }
226 return CollectionUtil.unmodifiableList(generatedSchemas);
227 }
228
229 private static void generateSchema(
230 @NonNull IModule module,
231 @NonNull IConfiguration<SchemaGenerationFeature<?>> schemaGenerationConfig,
232 @NonNull Path schemaPath,
233 @NonNull ISchemaGenerator generator) throws IOException {
234 try (@SuppressWarnings("resource")
235 Writer writer = ObjectUtils.notNull(Files.newBufferedWriter(
236 schemaPath,
237 StandardCharsets.UTF_8,
238 StandardOpenOption.CREATE,
239 StandardOpenOption.WRITE,
240 StandardOpenOption.TRUNCATE_EXISTING))) {
241 generator.generateFromModule(module, writer, schemaGenerationConfig);
242 }
243 }
244 }