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