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.selection;
28
29 import gov.nist.secauto.metaschema.model.common.metapath.item.IDocumentNodeItem;
30 import gov.nist.secauto.metaschema.model.common.metapath.item.IRequiredValueModelNodeItem;
31 import gov.nist.secauto.metaschema.model.common.metapath.item.IRootAssemblyNodeItem;
32 import gov.nist.secauto.metaschema.model.common.util.ObjectUtils;
33 import gov.nist.secauto.oscal.lib.model.Catalog;
34 import gov.nist.secauto.oscal.lib.model.CatalogGroup;
35 import gov.nist.secauto.oscal.lib.model.Control;
36 import gov.nist.secauto.oscal.lib.model.ControlPart;
37 import gov.nist.secauto.oscal.lib.profile.resolver.support.AbstractIndexingVisitor;
38 import gov.nist.secauto.oscal.lib.profile.resolver.support.IEntityItem;
39 import gov.nist.secauto.oscal.lib.profile.resolver.support.IIndexer;
40 import gov.nist.secauto.oscal.lib.profile.resolver.support.IIndexer.SelectionStatus;
41
42 import org.apache.logging.log4j.LogManager;
43 import org.apache.logging.log4j.Logger;
44
45 import edu.umd.cs.findbugs.annotations.NonNull;
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69 public class ControlSelectionVisitor
70 extends AbstractIndexingVisitor<IControlSelectionState, Boolean> {
71 private static final Logger LOGGER = LogManager.getLogger(ControlSelectionVisitor.class);
72
73 private static final ControlSelectionVisitor SINGLETON = new ControlSelectionVisitor();
74
75 public static ControlSelectionVisitor instance() {
76 return SINGLETON;
77 }
78
79 @Override
80 protected IIndexer getIndexer(IControlSelectionState state) {
81 return state.getIndex();
82 }
83
84 @Override
85 protected Boolean newDefaultResult(IControlSelectionState state) {
86 return false;
87 }
88
89 @Override
90 protected Boolean aggregateResults(Boolean first, Boolean second, IControlSelectionState state) {
91 return first || second;
92 }
93
94 public void visit(@NonNull IDocumentNodeItem catalogDocument, @NonNull IControlSelectionState state) {
95 visitCatalog(catalogDocument, state);
96 }
97
98 public void visitProfile(
99 @NonNull IDocumentNodeItem catalogDocument,
100 @NonNull IDocumentNodeItem profileDocument,
101 @NonNull IControlSelectionState state) {
102 visit(catalogDocument, state);
103
104 IRootAssemblyNodeItem root = profileDocument.getRootAssemblyNodeItem();
105
106 visitMetadata(root, state);
107 visitBackMatter(root, state);
108 }
109
110 @Override
111 public Boolean visitCatalog(IDocumentNodeItem catalogDocument, IControlSelectionState state) {
112 getIndexer(state).setSelectionStatus(catalogDocument, SelectionStatus.SELECTED);
113 return super.visitCatalog(catalogDocument, state);
114 }
115
116 @Override
117 public Boolean visitGroup(IRequiredValueModelNodeItem groupItem, Boolean childSelected,
118 IControlSelectionState state) {
119 super.visitGroup(groupItem, childSelected, state);
120 if (LOGGER.isTraceEnabled()) {
121 CatalogGroup group = (CatalogGroup) groupItem.getValue();
122 LOGGER.atTrace().log("Selecting group '{}'. match={}", group.getId(), childSelected);
123 }
124
125
126 assert state.isSelected(groupItem) == childSelected;
127
128 if (childSelected) {
129 getIndexer(state).setSelectionStatus(groupItem, SelectionStatus.SELECTED);
130 } else {
131 getIndexer(state).setSelectionStatus(groupItem, SelectionStatus.UNSELECTED);
132 }
133
134 handlePartSelection(groupItem, childSelected, state);
135 return childSelected;
136 }
137
138 private void handlePartSelection(
139 @NonNull IRequiredValueModelNodeItem groupOrControlItem,
140 boolean selected,
141 IControlSelectionState state) {
142 if (isVisitedItemType(IEntityItem.ItemType.PART)) {
143 SelectionStatus selectionStatus = selected ? SelectionStatus.SELECTED : SelectionStatus.UNSELECTED;
144
145 IIndexer index = getIndexer(state);
146 CHILD_PART_METAPATH.evaluate(groupOrControlItem).asStream()
147 .map(item -> (IRequiredValueModelNodeItem) item)
148 .forEachOrdered(partItem -> {
149 index.setSelectionStatus(ObjectUtils.requireNonNull(partItem), selectionStatus);
150 });
151 }
152 }
153
154 @Override
155 public Boolean visitControl(
156 IRequiredValueModelNodeItem controlItem,
157 Boolean childResult,
158 IControlSelectionState state) {
159 super.visitControl(controlItem, childResult, state);
160
161 boolean selected = state.isSelected(controlItem);
162 if (selected) {
163 getIndexer(state).setSelectionStatus(controlItem, SelectionStatus.SELECTED);
164 } else {
165 getIndexer(state).setSelectionStatus(controlItem, SelectionStatus.UNSELECTED);
166 }
167
168 handlePartSelection(controlItem, selected, state);
169 return selected;
170 }
171 }