Skip to content

Commit

Permalink
[#333] Only accept Vert.x style url
Browse files Browse the repository at this point in the history
  • Loading branch information
DavideD committed Feb 28, 2022
1 parent c741fd5 commit 07253ca
Show file tree
Hide file tree
Showing 22 changed files with 265 additions and 624 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ public interface Log extends BasicLogger {
@Message(id = 18, value = "Instantiating reactive pool: %1$s")
void instantiatingReactivePool(@FormatWith(ClassFormatter.class) Class<?> implClass);

@Message(id = 19, value = "Cannot specify URL using the JDBC syntax. Check the Hibernate Reactive or Vert.x SQL client documentation for more details." +
" Invalid URL: %s")
HibernateException invalidJdbcUrl(String url);

@LogMessage(level = WARN)
@Message(id = 21, value = "DDL command failed [%1$s]")
void ddlCommandFailed(String message);
Expand Down Expand Up @@ -253,5 +257,4 @@ public interface Log extends BasicLogger {
@LogMessage(level = WARN)
@Message(id = 447, value= "Explicit use of UPGRADE_SKIPLOCKED in lock() calls is not recommended; use normal UPGRADE locking instead")
void explicitSkipLockedLockCombo();

}
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ public void injectServices(ServiceRegistryImplementor serviceRegistry) {

@Override
public void configure(Map configuration) {
uri = jdbcUrl( configuration );
uri = connectionUri( configuration );
}

@Override
Expand Down Expand Up @@ -198,7 +198,7 @@ protected Pool createPool(URI uri, SqlConnectOptions connectOptions, PoolOptions
*
* @return the JDBC URL as a {@link URI}
*/
protected URI jdbcUrl(Map<?,?> configurationValues) {
protected URI connectionUri(Map<?,?> configurationValues) {
String url = ConfigurationHelper.getString( Settings.URL, configurationValues );
LOG.sqlClientUrl( url);
return parse( url );
Expand Down Expand Up @@ -240,21 +240,15 @@ public void stop() {
}

public static URI parse(String url) {

if ( url == null || url.trim().isEmpty() ) {
throw new HibernateError( "The configuration property '" + Settings.URL + "' was not provided, or is in invalid format. This is required when using the default DefaultSqlClientPool: " +
"either provide the configuration setting or integrate with a different SqlClientPool implementation" );
}

if ( url.startsWith( "jdbc:" ) ) {
return URI.create( updateUrl( url.substring( 5 ) ) );
throw LOG.invalidJdbcUrl( url );
}

return URI.create( updateUrl( url ) );
}

private static String updateUrl(String url) {
return url.replaceAll( "^cockroachdb:", "postgres:" );
return URI.create( url );
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import java.util.Map;
import java.util.concurrent.TimeUnit;

import org.hibernate.HibernateError;
import org.hibernate.reactive.logging.impl.Log;
import org.hibernate.reactive.logging.impl.LoggerFactory;
import org.hibernate.reactive.provider.Settings;
Expand Down Expand Up @@ -64,7 +63,6 @@ public void configure(Map configuration) {
@Override
public PoolOptions poolOptions() {
PoolOptions poolOptions = new PoolOptions();

LOG.connectionPoolSize( poolSize );
poolOptions.setMaxSize( poolSize );
if ( maxWaitQueueSize != null ) {
Expand All @@ -90,122 +88,23 @@ public PoolOptions poolOptions() {

@Override
public SqlConnectOptions connectOptions(URI uri) {
String scheme = uri.getScheme();
String path = scheme.equals( "oracle" )
? oraclePath( uri )
: uri.getPath();

String database = path.length() > 0
? path.substring( 1 )
: "";
String url = uri.toString().replaceAll( "^cockroachdb:", "postgres:" );
final SqlConnectOptions connectOptions = SqlConnectOptions.fromUri( url );

if ( scheme.equals( "db2" ) && database.indexOf( ':' ) > 0 ) {
// DB2 URLs are a bit odd and have the format:
// jdbc:db2://<HOST>:<PORT>/<DB>:key1=value1;key2=value2;
database = database.substring( 0, database.indexOf( ':' ) );
if ( connectOptions.getUser() == null && user == null ) {
throw new IllegalArgumentException( "database username not specified (set the property 'hibernate.connection.username', or include it as a parameter in the connection URL)" );
}

String host = scheme.equals( "oracle" )
? oracleHost( uri )
: uri.getHost();

int port = scheme.equals( "oracle" )
? oraclePort( uri )
: uri.getPort();

int index = uri.toString().indexOf( ';' );
if ( scheme.equals( "sqlserver" ) && index > 0 ) {
// SQL Server separates parameters in the url with a semicolon (';')
// and the URI class doesn't get the right value for host and port when the url
// contains parameters
URI uriWithoutParams = URI.create( uri.toString().substring( 0, index ) );
host = uriWithoutParams.getHost();
port = uriWithoutParams.getPort();
if ( user != null ) {
connectOptions.setUser( user );
}

if ( port == -1 ) {
port = defaultPort( scheme );
}

//see if the credentials were specified via properties
String username = user;
String password = pass;
if ( username == null || password == null ) {
//if not, look for URI-style user info first
String userInfo = uri.getUserInfo();
if ( userInfo != null ) {
String[] bits = userInfo.split( ":" );
username = bits[0];
if ( bits.length > 1 ) {
password = bits[1];
}
}
else {
//check the query for named parameters
//in case it's a JDBC-style URL
String[] params = {};
// DB2 URLs are a bit odd and have the format:
// jdbc:db2://<HOST>:<PORT>/<DB>:key1=value1;key2=value2;
if ( scheme.equals( "db2" ) ) {
int queryIndex = uri.getPath().indexOf( ':' ) + 1;
if ( queryIndex > 0 ) {
params = uri.getPath().substring( queryIndex ).split( ";" );
}
}
else if ( scheme.contains( "sqlserver" ) ) {
// SQL Server separates parameters in the url with a semicolon (';')
// Ex: jdbc:sqlserver://<server>:<port>;<database>=AdventureWorks;user=<user>;password=<password>
String query = uri.getQuery();
String rawQuery = uri.getRawQuery();
String s = uri.toString();
int queryIndex = s.indexOf( ';' ) + 1;
if ( queryIndex > 0 ) {
params = s.substring( queryIndex ).split( ";" );
}
}
else {
final String query = scheme.equals( "oracle" )
? oracleQuery( uri )
: uri.getQuery();
if ( query != null ) {
params = query.split( "&" );
}
}
for ( String param : params ) {
if ( param.startsWith( "user=" ) ) {
username = param.substring( 5 );
}
else if ( param.startsWith( "pass=" ) ) {
password = param.substring( 5 );
}
else if ( param.startsWith( "password=" ) ) {
password = param.substring( 9 );
}
else if ( param.startsWith( "database=" ) ) {
database = param.substring( 9 );
}
}
}
}

if ( username == null ) {
throw new HibernateError(
"database username not specified (set the property 'javax.persistence.jdbc.user', or include it as a parameter in the connection URL)" );
}

SqlConnectOptions connectOptions = new SqlConnectOptions()
.setHost( host )
.setPort( port )
.setDatabase( database )
.setUser( username );

if ( password != null ) {
connectOptions.setPassword( password );
if ( pass != null ) {
connectOptions.setPassword( pass );
}

//enable the prepared statement cache by default
connectOptions.setCachePreparedStatements( true );

if ( cacheMaxSize != null ) {
if ( cacheMaxSize <= 0 ) {
LOG.preparedStatementCacheDisabled();
Expand All @@ -225,86 +124,4 @@ else if ( param.startsWith( "database=" ) ) {

return connectOptions;
}

private int oraclePort(URI uri) {
String s = uri.toString().substring( "oracle:thin:".length() );
if ( s.indexOf( ':' ) > -1 ) {
// Example: localhost:1234...
s = s.substring( s.indexOf( ':' ) + 1 );
if ( s.indexOf( '/' ) != -1 ) {
// Example: 1234/
s = s.substring( 0, s.indexOf( '/' ) );
return Integer.valueOf( s );
}
if ( s.indexOf( '?' ) != -1 ) {
// Example: 1234?param=value
s = s.substring( 0, s.indexOf( '?' ) );
return Integer.valueOf( s );
}
// Example: 1234
return Integer.valueOf( s );
}
return -1;
}

// For Oracle the host part starts with a '@'
// Example oracle:thin:[username/password]@localhost:1234/database?param=value
private String oracleHost(URI uri) {
String s = uri.toString();
String host = s.substring( s.indexOf( '@' ) + 1 );
int end = host.indexOf( ':' );
if ( end == -1 ) {
end = host.indexOf( '/' );
if ( end == -1) {
end = host.indexOf( '?' );
}
}
return host.substring( 0, end );
}

private String oracleQuery(URI uri) {
String string = uri.toString();
int start = string.indexOf( '?' );
return start == -1
? null
: string.substring( start + 1 );
}

private String oraclePath(URI uri) {
String string = uri.toString();
// Remove everything before localhost:port
final int i = string.indexOf( '@' );
string = string.substring( i + 1 );
// Check the start of the path
int start = string.indexOf( '/' );
if ( start == -1) {
return "";
}
int end = string.indexOf( '?' ) == -1
? string.length()
: string.indexOf( '?' );
return string.substring( start, end );
}

private int defaultPort(String scheme) {
switch ( scheme ) {
case "postgresql":
case "postgres":
return 5432;
case "mariadb":
case "mysql":
return 3306;
case "db2":
return 50000;
case "cockroachdb":
return 26257;
case "sqlserver":
return 1433;
case "oracle":
return 1521;
default:
throw new IllegalArgumentException( "Unknown default port for scheme: " + scheme );
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
import java.util.stream.Collectors;

import org.hibernate.SessionFactory;
Expand Down Expand Up @@ -119,7 +120,7 @@ public static void test(Async async, TestContext context, Uni<?> uni) {
protected Configuration constructConfiguration() {
Configuration configuration = new Configuration();
configuration.setProperty( Settings.HBM2DDL_AUTO, "create" );
configuration.setProperty( Settings.URL, DatabaseConfiguration.getJdbcUrl() );
configuration.setProperty( Settings.URL, DatabaseConfiguration.getConnectionUri() );
if ( DatabaseConfiguration.dbType() == DBType.DB2 && !doneTablespace ) {
configuration.setProperty(Settings.HBM2DDL_IMPORT_FILES, "/db2.sql");
doneTablespace = true;
Expand Down Expand Up @@ -153,17 +154,21 @@ public CompletionStage<Void> deleteEntities(String... entities) {

@Before
public void before(TestContext context) {
test( context, setupSessionFactory( constructConfiguration() ) );
test( context, setupSessionFactory( () -> constructConfiguration() ) );
}

protected CompletionStage<Void> setupSessionFactory(Configuration configuration) {
return setupSessionFactory( () -> configuration );
}

protected CompletionStage<Void> setupSessionFactory(Supplier<Configuration> configurationSupplier) {
CompletableFuture<Void> future = new CompletableFuture<>();
vertxContextRule.vertx()
.executeBlocking(
// schema generation is a blocking operation and so it causes an
// exception when run on the Vert.x event loop. So call it using
// Vertx.executeBlocking()
promise -> startFactoryManager( promise, configuration ),
promise -> startFactoryManager( promise, configurationSupplier.get() ),
event -> {
if ( event.succeeded() ) {
future.complete( null );
Expand Down
Loading

0 comments on commit 07253ca

Please sign in to comment.