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