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.AbstractCommandExecutor;
11 import gov.nist.secauto.metaschema.cli.processor.command.AbstractTerminalCommand;
12 import gov.nist.secauto.metaschema.cli.processor.command.CommandExecutionException;
13 import gov.nist.secauto.metaschema.cli.processor.command.ExtraArgument;
14 import gov.nist.secauto.metaschema.core.model.MetaschemaException;
15 import gov.nist.secauto.metaschema.core.util.AutoCloser;
16 import gov.nist.secauto.metaschema.core.util.ObjectUtils;
17 import gov.nist.secauto.metaschema.databind.IBindingContext;
18 import gov.nist.secauto.metaschema.databind.io.Format;
19 import gov.nist.secauto.metaschema.databind.io.IBoundLoader;
20
21 import org.apache.commons.cli.CommandLine;
22 import org.apache.commons.cli.Option;
23 import org.apache.logging.log4j.LogManager;
24 import org.apache.logging.log4j.Logger;
25
26 import java.io.FileNotFoundException;
27 import java.io.IOException;
28 import java.io.OutputStreamWriter;
29 import java.io.Writer;
30 import java.net.URI;
31 import java.nio.charset.StandardCharsets;
32 import java.nio.file.Files;
33 import java.nio.file.Path;
34 import java.nio.file.StandardOpenOption;
35 import java.util.Collection;
36 import java.util.List;
37
38 import edu.umd.cs.findbugs.annotations.NonNull;
39
40
41
42
43 public abstract class AbstractConvertSubcommand
44 extends AbstractTerminalCommand {
45 private static final Logger LOGGER = LogManager.getLogger(AbstractConvertSubcommand.class);
46
47 @NonNull
48 private static final String COMMAND = "convert";
49 @NonNull
50 private static final List<ExtraArgument> EXTRA_ARGUMENTS = ObjectUtils.notNull(List.of(
51 ExtraArgument.newInstance("source-file-or-URL", true),
52 ExtraArgument.newInstance("destination-file", false)));
53
54 @Override
55 public String getName() {
56 return COMMAND;
57 }
58
59 @Override
60 public Collection<? extends Option> gatherOptions() {
61 return ObjectUtils.notNull(List.of(
62 MetaschemaCommands.OVERWRITE_OPTION,
63 MetaschemaCommands.TO_OPTION));
64 }
65
66 @Override
67 public List<ExtraArgument> getExtraArguments() {
68 return EXTRA_ARGUMENTS;
69 }
70
71
72
73
74
75 protected abstract static class AbstractConversionCommandExecutor
76 extends AbstractCommandExecutor {
77
78
79
80
81
82
83
84
85
86 protected AbstractConversionCommandExecutor(
87 @NonNull CallingContext callingContext,
88 @NonNull CommandLine commandLine) {
89 super(callingContext, commandLine);
90 }
91
92
93
94
95
96
97
98
99
100
101
102 @NonNull
103 protected abstract IBindingContext getBindingContext() throws CommandExecutionException, MetaschemaException;
104
105 @SuppressWarnings({
106 "PMD.OnlyOneReturn",
107 "PMD.CyclomaticComplexity", "PMD.CognitiveComplexity"
108 })
109 @Override
110 public void execute() throws CommandExecutionException {
111 CommandLine cmdLine = getCommandLine();
112
113 List<String> extraArgs = cmdLine.getArgList();
114
115 Path destination = null;
116 if (extraArgs.size() > 1) {
117 destination = MetaschemaCommands.handleDestination(ObjectUtils.requireNonNull(extraArgs.get(1)), cmdLine);
118 }
119
120 @SuppressWarnings("synthetic-access")
121 URI source = MetaschemaCommands.handleSource(
122 ObjectUtils.requireNonNull(extraArgs.get(0)),
123 ObjectUtils.notNull(getCurrentWorkingDirectory().toUri()));
124
125 Format toFormat = MetaschemaCommands.getFormat(cmdLine, MetaschemaCommands.TO_OPTION);
126
127 try {
128 IBindingContext bindingContext = getBindingContext();
129 IBoundLoader loader = bindingContext.newBoundLoader();
130 if (LOGGER.isInfoEnabled()) {
131 LOGGER.info("Converting '{}'.", source);
132 }
133
134 if (destination == null) {
135
136 try (OutputStreamWriter writer
137 = new OutputStreamWriter(AutoCloser.preventClose(System.out), StandardCharsets.UTF_8)) {
138 handleConversion(source, toFormat, writer, loader);
139 }
140 } else {
141 try (Writer writer = Files.newBufferedWriter(
142 destination,
143 StandardCharsets.UTF_8,
144 StandardOpenOption.CREATE,
145 StandardOpenOption.WRITE,
146 StandardOpenOption.TRUNCATE_EXISTING)) {
147 assert writer != null;
148 handleConversion(source, toFormat, writer, loader);
149 }
150 }
151 } catch (IllegalArgumentException | MetaschemaException ex) {
152 throw new CommandExecutionException(ExitCode.PROCESSING_ERROR, ex);
153 } catch (IOException ex) {
154 throw new CommandExecutionException(ExitCode.IO_ERROR, ex);
155 }
156 if (destination != null && LOGGER.isInfoEnabled()) {
157 LOGGER.info("Generated {} file: {}", toFormat.toString(), destination);
158 }
159 }
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177 protected abstract void handleConversion(
178 @NonNull URI source,
179 @NonNull Format toFormat,
180 @NonNull Writer writer,
181 @NonNull IBoundLoader loader) throws FileNotFoundException, IOException;
182 }
183 }