View Javadoc
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.AssemblyConstraints;
6   import gov.nist.secauto.metaschema.binding.model.annotations.BoundAssembly;
7   import gov.nist.secauto.metaschema.binding.model.annotations.BoundField;
8   import gov.nist.secauto.metaschema.binding.model.annotations.BoundFieldValue;
9   import gov.nist.secauto.metaschema.binding.model.annotations.BoundFlag;
10  import gov.nist.secauto.metaschema.binding.model.annotations.Expect;
11  import gov.nist.secauto.metaschema.binding.model.annotations.GroupAs;
12  import gov.nist.secauto.metaschema.binding.model.annotations.HasCardinality;
13  import gov.nist.secauto.metaschema.binding.model.annotations.Index;
14  import gov.nist.secauto.metaschema.binding.model.annotations.IsUnique;
15  import gov.nist.secauto.metaschema.binding.model.annotations.KeyField;
16  import gov.nist.secauto.metaschema.binding.model.annotations.Matches;
17  import gov.nist.secauto.metaschema.binding.model.annotations.MetaschemaAssembly;
18  import gov.nist.secauto.metaschema.binding.model.annotations.MetaschemaField;
19  import gov.nist.secauto.metaschema.binding.model.annotations.MetaschemaFieldValue;
20  import gov.nist.secauto.metaschema.binding.model.annotations.ValueConstraints;
21  import gov.nist.secauto.metaschema.model.common.JsonGroupAsBehavior;
22  import gov.nist.secauto.metaschema.model.common.constraint.IConstraint;
23  import gov.nist.secauto.metaschema.model.common.datatype.adapter.Base64Adapter;
24  import gov.nist.secauto.metaschema.model.common.datatype.adapter.DateTimeWithTZAdapter;
25  import gov.nist.secauto.metaschema.model.common.datatype.adapter.StringAdapter;
26  import gov.nist.secauto.metaschema.model.common.datatype.adapter.TokenAdapter;
27  import gov.nist.secauto.metaschema.model.common.datatype.adapter.UriReferenceAdapter;
28  import gov.nist.secauto.metaschema.model.common.datatype.adapter.UuidAdapter;
29  import gov.nist.secauto.metaschema.model.common.datatype.markup.MarkupLine;
30  import gov.nist.secauto.metaschema.model.common.datatype.markup.MarkupLineAdapter;
31  import gov.nist.secauto.metaschema.model.common.datatype.markup.MarkupMultiline;
32  import gov.nist.secauto.metaschema.model.common.datatype.markup.MarkupMultilineAdapter;
33  import gov.nist.secauto.metaschema.model.common.util.ObjectUtils;
34  import gov.nist.secauto.oscal.lib.model.metadata.AbstractBackMatter;
35  import java.lang.Override;
36  import java.lang.String;
37  import java.net.URI;
38  import java.nio.ByteBuffer;
39  import java.util.LinkedList;
40  import java.util.List;
41  import java.util.UUID;
42  import org.apache.commons.lang3.builder.MultilineRecursiveToStringStyle;
43  import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
44  
45  /**
46   * A collection of resources that may be referenced from within the OSCAL document instance.
47   */
48  @MetaschemaAssembly(
49      formalName = "Back matter",
50      description = "A collection of resources that may be referenced from within the OSCAL document instance.",
51      name = "back-matter",
52      metaschema = OscalMetadataMetaschema.class,
53      remarks = "Provides a collection of identified `resource` objects that can be referenced by a `link` with a `rel` value of \"reference\" and an `href` value that is a fragment \"#\" followed by a reference to a reference's `uuid`. Other specialized link \"rel\" values also use this pattern when indicated in that context of use."
54  )
55  @AssemblyConstraints(
56      index = @Index(level = IConstraint.Level.ERROR, target = "resource", name = "index-back-matter-resource", keyFields = @KeyField(target = "@uuid"))
57  )
58  public class BackMatter extends AbstractBackMatter {
59    /**
60     * "A resource associated with content in the containing document instance. A resource may be directly included in the document using base64 encoding or may point to one or more equivalent internet resources."
61     */
62    @BoundAssembly(
63        formalName = "Resource",
64        description = "A resource associated with content in the containing document instance. A resource may be directly included in the document using base64 encoding or may point to one or more equivalent internet resources.",
65        useName = "resource",
66        maxOccurs = -1,
67        remarks = "A resource can be used in two ways. 1) it may point to an specific retrievable network resource using a `rlink`, or 2) it may be included as an attachment using a `base64`. A resource may contain multiple `rlink` and `base64` entries that represent alternative download locations (rlink) and attachments (base64) for the same resource.\n"
68                + "\n"
69                + "Both rlink and base64 allow for a `media-type` to be specified, which is used to distinguish between different representations of the same resource (e.g., Microsoft Word, PDF). When multiple `rlink` and `base64` items are included for a given resource, all items must contain equivalent information. This allows the document consumer to choose a preferred item to process based on a the selected item's `media-type`. This is extremely important when the items represent OSCAL content that is represented in alternate formats (i.e., XML, JSON, YAML), allowing the same OSCAL data to be processed from any of the available formats indicated by the items.\n"
70                + "\n"
71                + "When a resource includes a citation, then the `title` and `citation` properties must both be included."
72    )
73    @GroupAs(
74        name = "resources",
75        inJson = JsonGroupAsBehavior.LIST
76    )
77    private List<Resource> _resources;
78  
79    public BackMatter() {
80    }
81  
82    public List<Resource> getResources() {
83      return _resources;
84    }
85  
86    public void setResources(List<Resource> value) {
87      _resources = value;
88    }
89  
90    /**
91     * Add a new {@link Resource} item to the underlying collection.
92     * @param item the item to add
93     * @return {@code true}
94     */
95    public boolean addResource(Resource item) {
96      Resource value = ObjectUtils.requireNonNull(item,"item cannot be null");
97      if (_resources == null) {
98        _resources = new LinkedList<>();
99      }
100     return _resources.add(value);
101   }
102 
103   /**
104    * Remove the first matching {@link Resource} item from the underlying collection.
105    * @param item the item to remove
106    * @return {@code true} if the item was removed or {@code false} otherwise
107    */
108   public boolean removeResource(Resource item) {
109     Resource value = ObjectUtils.requireNonNull(item,"item cannot be null");
110     return _resources == null ? false : _resources.remove(value);
111   }
112 
113   @Override
114   public String toString() {
115     return new ReflectionToStringBuilder(this, MultilineRecursiveToStringStyle.MULTI_LINE_STYLE).toString();
116   }
117 
118   /**
119    * A resource associated with content in the containing document instance. A resource may be directly included in the document using base64 encoding or may point to one or more equivalent internet resources.
120    */
121   @MetaschemaAssembly(
122       formalName = "Resource",
123       description = "A resource associated with content in the containing document instance. A resource may be directly included in the document using base64 encoding or may point to one or more equivalent internet resources.",
124       name = "resource",
125       metaschema = OscalMetadataMetaschema.class,
126       remarks = "A resource can be used in two ways. 1) it may point to an specific retrievable network resource using a `rlink`, or 2) it may be included as an attachment using a `base64`. A resource may contain multiple `rlink` and `base64` entries that represent alternative download locations (rlink) and attachments (base64) for the same resource.\n"
127               + "\n"
128               + "Both rlink and base64 allow for a `media-type` to be specified, which is used to distinguish between different representations of the same resource (e.g., Microsoft Word, PDF). When multiple `rlink` and `base64` items are included for a given resource, all items must contain equivalent information. This allows the document consumer to choose a preferred item to process based on a the selected item's `media-type`. This is extremely important when the items represent OSCAL content that is represented in alternate formats (i.e., XML, JSON, YAML), allowing the same OSCAL data to be processed from any of the available formats indicated by the items.\n"
129               + "\n"
130               + "When a resource includes a citation, then the `title` and `citation` properties must both be included."
131   )
132   @ValueConstraints(
133       allowedValues = {
134           @AllowedValues(level = IConstraint.Level.ERROR, target = "prop[has-oscal-namespace('http://csrc.nist.gov/ns/oscal')]/@name", values = {@AllowedValue(value = "type", description = "Identifies the type of resource represented. The most specific appropriate type value SHOULD be used."), @AllowedValue(value = "version", description = "For resources representing a published document, this represents the version number of that document."), @AllowedValue(value = "published", description = "For resources representing a published document, this represents the publication date of that document.")}),
135           @AllowedValues(level = IConstraint.Level.ERROR, target = "prop[has-oscal-namespace('http://csrc.nist.gov/ns/oscal') and @name='type']/@value", values = {@AllowedValue(value = "logo", description = "Indicates the resource is an organization's logo."), @AllowedValue(value = "image", description = "Indicates the resource represents an image."), @AllowedValue(value = "screen-shot", description = "Indicates the resource represents an image of screen content."), @AllowedValue(value = "law", description = "Indicates the resource represents an applicable law."), @AllowedValue(value = "regulation", description = "Indicates the resource represents an applicable regulation."), @AllowedValue(value = "standard", description = "Indicates the resource represents an applicable standard."), @AllowedValue(value = "external-guidance", description = "Indicates the resource represents applicable guidance."), @AllowedValue(value = "acronyms", description = "Indicates the resource provides a list of relevant acronyms."), @AllowedValue(value = "citation", description = "Indicates the resource cites relevant information."), @AllowedValue(value = "policy", description = "Indicates the resource is a policy."), @AllowedValue(value = "procedure", description = "Indicates the resource is a procedure."), @AllowedValue(value = "system-guide", description = "Indicates the resource is guidance document related to the subject system of an SSP."), @AllowedValue(value = "users-guide", description = "Indicates the resource is guidance document a user's guide or administrator's guide."), @AllowedValue(value = "administrators-guide", description = "Indicates the resource is guidance document a administrator's guide."), @AllowedValue(value = "rules-of-behavior", description = "Indicates the resource represents rules of behavior content."), @AllowedValue(value = "plan", description = "Indicates the resource represents a plan."), @AllowedValue(value = "artifact", description = "Indicates the resource represents an artifact, such as may be reviewed by an assessor."), @AllowedValue(value = "evidence", description = "Indicates the resource represents evidence, such as to support an assessment finding."), @AllowedValue(value = "tool-output", description = "Indicates the resource represents output from a tool."), @AllowedValue(value = "raw-data", description = "Indicates the resource represents machine data, which may require a tool or analysis for interpretation or presentation."), @AllowedValue(value = "interview-notes", description = "Indicates the resource represents notes from an interview, such as may be collected during an assessment."), @AllowedValue(value = "questionnaire", description = "Indicates the resource is a set of questions, possibly with responses."), @AllowedValue(value = "report", description = "Indicates the resource is a report."), @AllowedValue(value = "agreement", description = "Indicates the resource is a formal agreement between two or more parties.")})
136       },
137       matches = @Matches(level = IConstraint.Level.ERROR, target = "prop[has-oscal-namespace('http://csrc.nist.gov/ns/oscal') and @name='published']/@value", typeAdapter = DateTimeWithTZAdapter.class),
138       expect = @Expect(level = IConstraint.Level.ERROR, target = ".[citation]", test = "title")
139   )
140   @AssemblyConstraints(
141       isUnique = {
142           @IsUnique(id = "unique-resource-rlink-href", level = IConstraint.Level.ERROR, target = "rlink", keyFields = {@KeyField(target = "@href"), @KeyField(target = "@media-type")}),
143           @IsUnique(id = "unique-resource-base64-filename", level = IConstraint.Level.ERROR, target = "base64", keyFields = @KeyField(target = "@filename"))
144       },
145       hasCardinality = @HasCardinality(level = IConstraint.Level.WARNING, target = "rlink|base64", minOccurs = 1)
146   )
147   public static class Resource {
148     @BoundFlag(
149         formalName = "Resource Universally Unique Identifier",
150         description = "A unique identifier for a resource.",
151         useName = "uuid",
152         required = true,
153         typeAdapter = UuidAdapter.class
154     )
155     private UUID _uuid;
156 
157     /**
158      * "An optional name given to the resource, which may be used by a tool for display and navigation."
159      */
160     @BoundField(
161         formalName = "Resource Title",
162         description = "An optional name given to the resource, which may be used by a tool for display and navigation.",
163         useName = "title"
164     )
165     @BoundFieldValue(
166         typeAdapter = MarkupLineAdapter.class
167     )
168     private MarkupLine _title;
169 
170     /**
171      * "An optional short summary of the resource used to indicate the purpose of the resource."
172      */
173     @BoundField(
174         formalName = "Resource Description",
175         description = "An optional short summary of the resource used to indicate the purpose of the resource.",
176         useName = "description"
177     )
178     @BoundFieldValue(
179         typeAdapter = MarkupMultilineAdapter.class
180     )
181     private MarkupMultiline _description;
182 
183     @BoundAssembly(
184         formalName = "Property",
185         description = "An attribute, characteristic, or quality of the containing object expressed as a namespace qualified name/value pair.",
186         useName = "prop",
187         maxOccurs = -1
188     )
189     @GroupAs(
190         name = "props",
191         inJson = JsonGroupAsBehavior.LIST
192     )
193     private List<Property> _props;
194 
195     @BoundField(
196         formalName = "Document Identifier",
197         description = "A document identifier qualified by an identifier `scheme`.",
198         useName = "document-id",
199         maxOccurs = -1
200     )
201     @GroupAs(
202         name = "document-ids",
203         inJson = JsonGroupAsBehavior.LIST
204     )
205     private List<DocumentId> _documentIds;
206 
207     /**
208      * "An optional citation consisting of end note text using structured markup."
209      */
210     @BoundAssembly(
211         formalName = "Citation",
212         description = "An optional citation consisting of end note text using structured markup.",
213         useName = "citation"
214     )
215     private Citation _citation;
216 
217     /**
218      * "A URL-based pointer to an external resource with an optional hash for verification and change detection."
219      */
220     @BoundAssembly(
221         formalName = "Resource link",
222         description = "A URL-based pointer to an external resource with an optional hash for verification and change detection.",
223         useName = "rlink",
224         maxOccurs = -1,
225         remarks = "Multiple `rlink` objects can be included for a resource. In such a case, all provided `rlink` items are intended to be equivalent in content, but may differ in structure or format.\n"
226                 + "\n"
227                 + "A `media-type` is used to identify the format of a given rlink, and can be used to differentiate items in a collection of rlinks. The `media-type` provides a hint to the OSCAL document consumer about the structure of the resource referenced by the `rlink`."
228     )
229     @GroupAs(
230         name = "rlinks",
231         inJson = JsonGroupAsBehavior.LIST
232     )
233     private List<Rlink> _rlinks;
234 
235     /**
236      * "A resource encoded using the Base64 alphabet defined by <a href=\"https://www.rfc-editor.org/rfc/rfc2045.html\">RFC 2045</a>."
237      */
238     @BoundField(
239         formalName = "Base64",
240         description = "A resource encoded using the Base64 alphabet defined by [RFC 2045](https://www.rfc-editor.org/rfc/rfc2045.html).",
241         useName = "base64"
242     )
243     private Base64 _base64;
244 
245     @BoundField(
246         formalName = "Remarks",
247         description = "Additional commentary about the containing object.",
248         useName = "remarks"
249     )
250     @BoundFieldValue(
251         typeAdapter = MarkupMultilineAdapter.class
252     )
253     private MarkupMultiline _remarks;
254 
255     public Resource() {
256     }
257 
258     public UUID getUuid() {
259       return _uuid;
260     }
261 
262     public void setUuid(UUID value) {
263       _uuid = value;
264     }
265 
266     public MarkupLine getTitle() {
267       return _title;
268     }
269 
270     public void setTitle(MarkupLine value) {
271       _title = value;
272     }
273 
274     public MarkupMultiline getDescription() {
275       return _description;
276     }
277 
278     public void setDescription(MarkupMultiline value) {
279       _description = value;
280     }
281 
282     public List<Property> getProps() {
283       return _props;
284     }
285 
286     public void setProps(List<Property> value) {
287       _props = value;
288     }
289 
290     /**
291      * Add a new {@link Property} item to the underlying collection.
292      * @param item the item to add
293      * @return {@code true}
294      */
295     public boolean addProp(Property item) {
296       Property value = ObjectUtils.requireNonNull(item,"item cannot be null");
297       if (_props == null) {
298         _props = new LinkedList<>();
299       }
300       return _props.add(value);
301     }
302 
303     /**
304      * Remove the first matching {@link Property} item from the underlying collection.
305      * @param item the item to remove
306      * @return {@code true} if the item was removed or {@code false} otherwise
307      */
308     public boolean removeProp(Property item) {
309       Property value = ObjectUtils.requireNonNull(item,"item cannot be null");
310       return _props == null ? false : _props.remove(value);
311     }
312 
313     public List<DocumentId> getDocumentIds() {
314       return _documentIds;
315     }
316 
317     public void setDocumentIds(List<DocumentId> value) {
318       _documentIds = value;
319     }
320 
321     /**
322      * Add a new {@link DocumentId} item to the underlying collection.
323      * @param item the item to add
324      * @return {@code true}
325      */
326     public boolean addDocumentId(DocumentId item) {
327       DocumentId value = ObjectUtils.requireNonNull(item,"item cannot be null");
328       if (_documentIds == null) {
329         _documentIds = new LinkedList<>();
330       }
331       return _documentIds.add(value);
332     }
333 
334     /**
335      * Remove the first matching {@link DocumentId} item from the underlying collection.
336      * @param item the item to remove
337      * @return {@code true} if the item was removed or {@code false} otherwise
338      */
339     public boolean removeDocumentId(DocumentId item) {
340       DocumentId value = ObjectUtils.requireNonNull(item,"item cannot be null");
341       return _documentIds == null ? false : _documentIds.remove(value);
342     }
343 
344     public Citation getCitation() {
345       return _citation;
346     }
347 
348     public void setCitation(Citation value) {
349       _citation = value;
350     }
351 
352     public List<Rlink> getRlinks() {
353       return _rlinks;
354     }
355 
356     public void setRlinks(List<Rlink> value) {
357       _rlinks = value;
358     }
359 
360     /**
361      * Add a new {@link Rlink} item to the underlying collection.
362      * @param item the item to add
363      * @return {@code true}
364      */
365     public boolean addRlink(Rlink item) {
366       Rlink value = ObjectUtils.requireNonNull(item,"item cannot be null");
367       if (_rlinks == null) {
368         _rlinks = new LinkedList<>();
369       }
370       return _rlinks.add(value);
371     }
372 
373     /**
374      * Remove the first matching {@link Rlink} item from the underlying collection.
375      * @param item the item to remove
376      * @return {@code true} if the item was removed or {@code false} otherwise
377      */
378     public boolean removeRlink(Rlink item) {
379       Rlink value = ObjectUtils.requireNonNull(item,"item cannot be null");
380       return _rlinks == null ? false : _rlinks.remove(value);
381     }
382 
383     public Base64 getBase64() {
384       return _base64;
385     }
386 
387     public void setBase64(Base64 value) {
388       _base64 = value;
389     }
390 
391     public MarkupMultiline getRemarks() {
392       return _remarks;
393     }
394 
395     public void setRemarks(MarkupMultiline value) {
396       _remarks = value;
397     }
398 
399     @Override
400     public String toString() {
401       return new ReflectionToStringBuilder(this, MultilineRecursiveToStringStyle.MULTI_LINE_STYLE).toString();
402     }
403 
404     /**
405      * An optional citation consisting of end note text using structured markup.
406      */
407     @MetaschemaAssembly(
408         formalName = "Citation",
409         description = "An optional citation consisting of end note text using structured markup.",
410         name = "citation",
411         metaschema = OscalMetadataMetaschema.class
412     )
413     public static class Citation {
414       /**
415        * "A line of citation text."
416        */
417       @BoundField(
418           formalName = "Citation Text",
419           description = "A line of citation text.",
420           useName = "text",
421           minOccurs = 1
422       )
423       @BoundFieldValue(
424           typeAdapter = MarkupLineAdapter.class
425       )
426       private MarkupLine _text;
427 
428       @BoundAssembly(
429           formalName = "Property",
430           description = "An attribute, characteristic, or quality of the containing object expressed as a namespace qualified name/value pair.",
431           useName = "prop",
432           maxOccurs = -1
433       )
434       @GroupAs(
435           name = "props",
436           inJson = JsonGroupAsBehavior.LIST
437       )
438       private List<Property> _props;
439 
440       @BoundAssembly(
441           formalName = "Link",
442           description = "A reference to a local or remote resource, that has a specific relation to the containing object.",
443           useName = "link",
444           maxOccurs = -1
445       )
446       @GroupAs(
447           name = "links",
448           inJson = JsonGroupAsBehavior.LIST
449       )
450       private List<Link> _links;
451 
452       public Citation() {
453       }
454 
455       public MarkupLine getText() {
456         return _text;
457       }
458 
459       public void setText(MarkupLine value) {
460         _text = value;
461       }
462 
463       public List<Property> getProps() {
464         return _props;
465       }
466 
467       public void setProps(List<Property> value) {
468         _props = value;
469       }
470 
471       /**
472        * Add a new {@link Property} item to the underlying collection.
473        * @param item the item to add
474        * @return {@code true}
475        */
476       public boolean addProp(Property item) {
477         Property value = ObjectUtils.requireNonNull(item,"item cannot be null");
478         if (_props == null) {
479           _props = new LinkedList<>();
480         }
481         return _props.add(value);
482       }
483 
484       /**
485        * Remove the first matching {@link Property} item from the underlying collection.
486        * @param item the item to remove
487        * @return {@code true} if the item was removed or {@code false} otherwise
488        */
489       public boolean removeProp(Property item) {
490         Property value = ObjectUtils.requireNonNull(item,"item cannot be null");
491         return _props == null ? false : _props.remove(value);
492       }
493 
494       public List<Link> getLinks() {
495         return _links;
496       }
497 
498       public void setLinks(List<Link> value) {
499         _links = value;
500       }
501 
502       /**
503        * Add a new {@link Link} item to the underlying collection.
504        * @param item the item to add
505        * @return {@code true}
506        */
507       public boolean addLink(Link item) {
508         Link value = ObjectUtils.requireNonNull(item,"item cannot be null");
509         if (_links == null) {
510           _links = new LinkedList<>();
511         }
512         return _links.add(value);
513       }
514 
515       /**
516        * Remove the first matching {@link Link} item from the underlying collection.
517        * @param item the item to remove
518        * @return {@code true} if the item was removed or {@code false} otherwise
519        */
520       public boolean removeLink(Link item) {
521         Link value = ObjectUtils.requireNonNull(item,"item cannot be null");
522         return _links == null ? false : _links.remove(value);
523       }
524 
525       @Override
526       public String toString() {
527         return new ReflectionToStringBuilder(this, MultilineRecursiveToStringStyle.MULTI_LINE_STYLE).toString();
528       }
529     }
530 
531     /**
532      * A resource encoded using the Base64 alphabet defined by <a href="https://www.rfc-editor.org/rfc/rfc2045.html">RFC 2045</a>.
533      */
534     @MetaschemaField(
535         formalName = "Base64",
536         description = "A resource encoded using the Base64 alphabet defined by [RFC 2045](https://www.rfc-editor.org/rfc/rfc2045.html).",
537         name = "base64",
538         metaschema = OscalMetadataMetaschema.class,
539         isCollapsible = false
540     )
541     public static class Base64 {
542       @MetaschemaFieldValue(
543           valueKeyName = "value",
544           typeAdapter = Base64Adapter.class
545       )
546       private ByteBuffer _value;
547 
548       @BoundFlag(
549           formalName = "File Name",
550           description = "Name of the file before it was encoded as Base64 to be embedded in a `resource`. This is the name that will be assigned to the file when the file is decoded.",
551           useName = "filename",
552           typeAdapter = TokenAdapter.class
553       )
554       private String _filename;
555 
556       @BoundFlag(
557           formalName = "Media Type",
558           description = "A label that indicates the nature of a resource, as a data serialization or format.",
559           useName = "media-type",
560           typeAdapter = StringAdapter.class
561       )
562       private String _mediaType;
563 
564       public Base64() {
565       }
566 
567       public ByteBuffer getValue() {
568         return _value;
569       }
570 
571       public void setValue(ByteBuffer value) {
572         _value = value;
573       }
574 
575       public String getFilename() {
576         return _filename;
577       }
578 
579       public void setFilename(String value) {
580         _filename = value;
581       }
582 
583       public String getMediaType() {
584         return _mediaType;
585       }
586 
587       public void setMediaType(String value) {
588         _mediaType = value;
589       }
590 
591       @Override
592       public String toString() {
593         return new ReflectionToStringBuilder(this, MultilineRecursiveToStringStyle.MULTI_LINE_STYLE).toString();
594       }
595     }
596 
597     /**
598      * A URL-based pointer to an external resource with an optional hash for verification and change detection.
599      */
600     @MetaschemaAssembly(
601         formalName = "Resource link",
602         description = "A URL-based pointer to an external resource with an optional hash for verification and change detection.",
603         name = "rlink",
604         metaschema = OscalMetadataMetaschema.class,
605         remarks = "Multiple `rlink` objects can be included for a resource. In such a case, all provided `rlink` items are intended to be equivalent in content, but may differ in structure or format.\n"
606                 + "\n"
607                 + "A `media-type` is used to identify the format of a given rlink, and can be used to differentiate items in a collection of rlinks. The `media-type` provides a hint to the OSCAL document consumer about the structure of the resource referenced by the `rlink`."
608     )
609     public static class Rlink {
610       @BoundFlag(
611           formalName = "Hypertext Reference",
612           description = "A resolvable URL pointing to the referenced resource.",
613           useName = "href",
614           required = true,
615           typeAdapter = UriReferenceAdapter.class,
616           remarks = "This value may be either:\n"
617                   + "\n"
618                   + "1. an [absolute URI](https://pages.nist.gov/OSCAL/concepts/uri-use/#absolute-uri) that points to a network resolvable resource,\n"
619                   + "2. a [relative reference](https://pages.nist.gov/OSCAL/concepts/uri-use/#relative-reference) pointing to a network resolvable resource whose base URI is the URI of the containing document, or"
620       )
621       private URI _href;
622 
623       @BoundFlag(
624           formalName = "Media Type",
625           description = "A label that indicates the nature of a resource, as a data serialization or format.",
626           useName = "media-type",
627           typeAdapter = StringAdapter.class
628       )
629       private String _mediaType;
630 
631       /**
632        * "A hash of the resource identified by <code>href</code>, which can be used to verify the resource was not changed since it was hashed."
633        */
634       @BoundField(
635           formalName = "Hash",
636           description = "A hash of the resource identified by `href`, which can be used to verify the resource was not changed since it was hashed.",
637           useName = "hash",
638           maxOccurs = -1,
639           remarks = "The `hash` value can be used to confirm that the resource referenced by the `href` is the same resources that was hashed by retrieving the resource, calculating a hash, and comparing the result to this value."
640       )
641       @GroupAs(
642           name = "hashes",
643           inJson = JsonGroupAsBehavior.LIST
644       )
645       private List<Hash> _hashes;
646 
647       public Rlink() {
648       }
649 
650       public URI getHref() {
651         return _href;
652       }
653 
654       public void setHref(URI value) {
655         _href = value;
656       }
657 
658       public String getMediaType() {
659         return _mediaType;
660       }
661 
662       public void setMediaType(String value) {
663         _mediaType = value;
664       }
665 
666       public List<Hash> getHashes() {
667         return _hashes;
668       }
669 
670       public void setHashes(List<Hash> value) {
671         _hashes = value;
672       }
673 
674       /**
675        * Add a new {@link Hash} item to the underlying collection.
676        * @param item the item to add
677        * @return {@code true}
678        */
679       public boolean addHash(Hash item) {
680         Hash value = ObjectUtils.requireNonNull(item,"item cannot be null");
681         if (_hashes == null) {
682           _hashes = new LinkedList<>();
683         }
684         return _hashes.add(value);
685       }
686 
687       /**
688        * Remove the first matching {@link Hash} item from the underlying collection.
689        * @param item the item to remove
690        * @return {@code true} if the item was removed or {@code false} otherwise
691        */
692       public boolean removeHash(Hash item) {
693         Hash value = ObjectUtils.requireNonNull(item,"item cannot be null");
694         return _hashes == null ? false : _hashes.remove(value);
695       }
696 
697       @Override
698       public String toString() {
699         return new ReflectionToStringBuilder(this, MultilineRecursiveToStringStyle.MULTI_LINE_STYLE).toString();
700       }
701     }
702   }
703 }