001/* 002 * Portions of this software was developed by employees of the National Institute 003 * of Standards and Technology (NIST), an agency of the Federal Government and is 004 * being made available as a public service. Pursuant to title 17 United States 005 * Code Section 105, works of NIST employees are not subject to copyright 006 * protection in the United States. This software may be subject to foreign 007 * copyright. Permission in the United States and in foreign countries, to the 008 * extent that NIST may hold copyright, to use, copy, modify, create derivative 009 * works, and distribute this software and its documentation without fee is hereby 010 * granted on a non-exclusive basis, provided that this notice and disclaimer 011 * of warranty appears in all copies. 012 * 013 * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER 014 * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY 015 * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF 016 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM 017 * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE 018 * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT 019 * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, 020 * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, 021 * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, 022 * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR 023 * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT 024 * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. 025 */ 026 027package gov.nist.secauto.oscal.lib.profile.resolver.selection; 028 029import gov.nist.secauto.metaschema.model.common.util.ObjectUtils; 030import gov.nist.secauto.oscal.lib.model.Catalog; 031import gov.nist.secauto.oscal.lib.model.CatalogGroup; 032import gov.nist.secauto.oscal.lib.model.Control; 033import gov.nist.secauto.oscal.lib.model.Parameter; 034 035import org.apache.logging.log4j.LogManager; 036import org.apache.logging.log4j.Logger; 037 038import java.util.Collection; 039import java.util.Collections; 040import java.util.HashSet; 041import java.util.LinkedHashSet; 042import java.util.List; 043import java.util.Set; 044 045import edu.umd.cs.findbugs.annotations.NonNull; 046import nl.talsmasoftware.lazy4j.Lazy; 047 048public class DefaultResult implements IResult { 049 private static final Logger LOGGER = LogManager.getLogger(DefaultResult.class); 050 051 @NonNull 052 private final Lazy<Set<Control>> promotedControls = ObjectUtils.notNull(Lazy.lazy(LinkedHashSet::new)); 053 @NonNull 054 private final Lazy<Set<Parameter>> promotedParameters = ObjectUtils.notNull(Lazy.lazy(LinkedHashSet::new)); 055 @NonNull 056 private final Lazy<Set<CatalogGroup>> removedGroups = ObjectUtils.notNull(Lazy.lazy(HashSet::new)); 057 @NonNull 058 private final Lazy<Set<Control>> removedControls = ObjectUtils.notNull(Lazy.lazy(HashSet::new)); 059 @NonNull 060 private final Lazy<Set<Parameter>> removedParameters = ObjectUtils.notNull(Lazy.lazy(HashSet::new)); 061 062 @SuppressWarnings("null") 063 @NonNull 064 protected Collection<Parameter> getPromotedParameters() { 065 return promotedParameters.getIfAvailable().orElse(Collections.emptySet()); 066 } 067 068 @SuppressWarnings("null") 069 @NonNull 070 protected Collection<Control> getPromotedControls() { 071 return promotedControls.getIfAvailable().orElse(Collections.emptySet()); 072 } 073 074 @SuppressWarnings("null") 075 @NonNull 076 protected Collection<CatalogGroup> getRemovedGroups() { 077 return removedGroups.getIfAvailable().orElse(Collections.emptySet()); 078 } 079 080 @SuppressWarnings("null") 081 @NonNull 082 protected Collection<Control> getRemovedControls() { 083 return removedControls.getIfAvailable().orElse(Collections.emptySet()); 084 } 085 086 @SuppressWarnings("null") 087 @NonNull 088 protected Collection<Parameter> getRemovedParameters() { 089 return removedParameters.getIfAvailable().orElse(Collections.emptySet()); 090 } 091 092 @Override 093 public void promoteParameter(@NonNull Parameter param) { 094 if (LOGGER.isDebugEnabled()) { 095 LOGGER.atDebug().log("promoting parameter '{}'", param.getId()); 096 } 097 promotedParameters.get().add(param); 098 } 099 100 @Override 101 public void promoteControl(@NonNull Control control) { 102 if (LOGGER.isDebugEnabled()) { 103 LOGGER.atDebug().log("promoting control '{}'", control.getId()); 104 } 105 promotedControls.get().add(control); 106 } 107 108 @Override 109 public void applyTo(@NonNull Catalog parent) { 110 applyRemovesTo(parent); 111 getPromotedParameters().forEach(param -> parent.addParam(ObjectUtils.notNull(param))); 112 getPromotedControls().forEach(control -> { 113 assert control != null; 114 parent.addControl(control); 115 control.setParentControl(null); 116 }); 117 } 118 119 @Override 120 public void applyTo(@NonNull CatalogGroup parent) { 121 applyRemovesTo(parent); 122 getPromotedControls().forEach(control -> { 123 assert control != null; 124 parent.addControl(control); 125 control.setParentControl(null); 126 }); 127 getPromotedParameters().forEach(param -> parent.addParam(ObjectUtils.notNull(param))); 128 } 129 130 @Override 131 public void applyTo(@NonNull Control parent) { 132 applyRemovesTo(parent); 133 getPromotedControls().forEach(control -> { 134 assert control != null; 135 parent.addControl(control); 136 control.setParentControl(null); 137 }); 138 getPromotedParameters().forEach(param -> parent.addParam(ObjectUtils.notNull(param))); 139 } 140 141 public void applyRemovesTo(Catalog parent) { 142 removeItems(parent.getGroups(), getRemovedGroups()); 143 removeItems(parent.getControls(), getRemovedControls()); 144 removeItems(parent.getParams(), getRemovedParameters()); 145 } 146 147 public void applyRemovesTo(CatalogGroup parent) { 148 removeItems(parent.getGroups(), getRemovedGroups()); 149 removeItems(parent.getControls(), getRemovedControls()); 150 removeItems(parent.getParams(), getRemovedParameters()); 151 } 152 153 public void applyRemovesTo(Control parent) { 154 removeItems(parent.getControls(), getRemovedControls()); 155 removeItems(parent.getParams(), getRemovedParameters()); 156 } 157 158 public DefaultResult append(@NonNull DefaultResult that) { 159 lazyAppend(promotedControls, that.promotedControls); 160 lazyAppend(promotedParameters, that.promotedParameters); 161 lazyAppend(removedGroups, that.removedGroups); 162 lazyAppend(removedControls, that.removedControls); 163 lazyAppend(removedParameters, that.removedParameters); 164 return this; 165 } 166 167 public DefaultResult appendPromoted(@NonNull DefaultResult that) { 168 lazyAppend(promotedControls, that.promotedControls); 169 lazyAppend(promotedParameters, that.promotedParameters); 170 return this; 171 } 172 173 protected static <T> void lazyAppend(@NonNull Lazy<Set<T>> self, @NonNull Lazy<Set<T>> other) { 174 if (other.isAvailable()) { 175 Set<T> otherSet = other.get(); 176 if (!otherSet.isEmpty()) { 177 self.get().addAll(otherSet); 178 } 179 } 180 } 181 182 protected static <T> void removeItems(List<T> list, @NonNull Collection<T> itemsToDelete) { 183 itemsToDelete.forEach(item -> { 184 if (!list.remove(item)) { 185 LOGGER.atError().log("item didn't exist in list"); 186 } 187 }); 188 } 189 190 public void removeGroup(CatalogGroup group) { 191 if (LOGGER.isDebugEnabled()) { 192 LOGGER.atDebug().log("Requesting removal of group '{}'.", group.getId()); 193 } 194 removedGroups.get().add(group); 195 } 196 197 public void removeControl(Control control) { 198 if (LOGGER.isDebugEnabled()) { 199 LOGGER.atDebug().log("Requesting removal of control '{}'.", control.getId()); 200 } 201 removedControls.get().add(control); 202 } 203 204 public void removeParameter(Parameter parameter) { 205 if (LOGGER.isDebugEnabled()) { 206 LOGGER.atDebug().log("Requesting removal of parameter '{}'.", parameter.getId()); 207 } 208 removedParameters.get().add(parameter); 209 } 210}