au.net.causal.maven.plugins.boxdb.db.DataSourceBuilder Maven / Gradle / Ivy
package au.net.causal.maven.plugins.boxdb.db;
import au.net.causal.maven.plugins.boxdb.JavaRunner;
import org.eclipse.aether.resolution.DependencyResolutionException;
import javax.sql.DataSource;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* Construct and configure a data source.
*/
public class DataSourceBuilder
{
private final BoxContext context;
private final List dependencies = new ArrayList<>();
private final Map dataSourceMethodSetup = new LinkedHashMap<>();
private String dataSourceClassName;
public DataSourceBuilder(BoxContext context)
{
this.context = context;
}
/**
* Configures the class name of the data source.
*
* @param dataSourceClassName the fully qualified class name of the data source.
*
* @return this builder.
*/
public DataSourceBuilder dataSourceClassName(String dataSourceClassName)
{
this.dataSourceClassName = dataSourceClassName;
return this;
}
/**
* Configures JAR dependencies of the data source.
*
* @param dependencies the dependencies to set.
*
* @return this builder.
*/
public DataSourceBuilder dependencies(Collection extends RunnerDependency> dependencies)
{
this.dependencies.clear();
this.dependencies.addAll(dependencies);
return this;
}
private void configureDataSourceObject(DataSource dataSource, String methodName, Class> valueType, Object value)
throws NoSuchMethodException, InvocationTargetException, IllegalAccessException
{
if (value != null)
dataSource.getClass().getMethod(methodName, valueType).invoke(dataSource, value);
}
/**
* Configures how the data source object will be configured after construction through a method
* call.
*
* @param methodName the name of the method on the data source to call. e.g. 'setUrl'. Must take a single parameter.
* @param parameterType the parameter type of the method.
* @param value the value to use when calling the method.
*
* @return this builder.
*/
public DataSourceBuilder configureDataSource(String methodName, Class> parameterType, Object value)
{
dataSourceMethodSetup.put(methodName, new DataSourceConfigurationEntry(methodName, parameterType, value));
return this;
}
/**
* Creates a data source using the builder configuration.
*
* @return the created data source, configured for use.
*
* @throws IOException if an I/O error occurs.
* @throws BoxDatabaseException if another error occurs creating the data source.
*/
public DataSource create()
throws IOException, BoxDatabaseException
{
try
{
JavaRunner javaRunner = context.createJavaRunner(dataSourceClassName, dependencies);
Class> clientDataSourceClass = javaRunner.makeClass();
DataSource dataSource = (DataSource)clientDataSourceClass.getConstructor().newInstance();
for (DataSourceConfigurationEntry entry : dataSourceMethodSetup.values())
{
configureDataSourceObject(dataSource, entry.getMethodName(), entry.getParameterType(), entry.getValue());
}
return dataSource;
}
catch (DependencyResolutionException e)
{
throw new BoxDatabaseException("Failed to resolve database dependency: " + e, e);
}
catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e)
{
throw new BoxDatabaseException("Failed to create database data source: " + e, e);
}
}
/**
* Holds configuration for a single data source method call.
*/
private static class DataSourceConfigurationEntry
{
private final String methodName;
private final Class> parameterType;
private final Object value;
public DataSourceConfigurationEntry(String methodName, Class> parameterType, Object value)
{
this.methodName = methodName;
this.parameterType = parameterType;
this.value = value;
}
public String getMethodName()
{
return methodName;
}
public Class> getParameterType()
{
return parameterType;
}
public Object getValue()
{
return value;
}
}
}