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