001/* 002 * SPDX-FileCopyrightText: none 003 * SPDX-License-Identifier: CC0-1.0 004 */ 005 006package gov.nist.secauto.oscal.lib.profile.resolver.policy; 007 008import gov.nist.secauto.metaschema.core.metapath.format.IPathFormatter; 009import gov.nist.secauto.metaschema.core.metapath.item.node.IModelNodeItem; 010import gov.nist.secauto.metaschema.core.util.CollectionUtil; 011import gov.nist.secauto.metaschema.core.util.CustomCollectors; 012import gov.nist.secauto.oscal.lib.model.Link; 013import gov.nist.secauto.oscal.lib.profile.resolver.support.IEntityItem; 014 015import org.apache.logging.log4j.LogManager; 016import org.apache.logging.log4j.Logger; 017 018import java.net.URI; 019import java.util.List; 020import java.util.Locale; 021 022import edu.umd.cs.findbugs.annotations.NonNull; 023 024public class LinkReferencePolicy 025 extends AbstractMultiItemTypeReferencePolicy<Link> { 026 private static final Logger LOGGER = LogManager.getLogger(LinkReferencePolicy.class); 027 028 @SuppressWarnings("null") 029 @NonNull 030 public static LinkReferencePolicy create(@NonNull IEntityItem.ItemType itemType) { 031 return create(List.of(itemType)); 032 } 033 034 @NonNull 035 public static LinkReferencePolicy create(@NonNull List<IEntityItem.ItemType> itemTypes) { 036 return new LinkReferencePolicy(CollectionUtil.requireNonEmpty(itemTypes, "itemTypes")); 037 } 038 039 public LinkReferencePolicy(@NonNull List<IEntityItem.ItemType> itemTypes) { 040 super(IIdentifierParser.FRAGMENT_PARSER, itemTypes); 041 } 042 043 @Override 044 public String getReferenceText(@NonNull Link link) { 045 return link.getHref().toString(); 046 } 047 048 @Override 049 public void setReferenceText(@NonNull Link link, @NonNull String newValue) { 050 link.setHref(URI.create(newValue)); 051 } 052 053 @Override 054 protected void handleUnselected( 055 @NonNull IModelNodeItem<?, ?> contextItem, 056 @NonNull Link link, 057 @NonNull IEntityItem item, 058 @NonNull ReferenceCountingVisitor.Context visitorContext) { 059 URI linkHref = link.getHref(); 060 URI sourceUri = item.getSource(); 061 062 URI resolved = sourceUri.resolve(linkHref); 063 if (LOGGER.isTraceEnabled()) { 064 LOGGER.atTrace().log("At path '{}', remapping orphaned URI '{}' to '{}'", 065 contextItem.toPath(IPathFormatter.METAPATH_PATH_FORMATER), 066 linkHref.toString(), 067 resolved.toString()); 068 } 069 link.setHref(resolved); 070 } 071 072 @Override 073 protected boolean handleIndexMiss( 074 @NonNull IModelNodeItem<?, ?> contextItem, 075 @NonNull Link link, 076 @NonNull List<IEntityItem.ItemType> itemTypes, 077 @NonNull String identifier, 078 @NonNull ReferenceCountingVisitor.Context visitorContext) { 079 if (LOGGER.isWarnEnabled()) { 080 LOGGER.atWarn().log( 081 "The link at '{}' with rel '{}' should reference a {} identified by '{}'." 082 + " The index did not contain the identifier.", 083 contextItem.toPath(IPathFormatter.METAPATH_PATH_FORMATER), 084 link.getRel(), 085 itemTypes.stream() 086 .map(en -> en.name().toLowerCase(Locale.ROOT)) 087 .collect(CustomCollectors.joiningWithOxfordComma("or")), 088 identifier); 089 } 090 return true; 091 } 092 093 @Override 094 protected boolean handleIdentifierNonMatch( 095 @NonNull IModelNodeItem<?, ?> contextItem, 096 @NonNull Link reference, 097 @NonNull ReferenceCountingVisitor.Context visitorContext) { 098 if (LOGGER.isDebugEnabled()) { 099 LOGGER.atDebug().log("Ignoring URI '{}' at '{}'", 100 reference.getHref().toString(), 101 contextItem.toPath(IPathFormatter.METAPATH_PATH_FORMATER)); 102 } 103 104 return true; 105 } 106}