Merge pull request #37 from scottfrederick/query

Changed JDBC URL creation to retain query parameters.
This commit is contained in:
Ramnivas Laddad
2014-05-13 16:33:20 -07:00
6 changed files with 237 additions and 144 deletions

View File

@@ -67,7 +67,12 @@ public abstract class UriBasedServiceInfo extends BaseServiceInfo {
public String getPath() {
return uriInfo.getPath();
}
@ServiceProperty(category="connection")
public String getQuery() {
return uriInfo.getQuery();
}
/**
* Validate the URI and clean it up by using defaults for any missing information, if possible.
*

View File

@@ -3,29 +3,48 @@ package org.springframework.cloud.service.common;
import org.springframework.cloud.service.UriBasedServiceInfo;
/**
*
* @author Ramnivas Laddad
*
*/
public abstract class RelationalServiceInfo extends UriBasedServiceInfo {
protected String jdbcUrlDatabaseType;
protected String jdbcUrlDatabaseType;
public RelationalServiceInfo(String id, String uriString, String jdbcUrlDatabaseType) {
super(id, uriString);
this.jdbcUrlDatabaseType = jdbcUrlDatabaseType;
}
public RelationalServiceInfo(String id, String uriString, String jdbcUrlDatabaseType) {
super(id, uriString);
this.jdbcUrlDatabaseType = jdbcUrlDatabaseType;
}
@ServiceProperty(category="connection")
public String getJdbcUrl() {
if (getPort() != -1) {
return String.format("jdbc:%s://%s:%d/%s?user=%s&password=%s",
jdbcUrlDatabaseType, getHost(), getPort(), getPath(),
getUserName(), getPassword());
} else {
return String.format("jdbc:%s://%s/%s?user=%s&password=%s",
jdbcUrlDatabaseType, getHost(), getPath(),
getUserName(), getPassword());
}
}
@ServiceProperty(category = "connection")
public String getJdbcUrl() {
return String.format("jdbc:%s://%s%s/%s%s%s", jdbcUrlDatabaseType, getHost(), formatPort(),
getPath(), formatUserinfo(), formatQuery());
}
private String formatPort() {
if (getPort() != -1) {
return String.format(":%d", getPort());
}
return "";
}
private String formatUserinfo() {
if (getUserName() != null && getPassword() != null) {
return String.format("?user=%s&password=%s", getUserName(), getPassword());
}
if (getUserName() != null) {
return String.format("?user=%s", getUserName());
}
return "";
}
private String formatQuery() {
if (getQuery() != null) {
if (getUserName() == null && getPassword() == null) {
return String.format("?%s", getQuery());
} else {
return String.format("&%s", getQuery());
}
}
return "";
}
}

View File

@@ -6,64 +6,83 @@ import java.net.URLDecoder;
/**
* Factory for standard Cloud Foundry URIs which all conform to the format:
*
* [jdbc:]scheme://[user:pass]@authority/path
* <p/>
* [jdbc:]scheme://[user:pass]@authority[:port]/path
*/
public class StandardUriInfoFactory implements UriInfoFactory {
@Override
public UriInfo createUri(String uriString) {
String userName = null;
String password = null;
String path;
URI tmpUri;
if (uriString.startsWith("jdbc:")) {
int idx = uriString.indexOf(":");
uriString = uriString.substring(idx + 1);
}
public static final String JDBC_PREFIX = "jdbc:";
try {
tmpUri = new URI(uriString);
}
catch (URISyntaxException e) {
throw new IllegalArgumentException(e);
}
@Override
public UriInfo createUri(String scheme, String host, int port, String username, String password, String path) {
return new UriInfo(scheme, host, port, username, password, path);
}
String userInfo = tmpUri.getRawUserInfo();
if (userInfo != null) {
String userPass[] = userInfo.split(":");
if (userPass.length != 2) {
throw new IllegalArgumentException("bad user info in URI: " + tmpUri);
}
@Override
public UriInfo createUri(String uriString) {
userName = uriDecode(userPass[0]);
password = uriDecode(userPass[1]);
}
uriString = trimJdbcScheme(uriString);
String rawPath = tmpUri.getRawPath();
if (rawPath != null && rawPath.length() > 1) {
path = rawPath.substring(1);
}
else {
path = null;
}
return new UriInfo(tmpUri.getScheme(), tmpUri.getHost(), tmpUri.getPort(), userName, password, path);
}
URI tmpUri = createTmpUri(uriString);
@Override
public UriInfo createUri(String scheme, String host, int port, String username, String password, String path) {
return new UriInfo(scheme, host, port, username, password, path);
}
String[] userInfo = parseUserinfo(tmpUri);
String userName = uriDecode(userInfo[0]);
String password = uriDecode(userInfo[1]);
private static String uriDecode(String s) {
try {
// URLDecode decodes '+' to a space, as for
// form encoding. So protect plus signs.
return URLDecoder.decode(s.replace("+", "%2B"), "US-ASCII");
}
catch (java.io.UnsupportedEncodingException e) {
// US-ASCII is always supported
throw new RuntimeException(e);
}
}
return new UriInfo(tmpUri.getScheme(), tmpUri.getHost(), tmpUri.getPort(),
userName, password,
parsePath(tmpUri), tmpUri.getRawQuery());
}
private URI createTmpUri(String uriString) {
try {
return new URI(uriString);
} catch (URISyntaxException e) {
throw new IllegalArgumentException(e);
}
}
private String trimJdbcScheme(String uriString) {
if (uriString.startsWith(JDBC_PREFIX)) {
uriString = uriString.substring(JDBC_PREFIX.length());
}
return uriString;
}
private String[] parseUserinfo(URI uri) {
String userInfo = uri.getRawUserInfo();
if (userInfo != null) {
String[] userPass = userInfo.split(":");
if (userPass.length != 2) {
throw new IllegalArgumentException("Bad userinfo in URI: " + uri);
}
return userPass;
}
return new String[]{null, null};
}
private String parsePath(URI uri) {
String rawPath = uri.getRawPath();
if (rawPath != null && rawPath.length() > 1) {
return rawPath.substring(1);
}
return null;
}
private static String uriDecode(String s) {
if (s == null) {
return null;
}
try {
// URLDecode decodes '+' to a space, as for
// form encoding. So protect plus signs.
return URLDecoder.decode(s.replace("+", "%2B"), "US-ASCII");
} catch (java.io.UnsupportedEncodingException e) {
// US-ASCII is always supported
throw new RuntimeException(e);
}
}
}

View File

@@ -17,22 +17,28 @@ public class UriInfo {
private String password;
private String path;
private URI uri;
private String query;
public UriInfo(String scheme, String host, int port, String username, String password) {
this(scheme, host, port, username, password, "");
}
public UriInfo(String scheme, String host, int port, String username, String password, String path) {
this(scheme, host, port, username, password, path, null);
}
public UriInfo(String scheme, String host, int port, String username, String password, String path, String query) {
this.scheme = scheme;
this.host = host;
this.port = port;
this.userName = username;
this.password = password;
this.path = path;
this.query = query;
this.uri = buildUri();
}
public UriInfo(String scheme, String host, int port, String username, String password) {
this(scheme, host, port, username, password, "");
}
public String getScheme() {
return scheme;
}
@@ -57,11 +63,15 @@ public class UriInfo {
return path;
}
public String getQuery() {
return query;
}
public URI getUri() {
return uri;
}
public URI buildUri() throws IllegalArgumentException {
private URI buildUri() {
String userInfo = null;
if (userName != null && password != null) {
@@ -71,7 +81,7 @@ public class UriInfo {
String cleanedPath = path == null || path.startsWith("/") ? path : "/" + path;
try {
return new URI(scheme, userInfo, host, port, cleanedPath, null, null);
return new URI(scheme, userInfo, host, port, cleanedPath, query, null);
}
catch (URISyntaxException e) {
throw new IllegalArgumentException(e);

View File

@@ -5,86 +5,72 @@ import org.springframework.cloud.util.StandardUriInfoFactory;
import org.springframework.cloud.util.UriInfo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
/**
* @author Jens Deppe
*/
public class StandardUriInfoFactoryTest {
private static StandardUriInfoFactory factory = new StandardUriInfoFactory();
private static StandardUriInfoFactory factory = new StandardUriInfoFactory();
/**
* Basic sanity
*/
@Test
public void createUri1() {
String uri = "mysql://joe:joes_password@localhost:1527/big_db";
UriInfo result = factory.createUri(uri);
@Test
public void createUri() {
String uri = "mysql://joe:joes_password@localhost:1527/big_db";
UriInfo result = factory.createUri(uri);
assertEquals("localhost", result.getHost());
assertEquals(1527, result.getPort());
assertEquals("joe", result.getUserName());
assertEquals("joes_password", result.getPassword());
assertEquals("big_db", result.getPath());
assertEquals(uri, result.buildUri().toString());
}
assertUriInfoEquals(result, "localhost", 1527, "joe", "joes_password", "big_db", null);
assertEquals(uri, result.getUri().toString());
}
/**
* Test with a 'jdbc:...' URI
*/
@Test
public void createUri2() {
String uri = "mysql://joe:joes_password@localhost:1527/big_db";
String jdbcUri = "jdbc:" + uri;
UriInfo result = factory.createUri(jdbcUri);
@Test
public void createUriWithQuery() {
String uri = "mysql://joe:joes_password@localhost:1527/big_db?p1=v1&p2=v2";
UriInfo result = factory.createUri(uri);
assertEquals("localhost", result.getHost());
assertEquals(1527, result.getPort());
assertEquals("joe", result.getUserName());
assertEquals("joes_password", result.getPassword());
assertEquals("big_db", result.getPath());
assertEquals(uri, result.buildUri().toString());
}
assertUriInfoEquals(result, "localhost", 1527, "joe", "joes_password", "big_db", "p1=v1&p2=v2");
assertEquals(uri, result.getUri().toString());
}
/**
* Test without user/password
*/
@Test
public void createUri3() {
String uri = "mysql://localhost:1527/big_db";
UriInfo result = factory.createUri(uri);
@Test
public void createWithJdbcUri() {
String uri = "mysql://joe:joes_password@localhost:1527/big_db";
UriInfo result = factory.createUri("jdbc:" + uri);
assertEquals("localhost", result.getHost());
assertEquals(1527, result.getPort());
assertNull(result.getUserName());
assertNull(result.getPassword());
assertEquals("big_db", result.getPath());
assertEquals(uri, result.buildUri().toString());
}
assertUriInfoEquals(result, "localhost", 1527, "joe", "joes_password", "big_db", null);
assertEquals(uri, result.getUri().toString());
}
/**
* Test with just a user and no password
*/
@Test(expected = IllegalArgumentException.class)
public void createUri4() {
String uri = "mysql://joe@localhost:1527/big_db";
factory.createUri(uri);
}
@Test
public void createNoUsernamePassword() {
String uri = "mysql://localhost:1527/big_db";
UriInfo result = factory.createUri(uri);
/**
* Test when creating URI with explicit components
*/
@Test
public void createUri5() {
String uri = "mysql://joe:joes_password@localhost:1527/big_db";
UriInfo result = factory.createUri("mysql", "localhost", 1527, "joe", "joes_password", "big_db");
assertUriInfoEquals(result, "localhost", 1527, null, null, "big_db", null);
assertEquals(uri, result.getUri().toString());
}
assertEquals("localhost", result.getHost());
assertEquals(1527, result.getPort());
assertEquals("joe", result.getUserName());
assertEquals("joes_password", result.getPassword());
assertEquals("big_db", result.getPath());
assertEquals(uri, result.buildUri().toString());
}
@Test(expected = IllegalArgumentException.class)
public void createWithUsernameNoPassword() {
String uri = "mysql://joe@localhost:1527/big_db";
factory.createUri(uri);
}
@Test
public void createWithExplicitParameters() {
String uri = "mysql://joe:joes_password@localhost:1527/big_db";
UriInfo result = factory.createUri("mysql", "localhost", 1527, "joe", "joes_password", "big_db");
assertUriInfoEquals(result, "localhost", 1527, "joe", "joes_password", "big_db", null);
assertEquals(uri, result.getUri().toString());
}
private void assertUriInfoEquals(UriInfo result, String host, int port,
String username, String password, String path, String query) {
assertEquals(host, result.getHost());
assertEquals(port, result.getPort());
assertEquals(username, result.getUserName());
assertEquals(password, result.getPassword());
assertEquals(path, result.getPath());
assertEquals(query, result.getQuery());
}
}

View File

@@ -0,0 +1,54 @@
package org.springframework.cloud.service.common;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class RelationalServiceInfoTest {
@Test
public void jdbcFullUrl() {
RelationalServiceInfo serviceInfo = createServiceInfo("dbtype://username:password@hostname:1234/database");
assertEquals("jdbc:jdbcdbtype://hostname:1234/database?user=username&password=password", serviceInfo.getJdbcUrl());
}
@Test
public void jdbcUrlNoPort() {
RelationalServiceInfo serviceInfo = createServiceInfo("dbtype://username:password@hostname/database");
assertEquals("jdbc:jdbcdbtype://hostname/database?user=username&password=password", serviceInfo.getJdbcUrl());
}
@Test
public void jdbcUrlNoUsernamePassword() {
RelationalServiceInfo serviceInfo = createServiceInfo("dbtype://hostname:1234/database");
assertEquals("jdbc:jdbcdbtype://hostname:1234/database", serviceInfo.getJdbcUrl());
}
@Test(expected = java.lang.IllegalArgumentException.class)
public void jdbcUrlNoPassword() {
createServiceInfo("dbtype://username@hostname/database");
}
@Test
public void jdbcUrlWithQuery() {
RelationalServiceInfo serviceInfo = createServiceInfo("dbtype://username:password@hostname:1234/database?reconnect=true");
assertEquals("jdbc:jdbcdbtype://hostname:1234/database?user=username&password=password&reconnect=true", serviceInfo.getJdbcUrl());
}
@Test
public void jdbcUrlWithQueryNoUsernamePassword() {
RelationalServiceInfo serviceInfo = createServiceInfo("dbtype://hostname:1234/database?reconnect=true");
assertEquals("jdbc:jdbcdbtype://hostname:1234/database?reconnect=true", serviceInfo.getJdbcUrl());
}
private RelationalServiceInfo createServiceInfo(final String uri) {
return new RelationalServiceInfo("test", uri, "jdbcdbtype") {
};
}
}