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