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.command.ICommandExecutor;
10  import gov.nist.secauto.metaschema.core.configuration.DefaultConfiguration;
11  import gov.nist.secauto.metaschema.core.configuration.IMutableConfiguration;
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.util.XmlUtil;
17  import gov.nist.secauto.metaschema.core.model.xml.ExternalConstraintsModulePostProcessor;
18  import gov.nist.secauto.metaschema.core.model.xml.ModuleLoader;
19  import gov.nist.secauto.metaschema.core.util.CollectionUtil;
20  import gov.nist.secauto.metaschema.core.util.ObjectUtils;
21  import gov.nist.secauto.metaschema.databind.DefaultBindingContext;
22  import gov.nist.secauto.metaschema.databind.IBindingContext;
23  import gov.nist.secauto.metaschema.databind.model.binding.metaschema.METASCHEMA;
24  import gov.nist.secauto.metaschema.databind.model.binding.metaschema.MetaschemaModelModule;
25  import gov.nist.secauto.metaschema.schemagen.ISchemaGenerator;
26  import gov.nist.secauto.metaschema.schemagen.ISchemaGenerator.SchemaFormat;
27  import gov.nist.secauto.metaschema.schemagen.SchemaGenerationFeature;
28  
29  import org.apache.commons.cli.CommandLine;
30  import org.json.JSONObject;
31  
32  import java.io.BufferedReader;
33  import java.io.IOException;
34  import java.net.URL;
35  import java.nio.charset.StandardCharsets;
36  import java.nio.file.Files;
37  import java.nio.file.Path;
38  import java.util.LinkedList;
39  import java.util.List;
40  import java.util.Set;
41  
42  import javax.xml.transform.Source;
43  
44  import edu.umd.cs.findbugs.annotations.NonNull;
45  
46  public 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 ValidateModuleCommandExecutor(callingContext, commandLine);
64    }
65  
66    private final class ValidateModuleCommandExecutor
67        extends AbstractValidationCommandExecutor {
68      private Path tempDir;
69  
70      private ValidateModuleCommandExecutor(
71          @NonNull CallingContext callingContext,
72          @NonNull CommandLine commandLine) {
73        super(callingContext, commandLine);
74      }
75  
76      private Path getTempDir() throws IOException {
77        if (tempDir == null) {
78          tempDir = Files.createTempDirectory("validation-");
79          tempDir.toFile().deleteOnExit();
80        }
81        return tempDir;
82      }
83  
84      @Override
85      protected IBindingContext getBindingContext(Set<IConstraintSet> constraintSets)
86          throws MetaschemaException, IOException {
87        IBindingContext retval;
88        if (constraintSets.isEmpty()) {
89          retval = IBindingContext.instance();
90        } else {
91          ExternalConstraintsModulePostProcessor postProcessor
92              = new ExternalConstraintsModulePostProcessor(constraintSets);
93          retval = new DefaultBindingContext(CollectionUtil.singletonList(postProcessor));
94        }
95        retval.getBoundDefinitionForClass(METASCHEMA.class);
96        return retval;
97      }
98  
99      @Override
100     public List<Source> getXmlSchemas(@NonNull URL targetResource) throws IOException {
101       List<Source> retval = new LinkedList<>();
102       retval.add(XmlUtil.getStreamSource(
103           ObjectUtils.requireNonNull(
104               ModuleLoader.class.getResource("/schema/xml/metaschema.xsd"),
105               "Unable to load '/schema/xml/metaschema.xsd' on the classpath")));
106       return CollectionUtil.unmodifiableList(retval);
107     }
108 
109     @Override
110     public JSONObject getJsonSchema(@NonNull JSONObject json) throws IOException {
111       IModule module = IBindingContext.instance().registerModule(MetaschemaModelModule.class);
112 
113       Path schemaFile = Files.createTempFile(getTempDir(), "schema-", ".json");
114       assert schemaFile != null;
115       IMutableConfiguration<SchemaGenerationFeature<?>> configuration = new DefaultConfiguration<>();
116       ISchemaGenerator.generateSchema(module, schemaFile, SchemaFormat.JSON, configuration);
117       try (BufferedReader reader = ObjectUtils.notNull(Files.newBufferedReader(schemaFile, StandardCharsets.UTF_8))) {
118         return JsonUtil.toJsonObject(reader);
119       }
120     }
121   }
122 }