001/* 002 * SPDX-FileCopyrightText: none 003 * SPDX-License-Identifier: CC0-1.0 004 */ 005 006package dev.metaschema.cli.commands; 007 008import org.apache.commons.cli.CommandLine; 009import org.apache.commons.cli.Option; 010import org.json.JSONObject; 011import org.json.JSONTokener; 012import org.xml.sax.SAXException; 013 014import java.io.IOException; 015import java.io.Reader; 016import java.io.StringReader; 017import java.io.StringWriter; 018import java.net.URL; 019import java.util.ArrayList; 020import java.util.Collection; 021import java.util.List; 022import java.util.Set; 023 024import javax.xml.transform.stream.StreamSource; 025 026import dev.metaschema.cli.processor.CallingContext; 027import dev.metaschema.cli.processor.command.CommandExecutionException; 028import dev.metaschema.cli.processor.command.ICommandExecutor; 029import dev.metaschema.core.configuration.DefaultConfiguration; 030import dev.metaschema.core.configuration.IMutableConfiguration; 031import dev.metaschema.core.model.IModule; 032import dev.metaschema.core.model.constraint.IConstraintSet; 033import dev.metaschema.core.model.validation.JsonSchemaContentValidator; 034import dev.metaschema.core.model.validation.XmlSchemaContentValidator; 035import dev.metaschema.core.util.CollectionUtil; 036import dev.metaschema.core.util.ObjectUtils; 037import dev.metaschema.databind.IBindingContext; 038import dev.metaschema.databind.IBindingContext.ISchemaValidationProvider; 039import dev.metaschema.schemagen.ISchemaGenerator; 040import dev.metaschema.schemagen.ISchemaGenerator.SchemaFormat; 041import dev.metaschema.schemagen.SchemaGenerationFeature; 042import edu.umd.cs.findbugs.annotations.NonNull; 043 044/** 045 * This command implementation supports validation of a content instance based 046 * on a provided Metaschema module. 047 */ 048public class ValidateContentUsingModuleCommand 049 extends AbstractValidateContentCommand { 050 @NonNull 051 private static final String COMMAND = "validate-content"; 052 053 @Override 054 public String getName() { 055 return COMMAND; 056 } 057 058 @Override 059 public String getDescription() { 060 return "Verify that the provided resource is well-formed and valid to the provided Module-based model."; 061 } 062 063 @Override 064 public Collection<? extends Option> gatherOptions() { 065 Collection<? extends Option> orig = super.gatherOptions(); 066 067 List<Option> retval = new ArrayList<>(orig.size() + 1); 068 retval.addAll(orig); 069 retval.add(MetaschemaCommands.METASCHEMA_REQUIRED_OPTION); 070 071 return CollectionUtil.unmodifiableCollection(retval); 072 } 073 074 @Override 075 public ICommandExecutor newExecutor(CallingContext callingContext, CommandLine commandLine) { 076 return new CommandExecutor(callingContext, commandLine); 077 } 078 079 private final class CommandExecutor 080 extends AbstractValidationCommandExecutor { 081 082 private CommandExecutor( 083 @NonNull CallingContext callingContext, 084 @NonNull CommandLine commandLine) { 085 super(callingContext, commandLine); 086 } 087 088 @Override 089 protected IBindingContext getBindingContext(@NonNull Set<IConstraintSet> constraintSets) 090 throws CommandExecutionException { 091 return MetaschemaCommands.newBindingContextWithDynamicCompilation(constraintSets); 092 } 093 094 @SuppressWarnings("synthetic-access") 095 @Override 096 protected IModule getModule( 097 CommandLine commandLine, 098 IBindingContext bindingContext) throws CommandExecutionException { 099 return MetaschemaCommands.loadModule( 100 commandLine, 101 MetaschemaCommands.METASCHEMA_REQUIRED_OPTION, 102 ObjectUtils.notNull(getCurrentWorkingDirectory().toUri()), 103 bindingContext); 104 } 105 106 @Override 107 protected ISchemaValidationProvider getSchemaValidationProvider( 108 IModule module, 109 CommandLine commandLine, 110 IBindingContext bindingContext) { 111 return new ModuleValidationProvider(module); 112 } 113 114 } 115 116 private static final class ModuleValidationProvider implements ISchemaValidationProvider { 117 @NonNull 118 private final IModule module; 119 120 public ModuleValidationProvider(@NonNull IModule module) { 121 this.module = module; 122 } 123 124 @Override 125 public XmlSchemaContentValidator getXmlSchemas( 126 @NonNull URL targetResource, 127 @NonNull IBindingContext bindingContext) throws IOException, SAXException { 128 IMutableConfiguration<SchemaGenerationFeature<?>> configuration = new DefaultConfiguration<>(); 129 130 try (StringWriter writer = new StringWriter()) { 131 ISchemaGenerator.generateSchema(module, writer, SchemaFormat.XML, configuration); 132 try (Reader reader = new StringReader(writer.toString())) { 133 return new XmlSchemaContentValidator( 134 ObjectUtils.notNull(List.of(new StreamSource(reader)))); 135 } 136 } 137 } 138 139 @Override 140 public JsonSchemaContentValidator getJsonSchema( 141 @NonNull JSONObject json, 142 @NonNull IBindingContext bindingContext) throws IOException { 143 IMutableConfiguration<SchemaGenerationFeature<?>> configuration = new DefaultConfiguration<>(); 144 145 try (StringWriter writer = new StringWriter()) { 146 ISchemaGenerator.generateSchema(module, writer, SchemaFormat.JSON, configuration); 147 return new JsonSchemaContentValidator( 148 new JSONObject(new JSONTokener(writer.toString()))); 149 } 150 } 151 } 152}