001/*
002 * SPDX-FileCopyrightText: none
003 * SPDX-License-Identifier: CC0-1.0
004 */
005
006package dev.metaschema.oscal.tools.cli.core.commands;
007
008import org.apache.commons.cli.CommandLine;
009import org.json.JSONObject;
010import org.xml.sax.SAXException;
011
012import java.io.IOException;
013import java.net.URL;
014import java.util.Set;
015
016import dev.metaschema.cli.commands.AbstractValidateContentCommand;
017import dev.metaschema.cli.processor.CallingContext;
018import dev.metaschema.cli.processor.ExitCode;
019import dev.metaschema.cli.processor.command.CommandExecutionException;
020import dev.metaschema.cli.processor.command.ICommandExecutor;
021import dev.metaschema.core.model.IModule;
022import dev.metaschema.core.model.MetaschemaException;
023import dev.metaschema.core.model.constraint.IConstraintSet;
024import dev.metaschema.core.model.validation.JsonSchemaContentValidator;
025import dev.metaschema.core.model.validation.XmlSchemaContentValidator;
026import dev.metaschema.databind.IBindingContext;
027import dev.metaschema.databind.IBindingContext.ISchemaValidationProvider;
028import dev.metaschema.oscal.lib.OscalBindingContext;
029import dev.metaschema.oscal.lib.model.OscalCompleteModule;
030import edu.umd.cs.findbugs.annotations.NonNull;
031
032/**
033 * Used by implementing classes to provide an OSCAL content validation command.
034 */
035public abstract class AbstractOscalValidationCommand
036    extends AbstractValidateContentCommand {
037
038  /**
039   * Load the OSCAL XML schemas.
040   *
041   * @return the XML schema validator instance
042   * @throws IOException
043   *           if an error occurred while parsing the provided XML schemas
044   */
045  @NonNull
046  protected abstract XmlSchemaContentValidator getOscalXmlSchemas() throws IOException;
047
048  /**
049   * Load the OSCAL JSON schemas.
050   *
051   * @return the XML schema validator instance
052   * @throws IOException
053   *           if an error occurred while parsing the provided XML schemas
054   */
055  @NonNull
056  protected abstract JsonSchemaContentValidator getOscalJsonSchema() throws IOException;
057
058  @Override
059  public abstract ICommandExecutor newExecutor(CallingContext callingContext, CommandLine commandLine);
060
061  /**
062   * Provides OSCAL validation command execution support.
063   */
064  protected class OscalValidationCommandExecutor
065      extends AbstractValidateContentCommand.AbstractValidationCommandExecutor
066      implements ISchemaValidationProvider {
067
068    /**
069     * Construct a new command executor.
070     *
071     * @param callingContext
072     *          the context of the command execution
073     * @param commandLine
074     *          the parsed command line details
075     */
076    protected OscalValidationCommandExecutor(
077        @NonNull CallingContext callingContext,
078        @NonNull CommandLine commandLine) {
079      super(callingContext, commandLine);
080    }
081
082    @Override
083    protected IBindingContext getBindingContext(@NonNull Set<IConstraintSet> constraintSets) {
084      return OscalBindingContext.builder()
085          .constraintSet(constraintSets)
086          .build();
087    }
088
089    @Override
090    @NonNull
091    public XmlSchemaContentValidator getXmlSchemas(URL targetResource, IBindingContext bindingContext)
092        throws IOException, SAXException {
093      return getOscalXmlSchemas();
094    }
095
096    @Override
097    @NonNull
098    public JsonSchemaContentValidator getJsonSchema(JSONObject json, IBindingContext bindingContext)
099        throws IOException {
100      return getOscalJsonSchema();
101    }
102
103    @Override
104    @NonNull
105    protected ISchemaValidationProvider getSchemaValidationProvider(
106        @NonNull IModule module,
107        @NonNull CommandLine commandLine,
108        @NonNull IBindingContext bindingContext) {
109      return this;
110    }
111
112    @Override
113    protected IModule getModule(CommandLine commandLine, IBindingContext bindingContext)
114        throws CommandExecutionException {
115      try {
116        return bindingContext.registerModule(OscalCompleteModule.class);
117      } catch (MetaschemaException ex) {
118        throw new CommandExecutionException(ExitCode.PROCESSING_ERROR, "Failed to register OSCAL module", ex);
119      }
120    }
121  }
122}