001package gov.nist.secauto.oscal.lib.model; 002 003import gov.nist.secauto.metaschema.core.datatype.adapter.TokenAdapter; 004import gov.nist.secauto.metaschema.core.datatype.adapter.UriAdapter; 005import gov.nist.secauto.metaschema.core.datatype.adapter.UuidAdapter; 006import gov.nist.secauto.metaschema.core.datatype.markup.MarkupLine; 007import gov.nist.secauto.metaschema.core.datatype.markup.MarkupLineAdapter; 008import gov.nist.secauto.metaschema.core.datatype.markup.MarkupMultiline; 009import gov.nist.secauto.metaschema.core.datatype.markup.MarkupMultilineAdapter; 010import gov.nist.secauto.metaschema.core.model.IBoundObject; 011import gov.nist.secauto.metaschema.core.model.IMetaschemaData; 012import gov.nist.secauto.metaschema.core.model.JsonGroupAsBehavior; 013import gov.nist.secauto.metaschema.core.model.constraint.IConstraint; 014import gov.nist.secauto.metaschema.core.util.ObjectUtils; 015import gov.nist.secauto.metaschema.databind.model.annotations.AllowedValue; 016import gov.nist.secauto.metaschema.databind.model.annotations.AllowedValues; 017import gov.nist.secauto.metaschema.databind.model.annotations.AssemblyConstraints; 018import gov.nist.secauto.metaschema.databind.model.annotations.BoundAssembly; 019import gov.nist.secauto.metaschema.databind.model.annotations.BoundField; 020import gov.nist.secauto.metaschema.databind.model.annotations.BoundFlag; 021import gov.nist.secauto.metaschema.databind.model.annotations.GroupAs; 022import gov.nist.secauto.metaschema.databind.model.annotations.HasCardinality; 023import gov.nist.secauto.metaschema.databind.model.annotations.MetaschemaAssembly; 024import gov.nist.secauto.metaschema.databind.model.annotations.ValueConstraints; 025import java.lang.Override; 026import java.lang.String; 027import java.net.URI; 028import java.util.LinkedList; 029import java.util.List; 030import java.util.UUID; 031import org.apache.commons.lang3.builder.ReflectionToStringBuilder; 032import org.apache.commons.lang3.builder.ToStringStyle; 033 034/** 035 * A partition of an assessment plan or results or a child of another part. 036 */ 037@MetaschemaAssembly( 038 formalName = "Assessment Part", 039 description = "A partition of an assessment plan or results or a child of another part.", 040 name = "assessment-part", 041 moduleClass = OscalAssessmentCommonModule.class, 042 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" 043 + "\n" 044 + "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" 045 + "\n" 046 + "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" 047 + "\n" 048 + "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" 049 + "\n" 050 + "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.", 051 valueConstraints = @ValueConstraints(allowedValues = {@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\".")), @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.")})}), 052 modelConstraints = @AssemblyConstraints(cardinality = @HasCardinality(level = IConstraint.Level.ERROR, target = ".[@name='objective']/prop[has-oscal-namespace('http://csrc.nist.gov/ns/oscal') and @name='method']", minOccurs = 1)) 053) 054public class AssessmentPart implements IBoundObject { 055 private final IMetaschemaData __metaschemaData; 056 057 /** 058 * "A <a href=\"https://pages.nist.gov/OSCAL/concepts/identifier-use/#machine-oriented\">machine-oriented</a>, <a href=\"https://pages.nist.gov/OSCAL/concepts/identifier-use/#globally-unique\">globally unique</a> identifier with <a href=\"https://pages.nist.gov/OSCAL/concepts/identifier-use/#cross-instance\">cross-instance</a> scope that can be used to reference this part elsewhere in <a href=\"https://pages.nist.gov/OSCAL/concepts/identifier-use/#scope\">this or other OSCAL instances</a>. The locally defined <em>UUID</em> of the <code>part</code> can be used to reference the data item locally or globally (e.g., in an ported OSCAL instance). This UUID should be assigned <a href=\"https://pages.nist.gov/OSCAL/concepts/identifier-use/#consistency\">per-subject</a>, which means it should be consistently used to identify the same subject across revisions of the document." 059 */ 060 @BoundFlag( 061 formalName = "Part Identifier", 062 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.", 063 name = "uuid", 064 typeAdapter = UuidAdapter.class 065 ) 066 private UUID _uuid; 067 068 /** 069 * "A textual label that uniquely identifies the part's semantic type." 070 */ 071 @BoundFlag( 072 formalName = "Part Name", 073 description = "A textual label that uniquely identifies the part's semantic type.", 074 name = "name", 075 required = true, 076 typeAdapter = TokenAdapter.class, 077 valueConstraints = @ValueConstraints(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 /** 082 * "A namespace qualifying the part's name. This allows different organizations to associate distinct semantics with the same name." 083 */ 084 @BoundFlag( 085 formalName = "Part Namespace", 086 description = "A namespace qualifying the part's name. This allows different organizations to associate distinct semantics with the same name.", 087 name = "ns", 088 defaultValue = "http://csrc.nist.gov/ns/oscal", 089 typeAdapter = UriAdapter.class, 090 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" 091 + "\n" 092 + "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." 093 ) 094 private URI _ns; 095 096 /** 097 * "A textual label that provides a sub-type or characterization of the part's <code>name</code>. This can be used to further distinguish or discriminate between the semantics of multiple parts of the same control with the same <code>name</code> and <code>ns</code>." 098 */ 099 @BoundFlag( 100 formalName = "Part Class", 101 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`.", 102 name = "class", 103 typeAdapter = TokenAdapter.class, 104 remarks = "A `class` can be used in validation rules to express extra constraints over named items of a specific `class` value.\n" 105 + "\n" 106 + "A `class` can also be used in an OSCAL profile as a means to target an alteration to control content." 107 ) 108 private String _clazz; 109 110 @BoundField( 111 formalName = "Part Title", 112 description = "A name given to the part, which may be used by a tool for display and navigation.", 113 useName = "title", 114 typeAdapter = MarkupLineAdapter.class 115 ) 116 private MarkupLine _title; 117 118 @BoundAssembly( 119 formalName = "Property", 120 description = "An attribute, characteristic, or quality of the containing object expressed as a namespace qualified name/value pair.", 121 useName = "prop", 122 maxOccurs = -1, 123 groupAs = @GroupAs(name = "props", inJson = JsonGroupAsBehavior.LIST) 124 ) 125 private List<Property> _props; 126 127 @BoundField( 128 formalName = "Part Text", 129 description = "Permits multiple paragraphs, lists, tables etc.", 130 useName = "prose", 131 inXmlWrapped = false, 132 typeAdapter = MarkupMultilineAdapter.class 133 ) 134 private MarkupMultiline _prose; 135 136 @BoundAssembly( 137 formalName = "Assessment Part", 138 description = "A partition of an assessment plan or results or a child of another part.", 139 useName = "part", 140 maxOccurs = -1, 141 groupAs = @GroupAs(name = "parts", inJson = JsonGroupAsBehavior.LIST) 142 ) 143 private List<AssessmentPart> _parts; 144 145 @BoundAssembly( 146 formalName = "Link", 147 description = "A reference to a local or remote resource, that has a specific relation to the containing object.", 148 useName = "link", 149 maxOccurs = -1, 150 groupAs = @GroupAs(name = "links", inJson = JsonGroupAsBehavior.LIST) 151 ) 152 private List<Link> _links; 153 154 public AssessmentPart() { 155 this(null); 156 } 157 158 public AssessmentPart(IMetaschemaData data) { 159 this.__metaschemaData = data; 160 } 161 162 @Override 163 public IMetaschemaData getMetaschemaData() { 164 return __metaschemaData; 165 } 166 167 public UUID getUuid() { 168 return _uuid; 169 } 170 171 public void setUuid(UUID value) { 172 _uuid = value; 173 } 174 175 public String getName() { 176 return _name; 177 } 178 179 public void setName(String value) { 180 _name = value; 181 } 182 183 public URI getNs() { 184 return _ns; 185 } 186 187 public void setNs(URI value) { 188 _ns = value; 189 } 190 191 public String getClazz() { 192 return _clazz; 193 } 194 195 public void setClazz(String value) { 196 _clazz = value; 197 } 198 199 public MarkupLine getTitle() { 200 return _title; 201 } 202 203 public void setTitle(MarkupLine value) { 204 _title = value; 205 } 206 207 public List<Property> getProps() { 208 return _props; 209 } 210 211 public void setProps(List<Property> value) { 212 _props = value; 213 } 214 215 /** 216 * Add a new {@link Property} item to the underlying collection. 217 * @param item the item to add 218 * @return {@code true} 219 */ 220 public boolean addProp(Property item) { 221 Property value = ObjectUtils.requireNonNull(item,"item cannot be null"); 222 if (_props == null) { 223 _props = new LinkedList<>(); 224 } 225 return _props.add(value); 226 } 227 228 /** 229 * Remove the first matching {@link Property} item from the underlying collection. 230 * @param item the item to remove 231 * @return {@code true} if the item was removed or {@code false} otherwise 232 */ 233 public boolean removeProp(Property item) { 234 Property value = ObjectUtils.requireNonNull(item,"item cannot be null"); 235 return _props != null && _props.remove(value); 236 } 237 238 public MarkupMultiline getProse() { 239 return _prose; 240 } 241 242 public void setProse(MarkupMultiline value) { 243 _prose = value; 244 } 245 246 public List<AssessmentPart> getParts() { 247 return _parts; 248 } 249 250 public void setParts(List<AssessmentPart> value) { 251 _parts = value; 252 } 253 254 /** 255 * Add a new {@link AssessmentPart} item to the underlying collection. 256 * @param item the item to add 257 * @return {@code true} 258 */ 259 public boolean addPart(AssessmentPart item) { 260 AssessmentPart value = ObjectUtils.requireNonNull(item,"item cannot be null"); 261 if (_parts == null) { 262 _parts = new LinkedList<>(); 263 } 264 return _parts.add(value); 265 } 266 267 /** 268 * Remove the first matching {@link AssessmentPart} item from the underlying collection. 269 * @param item the item to remove 270 * @return {@code true} if the item was removed or {@code false} otherwise 271 */ 272 public boolean removePart(AssessmentPart item) { 273 AssessmentPart value = ObjectUtils.requireNonNull(item,"item cannot be null"); 274 return _parts != null && _parts.remove(value); 275 } 276 277 public List<Link> getLinks() { 278 return _links; 279 } 280 281 public void setLinks(List<Link> value) { 282 _links = value; 283 } 284 285 /** 286 * Add a new {@link Link} item to the underlying collection. 287 * @param item the item to add 288 * @return {@code true} 289 */ 290 public boolean addLink(Link item) { 291 Link value = ObjectUtils.requireNonNull(item,"item cannot be null"); 292 if (_links == null) { 293 _links = new LinkedList<>(); 294 } 295 return _links.add(value); 296 } 297 298 /** 299 * Remove the first matching {@link Link} item from the underlying collection. 300 * @param item the item to remove 301 * @return {@code true} if the item was removed or {@code false} otherwise 302 */ 303 public boolean removeLink(Link item) { 304 Link value = ObjectUtils.requireNonNull(item,"item cannot be null"); 305 return _links != null && _links.remove(value); 306 } 307 308 @Override 309 public String toString() { 310 return new ReflectionToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE).toString(); 311 } 312}