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