001/* 002 * SPDX-FileCopyrightText: none 003 * SPDX-License-Identifier: CC0-1.0 004 */ 005 006package gov.nist.secauto.oscal.lib.profile.resolver.merge; 007 008import gov.nist.secauto.metaschema.core.metapath.item.node.IAssemblyNodeItem; 009import gov.nist.secauto.metaschema.core.metapath.item.node.IDocumentNodeItem; 010import gov.nist.secauto.metaschema.core.metapath.item.node.IRootAssemblyNodeItem; 011import gov.nist.secauto.metaschema.core.util.ObjectUtils; 012import gov.nist.secauto.oscal.lib.model.BackMatter.Resource; 013import gov.nist.secauto.oscal.lib.model.CatalogGroup; 014import gov.nist.secauto.oscal.lib.model.Control; 015import gov.nist.secauto.oscal.lib.model.ControlPart; 016import gov.nist.secauto.oscal.lib.model.Metadata.Location; 017import gov.nist.secauto.oscal.lib.model.Metadata.Party; 018import gov.nist.secauto.oscal.lib.model.Metadata.Role; 019import gov.nist.secauto.oscal.lib.model.Parameter; 020import gov.nist.secauto.oscal.lib.profile.resolver.ProfileResolver; 021import gov.nist.secauto.oscal.lib.profile.resolver.policy.ReferenceCountingVisitor; 022import gov.nist.secauto.oscal.lib.profile.resolver.selection.DefaultResult; 023import gov.nist.secauto.oscal.lib.profile.resolver.selection.FilterNonSelectedVisitor; 024import gov.nist.secauto.oscal.lib.profile.resolver.support.AbstractCatalogEntityVisitor; 025import gov.nist.secauto.oscal.lib.profile.resolver.support.IEntityItem; 026import gov.nist.secauto.oscal.lib.profile.resolver.support.IEntityItem.ItemType; 027import gov.nist.secauto.oscal.lib.profile.resolver.support.IIndexer; 028import gov.nist.secauto.oscal.lib.profile.resolver.support.IIndexer.SelectionStatus; 029 030import java.util.EnumSet; 031import java.util.UUID; 032 033import edu.umd.cs.findbugs.annotations.NonNull; 034import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 035 036public class FlatteningStructuringVisitor 037 extends AbstractCatalogEntityVisitor<IIndexer, Void> { 038 @NonNull 039 private final ProfileResolver.UriResolver uriResolver; 040 041 public FlatteningStructuringVisitor(@NonNull ProfileResolver.UriResolver uriResolver) { 042 super(ObjectUtils.notNull(EnumSet.of(ItemType.GROUP, ItemType.CONTROL))); 043 this.uriResolver = uriResolver; 044 } 045 046 @Override 047 protected Void newDefaultResult(IIndexer state) { 048 // do nothing 049 return null; 050 } 051 052 @Override 053 protected Void aggregateResults(Void first, Void second, IIndexer state) { 054 // do nothing 055 return null; 056 } 057 058 @Override 059 public Void visitCatalog(@NonNull IDocumentNodeItem catalogItem, IIndexer index) { 060 index.resetSelectionStatus(); 061 062 index.setSelectionStatus(catalogItem, SelectionStatus.SELECTED); 063 super.visitCatalog(catalogItem, index); 064 065 for (ItemType itemType : ItemType.values()) { 066 assert itemType != null; 067 for (IEntityItem item : index.getEntitiesByItemType(itemType)) { 068 item.resetReferenceCount(); 069 } 070 } 071 072 // process references, looking for orphaned links to groups 073 ReferenceCountingVisitor.instance().visitCatalog(catalogItem, index, uriResolver); 074 075 FlatteningFilterNonSelectedVisitor.instance().visitCatalog(catalogItem, index); 076 return null; 077 } 078 079 @Override 080 public Void visitGroup( 081 IAssemblyNodeItem item, 082 Void childResult, 083 IIndexer index) { 084 CatalogGroup group = ObjectUtils.requireNonNull((CatalogGroup) item.getValue()); 085 String id = group.getId(); 086 if (id != null) { 087 IEntityItem entity = index.getEntity(ItemType.GROUP, id); 088 assert entity != null; 089 // refresh the instance 090 entity.setInstance(item); 091 } 092 093 index.setSelectionStatus(item, SelectionStatus.UNSELECTED); 094 handlePartSelection(item, index, SelectionStatus.UNSELECTED); 095 return super.visitGroup(item, childResult, index); 096 } 097 098 @Override 099 public Void visitControl( 100 IAssemblyNodeItem item, 101 Void childResult, 102 IIndexer index) { 103 Control control = ObjectUtils.requireNonNull((Control) item.getValue()); 104 String id = ObjectUtils.requireNonNull(control.getId()); 105 IEntityItem entity = index.getEntity(ItemType.CONTROL, id); 106 assert entity != null; 107 // refresh the instance 108 entity.setInstance(item); 109 110 index.setSelectionStatus(item, SelectionStatus.SELECTED); 111 handlePartSelection(item, index, SelectionStatus.SELECTED); 112 return null; 113 } 114 115 @Override 116 protected Void visitParameter( 117 IAssemblyNodeItem item, 118 IAssemblyNodeItem catalogOrGroupOrControl, 119 IIndexer index) { 120 Parameter parameter = ObjectUtils.requireNonNull((Parameter) item.getValue()); 121 String id = ObjectUtils.requireNonNull(parameter.getId()); 122 IEntityItem entity = index.getEntity(ItemType.PARAMETER, id); 123 assert entity != null; 124 // refresh the instance 125 entity.setInstance(item); 126 127 return null; 128 } 129 130 @Override 131 protected void visitRole( 132 IAssemblyNodeItem item, 133 IAssemblyNodeItem metadataItem, 134 IIndexer index) { 135 Role role = ObjectUtils.requireNonNull((Role) item.getValue()); 136 String id = ObjectUtils.requireNonNull(role.getId()); 137 IEntityItem entity = index.getEntity(ItemType.ROLE, id); 138 assert entity != null; 139 // refresh the instance 140 entity.setInstance(item); 141 } 142 143 @Override 144 protected void visitLocation( 145 IAssemblyNodeItem item, 146 IAssemblyNodeItem metadataItem, 147 IIndexer index) { 148 Location location = ObjectUtils.requireNonNull((Location) item.getValue()); 149 UUID uuid = ObjectUtils.requireNonNull(location.getUuid()); 150 IEntityItem entity = index.getEntity(ItemType.LOCATION, uuid); 151 assert entity != null; 152 // refresh the instance 153 entity.setInstance(item); 154 } 155 156 @Override 157 protected void visitParty( 158 IAssemblyNodeItem item, 159 IAssemblyNodeItem metadataItem, 160 IIndexer index) { 161 Party location = ObjectUtils.requireNonNull((Party) item.getValue()); 162 UUID uuid = ObjectUtils.requireNonNull(location.getUuid()); 163 IEntityItem entity = index.getEntity(ItemType.PARTY, uuid); 164 assert entity != null; 165 // refresh the instance 166 entity.setInstance(item); 167 } 168 169 @Override 170 protected void visitResource( 171 IAssemblyNodeItem item, 172 IRootAssemblyNodeItem rootItem, 173 IIndexer index) { 174 Resource location = ObjectUtils.requireNonNull((Resource) item.getValue()); 175 UUID uuid = ObjectUtils.requireNonNull(location.getUuid()); 176 IEntityItem entity = index.getEntity(ItemType.RESOURCE, uuid); 177 assert entity != null; 178 // refresh the instance 179 entity.setInstance(item); 180 } 181 182 private static void handlePartSelection( 183 @NonNull IAssemblyNodeItem groupOrControlItem, 184 @NonNull IIndexer index, 185 @NonNull SelectionStatus selectionStatus) { 186 CHILD_PART_METAPATH.evaluate(groupOrControlItem).stream() 187 .map(item -> (IAssemblyNodeItem) item) 188 .forEachOrdered(partItem -> { 189 index.setSelectionStatus(ObjectUtils.requireNonNull(partItem), selectionStatus); 190 191 ControlPart part = ObjectUtils.requireNonNull((ControlPart) partItem.getValue()); 192 String id = part.getId(); 193 if (id != null) { 194 IEntityItem entity = index.getEntity(ItemType.PART, id); 195 assert entity != null; 196 // refresh the instance 197 entity.setInstance(partItem); 198 } 199 }); 200 } 201 202 private static final class FlatteningFilterNonSelectedVisitor 203 extends FilterNonSelectedVisitor { 204 private static final FlatteningFilterNonSelectedVisitor SINGLETON = new FlatteningFilterNonSelectedVisitor(); 205 206 @SuppressFBWarnings(value = "SING_SINGLETON_GETTER_NOT_SYNCHRONIZED", justification = "class initialization") 207 public static FlatteningFilterNonSelectedVisitor instance() { 208 return SINGLETON; 209 } 210 211 @Override 212 public DefaultResult visitControl(IAssemblyNodeItem item, DefaultResult childResult, 213 Context context) { 214 assert childResult != null; 215 216 Control control = ObjectUtils.requireNonNull((Control) item.getValue()); 217 IIndexer index = context.getIndexer(); 218 // this control should always be found in the index 219 IEntityItem entity = ObjectUtils.requireNonNull( 220 index.getEntity(ItemType.CONTROL, ObjectUtils.requireNonNull(control.getId()), false)); 221 222 IAssemblyNodeItem parent = ObjectUtils.notNull(item.getParentContentNodeItem()); 223 DefaultResult retval = new DefaultResult(); 224 if (SelectionStatus.SELECTED.equals(index.getSelectionStatus(item))) { 225 // keep this control 226 227 // always promote the control and any children 228 retval.promoteControl(control); 229 230 retval.appendPromoted(childResult); 231 childResult.applyRemovesTo(control); 232 233 if (parent.getValue() instanceof Control && SelectionStatus.SELECTED.equals(index.getSelectionStatus(parent))) { 234 retval.removeControl(control); 235 } 236 } else { 237 // remove this control and promote any needed children 238 239 if (SelectionStatus.SELECTED.equals(index.getSelectionStatus(parent))) { 240 retval.removeControl(control); 241 } 242 retval.appendPromoted(ObjectUtils.notNull(childResult)); 243 index.removeItem(entity); 244 245 // remove any associated parts from the index 246 removePartsFromIndex(item, index); 247 } 248 return retval; 249 } 250 } 251}