001/*
002 * SPDX-FileCopyrightText: none
003 * SPDX-License-Identifier: CC0-1.0
004 */
005
006package gov.nist.secauto.oscal.lib;
007
008import gov.nist.secauto.metaschema.core.util.ObjectUtils;
009import gov.nist.secauto.oscal.lib.model.BackMatter.Resource;
010import gov.nist.secauto.oscal.lib.model.BackMatter.Resource.Rlink;
011
012import java.net.URI;
013import java.util.List;
014import java.util.regex.Matcher;
015import java.util.regex.Pattern;
016
017import edu.umd.cs.findbugs.annotations.NonNull;
018import edu.umd.cs.findbugs.annotations.Nullable;
019
020public final class OscalUtils {
021  private static final Pattern INTERNAL_REFERENCE_FRAGMENT_PATTERN = Pattern.compile("^#(.+)$");
022
023  private OscalUtils() {
024    // disable construction
025  }
026
027  @SuppressWarnings("PMD.OnlyOneReturn") // readability
028  public static boolean isInternalReference(@NonNull URI uri) {
029    if (uri.isAbsolute()) {
030      return false;
031    }
032
033    String schemeSpecificPart = uri.getSchemeSpecificPart();
034    return uri.getScheme() == null && (schemeSpecificPart == null || schemeSpecificPart.isEmpty())
035        && uri.getFragment() != null;
036  }
037
038  /**
039   * Get the id based on a URI's fragment.
040   *
041   * @param fragment
042   *          the URI to extract the identifier from
043   * @return the identifier
044   * @throws IllegalArgumentException
045   *           if the fragment does not contain an identifier
046   */
047  @NonNull
048  public static String internalReferenceFragmentToId(@NonNull URI fragment) {
049    return internalReferenceFragmentToId(ObjectUtils.notNull(fragment.toString()));
050  }
051
052  /**
053   * Get the id based on a URI's fragment.
054   *
055   * @param fragment
056   *          the URI to extract the identifier from
057   * @return the identifier
058   * @throws IllegalArgumentException
059   *           if the fragment does not contain an identifier
060   */
061  @NonNull
062  public static String internalReferenceFragmentToId(@NonNull String fragment) {
063    Matcher matcher = INTERNAL_REFERENCE_FRAGMENT_PATTERN.matcher(fragment);
064    String retval;
065    if (matcher.matches()) {
066      retval = ObjectUtils.notNull(matcher.group(1));
067    } else {
068      throw new IllegalArgumentException(String.format("The fragment '%s' does not match the pattern '%s'", fragment,
069          INTERNAL_REFERENCE_FRAGMENT_PATTERN.pattern()));
070    }
071    return retval;
072  }
073
074  @Nullable
075  public static Rlink findMatchingRLink(@NonNull Resource resource, @Nullable String preferredMediaType) {
076    // find a suitable rlink reference
077    List<Rlink> rlinks = resource.getRlinks();
078
079    Rlink retval = null;
080    if (rlinks != null) {
081      // check if there is a matching rlink for the mime type
082      if (preferredMediaType != null) {
083        // find preferred mime type first
084        retval = rlinks.stream().filter(rlink -> preferredMediaType.equals(rlink.getMediaType())).findFirst()
085            .orElse(null);
086      } else {
087        // use the first one instead
088        retval = rlinks.stream().findFirst().orElse(null);
089      }
090    }
091    return retval;
092  }
093}