001/* 002 * SPDX-FileCopyrightText: none 003 * SPDX-License-Identifier: CC0-1.0 004 */ 005 006package gov.nist.secauto.metaschema.cli.commands; 007 008import gov.nist.secauto.metaschema.cli.processor.CLIProcessor.CallingContext; 009import gov.nist.secauto.metaschema.cli.processor.command.ICommandExecutor; 010import gov.nist.secauto.metaschema.core.configuration.DefaultConfiguration; 011import gov.nist.secauto.metaschema.core.configuration.IMutableConfiguration; 012import gov.nist.secauto.metaschema.core.model.IModule; 013import gov.nist.secauto.metaschema.core.model.MetaschemaException; 014import gov.nist.secauto.metaschema.core.model.constraint.IConstraintSet; 015import gov.nist.secauto.metaschema.core.model.util.JsonUtil; 016import gov.nist.secauto.metaschema.core.model.util.XmlUtil; 017import gov.nist.secauto.metaschema.core.util.CollectionUtil; 018import gov.nist.secauto.metaschema.core.util.ObjectUtils; 019import gov.nist.secauto.metaschema.databind.DefaultBindingContext; 020import gov.nist.secauto.metaschema.databind.IBindingContext; 021import gov.nist.secauto.metaschema.schemagen.ISchemaGenerator; 022import gov.nist.secauto.metaschema.schemagen.ISchemaGenerator.SchemaFormat; 023import gov.nist.secauto.metaschema.schemagen.SchemaGenerationFeature; 024 025import org.apache.commons.cli.CommandLine; 026import org.apache.commons.cli.Option; 027import org.json.JSONObject; 028 029import java.io.BufferedReader; 030import java.io.IOException; 031import java.net.URI; 032import java.net.URISyntaxException; 033import java.net.URL; 034import java.nio.charset.StandardCharsets; 035import java.nio.file.Files; 036import java.nio.file.Path; 037import java.nio.file.Paths; 038import java.util.ArrayList; 039import java.util.Collection; 040import java.util.List; 041import java.util.Set; 042 043import javax.xml.transform.Source; 044 045import edu.umd.cs.findbugs.annotations.NonNull; 046 047public class ValidateContentUsingModuleCommand 048 extends AbstractValidateContentCommand { 049 @NonNull 050 private static final String COMMAND = "validate-content"; 051 052 @Override 053 public String getName() { 054 return COMMAND; 055 } 056 057 @Override 058 public String getDescription() { 059 return "Verify that the provided resource is well-formed and valid to the provided Module-based model."; 060 } 061 062 @Override 063 public Collection<? extends Option> gatherOptions() { 064 Collection<? extends Option> orig = super.gatherOptions(); 065 066 List<Option> retval = new ArrayList<>(orig.size() + 1); 067 retval.addAll(orig); 068 retval.add(MetaschemaCommands.METASCHEMA_OPTION); 069 070 return CollectionUtil.unmodifiableCollection(retval); 071 } 072 073 @Override 074 public ICommandExecutor newExecutor(CallingContext callingContext, CommandLine commandLine) { 075 return new OscalCommandExecutor(callingContext, commandLine); 076 } 077 078 private final class OscalCommandExecutor 079 extends AbstractValidationCommandExecutor { 080 081 private Path tempDir; 082 private IModule module; 083 084 private OscalCommandExecutor( 085 @NonNull CallingContext callingContext, 086 @NonNull CommandLine commandLine) { 087 super(callingContext, commandLine); 088 } 089 090 @NonNull 091 private Path getTempDir() throws IOException { 092 if (tempDir == null) { 093 tempDir = Files.createTempDirectory("validation-"); 094 tempDir.toFile().deleteOnExit(); 095 } 096 assert tempDir != null; 097 return tempDir; 098 } 099 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 // should be initialized already 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}