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