1
2
3
4
5
6 package gov.nist.secauto.oscal.lib.profile.resolver.support;
7
8 import gov.nist.secauto.metaschema.core.metapath.MetapathExpression;
9 import gov.nist.secauto.metaschema.core.metapath.MetapathExpression.ResultType;
10 import gov.nist.secauto.metaschema.core.metapath.item.node.IModelNodeItem;
11 import gov.nist.secauto.metaschema.core.metapath.item.node.INodeItem;
12 import gov.nist.secauto.metaschema.core.util.CustomCollectors;
13 import gov.nist.secauto.metaschema.core.util.ObjectUtils;
14 import gov.nist.secauto.oscal.lib.OscalBindingContext;
15 import gov.nist.secauto.oscal.lib.model.metadata.IProperty;
16 import gov.nist.secauto.oscal.lib.profile.resolver.support.IEntityItem.ItemType;
17
18 import org.apache.logging.log4j.Level;
19 import org.apache.logging.log4j.LogManager;
20 import org.apache.logging.log4j.Logger;
21
22 import java.util.Collection;
23 import java.util.HashSet;
24 import java.util.Map;
25 import java.util.Set;
26 import java.util.UUID;
27 import java.util.function.Function;
28 import java.util.function.Predicate;
29 import java.util.stream.Stream;
30
31 import edu.umd.cs.findbugs.annotations.NonNull;
32 import edu.umd.cs.findbugs.annotations.Nullable;
33
34 public interface IIndexer {
35 enum SelectionStatus {
36 SELECTED,
37 UNSELECTED,
38 UNKNOWN;
39 }
40
41 MetapathExpression HAS_PROP_KEEP_METAPATH = MetapathExpression.compile(
42 "prop[@name='keep' and has-oscal-namespace('" + IProperty.OSCAL_NAMESPACE + "')]/@value = 'always'",
43 OscalBindingContext.OSCAL_STATIC_METAPATH_CONTEXT);
44
45 Predicate<IEntityItem> KEEP_ENTITY_PREDICATE = entity -> entity.getReferenceCount() > 0
46 || (Boolean) ObjectUtils
47 .notNull(HAS_PROP_KEEP_METAPATH.evaluateAs(entity.getInstance(), ResultType.BOOLEAN));
48
49 static boolean isReferencedEntity(@NonNull IEntityItem entity) {
50 return KEEP_ENTITY_PREDICATE.test(entity);
51 }
52
53
54
55
56
57
58
59
60
61 static Stream<IEntityItem> getReferencedEntitiesAsStream(@NonNull Collection<IEntityItem> entities) {
62 return entities.stream().filter(KEEP_ENTITY_PREDICATE);
63 }
64
65
66
67
68
69
70
71
72
73 static Stream<IEntityItem> getUnreferencedEntitiesAsStream(@NonNull Collection<IEntityItem> entities) {
74 return entities.stream().filter(KEEP_ENTITY_PREDICATE.negate());
75 }
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99 static <T, K> Stream<T> filterDistinct(
100 @NonNull Stream<T> resolvedItems,
101 @NonNull Collection<IEntityItem> importedEntityItems,
102 @NonNull Function<? super T, ? extends K> keyMapper) {
103 @SuppressWarnings("unchecked") Stream<T> importedStream = getReferencedEntitiesAsStream(importedEntityItems)
104 .map(entity -> (T) entity.getInstanceValue());
105
106 return CustomCollectors.distinctByKey(
107 ObjectUtils.notNull(Stream.concat(resolvedItems, importedStream)),
108 keyMapper,
109 (key, value1, value2) -> value2);
110 }
111
112 static void logIndex(@NonNull IIndexer indexer, @NonNull Level logLevel) {
113 Logger logger = LogManager.getLogger();
114
115 Set<INodeItem> indexedItems = new HashSet<>();
116 if (logger.isEnabled(logLevel)) {
117 for (ItemType itemType : ItemType.values()) {
118 assert itemType != null;
119 for (IEntityItem item : indexer.getEntitiesByItemType(itemType)) {
120 INodeItem nodeItem = item.getInstance();
121 indexedItems.add(nodeItem);
122 logger.atLevel(logLevel).log("{} {}: selected: {}, reference count: {}",
123 itemType.name(),
124 item.isIdentifierReassigned() ? item.getIdentifier() + "(" + item.getOriginalIdentifier() + ")"
125 : item.getIdentifier(),
126 indexer.getSelectionStatus(nodeItem),
127 item.getReferenceCount());
128 }
129 }
130 }
131
132 for (Map.Entry<INodeItem, SelectionStatus> entry : indexer.getSelectionStatusMap().entrySet()) {
133 INodeItem nodeItem = entry.getKey();
134 if (!indexedItems.contains(nodeItem)) {
135 Object value = nodeItem.getValue();
136 logger.atLevel(logLevel).log("{}: {}", value == null ? "(null)" : value.getClass().getName(), entry.getValue());
137 }
138 }
139 }
140
141 @NonNull
142 IEntityItem addRole(@NonNull IModelNodeItem<?, ?> role);
143
144 @NonNull
145 IEntityItem addLocation(@NonNull IModelNodeItem<?, ?> location);
146
147 @NonNull
148 IEntityItem addParty(@NonNull IModelNodeItem<?, ?> party);
149
150 @Nullable
151 IEntityItem addGroup(@NonNull IModelNodeItem<?, ?> group);
152
153 @NonNull
154 IEntityItem addControl(@NonNull IModelNodeItem<?, ?> control);
155
156 @NonNull
157 IEntityItem addParameter(@NonNull IModelNodeItem<?, ?> parameter);
158
159 @Nullable
160 IEntityItem addPart(@NonNull IModelNodeItem<?, ?> part);
161
162 @NonNull
163 IEntityItem addResource(@NonNull IModelNodeItem<?, ?> resource);
164
165 @NonNull
166 Collection<IEntityItem> getEntitiesByItemType(@NonNull IEntityItem.ItemType itemType);
167
168 @Nullable
169 default IEntityItem getEntity(@NonNull IEntityItem.ItemType itemType, @NonNull UUID identifier) {
170 return getEntity(itemType, ObjectUtils.notNull(identifier.toString()), false);
171 }
172
173
174
175
176
177
178
179
180
181
182
183
184
185 @Nullable
186 default IEntityItem getEntity(@NonNull IEntityItem.ItemType itemType, @NonNull String identifier) {
187 return getEntity(itemType, identifier, itemType.isUuid());
188 }
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205 @Nullable
206 IEntityItem getEntity(@NonNull IEntityItem.ItemType itemType, @NonNull String identifier, boolean normalize);
207
208 boolean removeItem(@NonNull IEntityItem entity);
209
210 boolean isSelected(@NonNull IEntityItem entity);
211
212 Map<INodeItem, SelectionStatus> getSelectionStatusMap();
213
214 @NonNull
215 SelectionStatus getSelectionStatus(@NonNull INodeItem item);
216
217 void setSelectionStatus(@NonNull INodeItem item, @NonNull SelectionStatus selectionStatus);
218
219 void resetSelectionStatus();
220
221 void append(@NonNull IIndexer result);
222
223
224
225
226
227
228 @NonNull
229 Map<ItemType, Map<String, IEntityItem>> getEntities();
230 }