1
2
3
4
5
6 package gov.nist.secauto.oscal.lib.profile.resolver.merge;
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.BackMatter.Resource;
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.model.Metadata.Location;
17 import gov.nist.secauto.oscal.lib.model.Metadata.Party;
18 import gov.nist.secauto.oscal.lib.model.Metadata.Role;
19 import gov.nist.secauto.oscal.lib.model.Parameter;
20 import gov.nist.secauto.oscal.lib.profile.resolver.policy.ReferenceCountingVisitor;
21 import gov.nist.secauto.oscal.lib.profile.resolver.selection.DefaultResult;
22 import gov.nist.secauto.oscal.lib.profile.resolver.selection.FilterNonSelectedVisitor;
23 import gov.nist.secauto.oscal.lib.profile.resolver.support.AbstractCatalogEntityVisitor;
24 import gov.nist.secauto.oscal.lib.profile.resolver.support.IEntityItem;
25 import gov.nist.secauto.oscal.lib.profile.resolver.support.IEntityItem.ItemType;
26 import gov.nist.secauto.oscal.lib.profile.resolver.support.IIndexer;
27 import gov.nist.secauto.oscal.lib.profile.resolver.support.IIndexer.SelectionStatus;
28
29 import java.net.URI;
30 import java.util.EnumSet;
31 import java.util.UUID;
32
33 import edu.umd.cs.findbugs.annotations.NonNull;
34 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
35
36 public class FlatteningStructuringVisitor
37 extends AbstractCatalogEntityVisitor<IIndexer, Void> {
38 private static final FlatteningStructuringVisitor SINGLETON = new FlatteningStructuringVisitor();
39
40 @SuppressFBWarnings(value = "SING_SINGLETON_GETTER_NOT_SYNCHRONIZED", justification = "class initialization")
41 public static FlatteningStructuringVisitor instance() {
42 return SINGLETON;
43 }
44
45 @SuppressFBWarnings(value = "SING_SINGLETON_HAS_NONPRIVATE_CONSTRUCTOR",
46 justification = "public constructor allows for extension usecases")
47 public FlatteningStructuringVisitor() {
48 super(ObjectUtils.notNull(EnumSet.of(ItemType.GROUP, ItemType.CONTROL)));
49 }
50
51 @Override
52 protected Void newDefaultResult(IIndexer state) {
53
54 return null;
55 }
56
57 @Override
58 protected Void aggregateResults(Void first, Void second, IIndexer state) {
59
60 return null;
61 }
62
63 @Override
64 public Void visitCatalog(@NonNull IDocumentNodeItem catalogItem, IIndexer index) {
65 index.resetSelectionStatus();
66
67 index.setSelectionStatus(catalogItem, SelectionStatus.SELECTED);
68 super.visitCatalog(catalogItem, index);
69
70 for (ItemType itemType : ItemType.values()) {
71 assert itemType != null;
72 for (IEntityItem item : index.getEntitiesByItemType(itemType)) {
73 item.resetReferenceCount();
74 }
75 }
76
77
78 URI catalogUri = ObjectUtils.requireNonNull(catalogItem.getDocumentUri());
79 ReferenceCountingVisitor.instance().visitCatalog(catalogItem, index, catalogUri);
80
81 FlatteningFilterNonSelectedVisitor.instance().visitCatalog(catalogItem, index);
82 return null;
83 }
84
85 @Override
86 public Void visitGroup(
87 IAssemblyNodeItem item,
88 Void childResult,
89 IIndexer index) {
90 CatalogGroup group = ObjectUtils.requireNonNull((CatalogGroup) item.getValue());
91 String id = group.getId();
92 if (id != null) {
93 IEntityItem entity = index.getEntity(ItemType.GROUP, id);
94 assert entity != null;
95
96 entity.setInstance(item);
97 }
98
99 index.setSelectionStatus(item, SelectionStatus.UNSELECTED);
100 handlePartSelection(item, index, SelectionStatus.UNSELECTED);
101 return super.visitGroup(item, childResult, index);
102 }
103
104 @Override
105 public Void visitControl(
106 IAssemblyNodeItem item,
107 Void childResult,
108 IIndexer index) {
109 Control control = ObjectUtils.requireNonNull((Control) item.getValue());
110 String id = ObjectUtils.requireNonNull(control.getId());
111 IEntityItem entity = index.getEntity(ItemType.CONTROL, id);
112 assert entity != null;
113
114 entity.setInstance(item);
115
116 index.setSelectionStatus(item, SelectionStatus.SELECTED);
117 handlePartSelection(item, index, SelectionStatus.SELECTED);
118 return null;
119 }
120
121 @Override
122 protected Void visitParameter(
123 IAssemblyNodeItem item,
124 IAssemblyNodeItem catalogOrGroupOrControl,
125 IIndexer index) {
126 Parameter parameter = ObjectUtils.requireNonNull((Parameter) item.getValue());
127 String id = ObjectUtils.requireNonNull(parameter.getId());
128 IEntityItem entity = index.getEntity(ItemType.PARAMETER, id);
129 assert entity != null;
130
131 entity.setInstance(item);
132
133 return null;
134 }
135
136 @Override
137 protected void visitRole(
138 IAssemblyNodeItem item,
139 IAssemblyNodeItem metadataItem,
140 IIndexer index) {
141 Role role = ObjectUtils.requireNonNull((Role) item.getValue());
142 String id = ObjectUtils.requireNonNull(role.getId());
143 IEntityItem entity = index.getEntity(ItemType.ROLE, id);
144 assert entity != null;
145
146 entity.setInstance(item);
147 }
148
149 @Override
150 protected void visitLocation(
151 IAssemblyNodeItem item,
152 IAssemblyNodeItem metadataItem,
153 IIndexer index) {
154 Location location = ObjectUtils.requireNonNull((Location) item.getValue());
155 UUID uuid = ObjectUtils.requireNonNull(location.getUuid());
156 IEntityItem entity = index.getEntity(ItemType.LOCATION, uuid);
157 assert entity != null;
158
159 entity.setInstance(item);
160 }
161
162 @Override
163 protected void visitParty(
164 IAssemblyNodeItem item,
165 IAssemblyNodeItem metadataItem,
166 IIndexer index) {
167 Party location = ObjectUtils.requireNonNull((Party) item.getValue());
168 UUID uuid = ObjectUtils.requireNonNull(location.getUuid());
169 IEntityItem entity = index.getEntity(ItemType.PARTY, uuid);
170 assert entity != null;
171
172 entity.setInstance(item);
173 }
174
175 @Override
176 protected void visitResource(
177 IAssemblyNodeItem item,
178 IRootAssemblyNodeItem rootItem,
179 IIndexer index) {
180 Resource location = ObjectUtils.requireNonNull((Resource) item.getValue());
181 UUID uuid = ObjectUtils.requireNonNull(location.getUuid());
182 IEntityItem entity = index.getEntity(ItemType.RESOURCE, uuid);
183 assert entity != null;
184
185 entity.setInstance(item);
186 }
187
188 private static void handlePartSelection(
189 @NonNull IAssemblyNodeItem groupOrControlItem,
190 @NonNull IIndexer index,
191 @NonNull SelectionStatus selectionStatus) {
192 CHILD_PART_METAPATH.evaluate(groupOrControlItem).stream()
193 .map(item -> (IAssemblyNodeItem) item)
194 .forEachOrdered(partItem -> {
195 index.setSelectionStatus(ObjectUtils.requireNonNull(partItem), selectionStatus);
196
197 ControlPart part = ObjectUtils.requireNonNull((ControlPart) partItem.getValue());
198 String id = part.getId();
199 if (id != null) {
200 IEntityItem entity = index.getEntity(ItemType.PART, id);
201 assert entity != null;
202
203 entity.setInstance(partItem);
204 }
205 });
206 }
207
208 private static final class FlatteningFilterNonSelectedVisitor
209 extends FilterNonSelectedVisitor {
210 private static final FlatteningFilterNonSelectedVisitor SINGLETON = new FlatteningFilterNonSelectedVisitor();
211
212 @SuppressFBWarnings(value = "SING_SINGLETON_GETTER_NOT_SYNCHRONIZED", justification = "class initialization")
213 public static FlatteningFilterNonSelectedVisitor instance() {
214 return SINGLETON;
215 }
216
217 @Override
218 public DefaultResult visitControl(IAssemblyNodeItem item, DefaultResult childResult,
219 Context context) {
220 assert childResult != null;
221
222 Control control = ObjectUtils.requireNonNull((Control) item.getValue());
223 IIndexer index = context.getIndexer();
224
225 IEntityItem entity = ObjectUtils.requireNonNull(
226 index.getEntity(ItemType.CONTROL, ObjectUtils.requireNonNull(control.getId()), false));
227
228 IAssemblyNodeItem parent = ObjectUtils.notNull(item.getParentContentNodeItem());
229 DefaultResult retval = new DefaultResult();
230 if (SelectionStatus.SELECTED.equals(index.getSelectionStatus(item))) {
231
232
233
234 retval.promoteControl(control);
235
236 retval.appendPromoted(childResult);
237 childResult.applyRemovesTo(control);
238
239 if (parent.getValue() instanceof Control && SelectionStatus.SELECTED.equals(index.getSelectionStatus(parent))) {
240 retval.removeControl(control);
241 }
242 } else {
243
244
245 if (SelectionStatus.SELECTED.equals(index.getSelectionStatus(parent))) {
246 retval.removeControl(control);
247 }
248 retval.appendPromoted(ObjectUtils.notNull(childResult));
249 index.removeItem(entity);
250
251
252 removePartsFromIndex(item, index);
253 }
254 return retval;
255 }
256 }
257 }