1
2
3
4
5
6 package gov.nist.secauto.metaschema.cli.commands;
7
8 import gov.nist.secauto.metaschema.cli.processor.CLIProcessor.CallingContext;
9 import gov.nist.secauto.metaschema.cli.processor.ExitCode;
10 import gov.nist.secauto.metaschema.cli.processor.command.AbstractTerminalCommand;
11 import gov.nist.secauto.metaschema.cli.processor.command.CommandExecutionException;
12 import gov.nist.secauto.metaschema.cli.processor.command.ExtraArgument;
13 import gov.nist.secauto.metaschema.cli.processor.command.ICommandExecutor;
14 import gov.nist.secauto.metaschema.core.configuration.DefaultConfiguration;
15 import gov.nist.secauto.metaschema.core.configuration.IMutableConfiguration;
16 import gov.nist.secauto.metaschema.core.model.IModule;
17 import gov.nist.secauto.metaschema.core.model.MetaschemaException;
18 import gov.nist.secauto.metaschema.core.util.AutoCloser;
19 import gov.nist.secauto.metaschema.core.util.ObjectUtils;
20 import gov.nist.secauto.metaschema.databind.IBindingContext;
21 import gov.nist.secauto.metaschema.schemagen.ISchemaGenerator;
22 import gov.nist.secauto.metaschema.schemagen.ISchemaGenerator.SchemaFormat;
23 import gov.nist.secauto.metaschema.schemagen.SchemaGenerationFeature;
24
25 import org.apache.commons.cli.CommandLine;
26 import org.apache.commons.cli.Option;
27 import org.apache.logging.log4j.LogManager;
28 import org.apache.logging.log4j.Logger;
29
30 import java.io.IOException;
31 import java.io.OutputStream;
32 import java.io.OutputStreamWriter;
33 import java.nio.charset.StandardCharsets;
34 import java.nio.file.Path;
35 import java.util.Collection;
36 import java.util.List;
37
38 import edu.umd.cs.findbugs.annotations.NonNull;
39 import edu.umd.cs.findbugs.annotations.Nullable;
40
41
42
43
44
45 class GenerateSchemaCommand
46 extends AbstractTerminalCommand {
47 private static final Logger LOGGER = LogManager.getLogger(GenerateSchemaCommand.class);
48
49 @NonNull
50 private static final String COMMAND = "generate-schema";
51 @NonNull
52 private static final List<ExtraArgument> EXTRA_ARGUMENTS = ObjectUtils.notNull(List.of(
53 ExtraArgument.newInstance("metaschema-module-file-or-URL", true),
54 ExtraArgument.newInstance("destination-schema-file", false)));
55
56 private static final Option INLINE_TYPES_OPTION = ObjectUtils.notNull(
57 Option.builder()
58 .longOpt("inline-types")
59 .desc("definitions declared inline will be generated as inline types")
60 .get());
61
62 @Override
63 public String getName() {
64 return COMMAND;
65 }
66
67 @Override
68 public String getDescription() {
69 return "Generate a schema for the specified Module module";
70 }
71
72 @SuppressWarnings("null")
73 @Override
74 public Collection<? extends Option> gatherOptions() {
75 return List.of(
76 MetaschemaCommands.OVERWRITE_OPTION,
77 MetaschemaCommands.AS_SCHEMA_FORMAT_OPTION,
78 INLINE_TYPES_OPTION);
79 }
80
81 @Override
82 public List<ExtraArgument> getExtraArguments() {
83 return EXTRA_ARGUMENTS;
84 }
85
86 @Override
87 public ICommandExecutor newExecutor(CallingContext callingContext, CommandLine cmdLine) {
88 return ICommandExecutor.using(callingContext, cmdLine, this::executeCommand);
89 }
90
91
92
93
94
95
96
97
98
99
100
101 protected void executeCommand(
102 @NonNull CallingContext callingContext,
103 @NonNull CommandLine cmdLine) throws CommandExecutionException {
104 List<String> extraArgs = cmdLine.getArgList();
105
106 Path destination = extraArgs.size() > 1
107 ? MetaschemaCommands.handleDestination(
108 ObjectUtils.requireNonNull(extraArgs.get(1)),
109 cmdLine)
110 : null;
111
112 SchemaFormat asFormat = MetaschemaCommands.getSchemaFormat(cmdLine, MetaschemaCommands.AS_SCHEMA_FORMAT_OPTION);
113
114 IMutableConfiguration<SchemaGenerationFeature<?>> configuration = createConfiguration(cmdLine, asFormat);
115 generateSchema(extraArgs, destination, asFormat, configuration);
116 }
117
118 @NonNull
119 private static IMutableConfiguration<SchemaGenerationFeature<?>> createConfiguration(
120 @NonNull CommandLine cmdLine,
121 @NonNull SchemaFormat asFormat) {
122 IMutableConfiguration<SchemaGenerationFeature<?>> configuration = new DefaultConfiguration<>();
123 if (cmdLine.hasOption(INLINE_TYPES_OPTION)) {
124 configuration.enableFeature(SchemaGenerationFeature.INLINE_DEFINITIONS);
125 if (SchemaFormat.JSON.equals(asFormat)) {
126 configuration.disableFeature(SchemaGenerationFeature.INLINE_CHOICE_DEFINITIONS);
127 } else {
128 configuration.enableFeature(SchemaGenerationFeature.INLINE_CHOICE_DEFINITIONS);
129 }
130 }
131 return configuration;
132 }
133
134 private static void generateSchema(
135 @NonNull List<String> extraArgs,
136 @Nullable Path destination,
137 @NonNull SchemaFormat asFormat,
138 @NonNull IMutableConfiguration<SchemaGenerationFeature<?>> configuration) throws CommandExecutionException {
139 IBindingContext bindingContext = MetaschemaCommands.newBindingContextWithDynamicCompilation();
140 IModule module = MetaschemaCommands.loadModule(
141 ObjectUtils.requireNonNull(extraArgs.get(0)),
142 ObjectUtils.notNull(getCurrentWorkingDirectory().toUri()),
143 bindingContext);
144
145 try {
146 bindingContext.registerModule(module);
147 if (LOGGER.isInfoEnabled()) {
148 LOGGER.info("Generating {} schema for '{}'.", asFormat.name(), extraArgs.get(0));
149 }
150 if (destination == null) {
151 @SuppressWarnings({ "resource", "PMD.CloseResource" })
152 OutputStream os = ObjectUtils.notNull(System.out);
153
154 try (OutputStream out = AutoCloser.preventClose(os)) {
155 try (OutputStreamWriter writer = new OutputStreamWriter(out, StandardCharsets.UTF_8)) {
156 ISchemaGenerator.generateSchema(module, writer, asFormat, configuration);
157 }
158 }
159 } else {
160 ISchemaGenerator.generateSchema(module, destination, asFormat, configuration);
161 }
162 } catch (IOException | MetaschemaException ex) {
163 throw new CommandExecutionException(ExitCode.PROCESSING_ERROR, ex);
164 }
165 if (destination != null && LOGGER.isInfoEnabled()) {
166 LOGGER.info("Generated {} schema file: {}", asFormat.toString(), destination);
167 }
168 }
169 }