1
2
3
4
5
6 package gov.nist.secauto.oscal.lib.profile.resolver.policy;
7
8 import gov.nist.secauto.metaschema.core.metapath.format.IPathFormatter;
9 import gov.nist.secauto.metaschema.core.metapath.item.node.IModelNodeItem;
10 import gov.nist.secauto.metaschema.core.util.CollectionUtil;
11 import gov.nist.secauto.metaschema.core.util.CustomCollectors;
12 import gov.nist.secauto.metaschema.core.util.ObjectUtils;
13 import gov.nist.secauto.oscal.lib.model.Link;
14 import gov.nist.secauto.oscal.lib.profile.resolver.support.IEntityItem;
15
16 import org.apache.logging.log4j.LogManager;
17 import org.apache.logging.log4j.Logger;
18
19 import java.net.URI;
20 import java.util.List;
21 import java.util.Locale;
22
23 import edu.umd.cs.findbugs.annotations.NonNull;
24
25 public class LinkReferencePolicy
26 extends AbstractMultiItemTypeReferencePolicy<Link> {
27 private static final Logger LOGGER = LogManager.getLogger(LinkReferencePolicy.class);
28
29 @SuppressWarnings("null")
30 @NonNull
31 public static LinkReferencePolicy create(@NonNull IEntityItem.ItemType itemType) {
32 return create(List.of(itemType));
33 }
34
35 @NonNull
36 public static LinkReferencePolicy create(@NonNull List<IEntityItem.ItemType> itemTypes) {
37 return new LinkReferencePolicy(CollectionUtil.requireNonEmpty(itemTypes, "itemTypes"));
38 }
39
40 public LinkReferencePolicy(@NonNull List<IEntityItem.ItemType> itemTypes) {
41 super(IIdentifierParser.FRAGMENT_PARSER, itemTypes);
42 }
43
44 @Override
45 public String getReferenceText(@NonNull Link link) {
46 return link.getHref().toString();
47 }
48
49 @Override
50 public void setReferenceText(@NonNull Link link, @NonNull String newValue) {
51 link.setHref(URI.create(newValue));
52 }
53
54 @Override
55 protected void handleUnselected(
56 @NonNull IModelNodeItem<?, ?> contextItem,
57 @NonNull Link link,
58 @NonNull IEntityItem item,
59 @NonNull ReferenceCountingVisitor.Context visitorContext) {
60 URI linkHref = link.getHref();
61 URI sourceUri = item.getSource();
62
63 URI resolved = visitorContext.getUriResolver().resolve(ObjectUtils.requireNonNull(linkHref), sourceUri);
64 if (LOGGER.isTraceEnabled()) {
65 LOGGER.atTrace().log("At path '{}', remapping orphaned URI '{}' to '{}'",
66 contextItem.toPath(IPathFormatter.METAPATH_PATH_FORMATER),
67 linkHref.toString(),
68 resolved.toString());
69 }
70 link.setHref(resolved);
71 }
72
73 @Override
74 protected boolean handleIndexMiss(
75 @NonNull IModelNodeItem<?, ?> contextItem,
76 @NonNull Link link,
77 @NonNull List<IEntityItem.ItemType> itemTypes,
78 @NonNull String identifier,
79 @NonNull ReferenceCountingVisitor.Context visitorContext) {
80 if (LOGGER.isWarnEnabled()) {
81 LOGGER.atWarn().log(
82 "The link at '{}' with rel '{}' should reference a {} identified by '{}'."
83 + " The index did not contain the identifier.",
84 contextItem.toPath(IPathFormatter.METAPATH_PATH_FORMATER),
85 link.getRel(),
86 itemTypes.stream()
87 .map(en -> en.name().toLowerCase(Locale.ROOT))
88 .collect(CustomCollectors.joiningWithOxfordComma("or")),
89 identifier);
90 }
91 return true;
92 }
93
94 @Override
95 protected boolean handleIdentifierNonMatch(
96 @NonNull IModelNodeItem<?, ?> contextItem,
97 @NonNull Link reference,
98 @NonNull ReferenceCountingVisitor.Context visitorContext) {
99 if (LOGGER.isDebugEnabled()) {
100 LOGGER.atDebug().log("Ignoring URI '{}' at '{}'",
101 reference.getHref().toString(),
102 contextItem.toPath(IPathFormatter.METAPATH_PATH_FORMATER));
103 }
104
105 return true;
106 }
107 }