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.CustomCollectors;
11  import gov.nist.secauto.metaschema.core.util.ObjectUtils;
12  import gov.nist.secauto.oscal.lib.model.Property;
13  import gov.nist.secauto.oscal.lib.profile.resolver.support.IEntityItem;
14  
15  import org.apache.logging.log4j.LogManager;
16  import org.apache.logging.log4j.Logger;
17  
18  import java.net.URI;
19  import java.util.List;
20  import java.util.Locale;
21  
22  import edu.umd.cs.findbugs.annotations.NonNull;
23  
24  public class PropertyReferencePolicy
25      extends AbstractMultiItemTypeReferencePolicy<Property> {
26    private static final Logger LOGGER = LogManager.getLogger(PropertyReferencePolicy.class);
27  
28    @NonNull
29    public static PropertyReferencePolicy create(@NonNull IIdentifierParser identifierParser,
30        @NonNull IEntityItem.ItemType itemType) {
31      return create(identifierParser, ObjectUtils.notNull(List.of(itemType)));
32    }
33  
34    @NonNull
35    public static PropertyReferencePolicy create(@NonNull IIdentifierParser identifierParser,
36        @NonNull List<IEntityItem.ItemType> itemTypes) {
37      return new PropertyReferencePolicy(identifierParser, itemTypes);
38    }
39  
40    public PropertyReferencePolicy(
41        @NonNull IIdentifierParser identifierParser,
42        @NonNull List<IEntityItem.ItemType> itemTypes) {
43      super(identifierParser, itemTypes);
44    }
45  
46    @Override
47    public String getReferenceText(@NonNull Property property) {
48      return property.getValue();
49    }
50  
51    @Override
52    public void setReferenceText(@NonNull Property property, @NonNull String newValue) {
53      property.setValue(newValue);
54    }
55  
56    @Override
57    protected void handleUnselected(
58        @NonNull IModelNodeItem<?, ?> contextItem,
59        @NonNull Property property,
60        @NonNull IEntityItem item,
61        @NonNull ReferenceCountingVisitor.Context visitorContext) {
62      URI linkHref = URI.create(property.getValue());
63      URI sourceUri = item.getSource();
64  
65      URI resolved = sourceUri.resolve(linkHref);
66      if (LOGGER.isDebugEnabled()) {
67        LOGGER.atTrace().log("At path '{}', remapping orphaned URI '{}' to '{}'",
68            contextItem.toPath(IPathFormatter.METAPATH_PATH_FORMATER),
69            linkHref.toString(),
70            resolved.toString());
71      }
72      property.setValue(resolved.toString());
73    }
74  
75    @Override
76    protected boolean handleIndexMiss(
77        @NonNull IModelNodeItem<?, ?> contextItem,
78        @NonNull Property property,
79        @NonNull List<IEntityItem.ItemType> itemTypes,
80        @NonNull String identifier,
81        @NonNull ReferenceCountingVisitor.Context visitorContext) {
82      if (LOGGER.isWarnEnabled()) {
83        LOGGER.atWarn().log(
84            "The property '{}' at '{}' should reference a {} identified by '{}',"
85                + " but the identifier was not found in the index.",
86            property.getQName(),
87            contextItem.toPath(IPathFormatter.METAPATH_PATH_FORMATER),
88            itemTypes.stream()
89                .map(en -> en.name().toLowerCase(Locale.ROOT))
90                .collect(CustomCollectors.joiningWithOxfordComma("or")),
91            identifier);
92      }
93      return true;
94    }
95  }