001/*
002 * SPDX-FileCopyrightText: none
003 * SPDX-License-Identifier: CC0-1.0
004 */
005
006package gov.nist.secauto.oscal.tools.cli.core.commands;
007
008import gov.nist.secauto.metaschema.cli.commands.AbstractConvertSubcommand;
009import gov.nist.secauto.metaschema.cli.processor.CLIProcessor.CallingContext;
010import gov.nist.secauto.metaschema.cli.processor.command.ICommandExecutor;
011import gov.nist.secauto.metaschema.core.model.IBoundObject;
012import gov.nist.secauto.metaschema.databind.IBindingContext;
013import gov.nist.secauto.metaschema.databind.io.Format;
014import gov.nist.secauto.metaschema.databind.io.FormatDetector;
015import gov.nist.secauto.metaschema.databind.io.IBoundLoader;
016import gov.nist.secauto.metaschema.databind.io.ISerializer;
017import gov.nist.secauto.metaschema.databind.io.ModelDetector;
018import gov.nist.secauto.oscal.lib.OscalBindingContext;
019
020import org.apache.commons.cli.CommandLine;
021
022import java.io.FileNotFoundException;
023import java.io.IOException;
024import java.io.InputStream;
025import java.io.Writer;
026import java.net.URI;
027
028import edu.umd.cs.findbugs.annotations.NonNull;
029
030/**
031 * Provides an OSCAL content conversion command.
032 */
033public class ConvertCommand
034    extends AbstractConvertSubcommand {
035  @Override
036  public String getDescription() {
037    return "Check that the specified OSCAL instance is well-formed and valid to an OSCAL model.";
038  }
039
040  @Override
041  public ICommandExecutor newExecutor(CallingContext callingContext, CommandLine commandLine) {
042    return new CommandExecutor(callingContext, commandLine);
043  }
044
045  private static final class CommandExecutor
046      extends AbstractConversionCommandExecutor {
047
048    private CommandExecutor(
049        @NonNull CallingContext callingContext,
050        @NonNull CommandLine commandLine) {
051      super(callingContext, commandLine);
052    }
053
054    @Override
055    protected IBindingContext getBindingContext() {
056      return OscalBindingContext.instance();
057    }
058
059    @Override
060    protected void handleConversion(URI source, Format toFormat, Writer writer, IBoundLoader loader)
061        throws FileNotFoundException, IOException {
062
063      Class<? extends IBoundObject> boundClass;
064      IBoundObject object;
065      try (InputStream is = source.toURL().openStream()) {
066        assert is != null;
067        FormatDetector.Result formatResult = loader.detectFormat(is, source);
068        Format sourceformat = formatResult.getFormat();
069        try (InputStream fis = formatResult.getDataStream()) {
070          try (ModelDetector.Result modelResult = loader.detectModel(fis, source, sourceformat)) {
071            boundClass = modelResult.getBoundClass();
072            try (InputStream mis = modelResult.getDataStream()) {
073              object = loader.load(boundClass, sourceformat, mis, source);
074            }
075          }
076        }
077      }
078      ISerializer<?> serializer = getBindingContext().newSerializer(toFormat, boundClass);
079      serializer.serialize(object, writer);
080    }
081  }
082}