11package io .opentdf .platform .sdk .nanotdf ;
22
33import java .nio .ByteBuffer ;
4- import java .util .Arrays ;
5-
4+ import java .util .Objects ;
5+
6+ /**
7+ * The ResourceLocator class represents a resource locator containing a
8+ * protocol, body, and identifier. It provides methods to set and retrieve
9+ * the protocol, body, and identifier, as well as to get the resource URL and
10+ * the total size of the resource locator. It also provides methods to write
11+ * the resource locator into a ByteBuffer and obtain the identifier.
12+ */
613public class ResourceLocator {
14+ private static final String HTTP = "http://" ;
15+ private static final String HTTPS = "https://" ;
16+
717 private NanoTDFType .Protocol protocol ;
818 private int bodyLength ;
919 private byte [] body ;
20+ private NanoTDFType .IdentifierType identifierType ;
21+ private byte [] identifier ;
1022
1123 public ResourceLocator () {
1224 }
1325
14- public ResourceLocator (String resourceUrl ) {
15- if (resourceUrl .startsWith ("http://" )) {
26+ public ResourceLocator (final String resourceUrl ) {
27+ this (resourceUrl , null );
28+ }
29+
30+ /**
31+ * ResourceLocator represents a locator for a resource.
32+ * It takes a resource URL and an identifier as parameters and initializes the object.
33+ * The resource URL is used to determine the protocol and the body.
34+ * The identifier is used to determine the identifier type and the identifier value.
35+ *
36+ * @param resourceUrl the URL of the resource
37+ * @param identifier the identifier of the resource (optional, can be null)
38+ * @throws IllegalArgumentException if the resource URL has an unsupported protocol or if the identifier length is unsupported
39+ */
40+ public ResourceLocator (final String resourceUrl , final String identifier ) {
41+ if (resourceUrl .startsWith (HTTP )) {
1642 this .protocol = NanoTDFType .Protocol .HTTP ;
17- } else if (resourceUrl .startsWith ("https://" )) {
43+ } else if (resourceUrl .startsWith (HTTPS )) {
1844 this .protocol = NanoTDFType .Protocol .HTTPS ;
1945 } else {
20- throw new RuntimeException ("Unsupported protocol for resource locator" );
46+ throw new IllegalArgumentException ("Unsupported protocol for resource locator" );
2147 }
22-
48+ // body
2349 this .body = resourceUrl .substring (resourceUrl .indexOf ("://" ) + 3 ).getBytes ();
2450 this .bodyLength = this .body .length ;
51+ // identifier
52+ if (identifier == null ) {
53+ this .identifierType = NanoTDFType .IdentifierType .NONE ;
54+ this .identifier = new byte [NanoTDFType .IdentifierType .NONE .getLength ()];
55+ } else {
56+ int identifierLen = identifier .getBytes ().length ;
57+ if (identifierLen == 0 ) {
58+ this .identifierType = NanoTDFType .IdentifierType .NONE ;
59+ this .identifier = new byte [NanoTDFType .IdentifierType .NONE .getLength ()];
60+ } else if (identifierLen <= 2 ) {
61+ this .identifierType = NanoTDFType .IdentifierType .TWO_BYTES ;
62+ this .identifier = new byte [NanoTDFType .IdentifierType .TWO_BYTES .getLength ()];
63+ System .arraycopy (identifier .getBytes (), 0 , this .identifier , 0 , identifierLen );
64+ } else if (identifierLen <= 8 ) {
65+ this .identifierType = NanoTDFType .IdentifierType .EIGHT_BYTES ;
66+ this .identifier = new byte [NanoTDFType .IdentifierType .EIGHT_BYTES .getLength ()];
67+ System .arraycopy (identifier .getBytes (), 0 , this .identifier , 0 , identifierLen );
68+ } else if (identifierLen <= 32 ) {
69+ this .identifierType = NanoTDFType .IdentifierType .THIRTY_TWO_BYTES ;
70+ this .identifier = new byte [NanoTDFType .IdentifierType .THIRTY_TWO_BYTES .getLength ()];
71+ System .arraycopy (identifier .getBytes (), 0 , this .identifier , 0 , identifierLen );
72+ } else {
73+ throw new IllegalArgumentException ("Unsupported identifier length: " + identifierLen );
74+ }
75+ }
2576 }
2677
2778 public ResourceLocator (ByteBuffer buffer ) {
2879 // Get the first byte and mask it with 0xF to keep only the first four bits
29- byte protocolByte = buffer .get ();
30- int protocolIndex = protocolByte & 0xF ;
31- this .protocol = NanoTDFType .Protocol .values ()[protocolIndex ];
80+ final byte protocolWithIdentifier = buffer .get ();
81+ int protocolNibble = protocolWithIdentifier & 0x0F ;
82+ int identifierNibble = (protocolWithIdentifier & 0xF0 ) >> 4 ;
83+ this .protocol = NanoTDFType .Protocol .values ()[protocolNibble ];
84+ // body
3285 this .bodyLength = buffer .get ();
3386 this .body = new byte [this .bodyLength ];
3487 buffer .get (this .body );
88+ // identifier
89+ this .identifierType = NanoTDFType .IdentifierType .values ()[identifierNibble ];
90+ switch (this .identifierType ) {
91+ case NONE :
92+ this .identifier = new byte [0 ];
93+ break ;
94+ case TWO_BYTES :
95+ this .identifier = new byte [2 ];
96+ buffer .get (this .identifier );
97+ break ;
98+ case EIGHT_BYTES :
99+ this .identifier = new byte [8 ];
100+ buffer .get (this .identifier );
101+ break ;
102+ case THIRTY_TWO_BYTES :
103+ this .identifier = new byte [32 ];
104+ buffer .get (this .identifier );
105+ break ;
106+ default :
107+ throw new IllegalArgumentException ("Unexpected identifier type: " + identifierType );
108+ }
109+ }
110+
111+ public void setIdentifier (String identifier ) {
112+ if (identifier == null ) {
113+ this .identifierType = NanoTDFType .IdentifierType .NONE ;
114+ this .identifier = new byte [0 ];
115+ } else {
116+ byte [] identifierBytes = identifier .getBytes ();
117+ int identifierLen = identifierBytes .length ;
118+
119+ if (identifierLen == 0 ) {
120+ this .identifierType = NanoTDFType .IdentifierType .NONE ;
121+ this .identifier = new byte [0 ];
122+ } else if (identifierLen <= 2 ) {
123+ this .identifierType = NanoTDFType .IdentifierType .TWO_BYTES ;
124+ this .identifier = new byte [2 ];
125+ System .arraycopy (identifierBytes , 0 , this .identifier , 0 , identifierLen );
126+ } else if (identifierLen <= 8 ) {
127+ this .identifierType = NanoTDFType .IdentifierType .EIGHT_BYTES ;
128+ this .identifier = new byte [8 ];
129+ System .arraycopy (identifierBytes , 0 , this .identifier , 0 , identifierLen );
130+ } else if (identifierLen <= 32 ) {
131+ this .identifierType = NanoTDFType .IdentifierType .THIRTY_TWO_BYTES ;
132+ this .identifier = new byte [32 ];
133+ System .arraycopy (identifierBytes , 0 , this .identifier , 0 , identifierLen );
134+ } else {
135+ throw new IllegalArgumentException ("Unsupported identifier length: " + identifierLen );
136+ }
137+ }
35138 }
36139
37140 public void setProtocol (NanoTDFType .Protocol protocol ) {
@@ -49,13 +152,10 @@ public void setBody(byte[] body) {
49152 public String getResourceUrl () {
50153 StringBuilder sb = new StringBuilder ();
51154
52- switch (this .protocol ) {
53- case HTTP :
54- sb .append ("http://" );
55- break ;
56- case HTTPS :
57- sb .append ("https://" );
58- break ;
155+ if (Objects .requireNonNull (this .protocol ) == NanoTDFType .Protocol .HTTP ) {
156+ sb .append (HTTP );
157+ } else if (this .protocol == NanoTDFType .Protocol .HTTPS ) {
158+ sb .append (HTTPS );
59159 }
60160
61161 sb .append (new String (this .body ));
@@ -64,9 +164,16 @@ public String getResourceUrl() {
64164 }
65165
66166 public int getTotalSize () {
67- return 1 + 1 + this .body .length ;
167+ return 1 + 1 + this .body .length + this . identifier . length ;
68168 }
69169
170+ /**
171+ * Writes the resource locator into the provided ByteBuffer.
172+ *
173+ * @param buffer the ByteBuffer to write into
174+ * @return the number of bytes written
175+ * @throws RuntimeException if the buffer size is insufficient to write the resource locator
176+ */
70177 public int writeIntoBuffer (ByteBuffer buffer ) {
71178 int totalSize = getTotalSize ();
72179 if (buffer .remaining () < totalSize ) {
@@ -76,17 +183,43 @@ public int writeIntoBuffer(ByteBuffer buffer) {
76183 int totalBytesWritten = 0 ;
77184
78185 // Write the protocol type.
79- buffer .put ((byte ) protocol .ordinal ());
80- totalBytesWritten += 1 ; // size of byte
186+ if (identifierType == NanoTDFType .IdentifierType .NONE ) {
187+ buffer .put ((byte ) protocol .ordinal ());
188+ totalBytesWritten += 1 ; // size of byte
189+ } else {
190+ buffer .put ((byte ) (identifierType .ordinal () << 4 | protocol .ordinal ()));
191+ totalBytesWritten += 1 ;
192+ }
81193
82- // Write the url body length;
194+ // Write the url body length
83195 buffer .put ((byte )bodyLength );
84196 totalBytesWritten += 1 ;
85197
86- // Write the url body;
198+ // Write the url body
87199 buffer .put (body );
88200 totalBytesWritten += body .length ;
89201
202+ // Write the identifier
203+ if (identifierType != NanoTDFType .IdentifierType .NONE ) {
204+ buffer .put (identifier );
205+ totalBytesWritten += identifier .length ;
206+ }
207+
90208 return totalBytesWritten ;
91209 }
210+
211+ public byte [] getIdentifier () {
212+ return this .identifier ;
213+ }
214+
215+ // getIdentifierString removes potential padding
216+ public String getIdentifierString () {
217+ int actualLength = 0 ;
218+ for (int i = 0 ; i < this .identifier .length ; i ++) {
219+ if (this .identifier [i ] != 0 ) {
220+ actualLength = i + 1 ;
221+ }
222+ }
223+ return new String (this .identifier , 0 , actualLength );
224+ }
92225}
0 commit comments