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.CallingContext;
30 import gov.nist.secauto.metaschema.cli.processor.InvalidArgumentException;
31 import gov.nist.secauto.metaschema.cli.processor.command.ICommandExecutor;
32 import gov.nist.secauto.metaschema.core.configuration.DefaultConfiguration;
33 import gov.nist.secauto.metaschema.core.configuration.IMutableConfiguration;
34 import gov.nist.secauto.metaschema.core.model.IModule;
35 import gov.nist.secauto.metaschema.core.model.MetaschemaException;
36 import gov.nist.secauto.metaschema.core.model.constraint.IConstraintSet;
37 import gov.nist.secauto.metaschema.core.model.util.JsonUtil;
38 import gov.nist.secauto.metaschema.core.model.util.XmlUtil;
39 import gov.nist.secauto.metaschema.core.model.xml.ModuleLoader;
40 import gov.nist.secauto.metaschema.core.util.CollectionUtil;
41 import gov.nist.secauto.metaschema.core.util.ObjectUtils;
42 import gov.nist.secauto.metaschema.databind.IBindingContext;
43 import gov.nist.secauto.metaschema.schemagen.ISchemaGenerator;
44 import gov.nist.secauto.metaschema.schemagen.ISchemaGenerator.SchemaFormat;
45 import gov.nist.secauto.metaschema.schemagen.SchemaGenerationFeature;
46
47 import org.apache.commons.cli.CommandLine;
48 import org.apache.commons.cli.Option;
49 import org.json.JSONObject;
50
51 import java.io.BufferedReader;
52 import java.io.IOException;
53 import java.nio.charset.StandardCharsets;
54 import java.nio.file.Files;
55 import java.nio.file.Path;
56 import java.nio.file.Paths;
57 import java.util.ArrayList;
58 import java.util.Collection;
59 import java.util.List;
60 import java.util.Set;
61
62 import javax.xml.transform.Source;
63
64 import edu.umd.cs.findbugs.annotations.NonNull;
65
66 public class ValidateContentUsingModuleCommand
67 extends AbstractValidateContentCommand {
68 @NonNull
69 private static final String COMMAND = "validate-content";
70
71 @Override
72 public String getName() {
73 return COMMAND;
74 }
75
76 @Override
77 public String getDescription() {
78 return "Verify that the provided resource is well-formed and valid to the provided Module-based model.";
79 }
80
81 @Override
82 public Collection<? extends Option> gatherOptions() {
83 Collection<? extends Option> orig = super.gatherOptions();
84
85 List<Option> retval = new ArrayList<>(orig.size() + 1);
86 retval.addAll(orig);
87 retval.add(MetaschemaCommandSupport.METASCHEMA_OPTION);
88
89 return CollectionUtil.unmodifiableCollection(retval);
90 }
91
92 @Override
93 public void validateOptions(CallingContext callingContext, CommandLine cmdLine) throws InvalidArgumentException {
94 super.validateOptions(callingContext, cmdLine);
95
96 String metaschemaName = cmdLine.getOptionValue(MetaschemaCommandSupport.METASCHEMA_OPTION);
97 Path metaschema = Paths.get(metaschemaName);
98 if (!Files.exists(metaschema)) {
99 throw new InvalidArgumentException("The provided module '" + metaschema + "' does not exist.");
100 }
101 if (!Files.isReadable(metaschema)) {
102 throw new InvalidArgumentException("The provided module '" + metaschema + "' is not readable.");
103 }
104 }
105
106 @Override
107 public ICommandExecutor newExecutor(CallingContext callingContext, CommandLine commandLine) {
108 return new OscalCommandExecutor(callingContext, commandLine);
109 }
110
111 private class OscalCommandExecutor
112 extends AbstractValidationCommandExecutor {
113
114 private Path tempDir;
115 private IModule module;
116
117 private OscalCommandExecutor(
118 @NonNull CallingContext callingContext,
119 @NonNull CommandLine commandLine) {
120 super(callingContext, commandLine);
121 }
122
123 private Path getTempDir() throws IOException {
124 if (tempDir == null) {
125 tempDir = Files.createTempDirectory("validation-");
126 tempDir.toFile().deleteOnExit();
127 }
128 return tempDir;
129 }
130
131 @NonNull
132 private IModule getModule(@NonNull Set<IConstraintSet> constraintSets)
133 throws MetaschemaException, IOException {
134 if (module == null) {
135 String moduleName = getCommandLine().getOptionValue(MetaschemaCommandSupport.METASCHEMA_OPTION);
136 Path modulePath = Paths.get(moduleName);
137 assert modulePath != null;
138
139 ModuleLoader loader = new ModuleLoader(constraintSets);
140 loader.allowEntityResolution();
141 module = loader.load(modulePath);
142 }
143 assert module != null;
144 return module;
145 }
146
147 @NonNull
148 private IModule getModule() {
149
150 return ObjectUtils.requireNonNull(module);
151 }
152
153 @Override
154 protected IBindingContext getBindingContext(@NonNull Set<IConstraintSet> constraintSets)
155 throws MetaschemaException, IOException {
156
157 return IBindingContext.instance().registerModule(getModule(constraintSets), getTempDir());
158 }
159
160 @Override
161 public List<Source> getXmlSchemas() throws IOException {
162 Path schemaFile = Files.createTempFile(getTempDir(), "schema-", ".json");
163 assert schemaFile != null;
164 IMutableConfiguration<SchemaGenerationFeature<?>> configuration = new DefaultConfiguration<>();
165 ISchemaGenerator.generateSchema(getModule(), schemaFile, SchemaFormat.XML, configuration);
166 return ObjectUtils.requireNonNull(List.of(
167 XmlUtil.getStreamSource(schemaFile.toUri().toURL())));
168 }
169
170 @Override
171 public JSONObject getJsonSchema() throws IOException {
172 Path schemaFile = Files.createTempFile(getTempDir(), "schema-", ".json");
173 assert schemaFile != null;
174 IMutableConfiguration<SchemaGenerationFeature<?>> configuration = new DefaultConfiguration<>();
175 ISchemaGenerator.generateSchema(getModule(), schemaFile, SchemaFormat.JSON, configuration);
176 try (BufferedReader reader = ObjectUtils.notNull(Files.newBufferedReader(schemaFile, StandardCharsets.UTF_8))) {
177 return JsonUtil.toJsonObject(reader);
178 }
179 }
180 }
181
182 }