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.BoundField; 006import gov.nist.secauto.metaschema.binding.model.annotations.BoundFieldValue; 007import gov.nist.secauto.metaschema.binding.model.annotations.BoundFlag; 008import gov.nist.secauto.metaschema.binding.model.annotations.Expect; 009import gov.nist.secauto.metaschema.binding.model.annotations.IndexHasKey; 010import gov.nist.secauto.metaschema.binding.model.annotations.KeyField; 011import gov.nist.secauto.metaschema.binding.model.annotations.Matches; 012import gov.nist.secauto.metaschema.binding.model.annotations.MetaschemaAssembly; 013import gov.nist.secauto.metaschema.binding.model.annotations.ValueConstraints; 014import gov.nist.secauto.metaschema.model.common.constraint.IConstraint; 015import gov.nist.secauto.metaschema.model.common.datatype.adapter.StringAdapter; 016import gov.nist.secauto.metaschema.model.common.datatype.adapter.TokenAdapter; 017import gov.nist.secauto.metaschema.model.common.datatype.adapter.UriAdapter; 018import gov.nist.secauto.metaschema.model.common.datatype.adapter.UriReferenceAdapter; 019import gov.nist.secauto.metaschema.model.common.datatype.markup.MarkupLine; 020import gov.nist.secauto.metaschema.model.common.datatype.markup.MarkupLineAdapter; 021import gov.nist.secauto.oscal.lib.model.metadata.AbstractLink; 022import java.lang.Override; 023import java.lang.String; 024import java.net.URI; 025import org.apache.commons.lang3.builder.MultilineRecursiveToStringStyle; 026import org.apache.commons.lang3.builder.ReflectionToStringBuilder; 027 028/** 029 * A reference to a local or remote resource, that has a specific relation to the containing object. 030 */ 031@MetaschemaAssembly( 032 formalName = "Link", 033 description = "A reference to a local or remote resource, that has a specific relation to the containing object.", 034 name = "link", 035 metaschema = OscalMetadataMetaschema.class, 036 remarks = "To provide a cryptographic hash for a remote target resource, a local reference to a back matter `resource` is needed. The resource allows one or more hash values to be provided using the `rlink/hash` object.\n" 037 + "\n" 038 + "The OSCAL `link` is a roughly based on the HTML [link element](https://www.w3.org/TR/html401/struct/links.html#edef-LINK)." 039) 040@ValueConstraints( 041 indexHasKey = @IndexHasKey(level = IConstraint.Level.ERROR, target = ".[@rel=('reference') and starts-with(@href,'#')]", indexName = "index-back-matter-resource", keyFields = @KeyField(target = "@href", pattern = "#(.*)")), 042 matches = { 043 @Matches(level = IConstraint.Level.ERROR, target = ".[@rel=('reference') and starts-with(@href,'#')]/@href", typeAdapter = UriReferenceAdapter.class), 044 @Matches(level = IConstraint.Level.ERROR, target = ".[@rel=('reference') and not(starts-with(@href,'#'))]/@href", typeAdapter = UriAdapter.class), 045 @Matches(level = IConstraint.Level.ERROR, target = "@resource-fragment", pattern = "(?:[0-9a-zA-Z-._~/?!$&'()*+,;=:@]|%[0-9A-F][0-9A-F])+", remarks = "This pattern is based on the fragment Augmented Backus-Naur form (ABNF) syntax provided in \\[RFC3986 section 3.5\\](https://www.rfc-editor.org/rfc/rfc3986#section-3.5). Uppercase alpha hex digits are required, which is the preferred normalized form defined in RFC3986.") 046 }, 047 expect = @Expect(level = IConstraint.Level.ERROR, target = ".[starts-with(@href,'#')]", test = "not(exists(@media-type))", remarks = "Since both `link` and `back-matter/resource` both allow specification of a `media-type`, the `media-type` on `link` may conflict with the any `media-type` entries on a resource's `rlink` or `base64` objects. This constraint prevents this from occurring.") 048) 049public class Link extends AbstractLink { 050 @BoundFlag( 051 formalName = "Hypertext Reference", 052 description = "A resolvable URL reference to a resource.", 053 useName = "href", 054 required = true, 055 typeAdapter = UriReferenceAdapter.class, 056 remarks = "This value may be one of:\n" 057 + "\n" 058 + "1. an [absolute URI](https://pages.nist.gov/OSCAL/concepts/uri-use/#absolute-uri) that points to a network resolvable resource,\n" 059 + "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\n" 060 + "3. a bare URI fragment (i.e., \\`#uuid\\`) pointing to an OSCAL object by the objects identifier (e.g., id, uuid) in this or an imported document (see [linking to another OSCAL object](https://pages.nist.gov/OSCAL/concepts/uri-use/#linking-to-another-oscal-object)). The specific object type will differ based on the link relationship type." 061 ) 062 private URI _href; 063 064 @BoundFlag( 065 formalName = "Link Relation Type", 066 description = "Describes the type of relationship provided by the link's hypertext reference. This can be an indicator of the link's purpose.", 067 useName = "rel", 068 typeAdapter = TokenAdapter.class 069 ) 070 @ValueConstraints( 071 allowedValues = @AllowedValues(level = IConstraint.Level.ERROR, allowOthers = true, values = @AllowedValue(value = "reference", description = "A generalized reference to a network resource (relative or absolute) or to a `back-matter` resource by UUID expressed as a bare URI fragment.")) 072 ) 073 private String _rel; 074 075 @BoundFlag( 076 formalName = "Link Media Type", 077 description = "A label that indicates the nature of a resource, as a data serialization or format.", 078 useName = "media-type", 079 typeAdapter = StringAdapter.class, 080 remarks = "The `media-type` provides a hint about the content model of the referenced resource. A valid entry from the [IANA Media Types registry](https://www.iana.org/assignments/media-types/media-types.xhtml) SHOULD be used." 081 ) 082 private String _mediaType; 083 084 @BoundFlag( 085 formalName = "Resource Fragment", 086 description = "In case where the `href` points to a `back-matter/resource`, this value will indicate the URI [fragment](https://www.rfc-editor.org/rfc/rfc3986#section-3.5) to append to any `rlink` associated with the resource. This value MUST be [URI encoded](https://www.rfc-editor.org/rfc/rfc3986#section-2.1).", 087 useName = "resource-fragment", 088 typeAdapter = StringAdapter.class 089 ) 090 private String _resourceFragment; 091 092 /** 093 * "A textual label to associate with the link, which may be used for presentation in a tool." 094 */ 095 @BoundField( 096 formalName = "Link Text", 097 description = "A textual label to associate with the link, which may be used for presentation in a tool.", 098 useName = "text" 099 ) 100 @BoundFieldValue( 101 typeAdapter = MarkupLineAdapter.class 102 ) 103 private MarkupLine _text; 104 105 public Link() { 106 } 107 108 public URI getHref() { 109 return _href; 110 } 111 112 public void setHref(URI value) { 113 _href = value; 114 } 115 116 public String getRel() { 117 return _rel; 118 } 119 120 public void setRel(String value) { 121 _rel = value; 122 } 123 124 public String getMediaType() { 125 return _mediaType; 126 } 127 128 public void setMediaType(String value) { 129 _mediaType = value; 130 } 131 132 public String getResourceFragment() { 133 return _resourceFragment; 134 } 135 136 public void setResourceFragment(String value) { 137 _resourceFragment = value; 138 } 139 140 public MarkupLine getText() { 141 return _text; 142 } 143 144 public void setText(MarkupLine value) { 145 _text = value; 146 } 147 148 @Override 149 public String toString() { 150 return new ReflectionToStringBuilder(this, MultilineRecursiveToStringStyle.MULTI_LINE_STYLE).toString(); 151 } 152}