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