1   /*
2    * SPDX-FileCopyrightText: none
3    * SPDX-License-Identifier: CC0-1.0
4    */
5   
6   package dev.metaschema.oscal.lib;
7   
8   import java.net.URI;
9   import java.util.List;
10  import java.util.regex.Matcher;
11  import java.util.regex.Pattern;
12  
13  import dev.metaschema.core.util.ObjectUtils;
14  import dev.metaschema.oscal.lib.model.BackMatter.Resource;
15  import dev.metaschema.oscal.lib.model.BackMatter.Resource.Rlink;
16  import edu.umd.cs.findbugs.annotations.NonNull;
17  import edu.umd.cs.findbugs.annotations.Nullable;
18  
19  public final class OscalUtils {
20    private static final Pattern INTERNAL_REFERENCE_FRAGMENT_PATTERN = Pattern.compile("^#(.+)$");
21  
22    private OscalUtils() {
23      // disable construction
24    }
25  
26    @SuppressWarnings("PMD.OnlyOneReturn") // readability
27    public static boolean isInternalReference(@NonNull URI uri) {
28      if (uri.isAbsolute()) {
29        return false;
30      }
31  
32      String schemeSpecificPart = uri.getSchemeSpecificPart();
33      return uri.getScheme() == null && (schemeSpecificPart == null || schemeSpecificPart.isEmpty())
34          && uri.getFragment() != null;
35    }
36  
37    /**
38     * Get the id based on a URI's fragment.
39     *
40     * @param fragment
41     *          the URI to extract the identifier from
42     * @return the identifier
43     * @throws IllegalArgumentException
44     *           if the fragment does not contain an identifier
45     */
46    @NonNull
47    public static String internalReferenceFragmentToId(@NonNull URI fragment) {
48      return internalReferenceFragmentToId(ObjectUtils.notNull(fragment.toString()));
49    }
50  
51    /**
52     * Get the id based on a URI's fragment.
53     *
54     * @param fragment
55     *          the URI to extract the identifier from
56     * @return the identifier
57     * @throws IllegalArgumentException
58     *           if the fragment does not contain an identifier
59     */
60    @NonNull
61    public static String internalReferenceFragmentToId(@NonNull String fragment) {
62      Matcher matcher = INTERNAL_REFERENCE_FRAGMENT_PATTERN.matcher(fragment);
63      String retval;
64      if (matcher.matches()) {
65        retval = ObjectUtils.notNull(matcher.group(1));
66      } else {
67        throw new IllegalArgumentException(String.format("The fragment '%s' does not match the pattern '%s'", fragment,
68            INTERNAL_REFERENCE_FRAGMENT_PATTERN.pattern()));
69      }
70      return retval;
71    }
72  
73    @Nullable
74    public static Rlink findMatchingRLink(@NonNull Resource resource, @Nullable String preferredMediaType) {
75      // find a suitable rlink reference
76      List<Rlink> rlinks = resource.getRlinks();
77  
78      Rlink retval = null;
79      if (rlinks != null) {
80        // check if there is a matching rlink for the mime type
81        if (preferredMediaType != null) {
82          // find preferred mime type first
83          retval = rlinks.stream().filter(rlink -> preferredMediaType.equals(rlink.getMediaType())).findFirst()
84              .orElse(null);
85        } else {
86          // use the first one instead
87          retval = rlinks.stream().findFirst().orElse(null);
88        }
89      }
90      return retval;
91    }
92  }