1   /*
2    * SPDX-FileCopyrightText: none
3    * SPDX-License-Identifier: CC0-1.0
4    */
5   
6   package gov.nist.secauto.oscal.tools.cli.core.commands;
7   
8   import gov.nist.secauto.metaschema.cli.commands.AbstractConvertSubcommand;
9   import gov.nist.secauto.metaschema.cli.processor.CLIProcessor.CallingContext;
10  import gov.nist.secauto.metaschema.cli.processor.command.ICommandExecutor;
11  import gov.nist.secauto.metaschema.core.model.IBoundObject;
12  import gov.nist.secauto.metaschema.databind.IBindingContext;
13  import gov.nist.secauto.metaschema.databind.io.Format;
14  import gov.nist.secauto.metaschema.databind.io.FormatDetector;
15  import gov.nist.secauto.metaschema.databind.io.IBoundLoader;
16  import gov.nist.secauto.metaschema.databind.io.ISerializer;
17  import gov.nist.secauto.metaschema.databind.io.ModelDetector;
18  import gov.nist.secauto.oscal.lib.OscalBindingContext;
19  
20  import org.apache.commons.cli.CommandLine;
21  
22  import java.io.FileNotFoundException;
23  import java.io.IOException;
24  import java.io.InputStream;
25  import java.io.Writer;
26  import java.net.URI;
27  
28  import edu.umd.cs.findbugs.annotations.NonNull;
29  
30  /**
31   * Provides an OSCAL content conversion command.
32   */
33  public class ConvertCommand
34      extends AbstractConvertSubcommand {
35    @Override
36    public String getDescription() {
37      return "Check that the specified OSCAL instance is well-formed and valid to an OSCAL model.";
38    }
39  
40    @Override
41    public ICommandExecutor newExecutor(CallingContext callingContext, CommandLine commandLine) {
42      return new CommandExecutor(callingContext, commandLine);
43    }
44  
45    private static final class CommandExecutor
46        extends AbstractConversionCommandExecutor {
47  
48      private CommandExecutor(
49          @NonNull CallingContext callingContext,
50          @NonNull CommandLine commandLine) {
51        super(callingContext, commandLine);
52      }
53  
54      @Override
55      protected IBindingContext getBindingContext() {
56        return OscalBindingContext.instance();
57      }
58  
59      @Override
60      protected void handleConversion(URI source, Format toFormat, Writer writer, IBoundLoader loader)
61          throws FileNotFoundException, IOException {
62  
63        Class<? extends IBoundObject> boundClass;
64        IBoundObject object;
65        try (InputStream is = source.toURL().openStream()) {
66          assert is != null;
67          FormatDetector.Result formatResult = loader.detectFormat(is, source);
68          Format sourceformat = formatResult.getFormat();
69          try (InputStream fis = formatResult.getDataStream()) {
70            try (ModelDetector.Result modelResult = loader.detectModel(fis, source, sourceformat)) {
71              boundClass = modelResult.getBoundClass();
72              try (InputStream mis = modelResult.getDataStream()) {
73                object = loader.load(boundClass, sourceformat, mis, source);
74              }
75            }
76          }
77        }
78        ISerializer<?> serializer = getBindingContext().newSerializer(toFormat, boundClass);
79        serializer.serialize(object, writer);
80      }
81    }
82  }