1 /*
2 * SPDX-FileCopyrightText: none
3 * SPDX-License-Identifier: CC0-1.0
4 */
5
6 package dev.metaschema.oscal.lib.profile.resolver.support;
7
8 import dev.metaschema.core.metapath.item.node.IAssemblyNodeItem;
9 import dev.metaschema.core.metapath.item.node.IDocumentNodeItem;
10 import dev.metaschema.core.util.ObjectUtils;
11 import dev.metaschema.oscal.lib.OscalModelConstants;
12 import edu.umd.cs.findbugs.annotations.NonNull;
13
14 /**
15 * Used to visit a catalog containing groups and controls.
16 *
17 * @param <T>
18 * the type of the state object used to pass calling context
19 * information
20 * @param <R>
21 * the type of the result for visiting a collection of groups and/or
22 * controls
23 */
24 public abstract class AbstractCatalogVisitor<T, R> implements ICatalogVisitor<T, R> {
25
26 protected abstract R newDefaultResult(T state);
27
28 protected abstract R aggregateResults(R first, R second, T state);
29
30 protected R visitCatalog(@NonNull IDocumentNodeItem catalogDocument, T state) {
31 return catalogDocument.modelItems().reduce(
32 newDefaultResult(state),
33 (result, catalogOrGroup) -> visitGroupContainer(
34 ObjectUtils.requireNonNull((IAssemblyNodeItem) catalogOrGroup), result, state),
35 (result1, result2) -> aggregateResults(result1, result2, state));
36 }
37
38 /**
39 * Visit the child groups and controls (in that order) of a given catalog or
40 * group container.
41 *
42 * @param catalogOrGroup
43 * the catalog or group Metapath item currently being visited
44 * @param initialResult
45 * the initial result value to use when aggregating child results
46 * @param state
47 * the current visitor state
48 * @return a meaningful result of the given type
49 */
50 protected R visitGroupContainer(
51 @NonNull IAssemblyNodeItem catalogOrGroup,
52 R initialResult,
53 T state) {
54 R result = catalogOrGroup.getModelItemsByName(OscalModelConstants.QNAME_GROUP).stream()
55 .map(groupItem -> {
56 return visitGroupItem(
57 ObjectUtils.requireNonNull((IAssemblyNodeItem) groupItem),
58 state);
59 })
60 .reduce(initialResult, (first, second) -> aggregateResults(first, second, state));
61 return visitControlContainer(catalogOrGroup, result, state);
62 }
63
64 /**
65 * Called when visiting a group.
66 * <p>
67 * This method will first visit the group's children, then the group itself.
68 *
69 * @param group
70 * the group Metapath item to visit
71 * @param state
72 * the current visitor state
73 * @return a meaningful result of the given type
74 */
75 protected R visitGroupItem(@NonNull IAssemblyNodeItem group, T state) {
76 R childResult = visitGroupContainer(group, newDefaultResult(state), state);
77 return visitGroupInternal(group, childResult, state);
78 }
79
80 /**
81 * Called when visiting a group after visiting it's children.
82 *
83 * @param group
84 * the group Metapath item currently being visited
85 * @param childResult
86 * the result of visiting the group's children
87 * @param state
88 * the current visitor state
89 * @return a meaningful result of the given type
90 */
91 protected R visitGroupInternal(
92 @NonNull IAssemblyNodeItem group,
93 R childResult,
94 T state) {
95 return visitGroup(group, childResult, state);
96 }
97
98 /**
99 * Visit the child controls (in that order) of a given catalog, group, or
100 * control container.
101 *
102 * @param catalogOrGroupOrControl
103 * the catalog, group, or control Metapath item currently being visited
104 * @param initialResult
105 * the initial result value to use when aggregating child results
106 * @param state
107 * the current visitor state
108 * @return a meaningful result of the given type
109 */
110 protected R visitControlContainer(
111 @NonNull IAssemblyNodeItem catalogOrGroupOrControl,
112 R initialResult,
113 T state) {
114 return catalogOrGroupOrControl.getModelItemsByName(OscalModelConstants.QNAME_CONTROL).stream()
115 .map(control -> {
116 return visitControlItem(ObjectUtils.requireNonNull((IAssemblyNodeItem) control), state);
117 })
118 .reduce(initialResult, (first, second) -> aggregateResults(first, second, state));
119 }
120
121 /**
122 * Called when visiting a control.
123 * <p>
124 * This method will first visit the control's children, then the control itself.
125 *
126 * @param control
127 * the control Metapath item to visit
128 * @param state
129 * the current visitor state
130 * @return a meaningful result of the given type
131 */
132 protected R visitControlItem(@NonNull IAssemblyNodeItem control, T state) {
133 R childResult = visitControlContainer(control, newDefaultResult(state), state);
134 return visitControlInternal(control, childResult, state);
135 }
136
137 /**
138 * Called when visiting a control after visiting it's children.
139 *
140 * @param control
141 * the Metapath item for the control currently being visited
142 * @param childResult
143 * the result of visiting the control's children
144 * @param state
145 * the calling context information
146 * @return a meaningful result of the given type
147 */
148 protected R visitControlInternal(@NonNull IAssemblyNodeItem control, R childResult, T state) {
149 return visitControl(control, childResult, state);
150 }
151 }