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.command.ICommandExecutor;
10 import gov.nist.secauto.metaschema.core.configuration.DefaultConfiguration;
11 import gov.nist.secauto.metaschema.core.configuration.IMutableConfiguration;
12 import gov.nist.secauto.metaschema.core.model.IModule;
13 import gov.nist.secauto.metaschema.core.model.MetaschemaException;
14 import gov.nist.secauto.metaschema.core.model.constraint.IConstraintSet;
15 import gov.nist.secauto.metaschema.core.model.util.JsonUtil;
16 import gov.nist.secauto.metaschema.core.model.util.XmlUtil;
17 import gov.nist.secauto.metaschema.core.util.CollectionUtil;
18 import gov.nist.secauto.metaschema.core.util.ObjectUtils;
19 import gov.nist.secauto.metaschema.databind.DefaultBindingContext;
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.json.JSONObject;
28
29 import java.io.BufferedReader;
30 import java.io.IOException;
31 import java.net.URI;
32 import java.net.URISyntaxException;
33 import java.net.URL;
34 import java.nio.charset.StandardCharsets;
35 import java.nio.file.Files;
36 import java.nio.file.Path;
37 import java.nio.file.Paths;
38 import java.util.ArrayList;
39 import java.util.Collection;
40 import java.util.List;
41 import java.util.Set;
42
43 import javax.xml.transform.Source;
44
45 import edu.umd.cs.findbugs.annotations.NonNull;
46
47 public class ValidateContentUsingModuleCommand
48 extends AbstractValidateContentCommand {
49 @NonNull
50 private static final String COMMAND = "validate-content";
51
52 @Override
53 public String getName() {
54 return COMMAND;
55 }
56
57 @Override
58 public String getDescription() {
59 return "Verify that the provided resource is well-formed and valid to the provided Module-based model.";
60 }
61
62 @Override
63 public Collection<? extends Option> gatherOptions() {
64 Collection<? extends Option> orig = super.gatherOptions();
65
66 List<Option> retval = new ArrayList<>(orig.size() + 1);
67 retval.addAll(orig);
68 retval.add(MetaschemaCommands.METASCHEMA_OPTION);
69
70 return CollectionUtil.unmodifiableCollection(retval);
71 }
72
73 @Override
74 public ICommandExecutor newExecutor(CallingContext callingContext, CommandLine commandLine) {
75 return new OscalCommandExecutor(callingContext, commandLine);
76 }
77
78 private final class OscalCommandExecutor
79 extends AbstractValidationCommandExecutor {
80
81 private Path tempDir;
82 private IModule module;
83
84 private OscalCommandExecutor(
85 @NonNull CallingContext callingContext,
86 @NonNull CommandLine commandLine) {
87 super(callingContext, commandLine);
88 }
89
90 @NonNull
91 private Path getTempDir() throws IOException {
92 if (tempDir == null) {
93 tempDir = Files.createTempDirectory("validation-");
94 tempDir.toFile().deleteOnExit();
95 }
96 assert tempDir != null;
97 return tempDir;
98 }
99
100 @NonNull
101 private IModule getModule(@NonNull Set<IConstraintSet> constraintSets)
102 throws MetaschemaException, IOException {
103 URI cwd = ObjectUtils.notNull(Paths.get("").toAbsolutePath().toUri());
104
105 if (module == null) {
106 try {
107 module = MetaschemaCommands.handleModule(getCommandLine(), cwd, constraintSets);
108 } catch (URISyntaxException ex) {
109 throw new IOException(String.format("Cannot load module as '%s' is not a valid file or URL.", ex.getInput()),
110 ex);
111 }
112 }
113
114 assert module != null;
115 return module;
116 }
117
118 @NonNull
119 private IModule getModule() {
120
121 return ObjectUtils.requireNonNull(module);
122 }
123
124 @Override
125 protected IBindingContext getBindingContext(@NonNull Set<IConstraintSet> constraintSets)
126 throws MetaschemaException, IOException {
127
128 IBindingContext retval = new DefaultBindingContext();
129 retval.registerModule(getModule(constraintSets), getTempDir());
130 return retval;
131 }
132
133 @Override
134 public List<Source> getXmlSchemas(@NonNull URL targetResource) throws IOException {
135 Path schemaFile = Files.createTempFile(getTempDir(), "schema-", ".xml");
136 assert schemaFile != null;
137 IMutableConfiguration<SchemaGenerationFeature<?>> configuration = new DefaultConfiguration<>();
138 ISchemaGenerator.generateSchema(getModule(), schemaFile, SchemaFormat.XML, configuration);
139 return ObjectUtils.requireNonNull(List.of(
140 XmlUtil.getStreamSource(ObjectUtils.notNull(schemaFile.toUri().toURL()))));
141 }
142
143 @Override
144 public JSONObject getJsonSchema(@NonNull JSONObject json) throws IOException {
145 Path schemaFile = Files.createTempFile(getTempDir(), "schema-", ".json");
146 assert schemaFile != null;
147 IMutableConfiguration<SchemaGenerationFeature<?>> configuration = new DefaultConfiguration<>();
148 ISchemaGenerator.generateSchema(getModule(), schemaFile, SchemaFormat.JSON, configuration);
149 try (BufferedReader reader = ObjectUtils.notNull(Files.newBufferedReader(schemaFile, StandardCharsets.UTF_8))) {
150 return JsonUtil.toJsonObject(reader);
151 }
152 }
153 }
154
155 }