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.json.JSONObject; 010import org.xml.sax.SAXException; 011 012import java.io.BufferedReader; 013import java.io.IOException; 014import java.io.InputStream; 015import java.io.InputStreamReader; 016import java.net.URL; 017import java.nio.charset.StandardCharsets; 018import java.util.LinkedList; 019import java.util.List; 020import java.util.Set; 021 022import javax.xml.transform.Source; 023import javax.xml.transform.stream.StreamSource; 024 025import dev.metaschema.cli.processor.CallingContext; 026import dev.metaschema.cli.processor.ExitCode; 027import dev.metaschema.cli.processor.command.CommandExecutionException; 028import dev.metaschema.cli.processor.command.ICommandExecutor; 029import dev.metaschema.core.model.IModule; 030import dev.metaschema.core.model.MetaschemaException; 031import dev.metaschema.core.model.constraint.IConstraintSet; 032import dev.metaschema.core.model.util.JsonUtil; 033import dev.metaschema.core.model.validation.JsonSchemaContentValidator; 034import dev.metaschema.core.model.validation.XmlSchemaContentValidator; 035import dev.metaschema.core.util.ObjectUtils; 036import dev.metaschema.databind.IBindingContext; 037import dev.metaschema.databind.IBindingContext.ISchemaValidationProvider; 038import dev.metaschema.databind.model.metaschema.binding.MetaschemaModelModule; 039import edu.umd.cs.findbugs.annotations.NonNull; 040import nl.talsmasoftware.lazy4j.Lazy; 041 042/** 043 * This command implementation supports validation of a Metaschema module. 044 */ 045public class ValidateModuleCommand 046 extends AbstractValidateContentCommand { 047 @NonNull 048 private static final String COMMAND = "validate"; 049 050 @Override 051 public String getName() { 052 return COMMAND; 053 } 054 055 @Override 056 public String getDescription() { 057 return "Validate that the specified Module is well-formed and valid to the Module model"; 058 } 059 060 @Override 061 public ICommandExecutor newExecutor(CallingContext callingContext, CommandLine commandLine) { 062 return new CommandExecutor(callingContext, commandLine); 063 } 064 065 private final class CommandExecutor 066 extends AbstractValidationCommandExecutor { 067 private final Lazy<ValidationProvider> validationProvider = Lazy.of(ValidationProvider::new); 068 069 private CommandExecutor( 070 @NonNull CallingContext callingContext, 071 @NonNull CommandLine commandLine) { 072 super(callingContext, commandLine); 073 } 074 075 @Override 076 protected IBindingContext getBindingContext(Set<IConstraintSet> constraintSets) 077 throws CommandExecutionException { 078 return MetaschemaCommands.newBindingContextWithDynamicCompilation(constraintSets); 079 } 080 081 @Override 082 protected IModule getModule(CommandLine commandLine, IBindingContext bindingContext) 083 throws CommandExecutionException { 084 try { 085 return bindingContext.registerModule(MetaschemaModelModule.class); 086 } catch (MetaschemaException ex) { 087 throw new CommandExecutionException(ExitCode.PROCESSING_ERROR, ex); 088 } 089 } 090 091 @Override 092 protected ISchemaValidationProvider getSchemaValidationProvider( 093 IModule module, 094 CommandLine commandLine, 095 IBindingContext bindingContext) { 096 // ignore the arguments and return the pre-generated schema provider 097 return ObjectUtils.notNull(validationProvider.get()); 098 } 099 } 100 101 private static final class ValidationProvider implements ISchemaValidationProvider { 102 @SuppressWarnings("resource") 103 @Override 104 public XmlSchemaContentValidator getXmlSchemas( 105 @NonNull URL targetResource, 106 @NonNull IBindingContext bindingContext) throws IOException, SAXException { 107 try (InputStream is = this.getClass().getResourceAsStream("/schema/xml/metaschema-model_schema.xsd")) { 108 List<Source> sources = new LinkedList<>(); 109 sources.add(new StreamSource( 110 ObjectUtils.requireNonNull(is, 111 "Unable to load '/schema/xml/metaschema.xsd' on the classpath"))); 112 return new XmlSchemaContentValidator(sources); 113 } 114 } 115 116 @Override 117 public JsonSchemaContentValidator getJsonSchema( 118 @NonNull JSONObject json, 119 @NonNull IBindingContext bindingContext) throws IOException { 120 try (BufferedReader reader = new BufferedReader( 121 new InputStreamReader( 122 this.getClass().getResourceAsStream("/schema/json/metaschema-model_schema.json"), 123 StandardCharsets.UTF_8))) { 124 return new JsonSchemaContentValidator(JsonUtil.toJsonObject(reader)); 125 } 126 } 127 } 128}