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")
104 Stream<T> importedStream = getReferencedEntitiesAsStream(importedEntityItems)
105 .map(entity -> (T) entity.getInstanceValue());
106
107 return CustomCollectors.distinctByKey(
108 ObjectUtils.notNull(Stream.concat(resolvedItems, importedStream)),
109 keyMapper,
110 (key, value1, value2) -> value2);
111 }
112
113 static void logIndex(@NonNull IIndexer indexer, @NonNull Level logLevel) {
114 Logger logger = LogManager.getLogger();
115
116 Set<INodeItem> indexedItems = new HashSet<>();
117 if (logger.isEnabled(logLevel)) {
118 for (ItemType itemType : ItemType.values()) {
119 assert itemType != null;
120 for (IEntityItem item : indexer.getEntitiesByItemType(itemType)) {
121 INodeItem nodeItem = item.getInstance();
122 indexedItems.add(nodeItem);
123 logger.atLevel(logLevel).log("{} {}: selected: {}, reference count: {}",
124 itemType.name(),
125 item.isIdentifierReassigned() ? item.getIdentifier() + "(" + item.getOriginalIdentifier() + ")"
126 : item.getIdentifier(),
127 indexer.getSelectionStatus(nodeItem),
128 item.getReferenceCount());
129 }
130 }
131 }
132
133 for (Map.Entry<INodeItem, SelectionStatus> entry : indexer.getSelectionStatusMap().entrySet()) {
134 INodeItem nodeItem = entry.getKey();
135 if (!indexedItems.contains(nodeItem)) {
136 Object value = nodeItem.getValue();
137 logger.atLevel(logLevel).log("{}: {}", value == null ? "(null)" : value.getClass().getName(), entry.getValue());
138 }
139 }
140 }
141
142 @NonNull
143 IEntityItem addRole(@NonNull IModelNodeItem<?, ?> role);
144
145 @NonNull
146 IEntityItem addLocation(@NonNull IModelNodeItem<?, ?> location);
147
148 @NonNull
149 IEntityItem addParty(@NonNull IModelNodeItem<?, ?> party);
150
151 @Nullable
152 IEntityItem addGroup(@NonNull IModelNodeItem<?, ?> group);
153
154 @NonNull
155 IEntityItem addControl(@NonNull IModelNodeItem<?, ?> control);
156
157 @NonNull
158 IEntityItem addParameter(@NonNull IModelNodeItem<?, ?> parameter);
159
160 @Nullable
161 IEntityItem addPart(@NonNull IModelNodeItem<?, ?> part);
162
163 @NonNull
164 IEntityItem addResource(@NonNull IModelNodeItem<?, ?> resource);
165
166 @NonNull
167 Collection<IEntityItem> getEntitiesByItemType(@NonNull IEntityItem.ItemType itemType);
168
169 @Nullable
170 default IEntityItem getEntity(@NonNull IEntityItem.ItemType itemType, @NonNull UUID identifier) {
171 return getEntity(itemType, ObjectUtils.notNull(identifier.toString()), false);
172 }
173
174
175
176
177
178
179
180
181
182
183
184
185
186 @Nullable
187 default IEntityItem getEntity(@NonNull IEntityItem.ItemType itemType, @NonNull String identifier) {
188 return getEntity(itemType, identifier, itemType.isUuid());
189 }
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206 @Nullable
207 IEntityItem getEntity(@NonNull IEntityItem.ItemType itemType, @NonNull String identifier, boolean normalize);
208
209 boolean removeItem(@NonNull IEntityItem entity);
210
211 boolean isSelected(@NonNull IEntityItem entity);
212
213 Map<INodeItem, SelectionStatus> getSelectionStatusMap();
214
215 @NonNull
216 SelectionStatus getSelectionStatus(@NonNull INodeItem item);
217
218 void setSelectionStatus(@NonNull INodeItem item, @NonNull SelectionStatus selectionStatus);
219
220 void resetSelectionStatus();
221
222 void append(@NonNull IIndexer result);
223
224
225
226
227
228
229 @NonNull
230 Map<ItemType, Map<String, IEntityItem>> getEntities();
231 }