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.AssemblyConstraints;
006import gov.nist.secauto.metaschema.binding.model.annotations.BoundAssembly;
007import gov.nist.secauto.metaschema.binding.model.annotations.BoundField;
008import gov.nist.secauto.metaschema.binding.model.annotations.BoundFieldValue;
009import gov.nist.secauto.metaschema.binding.model.annotations.BoundFlag;
010import gov.nist.secauto.metaschema.binding.model.annotations.Expect;
011import gov.nist.secauto.metaschema.binding.model.annotations.GroupAs;
012import gov.nist.secauto.metaschema.binding.model.annotations.HasCardinality;
013import gov.nist.secauto.metaschema.binding.model.annotations.Index;
014import gov.nist.secauto.metaschema.binding.model.annotations.IsUnique;
015import gov.nist.secauto.metaschema.binding.model.annotations.KeyField;
016import gov.nist.secauto.metaschema.binding.model.annotations.Matches;
017import gov.nist.secauto.metaschema.binding.model.annotations.MetaschemaAssembly;
018import gov.nist.secauto.metaschema.binding.model.annotations.MetaschemaField;
019import gov.nist.secauto.metaschema.binding.model.annotations.MetaschemaFieldValue;
020import gov.nist.secauto.metaschema.binding.model.annotations.ValueConstraints;
021import gov.nist.secauto.metaschema.model.common.JsonGroupAsBehavior;
022import gov.nist.secauto.metaschema.model.common.constraint.IConstraint;
023import gov.nist.secauto.metaschema.model.common.datatype.adapter.Base64Adapter;
024import gov.nist.secauto.metaschema.model.common.datatype.adapter.DateTimeWithTZAdapter;
025import gov.nist.secauto.metaschema.model.common.datatype.adapter.StringAdapter;
026import gov.nist.secauto.metaschema.model.common.datatype.adapter.TokenAdapter;
027import gov.nist.secauto.metaschema.model.common.datatype.adapter.UriReferenceAdapter;
028import gov.nist.secauto.metaschema.model.common.datatype.adapter.UuidAdapter;
029import gov.nist.secauto.metaschema.model.common.datatype.markup.MarkupLine;
030import gov.nist.secauto.metaschema.model.common.datatype.markup.MarkupLineAdapter;
031import gov.nist.secauto.metaschema.model.common.datatype.markup.MarkupMultiline;
032import gov.nist.secauto.metaschema.model.common.datatype.markup.MarkupMultilineAdapter;
033import gov.nist.secauto.metaschema.model.common.util.ObjectUtils;
034import gov.nist.secauto.oscal.lib.model.metadata.AbstractBackMatter;
035import java.lang.Override;
036import java.lang.String;
037import java.net.URI;
038import java.nio.ByteBuffer;
039import java.util.LinkedList;
040import java.util.List;
041import java.util.UUID;
042import org.apache.commons.lang3.builder.MultilineRecursiveToStringStyle;
043import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
044
045/**
046 * A collection of resources that may be referenced from within the OSCAL document instance.
047 */
048@MetaschemaAssembly(
049    formalName = "Back matter",
050    description = "A collection of resources that may be referenced from within the OSCAL document instance.",
051    name = "back-matter",
052    metaschema = OscalMetadataMetaschema.class,
053    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."
054)
055@AssemblyConstraints(
056    index = @Index(level = IConstraint.Level.ERROR, target = "resource", name = "index-back-matter-resource", keyFields = @KeyField(target = "@uuid"))
057)
058public class BackMatter extends AbstractBackMatter {
059  /**
060   * "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."
061   */
062  @BoundAssembly(
063      formalName = "Resource",
064      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.",
065      useName = "resource",
066      maxOccurs = -1,
067      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"
068              + "\n"
069              + "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"
070              + "\n"
071              + "When a resource includes a citation, then the `title` and `citation` properties must both be included."
072  )
073  @GroupAs(
074      name = "resources",
075      inJson = JsonGroupAsBehavior.LIST
076  )
077  private List<Resource> _resources;
078
079  public BackMatter() {
080  }
081
082  public List<Resource> getResources() {
083    return _resources;
084  }
085
086  public void setResources(List<Resource> value) {
087    _resources = value;
088  }
089
090  /**
091   * Add a new {@link Resource} item to the underlying collection.
092   * @param item the item to add
093   * @return {@code true}
094   */
095  public boolean addResource(Resource item) {
096    Resource value = ObjectUtils.requireNonNull(item,"item cannot be null");
097    if (_resources == null) {
098      _resources = new LinkedList<>();
099    }
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}