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