001package gov.nist.secauto.oscal.lib.model; 002 003import gov.nist.secauto.metaschema.binding.model.annotations.AllowedValue; 004import gov.nist.secauto.metaschema.binding.model.annotations.AllowedValues; 005import gov.nist.secauto.metaschema.binding.model.annotations.AssemblyConstraints; 006import gov.nist.secauto.metaschema.binding.model.annotations.BoundAssembly; 007import gov.nist.secauto.metaschema.binding.model.annotations.BoundField; 008import gov.nist.secauto.metaschema.binding.model.annotations.BoundFieldValue; 009import gov.nist.secauto.metaschema.binding.model.annotations.BoundFlag; 010import gov.nist.secauto.metaschema.binding.model.annotations.GroupAs; 011import gov.nist.secauto.metaschema.binding.model.annotations.HasCardinality; 012import gov.nist.secauto.metaschema.binding.model.annotations.MetaschemaAssembly; 013import gov.nist.secauto.metaschema.binding.model.annotations.ValueConstraints; 014import gov.nist.secauto.metaschema.model.common.JsonGroupAsBehavior; 015import gov.nist.secauto.metaschema.model.common.constraint.IConstraint; 016import gov.nist.secauto.metaschema.model.common.datatype.adapter.TokenAdapter; 017import gov.nist.secauto.metaschema.model.common.datatype.adapter.UriAdapter; 018import gov.nist.secauto.metaschema.model.common.datatype.adapter.UuidAdapter; 019import gov.nist.secauto.metaschema.model.common.datatype.markup.MarkupLine; 020import gov.nist.secauto.metaschema.model.common.datatype.markup.MarkupLineAdapter; 021import gov.nist.secauto.metaschema.model.common.datatype.markup.MarkupMultiline; 022import gov.nist.secauto.metaschema.model.common.datatype.markup.MarkupMultilineAdapter; 023import gov.nist.secauto.metaschema.model.common.util.ObjectUtils; 024import java.lang.Override; 025import java.lang.String; 026import java.net.URI; 027import java.util.LinkedList; 028import java.util.List; 029import java.util.UUID; 030import org.apache.commons.lang3.builder.MultilineRecursiveToStringStyle; 031import org.apache.commons.lang3.builder.ReflectionToStringBuilder; 032 033/** 034 * A partition of an assessment plan or results or a child of another part. 035 */ 036@MetaschemaAssembly( 037 formalName = "Assessment Part", 038 description = "A partition of an assessment plan or results or a child of another part.", 039 name = "assessment-part", 040 metaschema = OscalAssessmentCommonMetaschema.class, 041 remarks = "A `part` provides for logical partitioning of prose, and can be thought of as a grouping structure (e.g., section). A `part` can have child parts allowing for arbitrary nesting of prose content (e.g., statement hierarchy). A `part` can contain `prop` objects that allow for enriching prose text with structured name/value information.\n" 042 + "\n" 043 + "A `part` can be assigned an optional `id`, which allows for internal and external references to the textual concept contained within a `part`. A `id` provides a means for an OSCAL profile, or a higher layer OSCAL model to reference a specific part within a `catalog`. For example, an `id` can be used to reference or to make modifications to a control statement in a profile.\n" 044 + "\n" 045 + "Use of `part` and `prop` provides for a wide degree of extensibility within the OSCAL catalog model. The optional `ns` provides a means to qualify a part's `name`, allowing for organization-specific vocabularies to be defined with clear semantics. Any organization that extends OSCAL in this way should consistently assign a `ns` value that represents the organization, making a given namespace qualified `name` unique to that organization. This allows the combination of `ns` and `name` to always be unique and unambiguous, even when mixed with extensions from other organizations. Each organization is responsible for governance of their own extensions, and is strongly encouraged to publish their extensions as standards to their user community. If no `ns` is provided, the name is expected to be in the \"OSCAL\" namespace.\n" 046 + "\n" 047 + "To ensure a `ns` is unique to an organization and naming conflicts are avoided, a URI containing a DNS or other globally defined organization name should be used. For example, if FedRAMP and DoD both extend OSCAL, FedRAMP will use the `ns` `http://fedramp.gov/ns/oscal`, while DoD might use the `ns` `https://defense.gov` for any organization specific `name`.\n" 048 + "\n" 049 + "Tools that process OSCAL content are not required to interpret unrecognized OSCAL extensions; however, OSCAL compliant tools should not modify or remove unrecognized extensions, unless there is a compelling reason to do so, such as data sensitivity." 050) 051@ValueConstraints( 052 allowedValues = { 053 @AllowedValues(level = IConstraint.Level.ERROR, target = ".[@name='objective']/prop[has-oscal-namespace('http://csrc.nist.gov/ns/oscal')]/@name", values = @AllowedValue(value = "method", description = "The assessment method to use. This typically appears on parts with the name \"objective\".")), 054 @AllowedValues(level = IConstraint.Level.ERROR, target = ".[@name='objective']/prop[has-oscal-namespace('http://csrc.nist.gov/ns/oscal') and @name='method']/@value", values = {@AllowedValue(value = "INTERVIEW", description = "The process of holding discussions with individuals or groups of individuals within an organization to once again, facilitate assessor understanding, achieve clarification, or obtain evidence."), @AllowedValue(value = "EXAMINE", description = "The process of reviewing, inspecting, observing, studying, or analyzing one or more assessment objects (i.e., specifications, mechanisms, or activities)."), @AllowedValue(value = "TEST", description = "The process of exercising one or more assessment objects (i.e., activities or mechanisms) under specified conditions to compare actual with expected behavior.")}) 055 } 056) 057@AssemblyConstraints( 058 hasCardinality = @HasCardinality(level = IConstraint.Level.ERROR, target = ".[@name='objective']/prop[has-oscal-namespace('http://csrc.nist.gov/ns/oscal') and @name='method']", minOccurs = 1) 059) 060public class AssessmentPart { 061 @BoundFlag( 062 formalName = "Part Identifier", 063 description = "A [machine-oriented](https://pages.nist.gov/OSCAL/concepts/identifier-use/#machine-oriented), [globally unique](https://pages.nist.gov/OSCAL/concepts/identifier-use/#globally-unique) identifier with [cross-instance](https://pages.nist.gov/OSCAL/concepts/identifier-use/#cross-instance) scope that can be used to reference this part elsewhere in [this or other OSCAL instances](https://pages.nist.gov/OSCAL/concepts/identifier-use/#scope). The locally defined *UUID* of the `part` can be used to reference the data item locally or globally (e.g., in an ported OSCAL instance). This UUID should be assigned [per-subject](https://pages.nist.gov/OSCAL/concepts/identifier-use/#consistency), which means it should be consistently used to identify the same subject across revisions of the document.", 064 useName = "uuid", 065 typeAdapter = UuidAdapter.class 066 ) 067 private UUID _uuid; 068 069 @BoundFlag( 070 formalName = "Part Name", 071 description = "A textual label that uniquely identifies the part's semantic type.", 072 useName = "name", 073 required = true, 074 typeAdapter = TokenAdapter.class 075 ) 076 @ValueConstraints( 077 allowedValues = @AllowedValues(level = IConstraint.Level.ERROR, allowOthers = true, values = {@AllowedValue(value = "asset", description = "An assessment asset."), @AllowedValue(value = "method", description = "An assessment method."), @AllowedValue(value = "objective", description = "Describes a set of control objectives.")}) 078 ) 079 private String _name; 080 081 @BoundFlag( 082 formalName = "Part Namespace", 083 description = "A namespace qualifying the part's name. This allows different organizations to associate distinct semantics with the same name.", 084 useName = "ns", 085 typeAdapter = UriAdapter.class, 086 remarks = "This value must be an [absolute URI](https://pages.nist.gov/OSCAL/concepts/uri-use/#absolute-uri) that serves as a [naming system identifier](https://pages.nist.gov/OSCAL/concepts/uri-use/#use-as-a-naming-system-identifier).\n" 087 + "\n" 088 + "When a `ns` is not provided, its value should be assumed to be `http://csrc.nist.gov/ns/oscal` and the name should be a name defined by the associated OSCAL model." 089 ) 090 private URI _ns; 091 092 @BoundFlag( 093 formalName = "Part Class", 094 description = "A textual label that provides a sub-type or characterization of the part's `name`. This can be used to further distinguish or discriminate between the semantics of multiple parts of the same control with the same `name` and `ns`.", 095 useName = "class", 096 typeAdapter = TokenAdapter.class, 097 remarks = "A `class` can be used in validation rules to express extra constraints over named items of a specific `class` value.\n" 098 + "\n" 099 + "A `class` can also be used in an OSCAL profile as a means to target an alteration to control content." 100 ) 101 private String _clazz; 102 103 /** 104 * "A name given to the part, which may be used by a tool for display and navigation." 105 */ 106 @BoundField( 107 formalName = "Part Title", 108 description = "A name given to the part, which may be used by a tool for display and navigation.", 109 useName = "title" 110 ) 111 @BoundFieldValue( 112 typeAdapter = MarkupLineAdapter.class 113 ) 114 private MarkupLine _title; 115 116 @BoundAssembly( 117 formalName = "Property", 118 description = "An attribute, characteristic, or quality of the containing object expressed as a namespace qualified name/value pair.", 119 useName = "prop", 120 maxOccurs = -1 121 ) 122 @GroupAs( 123 name = "props", 124 inJson = JsonGroupAsBehavior.LIST 125 ) 126 private List<Property> _props; 127 128 /** 129 * "Permits multiple paragraphs, lists, tables etc." 130 */ 131 @BoundField( 132 formalName = "Part Text", 133 description = "Permits multiple paragraphs, lists, tables etc.", 134 useName = "prose", 135 namespace = "##none", 136 inXmlWrapped = false 137 ) 138 @BoundFieldValue( 139 typeAdapter = MarkupMultilineAdapter.class 140 ) 141 private MarkupMultiline _prose; 142 143 @BoundAssembly( 144 formalName = "Assessment Part", 145 description = "A partition of an assessment plan or results or a child of another part.", 146 useName = "part", 147 maxOccurs = -1 148 ) 149 @GroupAs( 150 name = "parts", 151 inJson = JsonGroupAsBehavior.LIST 152 ) 153 private List<AssessmentPart> _parts; 154 155 @BoundAssembly( 156 formalName = "Link", 157 description = "A reference to a local or remote resource, that has a specific relation to the containing object.", 158 useName = "link", 159 maxOccurs = -1 160 ) 161 @GroupAs( 162 name = "links", 163 inJson = JsonGroupAsBehavior.LIST 164 ) 165 private List<Link> _links; 166 167 public AssessmentPart() { 168 } 169 170 public UUID getUuid() { 171 return _uuid; 172 } 173 174 public void setUuid(UUID value) { 175 _uuid = value; 176 } 177 178 public String getName() { 179 return _name; 180 } 181 182 public void setName(String value) { 183 _name = value; 184 } 185 186 public URI getNs() { 187 return _ns; 188 } 189 190 public void setNs(URI value) { 191 _ns = value; 192 } 193 194 public String getClazz() { 195 return _clazz; 196 } 197 198 public void setClazz(String value) { 199 _clazz = value; 200 } 201 202 public MarkupLine getTitle() { 203 return _title; 204 } 205 206 public void setTitle(MarkupLine value) { 207 _title = value; 208 } 209 210 public List<Property> getProps() { 211 return _props; 212 } 213 214 public void setProps(List<Property> value) { 215 _props = value; 216 } 217 218 /** 219 * Add a new {@link Property} item to the underlying collection. 220 * @param item the item to add 221 * @return {@code true} 222 */ 223 public boolean addProp(Property item) { 224 Property value = ObjectUtils.requireNonNull(item,"item cannot be null"); 225 if (_props == null) { 226 _props = new LinkedList<>(); 227 } 228 return _props.add(value); 229 } 230 231 /** 232 * Remove the first matching {@link Property} item from the underlying collection. 233 * @param item the item to remove 234 * @return {@code true} if the item was removed or {@code false} otherwise 235 */ 236 public boolean removeProp(Property item) { 237 Property value = ObjectUtils.requireNonNull(item,"item cannot be null"); 238 return _props == null ? false : _props.remove(value); 239 } 240 241 public MarkupMultiline getProse() { 242 return _prose; 243 } 244 245 public void setProse(MarkupMultiline value) { 246 _prose = value; 247 } 248 249 public List<AssessmentPart> getParts() { 250 return _parts; 251 } 252 253 public void setParts(List<AssessmentPart> value) { 254 _parts = value; 255 } 256 257 /** 258 * Add a new {@link AssessmentPart} item to the underlying collection. 259 * @param item the item to add 260 * @return {@code true} 261 */ 262 public boolean addPart(AssessmentPart item) { 263 AssessmentPart value = ObjectUtils.requireNonNull(item,"item cannot be null"); 264 if (_parts == null) { 265 _parts = new LinkedList<>(); 266 } 267 return _parts.add(value); 268 } 269 270 /** 271 * Remove the first matching {@link AssessmentPart} item from the underlying collection. 272 * @param item the item to remove 273 * @return {@code true} if the item was removed or {@code false} otherwise 274 */ 275 public boolean removePart(AssessmentPart item) { 276 AssessmentPart value = ObjectUtils.requireNonNull(item,"item cannot be null"); 277 return _parts == null ? false : _parts.remove(value); 278 } 279 280 public List<Link> getLinks() { 281 return _links; 282 } 283 284 public void setLinks(List<Link> value) { 285 _links = value; 286 } 287 288 /** 289 * Add a new {@link Link} item to the underlying collection. 290 * @param item the item to add 291 * @return {@code true} 292 */ 293 public boolean addLink(Link item) { 294 Link value = ObjectUtils.requireNonNull(item,"item cannot be null"); 295 if (_links == null) { 296 _links = new LinkedList<>(); 297 } 298 return _links.add(value); 299 } 300 301 /** 302 * Remove the first matching {@link Link} item from the underlying collection. 303 * @param item the item to remove 304 * @return {@code true} if the item was removed or {@code false} otherwise 305 */ 306 public boolean removeLink(Link item) { 307 Link value = ObjectUtils.requireNonNull(item,"item cannot be null"); 308 return _links == null ? false : _links.remove(value); 309 } 310 311 @Override 312 public String toString() { 313 return new ReflectionToStringBuilder(this, MultilineRecursiveToStringStyle.MULTI_LINE_STYLE).toString(); 314 } 315}