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.model.xml.ExternalConstraintsModulePostProcessor;
018import gov.nist.secauto.metaschema.core.model.xml.ModuleLoader;
019import gov.nist.secauto.metaschema.core.util.CollectionUtil;
020import gov.nist.secauto.metaschema.core.util.ObjectUtils;
021import gov.nist.secauto.metaschema.databind.DefaultBindingContext;
022import gov.nist.secauto.metaschema.databind.IBindingContext;
023import gov.nist.secauto.metaschema.databind.model.binding.metaschema.METASCHEMA;
024import gov.nist.secauto.metaschema.databind.model.binding.metaschema.MetaschemaModelModule;
025import gov.nist.secauto.metaschema.schemagen.ISchemaGenerator;
026import gov.nist.secauto.metaschema.schemagen.ISchemaGenerator.SchemaFormat;
027import gov.nist.secauto.metaschema.schemagen.SchemaGenerationFeature;
028
029import org.apache.commons.cli.CommandLine;
030import org.json.JSONObject;
031
032import java.io.BufferedReader;
033import java.io.IOException;
034import java.net.URL;
035import java.nio.charset.StandardCharsets;
036import java.nio.file.Files;
037import java.nio.file.Path;
038import java.util.LinkedList;
039import java.util.List;
040import java.util.Set;
041
042import javax.xml.transform.Source;
043
044import edu.umd.cs.findbugs.annotations.NonNull;
045
046public class ValidateModuleCommand
047    extends AbstractValidateContentCommand {
048  @NonNull
049  private static final String COMMAND = "validate";
050
051  @Override
052  public String getName() {
053    return COMMAND;
054  }
055
056  @Override
057  public String getDescription() {
058    return "Validate that the specified Module is well-formed and valid to the Module model";
059  }
060
061  @Override
062  public ICommandExecutor newExecutor(CallingContext callingContext, CommandLine commandLine) {
063    return new ValidateModuleCommandExecutor(callingContext, commandLine);
064  }
065
066  private final class ValidateModuleCommandExecutor
067      extends AbstractValidationCommandExecutor {
068    private Path tempDir;
069
070    private ValidateModuleCommandExecutor(
071        @NonNull CallingContext callingContext,
072        @NonNull CommandLine commandLine) {
073      super(callingContext, commandLine);
074    }
075
076    private Path getTempDir() throws IOException {
077      if (tempDir == null) {
078        tempDir = Files.createTempDirectory("validation-");
079        tempDir.toFile().deleteOnExit();
080      }
081      return tempDir;
082    }
083
084    @Override
085    protected IBindingContext getBindingContext(Set<IConstraintSet> constraintSets)
086        throws MetaschemaException, IOException {
087      IBindingContext retval;
088      if (constraintSets.isEmpty()) {
089        retval = IBindingContext.instance();
090      } else {
091        ExternalConstraintsModulePostProcessor postProcessor
092            = new ExternalConstraintsModulePostProcessor(constraintSets);
093        retval = new DefaultBindingContext(CollectionUtil.singletonList(postProcessor));
094      }
095      retval.getBoundDefinitionForClass(METASCHEMA.class);
096      return retval;
097    }
098
099    @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}