@@ -81,11 +81,17 @@ public final class InternetDomainName {
81
81
private static final Joiner DOT_JOINER = Joiner .on ('.' );
82
82
83
83
/**
84
- * Value of {@link #publicSuffixIndex} or {@link #registrySuffixIndex} which indicates that no
84
+ * Value of {@link #publicSuffixIndex() } or {@link #registrySuffixIndex() } which indicates that no
85
85
* relevant suffix was found.
86
86
*/
87
87
private static final int NO_SUFFIX_FOUND = -1 ;
88
88
89
+ /**
90
+ * Value of {@link #publicSuffixIndexCache} or {@link #registrySuffixIndexCache} which indicates
91
+ * that they were not initialized yet.
92
+ */
93
+ private static final int SUFFIX_NOT_INITIALIZED = -2 ;
94
+
89
95
/**
90
96
* Maximum parts (labels) in a domain name. This value arises from the 255-octet limit described
91
97
* in <a href="http://www.ietf.org/rfc/rfc2181.txt">RFC 2181</a> part 11 with the fact that the
@@ -113,20 +119,24 @@ public final class InternetDomainName {
113
119
private final ImmutableList <String > parts ;
114
120
115
121
/**
116
- * The index in the {@link #parts()} list at which the public suffix begins. For example, for the
117
- * domain name {@code myblog.blogspot.co.uk}, the value would be 1 (the index of the {@code
118
- * blogspot} part). The value is negative (specifically, {@link #NO_SUFFIX_FOUND}) if no public
119
- * suffix was found.
122
+ * Cached value of #publicSuffixIndex(). Do not use directly.
123
+ *
124
+ * <p>Since this field isn't {@code volatile}, if an instance of this class is shared across
125
+ * threads before it is initialized, then each thread is likely to compute their own copy of the
126
+ * value.
120
127
*/
121
- private final int publicSuffixIndex ;
128
+ @ SuppressWarnings ("Immutable" )
129
+ private int publicSuffixIndexCache = SUFFIX_NOT_INITIALIZED ;
122
130
123
131
/**
124
- * The index in the {@link #parts()} list at which the registry suffix begins. For example, for
125
- * the domain name {@code myblog.blogspot.co.uk}, the value would be 2 (the index of the {@code
126
- * co} part). The value is negative (specifically, {@link #NO_SUFFIX_FOUND}) if no registry suffix
127
- * was found.
132
+ * Cached value of #registrySuffixIndex(). Do not use directly.
133
+ *
134
+ * <p>Since this field isn't {@code volatile}, if an instance of this class is shared across
135
+ * threads before it is initialized, then each thread is likely to compute their own copy of the
136
+ * value.
128
137
*/
129
- private final int registrySuffixIndex ;
138
+ @ SuppressWarnings ("Immutable" )
139
+ private int registrySuffixIndexCache = SUFFIX_NOT_INITIALIZED ;
130
140
131
141
/** Constructor used to implement {@link #from(String)}, and from subclasses. */
132
142
InternetDomainName (String name ) {
@@ -147,9 +157,32 @@ public final class InternetDomainName {
147
157
this .parts = ImmutableList .copyOf (DOT_SPLITTER .split (name ));
148
158
checkArgument (parts .size () <= MAX_PARTS , "Domain has too many parts: '%s'" , name );
149
159
checkArgument (validateSyntax (parts ), "Not a valid domain name: '%s'" , name );
160
+ }
161
+
162
+ /**
163
+ * The index in the {@link #parts()} list at which the public suffix begins. For example, for the
164
+ * domain name {@code myblog.blogspot.co.uk}, the value would be 1 (the index of the {@code
165
+ * blogspot} part). The value is negative (specifically, {@link #NO_SUFFIX_FOUND}) if no public
166
+ * suffix was found.
167
+ */
168
+ private int publicSuffixIndex () {
169
+ if (publicSuffixIndexCache == SUFFIX_NOT_INITIALIZED ) {
170
+ publicSuffixIndexCache = findSuffixOfType (Optional .<PublicSuffixType >absent ());
171
+ }
172
+ return publicSuffixIndexCache ;
173
+ }
150
174
151
- this .publicSuffixIndex = findSuffixOfType (Optional .<PublicSuffixType >absent ());
152
- this .registrySuffixIndex = findSuffixOfType (Optional .of (PublicSuffixType .REGISTRY ));
175
+ /**
176
+ * The index in the {@link #parts()} list at which the registry suffix begins. For example, for
177
+ * the domain name {@code myblog.blogspot.co.uk}, the value would be 2 (the index of the {@code
178
+ * co} part). The value is negative (specifically, {@link #NO_SUFFIX_FOUND}) if no registry suffix
179
+ * was found.
180
+ */
181
+ private int registrySuffixIndex () {
182
+ if (registrySuffixIndexCache == SUFFIX_NOT_INITIALIZED ) {
183
+ registrySuffixIndexCache = findSuffixOfType (Optional .of (PublicSuffixType .REGISTRY ));
184
+ }
185
+ return registrySuffixIndexCache ;
153
186
}
154
187
155
188
/**
@@ -331,7 +364,7 @@ public ImmutableList<String> parts() {
331
364
* @since 6.0
332
365
*/
333
366
public boolean isPublicSuffix () {
334
- return publicSuffixIndex == 0 ;
367
+ return publicSuffixIndex () == 0 ;
335
368
}
336
369
337
370
/**
@@ -347,7 +380,7 @@ public boolean isPublicSuffix() {
347
380
* @since 6.0
348
381
*/
349
382
public boolean hasPublicSuffix () {
350
- return publicSuffixIndex != NO_SUFFIX_FOUND ;
383
+ return publicSuffixIndex () != NO_SUFFIX_FOUND ;
351
384
}
352
385
353
386
/**
@@ -358,7 +391,7 @@ public boolean hasPublicSuffix() {
358
391
*/
359
392
@ CheckForNull
360
393
public InternetDomainName publicSuffix () {
361
- return hasPublicSuffix () ? ancestor (publicSuffixIndex ) : null ;
394
+ return hasPublicSuffix () ? ancestor (publicSuffixIndex () ) : null ;
362
395
}
363
396
364
397
/**
@@ -374,7 +407,7 @@ public InternetDomainName publicSuffix() {
374
407
* @since 6.0
375
408
*/
376
409
public boolean isUnderPublicSuffix () {
377
- return publicSuffixIndex > 0 ;
410
+ return publicSuffixIndex () > 0 ;
378
411
}
379
412
380
413
/**
@@ -390,7 +423,7 @@ public boolean isUnderPublicSuffix() {
390
423
* @since 6.0
391
424
*/
392
425
public boolean isTopPrivateDomain () {
393
- return publicSuffixIndex == 1 ;
426
+ return publicSuffixIndex () == 1 ;
394
427
}
395
428
396
429
/**
@@ -414,7 +447,7 @@ public InternetDomainName topPrivateDomain() {
414
447
return this ;
415
448
}
416
449
checkState (isUnderPublicSuffix (), "Not under a public suffix: %s" , name );
417
- return ancestor (publicSuffixIndex - 1 );
450
+ return ancestor (publicSuffixIndex () - 1 );
418
451
}
419
452
420
453
/**
@@ -441,7 +474,7 @@ public InternetDomainName topPrivateDomain() {
441
474
* @since 23.3
442
475
*/
443
476
public boolean isRegistrySuffix () {
444
- return registrySuffixIndex == 0 ;
477
+ return registrySuffixIndex () == 0 ;
445
478
}
446
479
447
480
/**
@@ -456,7 +489,7 @@ public boolean isRegistrySuffix() {
456
489
* @since 23.3
457
490
*/
458
491
public boolean hasRegistrySuffix () {
459
- return registrySuffixIndex != NO_SUFFIX_FOUND ;
492
+ return registrySuffixIndex () != NO_SUFFIX_FOUND ;
460
493
}
461
494
462
495
/**
@@ -467,7 +500,7 @@ public boolean hasRegistrySuffix() {
467
500
*/
468
501
@ CheckForNull
469
502
public InternetDomainName registrySuffix () {
470
- return hasRegistrySuffix () ? ancestor (registrySuffixIndex ) : null ;
503
+ return hasRegistrySuffix () ? ancestor (registrySuffixIndex () ) : null ;
471
504
}
472
505
473
506
/**
@@ -479,7 +512,7 @@ public InternetDomainName registrySuffix() {
479
512
* @since 23.3
480
513
*/
481
514
public boolean isUnderRegistrySuffix () {
482
- return registrySuffixIndex > 0 ;
515
+ return registrySuffixIndex () > 0 ;
483
516
}
484
517
485
518
/**
@@ -494,7 +527,7 @@ public boolean isUnderRegistrySuffix() {
494
527
* @since 23.3
495
528
*/
496
529
public boolean isTopDomainUnderRegistrySuffix () {
497
- return registrySuffixIndex == 1 ;
530
+ return registrySuffixIndex () == 1 ;
498
531
}
499
532
500
533
/**
@@ -517,7 +550,7 @@ public InternetDomainName topDomainUnderRegistrySuffix() {
517
550
return this ;
518
551
}
519
552
checkState (isUnderRegistrySuffix (), "Not under a registry suffix: %s" , name );
520
- return ancestor (registrySuffixIndex - 1 );
553
+ return ancestor (registrySuffixIndex () - 1 );
521
554
}
522
555
523
556
/** Indicates whether this domain is composed of two or more parts. */
0 commit comments