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