1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 package gov.nist.secauto.metaschema.cli.commands;
28
29 import gov.nist.secauto.metaschema.cli.processor.CLIProcessor;
30 import gov.nist.secauto.metaschema.cli.processor.CLIProcessor.CallingContext;
31 import gov.nist.secauto.metaschema.cli.processor.ExitCode;
32 import gov.nist.secauto.metaschema.cli.processor.ExitStatus;
33 import gov.nist.secauto.metaschema.cli.processor.InvalidArgumentException;
34 import gov.nist.secauto.metaschema.cli.processor.command.AbstractTerminalCommand;
35 import gov.nist.secauto.metaschema.cli.processor.command.DefaultExtraArgument;
36 import gov.nist.secauto.metaschema.cli.processor.command.ExtraArgument;
37 import gov.nist.secauto.metaschema.cli.processor.command.ICommandExecutor;
38 import gov.nist.secauto.metaschema.cli.util.LoggingValidationHandler;
39 import gov.nist.secauto.metaschema.core.model.util.XmlUtil;
40 import gov.nist.secauto.metaschema.core.model.validation.IContentValidator;
41 import gov.nist.secauto.metaschema.core.model.validation.IValidationResult;
42 import gov.nist.secauto.metaschema.core.model.xml.ModuleLoader;
43 import gov.nist.secauto.metaschema.core.util.CollectionUtil;
44 import gov.nist.secauto.metaschema.core.util.ObjectUtils;
45
46 import org.apache.commons.cli.CommandLine;
47 import org.apache.logging.log4j.LogManager;
48 import org.apache.logging.log4j.Logger;
49 import org.xml.sax.SAXException;
50
51 import java.io.File;
52 import java.io.IOException;
53 import java.nio.file.Path;
54 import java.nio.file.Paths;
55 import java.util.LinkedList;
56 import java.util.List;
57
58 import javax.xml.transform.Source;
59
60 import edu.umd.cs.findbugs.annotations.NonNull;
61
62 public class ValidateModuleCommand
63 extends AbstractTerminalCommand {
64 private static final Logger LOGGER = LogManager.getLogger(ValidateModuleCommand.class);
65 @NonNull
66 private static final String COMMAND = "validate";
67 @NonNull
68 private static final List<ExtraArgument> EXTRA_ARGUMENTS;
69
70 static {
71 EXTRA_ARGUMENTS = ObjectUtils.notNull(List.of(
72 new DefaultExtraArgument("Module file to validate", true)));
73 }
74
75 @Override
76 public String getName() {
77 return COMMAND;
78 }
79
80 @Override
81 public String getDescription() {
82 return "Validate that the specified Module is well-formed and valid to the Module model";
83 }
84
85 @Override
86 public List<ExtraArgument> getExtraArguments() {
87 return EXTRA_ARGUMENTS;
88 }
89
90 @NonNull
91 protected List<Source> getXmlSchemaSources() throws IOException {
92 List<Source> retval = new LinkedList<>();
93 retval.add(XmlUtil.getStreamSource(
94 ObjectUtils.requireNonNull(
95 ModuleLoader.class.getResource("/schema/xml/metaschema.xsd"),
96 "Unable to load '/schema/xml/metaschema.xsd' on the classpath")));
97 return CollectionUtil.unmodifiableList(retval);
98 }
99
100 @Override
101 public void validateOptions(CallingContext callingContext, CommandLine cmdLine) throws InvalidArgumentException {
102 List<String> extraArgs = cmdLine.getArgList();
103 if (extraArgs.size() != 1) {
104 throw new InvalidArgumentException("The source to validate must be provided.");
105 }
106
107 File target = new File(extraArgs.get(0));
108 if (!target.exists()) {
109 throw new InvalidArgumentException("The provided source file '" + target.getPath() + "' does not exist.");
110 }
111 if (!target.canRead()) {
112 throw new InvalidArgumentException("The provided source file '" + target.getPath() + "' is not readable.");
113 }
114 }
115
116 @Override
117 public ICommandExecutor newExecutor(CallingContext callingContext, CommandLine cmdLine) {
118 return ICommandExecutor.using(callingContext, cmdLine, this::executeCommand);
119 }
120
121 @SuppressWarnings({ "PMD.OnlyOneReturn", "unused" })
122 @NonNull
123 protected ExitStatus executeCommand(CallingContext callingContext, CommandLine cmdLine) {
124 List<String> extraArgs = cmdLine.getArgList();
125 Path target = Paths.get(extraArgs.get(0));
126 assert target != null;
127
128 IValidationResult schemaValidationResult;
129 try {
130 List<Source> schemaSources = getXmlSchemaSources();
131 schemaValidationResult = IContentValidator.validateWithXmlSchema(
132 ObjectUtils.notNull(target.toUri()),
133 schemaSources);
134 } catch (IOException | SAXException ex) {
135 return ExitCode.PROCESSING_ERROR.exit().withThrowable(ex);
136 }
137
138 if (!schemaValidationResult.isPassing()) {
139 if (LOGGER.isErrorEnabled()) {
140 LOGGER.error("The file '{}' has validation issue(s). The issues are:", target);
141 }
142 LoggingValidationHandler.instance().handleValidationResults(schemaValidationResult);
143 return ExitCode.FAIL.exit();
144 }
145
146 if (schemaValidationResult.isPassing() && !cmdLine.hasOption(CLIProcessor.QUIET_OPTION) && LOGGER.isInfoEnabled()) {
147 LOGGER.info("The file '{}' is valid.", target);
148 }
149 return ExitCode.OK.exit();
150 }
151 }