1
2
3
4
5
6 package dev.metaschema.oscal.lib.profile.resolver.support;
7
8 import java.util.Collections;
9 import java.util.EnumSet;
10 import java.util.Set;
11
12 import dev.metaschema.core.metapath.IMetapathExpression;
13 import dev.metaschema.core.metapath.item.node.IAssemblyNodeItem;
14 import dev.metaschema.core.metapath.item.node.IDocumentNodeItem;
15 import dev.metaschema.core.metapath.item.node.IRootAssemblyNodeItem;
16 import dev.metaschema.core.util.CollectionUtil;
17 import dev.metaschema.core.util.ObjectUtils;
18 import dev.metaschema.oscal.lib.OscalBindingContext;
19 import dev.metaschema.oscal.lib.OscalModelConstants;
20 import edu.umd.cs.findbugs.annotations.NonNull;
21
22
23
24
25
26
27
28
29
30
31
32
33 public abstract class AbstractCatalogEntityVisitor<T, R>
34 extends AbstractCatalogVisitor<T, R> {
35 @NonNull
36 public static final IMetapathExpression CHILD_PART_METAPATH
37 = IMetapathExpression.compile("part|part//part",
38 OscalBindingContext.OSCAL_STATIC_METAPATH_CONTEXT);
39 @NonNull
40 private static final IMetapathExpression BACK_MATTER_RESOURCES_METAPATH
41 = IMetapathExpression.compile("back-matter/resource",
42 OscalBindingContext.OSCAL_STATIC_METAPATH_CONTEXT);
43 @NonNull
44 private static final Set<IEntityItem.ItemType> GROUP_CONTAINER_TYPES
45 = ObjectUtils.notNull(EnumSet.of(
46 IEntityItem.ItemType.GROUP,
47 IEntityItem.ItemType.CONTROL,
48 IEntityItem.ItemType.PARAMETER,
49 IEntityItem.ItemType.PART));
50 @NonNull
51 private static final Set<IEntityItem.ItemType> CONTROL_CONTAINER_TYPES
52 = ObjectUtils.notNull(EnumSet.of(
53 IEntityItem.ItemType.CONTROL,
54 IEntityItem.ItemType.PARAMETER,
55 IEntityItem.ItemType.PART));
56 @NonNull
57 private final Set<IEntityItem.ItemType> itemTypesToVisit;
58
59
60
61
62
63
64
65
66 public AbstractCatalogEntityVisitor(@NonNull Set<IEntityItem.ItemType> itemTypesToVisit) {
67 this.itemTypesToVisit = CollectionUtil.unmodifiableSet(itemTypesToVisit);
68 }
69
70 public Set<IEntityItem.ItemType> getItemTypesToVisit() {
71 return CollectionUtil.unmodifiableSet(itemTypesToVisit);
72 }
73
74 protected boolean isVisitedItemType(@NonNull IEntityItem.ItemType type) {
75 return itemTypesToVisit.contains(type);
76 }
77
78 @Override
79 public R visitCatalog(IDocumentNodeItem catalogDocument, T state) {
80 R result = super.visitCatalog(catalogDocument, state);
81
82 catalogDocument.modelItems().forEachOrdered(item -> {
83 IRootAssemblyNodeItem root = ObjectUtils.requireNonNull((IRootAssemblyNodeItem) item);
84 visitMetadata(root, state);
85 visitBackMatter(root, state);
86 });
87 return result;
88 }
89
90 @Override
91 protected R visitGroupContainer(IAssemblyNodeItem catalogOrGroup, R initialResult, T state) {
92 R retval;
93 if (Collections.disjoint(getItemTypesToVisit(), GROUP_CONTAINER_TYPES)) {
94 retval = initialResult;
95 } else {
96 retval = super.visitGroupContainer(catalogOrGroup, initialResult, state);
97 }
98 return retval;
99 }
100
101 @Override
102 protected R visitControlContainer(IAssemblyNodeItem catalogOrGroupOrControl, R initialResult, T state) {
103 R retval;
104 if (Collections.disjoint(getItemTypesToVisit(), CONTROL_CONTAINER_TYPES)) {
105 retval = initialResult;
106 } else {
107
108 retval = super.visitControlContainer(catalogOrGroupOrControl, initialResult, state);
109
110
111 if (isVisitedItemType(IEntityItem.ItemType.PARAMETER)) {
112 retval = catalogOrGroupOrControl.getModelItemsByName(OscalModelConstants.QNAME_PARAM).stream()
113 .map(paramItem -> visitParameter(
114 ObjectUtils.requireNonNull((IAssemblyNodeItem) paramItem),
115 catalogOrGroupOrControl,
116 state))
117 .reduce(retval, (first, second) -> aggregateResults(first, second, state));
118 }
119 }
120 return retval;
121 }
122
123 protected void visitParts(@NonNull IAssemblyNodeItem groupOrControlItem, T state) {
124
125 if (isVisitedItemType(IEntityItem.ItemType.PART)) {
126 CHILD_PART_METAPATH.evaluate(groupOrControlItem).stream()
127 .map(item -> (IAssemblyNodeItem) item)
128 .forEachOrdered(partItem -> {
129 visitPart(ObjectUtils.requireNonNull(partItem), groupOrControlItem, state);
130 });
131 }
132 }
133
134 @Override
135 protected R visitGroupInternal(@NonNull IAssemblyNodeItem item, R childResult, T state) {
136 if (isVisitedItemType(IEntityItem.ItemType.PART)) {
137 visitParts(item, state);
138 }
139
140 R retval = childResult;
141 if (isVisitedItemType(IEntityItem.ItemType.GROUP)) {
142 retval = visitGroup(item, retval, state);
143 }
144 return retval;
145 }
146
147 @Override
148 protected R visitControlInternal(IAssemblyNodeItem item, R childResult, T state) {
149 if (isVisitedItemType(IEntityItem.ItemType.PART)) {
150 visitParts(item, state);
151 }
152
153 R retval = childResult;
154 if (isVisitedItemType(IEntityItem.ItemType.CONTROL)) {
155 retval = visitControl(item, retval, state);
156 }
157 return retval;
158 }
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174 protected R visitParameter(
175 @NonNull IAssemblyNodeItem item,
176 @NonNull IAssemblyNodeItem catalogOrGroupOrControl,
177 T state) {
178
179 return newDefaultResult(state);
180 }
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195 protected void visitPart(
196 @NonNull IAssemblyNodeItem item,
197 @NonNull IAssemblyNodeItem groupOrControl,
198 T state) {
199
200 }
201
202
203
204
205
206
207
208
209
210
211
212 protected void visitMetadata(@NonNull IRootAssemblyNodeItem rootItem, T state) {
213 rootItem.getModelItemsByName(OscalModelConstants.QNAME_METADATA).stream()
214 .map(metadataItem -> (IAssemblyNodeItem) metadataItem)
215 .forEach(metadataItem -> {
216 if (isVisitedItemType(IEntityItem.ItemType.ROLE)) {
217 metadataItem.getModelItemsByName(OscalModelConstants.QNAME_ROLE).stream()
218 .map(roleItem -> (IAssemblyNodeItem) roleItem)
219 .forEachOrdered(roleItem -> {
220 visitRole(ObjectUtils.requireNonNull(roleItem), metadataItem, state);
221 });
222 }
223
224 if (isVisitedItemType(IEntityItem.ItemType.LOCATION)) {
225 metadataItem.getModelItemsByName(OscalModelConstants.QNAME_LOCATION).stream()
226 .map(locationItem -> (IAssemblyNodeItem) locationItem)
227 .forEachOrdered(locationItem -> {
228 visitLocation(ObjectUtils.requireNonNull(locationItem), metadataItem, state);
229 });
230 }
231
232 if (isVisitedItemType(IEntityItem.ItemType.PARTY)) {
233 metadataItem.getModelItemsByName(OscalModelConstants.QNAME_PARTY).stream()
234 .map(partyItem -> (IAssemblyNodeItem) partyItem)
235 .forEachOrdered(partyItem -> {
236 visitParty(ObjectUtils.requireNonNull(partyItem), metadataItem, state);
237 });
238 }
239 });
240 }
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255 protected void visitRole(
256 @NonNull IAssemblyNodeItem item,
257 @NonNull IAssemblyNodeItem metadataItem,
258 T state) {
259
260 }
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277 protected void visitLocation(
278 @NonNull IAssemblyNodeItem item,
279 @NonNull IAssemblyNodeItem metadataItem,
280 T state) {
281
282 }
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297 protected void visitParty(
298 @NonNull IAssemblyNodeItem item,
299 @NonNull IAssemblyNodeItem metadataItem,
300 T state) {
301
302 }
303
304
305
306
307
308
309
310
311
312
313
314 protected void visitBackMatter(@NonNull IRootAssemblyNodeItem rootItem, T state) {
315 if (isVisitedItemType(IEntityItem.ItemType.RESOURCE)) {
316 BACK_MATTER_RESOURCES_METAPATH.evaluate(rootItem).stream()
317 .map(item -> (IAssemblyNodeItem) item)
318 .forEachOrdered(resourceItem -> {
319 visitResource(ObjectUtils.requireNonNull(resourceItem), rootItem, state);
320 });
321 }
322 }
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339 protected void visitResource(
340 @NonNull IAssemblyNodeItem resource,
341 @NonNull IRootAssemblyNodeItem backMatter,
342 T state) {
343
344 }
345 }