44import java .net .URI ;
55import java .net .URISyntaxException ;
66import java .util .Objects ;
7+ import java .util .function .IntPredicate ;
78
89public class Did implements Serializable {
910
1011 private static final long serialVersionUID = -3127318269811273712L ;
1112
12- public static final String SCHEME = "did" ;
13+ /*
14+ * method-char = %x61-7A / DIGIT
15+ */
16+ static final IntPredicate METHOD_CHAR = ch -> (0x61 <= ch && ch <= 0x7A ) || ('0' <= ch && ch <= '9' );
1317
18+ public static final String SCHEME = "did" ;
19+
1420 protected final String method ;
15- protected final String version ;
16- protected final String methodSpecificId ;
21+ protected final String specificId ;
1722
18- protected Did (final String method , final String version , final String methodSpecificId ) {
23+ protected Did (final String method , final String specificId ) {
1924 this .method = method ;
20- this .version = version ;
21- this .methodSpecificId = methodSpecificId ;
25+ this .specificId = specificId ;
2226 }
2327
2428 public static boolean isDid (final URI uri ) {
@@ -29,29 +33,32 @@ public static boolean isDid(final URI uri) {
2933 || isNotBlank (uri .getHost ())
3034 || isNotBlank (uri .getPath ())
3135 || isNotBlank (uri .getQuery ())
32- || isNotBlank (uri .getFragment ())
33- ) {
34- return false ;
35- }
36+ || isNotBlank (uri .getFragment ())) {
37+ return false ;
38+ }
3639
37- final String [] parts = uri .getSchemeSpecificPart ().split (":" );
40+ final String [] parts = uri .getSchemeSpecificPart ().split (":" , 2 );
3841
39- return parts .length == 2 || parts .length == 3 ;
42+ return parts .length == 2
43+ && parts [0 ].length () > 0
44+ && parts [1 ].length () > 0
45+ && parts [0 ].codePoints ().allMatch (METHOD_CHAR )
46+ ;
4047 }
4148
4249 public static boolean isDid (final String uri ) {
4350
44- if (isBlank ( uri ) ) {
51+ if (uri == null ) {
4552 return false ;
4653 }
4754
48- final String [] parts = uri .split (":" );
55+ final String [] parts = uri .split (":" , 3 );
4956
50- return ( parts .length == 3 || parts . length == 4 )
57+ return parts .length == 3
5158 && Did .SCHEME .equalsIgnoreCase (parts [0 ])
52- && ! parts [parts . length - 1 ].contains ( "/" ) // path
53- && ! parts [parts . length - 1 ]. contains ( "?" ) // query
54- && ! parts [parts . length - 1 ].contains ( "#" ) // fragment
59+ && parts [1 ].length () > 0
60+ && parts [2 ]. length () > 0
61+ && parts [1 ].codePoints (). allMatch ( METHOD_CHAR )
5562 ;
5663 }
5764
@@ -61,19 +68,21 @@ public static boolean isDid(final String uri) {
6168 * @param uri The source URI to be transformed into DID
6269 * @return The new DID
6370 *
64- * @throws NullPointerException
65- * If {@code uri} is {@code null}
71+ * @throws NullPointerException If {@code uri} is {@code null}
6672 *
67- * @throws IllegalArgumentException
68- * If the given {@code uri} is not valid DID
73+ * @throws IllegalArgumentException If the given {@code uri} is not valid DID
6974 */
7075 public static Did from (final URI uri ) {
7176
72- if (! isDid ( uri ) ) {
73- throw new IllegalArgumentException ("The URI [" + uri + "] is not valid DID key, does not start with 'did:' ." );
77+ if (uri == null ) {
78+ throw new IllegalArgumentException ("The DID must not be null ." );
7479 }
7580
76- return from (uri , uri .getSchemeSpecificPart ().split (":" ), 3 );
81+ if (!Did .SCHEME .equalsIgnoreCase (uri .getScheme ())) {
82+ throw new IllegalArgumentException ("The URI [" + uri + "] is not valid DID, must start with 'did:' prefix." );
83+ }
84+
85+ return from (uri , uri .getSchemeSpecificPart ().split (":" , 2 ));
7786 }
7887
7988 /**
@@ -82,59 +91,58 @@ public static Did from(final URI uri) {
8291 * @param uri The source URI to be transformed into DID
8392 * @return The new DID
8493 *
85- * @throws NullPointerException
86- * If {@code uri} is {@code null}
94+ * @throws NullPointerException If {@code uri} is {@code null}
8795 *
88- * @throws IllegalArgumentException
89- * If the given {@code uri} is not valid DID
96+ * @throws IllegalArgumentException If the given {@code uri} is not valid DID
9097 */
9198 public static Did from (final String uri ) {
99+ if (uri == null || uri .length () == 0 ) {
100+ throw new IllegalArgumentException ("The DID must not be null or blank string." );
101+ }
92102
93- if (!isDid (uri )) {
94- throw new IllegalArgumentException ("The URI [" + uri + "] is not valid DID key, does not start with 'did:'." );
103+ final String [] parts = uri .split (":" , 3 );
104+
105+ if (parts .length != 3 ) {
106+ throw new IllegalArgumentException ("The URI [" + uri + "] is not valid DID, must be in form 'did:method:method-specific-id'." );
95107 }
96108
97- return from (uri , uri .split (":" ), 4 );
98- }
109+ if (!Did .SCHEME .equalsIgnoreCase (parts [0 ])) {
110+ throw new IllegalArgumentException ("The URI [" + uri + "] is not valid DID, must start with 'did:' prefix." );
111+ }
99112
100- protected static Did from (final Object uri , final String [] parts , int max ) {
113+ return from (uri , new String [] { parts [1 ], parts [2 ] });
114+ }
101115
102- if (parts .length < max - 1
103- || parts .length > max
104- || isBlank (parts [max - 3 ])
105- || isBlank (parts [max - 2 ])
106- ) {
116+ protected static Did from (final Object uri , final String [] parts ) {
117+ if (parts .length != 2 ) {
107118 throw new IllegalArgumentException ("The URI [" + uri + "] is not valid DID, must be in form 'did:method:method-specific-id'." );
108119 }
109120
110- String methodSpecificId = parts [ max - 2 ];
111- String version = "1" ; // default DID version
112-
113- if ( parts . length == max ) {
114- if ( isBlank ( parts [ max - 1 ])) {
115- throw new IllegalArgumentException ( "The URI [" + uri + "] is not valid DID, must be in form 'did:method:method-specific-id'." );
116- }
117- version = parts [max - 2 ];
118- methodSpecificId = parts [ max - 1 ] ;
121+ // check method
122+ if ( parts [ 0 ]. length () == 0
123+ || ! parts [ 0 ]. codePoints (). allMatch ( METHOD_CHAR )) {
124+ throw new IllegalArgumentException ( "The URI [" + uri + "] is not valid DID, method [" + parts [ 0 ] + "] syntax is blank or invalid." );
125+ }
126+
127+ // check method specific id
128+ if ( parts [1 ]. length () == 0 ) {
129+ throw new IllegalArgumentException ( "The URI [" + uri + "] is not valid DID, method specific id [" + parts [ 1 ] + "] is blank." ) ;
119130 }
120131
121- return new Did (parts [max - 3 ], version , methodSpecificId );
132+ return new Did (parts [0 ], parts [ 1 ] );
122133 }
134+
123135 public String getMethod () {
124136 return method ;
125137 }
126138
127- public String getVersion () {
128- return version ;
129- }
130-
131139 public String getMethodSpecificId () {
132- return methodSpecificId ;
140+ return specificId ;
133141 }
134142
135143 public URI toUri () {
136144 try {
137- return new URI (SCHEME , method + ":" + methodSpecificId , null );
145+ return new URI (SCHEME , method + ":" + specificId , null );
138146 } catch (URISyntaxException e ) {
139147 throw new IllegalStateException (e );
140148 }
@@ -150,23 +158,17 @@ public DidUrl asDidUrl() {
150158
151159 @ Override
152160 public String toString () {
153- final StringBuilder builder = new StringBuilder ()
154- .append (SCHEME )
155- .append (':' )
156- .append (method )
157- .append (':' );
158-
159- if (!"1" .equals (version )) {
160- builder
161- .append (version )
162- .append (':' );
163- }
164- return builder .append (methodSpecificId ).toString ();
161+ return new StringBuilder ()
162+ .append (SCHEME )
163+ .append (':' )
164+ .append (method )
165+ .append (':' )
166+ .append (specificId ).toString ();
165167 }
166168
167169 @ Override
168170 public int hashCode () {
169- return Objects .hash (method , methodSpecificId , version );
171+ return Objects .hash (method , specificId );
170172 }
171173
172174 @ Override
@@ -181,16 +183,15 @@ public boolean equals(final Object obj) {
181183 return false ;
182184 }
183185 Did other = (Did ) obj ;
184- return Objects .equals (method , other .method ) && Objects .equals (methodSpecificId , other .methodSpecificId )
185- && Objects . equals ( version , other . version );
186+ return Objects .equals (method , other .method ) && Objects .equals (specificId , other .specificId );
187+
186188 }
187-
189+
188190 static final boolean isNotBlank (String value ) {
189191 return value != null && !value .trim ().isEmpty ();
190192 }
191193
192194 static final boolean isBlank (String value ) {
193195 return value == null || value .trim ().isEmpty ();
194196 }
195-
196197}
0 commit comments