@@ -628,11 +628,16 @@ private Builder() {}
628
628
public static final String SPANNER_URI_FORMAT =
629
629
"(?:cloudspanner:)(?<HOSTGROUP>//[\\ w.-]+(?:\\ .[\\ w\\ .-]+)*[\\ w\\ -\\ ._~:/?#\\ [\\ ]@!\\ $&'\\ (\\ )\\ *\\ +,;=.]+)?/projects/(?<PROJECTGROUP>(([a-z]|[-.:]|[0-9])+|(DEFAULT_PROJECT_ID)))(/instances/(?<INSTANCEGROUP>([a-z]|[-]|[0-9])+)(/databases/(?<DATABASEGROUP>([a-z]|[-]|[_]|[0-9])+))?)?(?:[?|;].*)?" ;
630
630
631
+ public static final String EXTERNAL_HOST_FORMAT =
632
+ "(?:cloudspanner:)(?<HOSTGROUP>//[\\ w.-]+(?::\\ d+)?)(/instances/(?<INSTANCEGROUP>[a-z0-9-]+))?(/databases/(?<DATABASEGROUP>[a-z0-9_-]+))(?:[?;].*)?" ;
631
633
private static final String SPANNER_URI_REGEX = "(?is)^" + SPANNER_URI_FORMAT + "$" ;
632
634
633
635
@ VisibleForTesting
634
636
static final Pattern SPANNER_URI_PATTERN = Pattern .compile (SPANNER_URI_REGEX );
635
637
638
+ @ VisibleForTesting
639
+ static final Pattern EXTERNAL_HOST_PATTERN = Pattern .compile (EXTERNAL_HOST_FORMAT );
640
+
636
641
private static final String HOST_GROUP = "HOSTGROUP" ;
637
642
private static final String PROJECT_GROUP = "PROJECTGROUP" ;
638
643
private static final String INSTANCE_GROUP = "INSTANCEGROUP" ;
@@ -643,6 +648,10 @@ private boolean isValidUri(String uri) {
643
648
return SPANNER_URI_PATTERN .matcher (uri ).matches ();
644
649
}
645
650
651
+ private boolean isValidExternalHostUri (String uri ) {
652
+ return EXTERNAL_HOST_PATTERN .matcher (uri ).matches ();
653
+ }
654
+
646
655
/**
647
656
* Sets the URI of the Cloud Spanner database to connect to. A connection URI must be specified
648
657
* in this format:
@@ -700,9 +709,11 @@ private boolean isValidUri(String uri) {
700
709
* @return this builder
701
710
*/
702
711
public Builder setUri (String uri ) {
703
- Preconditions .checkArgument (
704
- isValidUri (uri ),
705
- "The specified URI is not a valid Cloud Spanner connection URI. Please specify a URI in the format \" cloudspanner:[//host[:port]]/projects/project-id[/instances/instance-id[/databases/database-name]][\\ ?property-name=property-value[;property-name=property-value]*]?\" " );
712
+ if (!isValidExternalHostUri (uri )) {
713
+ Preconditions .checkArgument (
714
+ isValidUri (uri ),
715
+ "The specified URI is not a valid Cloud Spanner connection URI. Please specify a URI in the format \" cloudspanner:[//host[:port]]/projects/project-id[/instances/instance-id[/databases/database-name]][\\ ?property-name=property-value[;property-name=property-value]*]?\" " );
716
+ }
706
717
ConnectionPropertyValue <Boolean > value =
707
718
cast (ConnectionProperties .parseValues (uri ).get (LENIENT .getKey ()));
708
719
checkValidProperties (value != null && value .getValue (), uri );
@@ -829,7 +840,14 @@ public static Builder newBuilder() {
829
840
private final SpannerOptionsConfigurator configurator ;
830
841
831
842
private ConnectionOptions (Builder builder ) {
832
- Matcher matcher = Builder .SPANNER_URI_PATTERN .matcher (builder .uri );
843
+ Matcher matcher ;
844
+ boolean isExternalHost = false ;
845
+ if (builder .isValidExternalHostUri (builder .uri )) {
846
+ matcher = Builder .EXTERNAL_HOST_PATTERN .matcher (builder .uri );
847
+ isExternalHost = true ;
848
+ } else {
849
+ matcher = Builder .SPANNER_URI_PATTERN .matcher (builder .uri );
850
+ }
833
851
Preconditions .checkArgument (
834
852
matcher .find (), String .format ("Invalid connection URI specified: %s" , builder .uri ));
835
853
@@ -947,12 +965,18 @@ && getInitialConnectionPropertyValue(OAUTH_TOKEN) == null
947
965
this .sessionPoolOptions = SessionPoolOptions .newBuilder ().setAutoDetectDialect (true ).build ();
948
966
}
949
967
950
- String projectId = matcher .group (Builder .PROJECT_GROUP );
968
+ String projectId = "default" ;
969
+ String instanceId = matcher .group (Builder .INSTANCE_GROUP );
970
+ if (!isExternalHost ) {
971
+ projectId = matcher .group (Builder .PROJECT_GROUP );
972
+ } else if (instanceId == null ) {
973
+ instanceId = "default" ;
974
+ }
951
975
if (Builder .DEFAULT_PROJECT_ID_PLACEHOLDER .equalsIgnoreCase (projectId )) {
952
976
projectId = getDefaultProjectId (this .credentials );
953
977
}
954
978
this .projectId = projectId ;
955
- this .instanceId = matcher . group ( Builder . INSTANCE_GROUP ) ;
979
+ this .instanceId = instanceId ;
956
980
this .databaseName = matcher .group (Builder .DATABASE_GROUP );
957
981
}
958
982
@@ -981,6 +1005,10 @@ static String determineHost(
981
1005
// The leading '//' is already included in the regex for the connection URL, so we don't need
982
1006
// to add the leading '//' to the host name here.
983
1007
host = matcher .group (Builder .HOST_GROUP );
1008
+ if (Builder .EXTERNAL_HOST_FORMAT .equals (matcher .pattern ().pattern ())
1009
+ && !host .matches (".*:\\ d+$" )) {
1010
+ host = String .format ("%s:15000" , host );
1011
+ }
984
1012
}
985
1013
if (usePlainText ) {
986
1014
return PLAIN_TEXT_PROTOCOL + host ;
0 commit comments