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.model.control.catalog; 028 029import gov.nist.secauto.metaschema.binding.io.IDeserializationHandler; 030import gov.nist.secauto.metaschema.model.common.datatype.markup.MarkupLine; 031import gov.nist.secauto.metaschema.model.common.util.CollectionUtil; 032import gov.nist.secauto.metaschema.model.common.util.ObjectUtils; 033import gov.nist.secauto.oscal.lib.model.Control; 034import gov.nist.secauto.oscal.lib.model.ControlPart; 035import gov.nist.secauto.oscal.lib.model.Link; 036import gov.nist.secauto.oscal.lib.model.Parameter; 037import gov.nist.secauto.oscal.lib.model.Property; 038 039import java.util.LinkedList; 040import java.util.List; 041import java.util.Objects; 042import java.util.stream.Stream; 043 044import edu.umd.cs.findbugs.annotations.NonNull; 045 046public abstract class AbstractControl 047 implements IDeserializationHandler, IControl { 048 private Control parent; 049 050 @Override 051 public Control getParentControl() { 052 return parent; 053 } 054 055 @Override 056 public void setParentControl(Control parent) { 057 this.parent = parent; 058 } 059 060 @Override 061 public void beforeDeserialize(Object parent) { // NOPMD noop default 062 // do nothing 063 } 064 065 @Override 066 public void afterDeserialize(Object parent) { 067 if (parent instanceof Control) { 068 setParentControl((Control) parent); 069 } 070 } 071 072 @NonNull 073 @Override 074 public Stream<String> getReferencedParameterIds() { 075 076 // get parameters referenced by the group's parts 077 Stream<String> insertIds = CollectionUtil.listOrEmpty(getParts()).stream() 078 // Get the full part hierarchy 079 .flatMap(part -> Stream.concat(Stream.of(part), part.getPartsRecursively())) 080 // Get the inserts for each part 081 .flatMap(part -> part.getInserts(insert -> "param".equals(insert.getType().toString()))) 082 // Get the param ids for each insert 083 .map(insert -> insert.getIdReference().toString()) 084 .flatMap(ObjectUtils::filterNull); 085 086 // get parameters referenced by the control's parameters 087 Stream<String> parameterIds = CollectionUtil.listOrEmpty(getParams()).stream() 088 .flatMap(ObjectUtils::filterNull) 089 .flatMap(param -> param.getParameterReferences()); 090 091 return ObjectUtils.notNull( 092 Stream.concat(insertIds, parameterIds).distinct()); 093 } 094 095 @NonNull 096 public static Builder builder(@NonNull String id) { 097 return new Builder(id); 098 } 099 100 public static class Builder { 101 @NonNull 102 private final String id; 103 104 private String clazz; 105 private MarkupLine title; 106 private final List<Parameter> params = new LinkedList<>(); 107 private final List<Property> props = new LinkedList<>(); 108 private final List<Link> links = new LinkedList<>(); 109 private final List<ControlPart> parts = new LinkedList<>(); 110 private final List<Control> controls = new LinkedList<>(); 111 112 public Builder(@NonNull String id) { 113 this.id = Objects.requireNonNull(id, "id"); 114 } 115 116 @NonNull 117 public Builder clazz(@NonNull String value) { 118 this.clazz = Objects.requireNonNull(value); 119 return this; 120 } 121 122 @NonNull 123 public Builder title(@NonNull String markdown) { 124 this.title = MarkupLine.fromMarkdown(Objects.requireNonNull(markdown)); 125 return this; 126 } 127 128 @NonNull 129 public Builder title(@NonNull MarkupLine value) { 130 this.title = Objects.requireNonNull(value); 131 return this; 132 } 133 134 @NonNull 135 public Builder param(@NonNull Parameter value) { 136 this.params.add(Objects.requireNonNull(value)); 137 return this; 138 } 139 140 @NonNull 141 public Builder prop(@NonNull Property value) { 142 this.props.add(Objects.requireNonNull(value)); 143 return this; 144 } 145 146 @NonNull 147 public Builder link(@NonNull Link value) { 148 this.links.add(Objects.requireNonNull(value)); 149 return this; 150 } 151 152 @NonNull 153 public Builder part(@NonNull ControlPart value) { 154 this.parts.add(Objects.requireNonNull(value)); 155 return this; 156 } 157 158 @NonNull 159 public Builder control(@NonNull Control value) { 160 this.controls.add(Objects.requireNonNull(value)); 161 return this; 162 } 163 164 @NonNull 165 public Control build() { 166 Control retval = new Control(); 167 retval.setId(id); 168 169 if (title == null) { 170 throw new IllegalStateException("a title must be provided"); 171 } 172 retval.setTitle(title); 173 174 if (clazz != null) { 175 retval.setClazz(clazz); 176 } 177 if (!params.isEmpty()) { 178 retval.setParams(params); 179 } 180 if (!props.isEmpty()) { 181 retval.setProps(props); 182 } 183 if (!links.isEmpty()) { 184 retval.setLinks(links); 185 } 186 if (!parts.isEmpty()) { 187 retval.setParts(parts); 188 } 189 if (!controls.isEmpty()) { 190 controls.forEach(control -> control.setParentControl(retval)); 191 retval.setControls(controls); 192 } 193 194 return retval; 195 } 196 } 197}