Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Only accept Vert.x style url #1221

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

<!-- PostgreSQL -->
<property name="javax.persistence.jdbc.url"
value="jdbc:postgresql://localhost/hreact"/>
value="postgresql://localhost/hreact"/>

<!-- Credentials -->
<property name="javax.persistence.jdbc.user"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

<!-- PostgreSQL -->
<property name="javax.persistence.jdbc.url"
value="jdbc:postgresql://localhost/hreact"/>
value="postgresql://localhost/hreact"/>

<!-- Credentials -->
<property name="javax.persistence.jdbc.user"
Expand Down Expand Up @@ -48,7 +48,7 @@

<!-- MySQL -->
<property name="javax.persistence.jdbc.url"
value="jdbc:mysql://localhost/hreact"/>
value="mysql://localhost/hreact"/>

<!-- Credentials -->
<property name="javax.persistence.jdbc.user"
Expand Down
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