1   /*
2    * SPDX-FileCopyrightText: none
3    * SPDX-License-Identifier: CC0-1.0
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 }