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