1 package gov.nist.secauto.oscal.lib.model;
2
3 import gov.nist.secauto.metaschema.binding.model.annotations.AllowedValue;
4 import gov.nist.secauto.metaschema.binding.model.annotations.AllowedValues;
5 import gov.nist.secauto.metaschema.binding.model.annotations.BoundAssembly;
6 import gov.nist.secauto.metaschema.binding.model.annotations.BoundField;
7 import gov.nist.secauto.metaschema.binding.model.annotations.BoundFieldValue;
8 import gov.nist.secauto.metaschema.binding.model.annotations.BoundFlag;
9 import gov.nist.secauto.metaschema.binding.model.annotations.GroupAs;
10 import gov.nist.secauto.metaschema.binding.model.annotations.MetaschemaAssembly;
11 import gov.nist.secauto.metaschema.binding.model.annotations.ValueConstraints;
12 import gov.nist.secauto.metaschema.model.common.JsonGroupAsBehavior;
13 import gov.nist.secauto.metaschema.model.common.constraint.IConstraint;
14 import gov.nist.secauto.metaschema.model.common.datatype.adapter.TokenAdapter;
15 import gov.nist.secauto.metaschema.model.common.datatype.adapter.UriAdapter;
16 import gov.nist.secauto.metaschema.model.common.datatype.markup.MarkupLine;
17 import gov.nist.secauto.metaschema.model.common.datatype.markup.MarkupLineAdapter;
18 import gov.nist.secauto.metaschema.model.common.datatype.markup.MarkupMultiline;
19 import gov.nist.secauto.metaschema.model.common.datatype.markup.MarkupMultilineAdapter;
20 import gov.nist.secauto.metaschema.model.common.util.ObjectUtils;
21 import gov.nist.secauto.oscal.lib.model.control.AbstractPart;
22 import java.lang.Override;
23 import java.lang.String;
24 import java.net.URI;
25 import java.util.LinkedList;
26 import java.util.List;
27 import org.apache.commons.lang3.builder.MultilineRecursiveToStringStyle;
28 import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
29
30
31
32
33 @MetaschemaAssembly(
34 formalName = "Part",
35 description = "An annotated, markup-based textual element of a control's or catalog group's definition, or a child of another part.",
36 name = "part",
37 metaschema = OscalControlCommonMetaschema.class,
38 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"
39 + "\n"
40 + "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"
41 + "\n"
42 + "- Referencing a part by id to tailor (make modifications to) a control statement in a profile.\n"
43 + "- Referencing a control statement represented by a part in a system security plan implemented-requirement where a statement-level response is desired.\n"
44 + "\n"
45 + "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"
46 + "\n"
47 + "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"
48 + "\n"
49 + "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."
50 )
51 @ValueConstraints(
52 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.")})
53 )
54 public class ControlPart extends AbstractPart {
55 @BoundFlag(
56 formalName = "Part Identifier",
57 description = "A unique identifier for the part.",
58 useName = "id",
59 typeAdapter = TokenAdapter.class,
60 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."
61 )
62 private String _id;
63
64 @BoundFlag(
65 formalName = "Part Name",
66 description = "A textual label that uniquely identifies the part's semantic type, which exists in a value space qualified by the `ns`.",
67 useName = "name",
68 required = true,
69 typeAdapter = TokenAdapter.class
70 )
71 private String _name;
72
73 @BoundFlag(
74 formalName = "Part Namespace",
75 description = "An optional namespace qualifying the part's `name`. This allows different organizations to associate distinct semantics with the same name.",
76 useName = "ns",
77 typeAdapter = UriAdapter.class,
78 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"
79 + "\n"
80 + "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."
81 )
82 private URI _ns;
83
84 @BoundFlag(
85 formalName = "Part Class",
86 description = "An optional textual providing a sub-type or characterization of the part's `name`, or a category to which the part belongs.",
87 useName = "class",
88 typeAdapter = TokenAdapter.class,
89 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"
90 + "\n"
91 + "A `class` can be used in validation rules to express extra constraints over named items of a specific `class` value.\n"
92 + "\n"
93 + "A `class` can also be used in an OSCAL profile as a means to target an alteration to control content."
94 )
95 private String _clazz;
96
97
98
99
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
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
214
215
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
227
228
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
253
254
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
266
267
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
284
285
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
297
298
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 }