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}