001/*
002 * SPDX-FileCopyrightText: none
003 * SPDX-License-Identifier: CC0-1.0
004 */
005
006package gov.nist.secauto.metaschema.databind.io.yaml;
007
008import gov.nist.secauto.metaschema.core.util.ObjectUtils;
009
010import org.json.JSONException;
011import org.json.JSONObject;
012import org.yaml.snakeyaml.DumperOptions;
013import org.yaml.snakeyaml.LoaderOptions;
014import org.yaml.snakeyaml.Yaml;
015import org.yaml.snakeyaml.constructor.Constructor;
016import org.yaml.snakeyaml.nodes.Tag;
017import org.yaml.snakeyaml.representer.Representer;
018import org.yaml.snakeyaml.resolver.Resolver;
019
020import java.io.BufferedInputStream;
021import java.io.IOException;
022import java.net.URI;
023import java.util.Map;
024
025import edu.umd.cs.findbugs.annotations.NonNull;
026
027public final class YamlOperations {
028  private static final Yaml YAML_PARSER;
029
030  static {
031    LoaderOptions loaderOptions = new LoaderOptions();
032    loaderOptions.setCodePointLimit(Integer.MAX_VALUE - 1); // 2GB
033    Constructor constructor = new Constructor(loaderOptions);
034    DumperOptions dumperOptions = new DumperOptions();
035    Representer representer = new Representer(dumperOptions);
036    YAML_PARSER = new Yaml(constructor, representer, dumperOptions, loaderOptions, new Resolver() {
037      @Override
038      protected void addImplicitResolvers() {
039        addImplicitResolver(Tag.BOOL, BOOL, "yYnNtTfFoO");
040        addImplicitResolver(Tag.INT, INT, "-+0123456789");
041        addImplicitResolver(Tag.FLOAT, FLOAT, "-+0123456789.");
042        addImplicitResolver(Tag.MERGE, MERGE, "<");
043        addImplicitResolver(Tag.NULL, NULL, "~nN\0");
044        addImplicitResolver(Tag.NULL, EMPTY, null);
045        // addImplicitResolver(Tag.TIMESTAMP, TIMESTAMP, "0123456789");
046      }
047    });
048  }
049
050  private YamlOperations() {
051    // disable construction
052  }
053
054  /**
055   * Parse the data represented in YAML in the provided {@code target}, producing
056   * an mapping of field names to Java object values.
057   *
058   * @param target
059   *          the YAML file to parse
060   * @return the mapping of field names to Java object values
061   * @throws IOException
062   *           if an error occurred while parsing the YAML content
063   */
064  @SuppressWarnings({ "unchecked", "null" })
065  @NonNull
066  public static Map<String, Object> parseYaml(URI target) throws IOException {
067    try (BufferedInputStream is = new BufferedInputStream(ObjectUtils.notNull(target.toURL().openStream()))) {
068      return (Map<String, Object>) YAML_PARSER.load(is);
069    }
070  }
071
072  /**
073   * Converts the provided YAML {@code map} into JSON.
074   *
075   * @param map
076   *          the YAML map
077   * @return the JSON object
078   * @throws JSONException
079   *           if an error occurred while building the JSON tree
080   */
081  public static JSONObject yamlToJson(@NonNull Map<String, Object> map) {
082    return new JSONObject(map);
083  }
084}