Skip to content

Commit

Permalink
manifold-sql changes
Browse files Browse the repository at this point in the history
- change usage of multiple service provider interfaces to a single SPI that is basically a simple dependency injection configuration point, much easier manage and override default behavior
- other cleanup
  • Loading branch information
rsmckinney committed Aug 14, 2023
1 parent e85d9ca commit aa01545
Show file tree
Hide file tree
Showing 76 changed files with 393 additions and 409 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -16,38 +16,14 @@

package manifold.sql.rt.api;

import manifold.rt.api.util.ServiceUtil;
import manifold.util.concurrent.LocklessLazyVar;

import java.sql.Connection;
import java.sql.Driver;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.Set;

/**
* Implementors provide JDBC connections for all manifold-sql JDBC operations.
*/
public interface ConnectionProvider
{
LocklessLazyVar<Set<ConnectionProvider>> PROVIDERS =
LocklessLazyVar.make( () -> {
// first, ensure jdbc drivers are loaded
Set<Driver> drivers = new HashSet<>();
ServiceUtil.loadRegisteredServices( drivers, Driver.class, ConnectionProvider.class.getClassLoader() );

Set<ConnectionProvider> registered = new HashSet<>();
ServiceUtil.loadRegisteredServices( registered, ConnectionProvider.class, ConnectionProvider.class.getClassLoader() );
return registered;
} );

static ConnectionProvider findFirst()
{
return ConnectionProvider.PROVIDERS.get().stream()
.findFirst()
.orElseThrow( () -> new RuntimeException( "Could not find SQL connection provider" ) );
}

/**
* Provides a JDBC connection corresponding with the {@code configName} {@link DbConfig} and optional {@code classContext}.
* A standard implementation sources the {@code configName} DbConfig in the following order:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,44 +16,12 @@

package manifold.sql.rt.api;

import manifold.rt.api.util.ServiceUtil;
import manifold.util.concurrent.LocklessLazyVar;

import java.sql.Connection;
import java.util.*;
import java.util.function.Supplier;

public interface CrudProvider
{
LocklessLazyVar<Set<CrudProvider>> PROVIDERS =
LocklessLazyVar.make( () -> {
Set<CrudProvider> registered = new HashSet<>();
ServiceUtil.loadRegisteredServices( registered, CrudProvider.class, CrudProvider.class.getClassLoader() );
return registered;
} );

LocklessLazyVar<CrudProvider> BY_PRIORITY =
LocklessLazyVar.make( () ->
PROVIDERS.get().stream().max( Comparator.comparingInt( CrudProvider::getPriority ) )
.orElseThrow( () -> new IllegalStateException() ) );

static CrudProvider instance()
{
return BY_PRIORITY.get();
}


<T extends TableRow> void create( Connection c, UpdateContext<T> ctx );
<T extends TableRow> T read( QueryContext<T> ctx );
<T extends TableRow> void update( Connection c, UpdateContext<T> ctx );
<T extends TableRow> void delete( Connection c, UpdateContext<T> ctx );

/**
* Greater = higher priority. Higher priority overrides lower. Default implementations are lowest priority. They can be
* overridden.
*/
default int getPriority()
{
return Integer.MIN_VALUE;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,7 @@

package manifold.sql.rt.api;

import manifold.rt.api.util.ServiceUtil;
import manifold.util.concurrent.LocklessLazyVar;

import java.util.HashSet;
import java.util.Set;

public interface DbConfigProvider
{
LocklessLazyVar<Set<DbConfigProvider>> PROVIDERS =
LocklessLazyVar.make( () -> {
Set<DbConfigProvider> registered = new HashSet<>();
ServiceUtil.loadRegisteredServices( registered, DbConfigProvider.class, DbConfigProvider.class.getClassLoader() );
return registered;
} );

DbConfig loadDbConfig( String configName, Class<?> ctx );
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,17 @@

import manifold.api.fs.IFile;
import manifold.api.util.cache.FqnCache;
import manifold.rt.api.util.ServiceUtil;
import manifold.util.concurrent.LocklessLazyVar;

import java.util.HashSet;
import java.util.Set;
import java.util.function.Function;

/**
* Note, implementers must chain/forward to the default provider to fall back on existing behavior.
*/
public interface DbLocationProvider
{
String PROVIDED = "#";
Object UNHANDLED = new Object() {};

LocklessLazyVar<Set<DbLocationProvider>> PROVIDERS =
LocklessLazyVar.make( () -> {
Set<DbLocationProvider> registered = new HashSet<>();
ServiceUtil.loadRegisteredServices( registered, DbLocationProvider.class, DbLocationProvider.class.getClassLoader() );
return registered;
} );

enum Mode {CompileTime, DesignTime, Runtime, Unknown}

Object getLocation( Function<String, FqnCache<IFile>> resByExt, Mode mode, String tag, String... args );
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* Copyright (c) 2023 - Manifold Systems LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package manifold.sql.rt.api;

import manifold.rt.api.util.ServiceUtil;
import manifold.sql.rt.config.DefaultDependencies;
import manifold.util.concurrent.LocklessLazyVar;

import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;

public interface Dependencies
{
LocklessLazyVar<Set<Dependencies>> PROVIDERS =
LocklessLazyVar.make( () -> {
Set<Dependencies> registered = new LinkedHashSet<>();
ServiceUtil.loadRegisteredServices( registered, Dependencies.class, Dependencies.class.getClassLoader() );
return registered;
} );

static Dependencies instance()
{
if( PROVIDERS.get().isEmpty() )
{
throw new RuntimeException( "Could not find Dependencies service provider" );
}

Dependencies result = null;
for( Dependencies dependencies : PROVIDERS.get() )
{
// favor non-default dependencies
if( result == null || result instanceof DefaultDependencies )
{
result = dependencies;
}
}
return result;
}

DbConfigProvider getDbConfigProvider();

ConnectionProvider getConnectionProvider();

CrudProvider getCrudProvider();

DbLocationProvider getDbLocationProvider();

TxScopeProvider getTxScopeProvider();

ValueAccessorProvider getValueAccessorProvider();

<T> T fetch( Class<T> cls );
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,11 @@ private <B extends Bindings> void rip( ResultSet resultSet, Function<DataBinding
for( boolean isOnRow = resultSet.next(); isOnRow; isOnRow = resultSet.next() )
{
DataBindings row = new DataBindings();
ValueAccessorProvider accProvider = Dependencies.instance().getValueAccessorProvider();
for( int i = 1; i <= metaData.getColumnCount(); i++ )
{
String column = metaData.getColumnLabel( i );
ValueAccessor accessor = ValueAccessor.get( metaData.getColumnType( i ) );
ValueAccessor accessor = accProvider.get( metaData.getColumnType( i ) );
Object value = accessor.getRowValue( resultSet, new ResultColumn( metaData, i ) );
row.put( column, value );
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,20 +34,15 @@ public Runner( QueryContext<T> ctx, String sqlQuery )
@SuppressWarnings( "unused" )
public Result<T> run()
{
ConnectionProvider cp = ConnectionProvider.findFirst();
ConnectionProvider cp = Dependencies.instance().getConnectionProvider();
try( Connection c = cp.getConnection( _ctx.getConfigName(), _ctx.getQueryClass() ) )
{
for( ConnectionNotifier p : ConnectionNotifier.PROVIDERS.get() )
{
p.init( c );
}

try( PreparedStatement ps = c.prepareStatement( _sqlQuery ) )
{
setParameters( ps );
try( ResultSet resultSet = ps.executeQuery() )
{
return new Result<T>( _ctx.getTxScope(), resultSet, _ctx.getRowMaker() );
return new Result<>( _ctx.getTxScope(), resultSet, _ctx.getRowMaker() );
}
}
}
Expand All @@ -60,9 +55,10 @@ public Result<T> run()
private void setParameters( PreparedStatement ps ) throws SQLException
{
int i = 0;
ValueAccessorProvider accProvider = Dependencies.instance().getValueAccessorProvider();
for( Object param : _ctx.getParams().values() )
{
ValueAccessor accessor = ValueAccessor.get( _ctx.getJdbcParamTypes()[i] );
ValueAccessor accessor = accProvider.get( _ctx.getJdbcParamTypes()[i] );
accessor.setParameter( ps, ++i, param );
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,42 +16,7 @@

package manifold.sql.rt.api;

import manifold.rt.api.util.ServiceUtil;
import manifold.util.concurrent.LocklessLazyVar;

import java.util.Comparator;
import java.util.HashSet;
import java.util.Set;

public interface TxScopeProvider
{
LocklessLazyVar<Set<TxScopeProvider>> PROVIDERS =
LocklessLazyVar.make( () -> {
Set<TxScopeProvider> registered = new HashSet<>();
ServiceUtil.loadRegisteredServices( registered, TxScopeProvider.class, TxScopeProvider.class.getClassLoader() );
return registered;
} );

LocklessLazyVar<TxScopeProvider> BY_PRIORITY =
LocklessLazyVar.make( () ->
PROVIDERS.get().stream().max( Comparator.comparingInt( TxScopeProvider::getPriority ) )
.orElseThrow( () -> new IllegalStateException( "No " + TxScopeProvider.class.getSimpleName() + "'s found." ) ) );

static TxScope newScope( Class<? extends SchemaType> schemaClass )
{
return BY_PRIORITY.get().create( schemaClass );
}


TxScope create( Class<? extends SchemaType> schemaClass );


/**
* Greater = higher priority. Higher priority overrides lower. Default implementations are lowest priority. They can be
* overridden.
*/
default int getPriority()
{
return Integer.MIN_VALUE;
}
TxScope newScope( Class<? extends SchemaType> schemaClass );
}
Loading

0 comments on commit aa01545

Please sign in to comment.