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