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.BoundAssembly;
006import gov.nist.secauto.metaschema.binding.model.annotations.BoundField;
007import gov.nist.secauto.metaschema.binding.model.annotations.BoundFieldValue;
008import gov.nist.secauto.metaschema.binding.model.annotations.BoundFlag;
009import gov.nist.secauto.metaschema.binding.model.annotations.GroupAs;
010import gov.nist.secauto.metaschema.binding.model.annotations.MetaschemaAssembly;
011import gov.nist.secauto.metaschema.binding.model.annotations.ValueConstraints;
012import gov.nist.secauto.metaschema.model.common.JsonGroupAsBehavior;
013import gov.nist.secauto.metaschema.model.common.constraint.IConstraint;
014import gov.nist.secauto.metaschema.model.common.datatype.adapter.TokenAdapter;
015import gov.nist.secauto.metaschema.model.common.datatype.adapter.UriAdapter;
016import gov.nist.secauto.metaschema.model.common.datatype.markup.MarkupLine;
017import gov.nist.secauto.metaschema.model.common.datatype.markup.MarkupLineAdapter;
018import gov.nist.secauto.metaschema.model.common.datatype.markup.MarkupMultiline;
019import gov.nist.secauto.metaschema.model.common.datatype.markup.MarkupMultilineAdapter;
020import gov.nist.secauto.metaschema.model.common.util.ObjectUtils;
021import gov.nist.secauto.oscal.lib.model.control.AbstractPart;
022import java.lang.Override;
023import java.lang.String;
024import java.net.URI;
025import java.util.LinkedList;
026import java.util.List;
027import org.apache.commons.lang3.builder.MultilineRecursiveToStringStyle;
028import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
029
030/**
031 * An annotated, markup-based textual element of a control's or catalog group's definition, or a child of another part.
032 */
033@MetaschemaAssembly(
034    formalName = "Part",
035    description = "An annotated, markup-based textual element of a control's or catalog group's definition, or a child of another part.",
036    name = "part",
037    metaschema = OscalControlCommonMetaschema.class,
038    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"
039            + "\n"
040            + "A `part` can be assigned an optional `id`, which allows references to this part from within a catalog, or within an instance of another OSCAL model that has a need to reference the part. Examples of where part referencing is used in OSCAL include:\n"
041            + "\n"
042            + "- Referencing a part by id to tailor (make modifications to) a control statement in a profile.\n"
043            + "- Referencing a control statement represented by a part in a system security plan implemented-requirement where a statement-level response is desired.\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 = @AllowedValues(level = IConstraint.Level.ERROR, target = "prop[has-oscal-namespace('http://csrc.nist.gov/ns/oscal')]/@name", values = {@AllowedValue(value = "label", description = "A human-readable label for the parent context, which may be rendered in place of the actual identifier for some use cases."), @AllowedValue(value = "sort-id", description = "An alternative identifier, whose value is easily sortable among other such values in the document."), @AllowedValue(value = "alt-identifier", description = "An alternate or aliased identifier for the parent context.")})
053)
054public class ControlPart extends AbstractPart {
055  @BoundFlag(
056      formalName = "Part Identifier",
057      description = "A unique identifier for the part.",
058      useName = "id",
059      typeAdapter = TokenAdapter.class,
060      remarks = "While a part is not required to have an id, it is often desirable for an identifier to be provided, which allows the part to be referenced elsewhere in OSCAL document instances. For this reason, it is RECOMMENDED to provide a part identifier."
061  )
062  private String _id;
063
064  @BoundFlag(
065      formalName = "Part Name",
066      description = "A textual label that uniquely identifies the part's semantic type, which exists in a value space qualified by the `ns`.",
067      useName = "name",
068      required = true,
069      typeAdapter = TokenAdapter.class
070  )
071  private String _name;
072
073  @BoundFlag(
074      formalName = "Part Namespace",
075      description = "An optional namespace qualifying the part's `name`. This allows different organizations to associate distinct semantics with the same name.",
076      useName = "ns",
077      typeAdapter = UriAdapter.class,
078      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"
079              + "\n"
080              + "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."
081  )
082  private URI _ns;
083
084  @BoundFlag(
085      formalName = "Part Class",
086      description = "An optional textual providing a sub-type or characterization of the part's `name`, or a category to which the part belongs.",
087      useName = "class",
088      typeAdapter = TokenAdapter.class,
089      remarks = "One use of this flag is to distinguish or discriminate between the semantics of multiple parts of the same control with the same `name` and `ns` (since even within a given namespace it can be useful to overload a name).\n"
090              + "\n"
091              + "A `class` can be used in validation rules to express extra constraints over named items of a specific `class` value.\n"
092              + "\n"
093              + "A `class` can also be used in an OSCAL profile as a means to target an alteration to control content."
094  )
095  private String _clazz;
096
097  /**
098   * "An optional name given to the part, which may be used by a tool for display and navigation."
099   */
100  @BoundField(
101      formalName = "Part Title",
102      description = "An optional name given to the part, which may be used by a tool for display and navigation.",
103      useName = "title"
104  )
105  @BoundFieldValue(
106      typeAdapter = MarkupLineAdapter.class
107  )
108  private MarkupLine _title;
109
110  @BoundAssembly(
111      formalName = "Property",
112      description = "An attribute, characteristic, or quality of the containing object expressed as a namespace qualified name/value pair.",
113      useName = "prop",
114      maxOccurs = -1
115  )
116  @GroupAs(
117      name = "props",
118      inJson = JsonGroupAsBehavior.LIST
119  )
120  private List<Property> _props;
121
122  /**
123   * "Permits multiple paragraphs, lists, tables etc."
124   */
125  @BoundField(
126      formalName = "Part Text",
127      description = "Permits multiple paragraphs, lists, tables etc.",
128      useName = "prose",
129      namespace = "##none",
130      inXmlWrapped = false
131  )
132  @BoundFieldValue(
133      typeAdapter = MarkupMultilineAdapter.class
134  )
135  private MarkupMultiline _prose;
136
137  @BoundAssembly(
138      formalName = "Part",
139      description = "An annotated, markup-based textual element of a control's or catalog group's definition, or a child of another part.",
140      useName = "part",
141      maxOccurs = -1
142  )
143  @GroupAs(
144      name = "parts",
145      inJson = JsonGroupAsBehavior.LIST
146  )
147  private List<ControlPart> _parts;
148
149  @BoundAssembly(
150      formalName = "Link",
151      description = "A reference to a local or remote resource, that has a specific relation to the containing object.",
152      useName = "link",
153      maxOccurs = -1
154  )
155  @GroupAs(
156      name = "links",
157      inJson = JsonGroupAsBehavior.LIST
158  )
159  private List<Link> _links;
160
161  public ControlPart() {
162  }
163
164  public String getId() {
165    return _id;
166  }
167
168  public void setId(String value) {
169    _id = value;
170  }
171
172  public String getName() {
173    return _name;
174  }
175
176  public void setName(String value) {
177    _name = value;
178  }
179
180  public URI getNs() {
181    return _ns;
182  }
183
184  public void setNs(URI value) {
185    _ns = value;
186  }
187
188  public String getClazz() {
189    return _clazz;
190  }
191
192  public void setClazz(String value) {
193    _clazz = value;
194  }
195
196  public MarkupLine getTitle() {
197    return _title;
198  }
199
200  public void setTitle(MarkupLine value) {
201    _title = value;
202  }
203
204  public List<Property> getProps() {
205    return _props;
206  }
207
208  public void setProps(List<Property> value) {
209    _props = value;
210  }
211
212  /**
213   * Add a new {@link Property} item to the underlying collection.
214   * @param item the item to add
215   * @return {@code true}
216   */
217  public boolean addProp(Property item) {
218    Property value = ObjectUtils.requireNonNull(item,"item cannot be null");
219    if (_props == null) {
220      _props = new LinkedList<>();
221    }
222    return _props.add(value);
223  }
224
225  /**
226   * Remove the first matching {@link Property} item from the underlying collection.
227   * @param item the item to remove
228   * @return {@code true} if the item was removed or {@code false} otherwise
229   */
230  public boolean removeProp(Property item) {
231    Property value = ObjectUtils.requireNonNull(item,"item cannot be null");
232    return _props == null ? false : _props.remove(value);
233  }
234
235  public MarkupMultiline getProse() {
236    return _prose;
237  }
238
239  public void setProse(MarkupMultiline value) {
240    _prose = value;
241  }
242
243  public List<ControlPart> getParts() {
244    return _parts;
245  }
246
247  public void setParts(List<ControlPart> value) {
248    _parts = value;
249  }
250
251  /**
252   * Add a new {@link ControlPart} item to the underlying collection.
253   * @param item the item to add
254   * @return {@code true}
255   */
256  public boolean addPart(ControlPart item) {
257    ControlPart value = ObjectUtils.requireNonNull(item,"item cannot be null");
258    if (_parts == null) {
259      _parts = new LinkedList<>();
260    }
261    return _parts.add(value);
262  }
263
264  /**
265   * Remove the first matching {@link ControlPart} item from the underlying collection.
266   * @param item the item to remove
267   * @return {@code true} if the item was removed or {@code false} otherwise
268   */
269  public boolean removePart(ControlPart item) {
270    ControlPart value = ObjectUtils.requireNonNull(item,"item cannot be null");
271    return _parts == null ? false : _parts.remove(value);
272  }
273
274  public List<Link> getLinks() {
275    return _links;
276  }
277
278  public void setLinks(List<Link> value) {
279    _links = value;
280  }
281
282  /**
283   * Add a new {@link Link} item to the underlying collection.
284   * @param item the item to add
285   * @return {@code true}
286   */
287  public boolean addLink(Link item) {
288    Link value = ObjectUtils.requireNonNull(item,"item cannot be null");
289    if (_links == null) {
290      _links = new LinkedList<>();
291    }
292    return _links.add(value);
293  }
294
295  /**
296   * Remove the first matching {@link Link} item from the underlying collection.
297   * @param item the item to remove
298   * @return {@code true} if the item was removed or {@code false} otherwise
299   */
300  public boolean removeLink(Link item) {
301    Link value = ObjectUtils.requireNonNull(item,"item cannot be null");
302    return _links == null ? false : _links.remove(value);
303  }
304
305  @Override
306  public String toString() {
307    return new ReflectionToStringBuilder(this, MultilineRecursiveToStringStyle.MULTI_LINE_STYLE).toString();
308  }
309}