1   /*
2    * SPDX-FileCopyrightText: none
3    * SPDX-License-Identifier: CC0-1.0
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.ExitCode;
10  import gov.nist.secauto.metaschema.cli.processor.command.CommandExecutionException;
11  import gov.nist.secauto.metaschema.cli.processor.command.ICommandExecutor;
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.validation.JsonSchemaContentValidator;
17  import gov.nist.secauto.metaschema.core.model.validation.XmlSchemaContentValidator;
18  import gov.nist.secauto.metaschema.core.util.ObjectUtils;
19  import gov.nist.secauto.metaschema.databind.IBindingContext;
20  import gov.nist.secauto.metaschema.databind.IBindingContext.ISchemaValidationProvider;
21  import gov.nist.secauto.metaschema.databind.model.metaschema.binding.MetaschemaModelModule;
22  
23  import org.apache.commons.cli.CommandLine;
24  import org.json.JSONObject;
25  import org.xml.sax.SAXException;
26  
27  import java.io.BufferedReader;
28  import java.io.IOException;
29  import java.io.InputStream;
30  import java.io.InputStreamReader;
31  import java.net.URL;
32  import java.nio.charset.StandardCharsets;
33  import java.util.LinkedList;
34  import java.util.List;
35  import java.util.Set;
36  
37  import javax.xml.transform.Source;
38  import javax.xml.transform.stream.StreamSource;
39  
40  import edu.umd.cs.findbugs.annotations.NonNull;
41  import nl.talsmasoftware.lazy4j.Lazy;
42  
43  /**
44   * This command implementation supports validation a Metaschema module.
45   */
46  class ValidateModuleCommand
47      extends AbstractValidateContentCommand {
48    @NonNull
49    private static final String COMMAND = "validate";
50  
51    @Override
52    public String getName() {
53      return COMMAND;
54    }
55  
56    @Override
57    public String getDescription() {
58      return "Validate that the specified Module is well-formed and valid to the Module model";
59    }
60  
61    @Override
62    public ICommandExecutor newExecutor(CallingContext callingContext, CommandLine commandLine) {
63      return new CommandExecutor(callingContext, commandLine);
64    }
65  
66    private final class CommandExecutor
67        extends AbstractValidationCommandExecutor {
68      private final Lazy<ValidationProvider> validationProvider = Lazy.of(ValidationProvider::new);
69  
70      private CommandExecutor(
71          @NonNull CallingContext callingContext,
72          @NonNull CommandLine commandLine) {
73        super(callingContext, commandLine);
74      }
75  
76      @Override
77      protected IBindingContext getBindingContext(Set<IConstraintSet> constraintSets)
78          throws CommandExecutionException {
79        return MetaschemaCommands.newBindingContextWithDynamicCompilation(constraintSets);
80      }
81  
82      @Override
83      protected IModule getModule(CommandLine commandLine, IBindingContext bindingContext)
84          throws CommandExecutionException {
85        try {
86          return bindingContext.registerModule(MetaschemaModelModule.class);
87        } catch (MetaschemaException ex) {
88          throw new CommandExecutionException(ExitCode.PROCESSING_ERROR, ex);
89        }
90      }
91  
92      @Override
93      protected ISchemaValidationProvider getSchemaValidationProvider(
94          IModule module,
95          CommandLine commandLine,
96          IBindingContext bindingContext) {
97        // ignore the arguments and return the pre-generated schema provider
98        return ObjectUtils.notNull(validationProvider.get());
99      }
100   }
101 
102   private static final class ValidationProvider implements ISchemaValidationProvider {
103     @SuppressWarnings("resource")
104     @Override
105     public XmlSchemaContentValidator getXmlSchemas(
106         @NonNull URL targetResource,
107         @NonNull IBindingContext bindingContext) throws IOException, SAXException {
108       try (InputStream is = this.getClass().getResourceAsStream("/schema/xml/metaschema-model_schema.xsd")) {
109         List<Source> sources = new LinkedList<>();
110         sources.add(new StreamSource(
111             ObjectUtils.requireNonNull(is,
112                 "Unable to load '/schema/xml/metaschema.xsd' on the classpath")));
113         return new XmlSchemaContentValidator(sources);
114       }
115     }
116 
117     @Override
118     public JsonSchemaContentValidator getJsonSchema(
119         @NonNull JSONObject json,
120         @NonNull IBindingContext bindingContext) throws IOException {
121       try (BufferedReader reader = new BufferedReader(
122           new InputStreamReader(
123               this.getClass().getResourceAsStream("/schema/json/metaschema-model_schema.json"),
124               StandardCharsets.UTF_8))) {
125         return new JsonSchemaContentValidator(JsonUtil.toJsonObject(reader));
126       }
127     }
128   }
129 }