[#1895] Decouple Executor from Configuration. Use composition rather

than inheritance - Removed Executor.DEFAULT_INSTANCES, remainders of
early jOOQ days
This commit is contained in:
Lukas Eder 2012-10-27 19:32:32 +02:00
parent 16be60c44a
commit 36c98e4cc4
5 changed files with 55 additions and 45 deletions

View File

@ -54,7 +54,6 @@ import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.SQLOutput;
import java.sql.Time;
import java.sql.Timestamp;
import java.sql.Types;
@ -81,22 +80,10 @@ class DefaultBindContext extends AbstractBindContext {
/**
* Generated UID
*/
private static final long serialVersionUID = -5457385919209241505L;
private static final JooqLogger log = JooqLogger.getLogger(DefaultBindContext.class);
private static final long serialVersionUID = -5457385919209241505L;
private static final JooqLogger log = JooqLogger.getLogger(DefaultBindContext.class);
/**
* The localConfiguration is used to communicate a Configuration to an
* {@link ArrayRecord}, in case that ArrayRecord is serialised to a
* {@link SQLOutput} object.
* <p>
* This is probably the only solution to circumvent this bad JDBC design.
* See also <a
* href="http://stackoverflow.com/q/11439543/521799">http://stackoverflow
* .com/q/11439543/521799</a>
*/
static final ThreadLocal<Configuration> LOCAL_CONFIGURATION = new ThreadLocal<Configuration>();
private final PreparedStatement stmt;
private final PreparedStatement stmt;
DefaultBindContext(Configuration configuration, PreparedStatement stmt) {
super(configuration);
@ -305,15 +292,7 @@ class DefaultBindContext extends AbstractBindContext {
stmt.setString(nextIndex(), ((EnumType) value).getLiteral());
}
else {
try {
// [#1544] Set the local configuration, in case an array needs
// to be serialised to SQLOutput
LOCAL_CONFIGURATION.set(this);
stmt.setObject(nextIndex(), value);
}
finally {
LOCAL_CONFIGURATION.remove();
}
stmt.setObject(nextIndex(), value);
}
return this;

View File

@ -37,9 +37,11 @@ package org.jooq.impl;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.SQLOutput;
import java.util.ArrayList;
import java.util.List;
@ -93,7 +95,9 @@ class DefaultExecuteContext extends AbstractConfiguration implements ExecuteCont
private static final ThreadLocal<List<Clob>> CLOBS = new ThreadLocal<List<Clob>>();
/**
* Clean up blobs and clobs.
* Clean up blobs, clobs and the local configuration.
* <p>
* <h3>BLOBS and CLOBS</h3>
* <p>
* [#1326] This is necessary in those dialects that have long-lived
* temporary lob objects, which can cause memory leaks in certain contexts,
@ -106,6 +110,22 @@ class DefaultExecuteContext extends AbstractConfiguration implements ExecuteCont
* <li>Not freeing the lob after execution will cause an
* {@link OutOfMemoryError}</li>
* </ol>
* <p>
* <h3>Local configuration</h3>
* <p>
* [#1544] There exist some corner-cases regarding the {@link SQLOutput}
* API, used for UDT serialisation / deserialisation, which have no elegant
* solutions of obtaining a {@link Configuration} and thus a JDBC
* {@link Connection} object short of:
* <ul>
* <li>Making assumptions about the JDBC driver and using proprietary API,
* e.g. that of ojdbc</li>
* <li>Dealing with this problem globally by using such a local
* configuration</li>
* </ul>
*
* @see <a
* href="http://stackoverflow.com/q/11439543/521799">http://stackoverflow.com/q/11439543/521799</a>
*/
static final void clean() {
List<Blob> blobs = BLOBS.get();
@ -126,6 +146,8 @@ class DefaultExecuteContext extends AbstractConfiguration implements ExecuteCont
CLOBS.remove();
}
LOCAL_CONFIGURATION.remove();
}
/**
@ -142,6 +164,30 @@ class DefaultExecuteContext extends AbstractConfiguration implements ExecuteCont
CLOBS.get().add(clob);
}
// ------------------------------------------------------------------------
// XXX: Static utility methods for handling Configuration lifecycle
// ------------------------------------------------------------------------
private static final ThreadLocal<Configuration> LOCAL_CONFIGURATION = new ThreadLocal<Configuration>();
/**
* Register a configuration for later cleanup with {@link #clean()}
*/
static final void register(Configuration configuration) {
LOCAL_CONFIGURATION.set(configuration);
}
/**
* Get the registered configuration
* <p>
* It can be safely assumed that such a configuration is available once the
* {@link ExecuteContext} has been established, until the statement is
* closed.
*/
static final Configuration registeredConfiguration() {
return LOCAL_CONFIGURATION.get();
}
// ------------------------------------------------------------------------
// XXX: Constructors
// ------------------------------------------------------------------------
@ -182,6 +228,7 @@ class DefaultExecuteContext extends AbstractConfiguration implements ExecuteCont
clean();
BLOBS.set(new ArrayList<Blob>());
CLOBS.set(new ArrayList<Clob>());
LOCAL_CONFIGURATION.set(configuration);
}
@Override

View File

@ -160,7 +160,6 @@ public class Executor implements FactoryOperations {
private static final long serialVersionUID = 2681360188806309513L;
private static final JooqLogger log = JooqLogger.getLogger(Factory.class);
private static final Executor[] DEFAULT_INSTANCES = new Executor[SQLDialect.values().length];
private final Configuration configuration;
// -------------------------------------------------------------------------
@ -1558,19 +1557,6 @@ public class Executor implements FactoryOperations {
return configuration.toString();
}
static {
for (SQLDialect dialect : SQLDialect.values()) {
DEFAULT_INSTANCES[dialect.ordinal()] = new Executor(dialect);
}
}
/**
* Get a default <code>Factory</code> without a {@link Connection}
*/
final static Executor getNewFactory(SQLDialect dialect) {
return getNewFactory(DEFAULT_INSTANCES[dialect.ordinal()]);
}
/**
* Get a default <code>Factory</code> with a {@link Connection}
*/

View File

@ -346,7 +346,7 @@ public final class FieldTypeHelper {
// [#1544] We can safely assume that localConfiguration has been
// set on DefaultBindContext, prior to serialising arrays to SQLOut
Connection connection = getDriverConnection(DefaultBindContext.LOCAL_CONFIGURATION.get());
Connection connection = getDriverConnection(DefaultExecuteContext.registeredConfiguration());
ArrayRecord<?> arrayRecord = (ArrayRecord<?>) value;
stream.writeArray(on(connection).call("createARRAY", arrayRecord.getName(), arrayRecord.get()).<Array>get());
}

View File

@ -76,7 +76,7 @@ public class UDTRecordImpl<R extends UDTRecord<R>> extends AbstractRecord implem
// [#1693] This needs to return the fully qualified SQL type name, in
// case the connected user is not the owner of the UDT
Configuration configuration = DefaultBindContext.LOCAL_CONFIGURATION.get();
Configuration configuration = DefaultExecuteContext.registeredConfiguration();
if (configuration != null) {
Schema schema = Util.getMappedSchema(configuration, getUDT().getSchema());
@ -92,10 +92,8 @@ public class UDTRecordImpl<R extends UDTRecord<R>> extends AbstractRecord implem
@Override
public final void readSQL(SQLInput stream, String typeName) throws SQLException {
Executor configuration = Executor.getNewFactory(getUDT().getDataType().getDialect());
for (Field<?> field : getUDT().getFields()) {
setValue(configuration, stream, field);
setValue(DefaultExecuteContext.registeredConfiguration(), stream, field);
}
}