[#2388] Replace Configuration's List<ExecuteListener> with an

ExecuteListenerProvider to simplify correct and thread-safe client
implementations
This commit is contained in:
Lukas Eder 2013-04-07 16:57:23 +02:00
parent d104467645
commit c3883d2b92
13 changed files with 459 additions and 123 deletions

View File

@ -59,6 +59,7 @@ import org.jooq.Configuration;
import org.jooq.DAO;
import org.jooq.DSLContext;
import org.jooq.DataType;
import org.jooq.ExecuteListener;
import org.jooq.Field;
import org.jooq.ForeignKey;
import org.jooq.Record;
@ -707,18 +708,26 @@ public abstract class BaseTest<
return delegate.getCastableDataTypes();
}
protected DSLContext create(Settings settings) {
protected final DSLContext create(Settings settings) {
DSLContext create = delegate.create(settings);
create.configuration().getExecuteListeners().add(new TestStatisticsListener());
addListeners(create.configuration(), new TestStatisticsListener());
return create;
}
protected final DSLContext create(Configuration configuration) {
DSLContext create = DSL.using(configuration);
create.configuration().getExecuteListeners().add(new TestStatisticsListener());
addListeners(create.configuration(), new TestStatisticsListener());
return create;
}
protected final List<ExecuteListener> getListeners(Configuration configuration) {
return delegate.getListeners(configuration);
}
protected final void addListeners(Configuration configuration, ExecuteListener... listeners) {
delegate.addListeners(configuration, listeners);
}
protected final Connection getConnection() {
return delegate.getConnection();
}

View File

@ -38,11 +38,10 @@ package org.jooq.test._.testcases;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Random;
import org.jooq.Configuration;
import org.jooq.DSLContext;
import org.jooq.ExecuteListener;
import org.jooq.Record1;
import org.jooq.Record2;
import org.jooq.Record3;
@ -51,7 +50,6 @@ import org.jooq.Result;
import org.jooq.Select;
import org.jooq.TableRecord;
import org.jooq.UpdatableRecord;
import org.jooq.impl.DefaultConfiguration;
import org.jooq.test.BaseTest;
import org.jooq.test.jOOQAbstractTest;
import org.jooq.tools.StopWatch;
@ -128,9 +126,9 @@ extends BaseTest<A, AP, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, UU, I, IPK, T7
// This benchmark is contributed by "jjYBdx4IL" on GitHub:
// https://github.com/jOOQ/jOOQ/issues/1625
DefaultConfiguration configuration = new DefaultConfiguration(create().configuration());
Configuration configuration = create().configuration().derive();
configuration.getSettings().setExecuteLogging(false);
configuration.setExecuteListeners(new ArrayList<ExecuteListener>());
getListeners(configuration).clear();
DSLContext create = create(configuration);
// Dry-run to avoid side-effects

View File

@ -53,8 +53,8 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import org.jooq.DSLContext;
import org.jooq.Cursor;
import org.jooq.DSLContext;
import org.jooq.ExecuteContext;
import org.jooq.ExecuteListener;
import org.jooq.ExecuteType;
@ -101,7 +101,7 @@ extends BaseTest<A, AP, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, UU, I, IPK, T7
@Test
public void testExecuteListenerWithData() throws Exception {
DSLContext create = create();
create.configuration().getExecuteListeners().add(new DataListener());
addListeners(create.configuration(), new DataListener());
create.selectOne().fetch();
}
@ -211,7 +211,7 @@ extends BaseTest<A, AP, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, UU, I, IPK, T7
@Test
public void testExecuteListenerCustomException() throws Exception {
DSLContext create = create();
create.configuration().getExecuteListeners().add(new CustomExceptionListener());
addListeners(create.configuration(), new CustomExceptionListener());
try {
create.fetch("invalid sql");
@ -237,7 +237,7 @@ extends BaseTest<A, AP, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, UU, I, IPK, T7
@Test
public void testExecuteListenerOnResultQuery() throws Exception {
DSLContext create = create();
create.configuration().getExecuteListeners().add(new ResultQueryListener());
addListeners(create.configuration(), new ResultQueryListener());
create.configuration().setData("Foo", "Bar");
create.configuration().setData("Bar", "Baz");
@ -581,7 +581,7 @@ extends BaseTest<A, AP, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, UU, I, IPK, T7
jOOQAbstractTest.reset = false;
DSLContext create = create();
create.configuration().getExecuteListeners().add(new BatchSingleListener());
addListeners(create.configuration(), new BatchSingleListener());
create.configuration().setData("Foo", "Bar");
create.configuration().setData("Bar", "Baz");
@ -795,7 +795,7 @@ extends BaseTest<A, AP, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, UU, I, IPK, T7
jOOQAbstractTest.reset = false;
DSLContext create = create();
create.configuration().getExecuteListeners().add(new BatchMultipleListener());
addListeners(create.configuration(), new BatchMultipleListener());
create.configuration().setData("Foo", "Bar");
create.configuration().setData("Bar", "Baz");
@ -1021,7 +1021,7 @@ extends BaseTest<A, AP, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, UU, I, IPK, T7
@Test
public void testExecuteListenerFetchLazyTest() throws Exception {
DSLContext create = create();
create.configuration().getExecuteListeners().add(new FetchLazyListener());
addListeners(create.configuration(), new FetchLazyListener());
FetchLazyListener.reset();
create.selectFrom(TAuthor()).fetch();

View File

@ -233,7 +233,7 @@ extends BaseTest<A, AP, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, UU, I, IPK, T7
ConnectionProviderListener.c = create().configuration().getConnectionProvider().acquire();
try {
DSLContext create = create();
create.configuration().getExecuteListeners().add(new ConnectionProviderListener());
addListeners(create.configuration(), new ConnectionProviderListener());
q = create
.selectFrom(TAuthor())
.orderBy(TAuthor_LAST_NAME());

View File

@ -51,8 +51,8 @@ import java.sql.PreparedStatement;
import java.util.ArrayList;
import java.util.List;
import org.jooq.DSLContext;
import org.jooq.Cursor;
import org.jooq.DSLContext;
import org.jooq.ExecuteContext;
import org.jooq.Record1;
import org.jooq.Record2;
@ -100,7 +100,7 @@ extends BaseTest<A, AP, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, UU, I, IPK, T7
@Test
public void testKeepStatement() throws Exception {
DSLContext create = create();
create.configuration().getExecuteListeners().add(new KeepStatementListener());
addListeners(create.configuration(), new KeepStatementListener());
// [#385] By default, new statements are created for every execution
KeepStatementListener.reset();

View File

@ -66,6 +66,7 @@ import org.jooq.ArrayRecord;
import org.jooq.DAO;
import org.jooq.DSLContext;
import org.jooq.DataType;
import org.jooq.ExecuteListener;
import org.jooq.ExecuteType;
import org.jooq.Field;
import org.jooq.ForeignKey;
@ -90,6 +91,7 @@ import org.jooq.debug.Debugger;
import org.jooq.debug.console.Console;
import org.jooq.debug.impl.DebuggerFactory;
import org.jooq.impl.DSL;
import org.jooq.impl.DefaultExecuteListenerProvider;
import org.jooq.test._.LifecycleWatcherListener;
import org.jooq.test._.PrettyPrinter;
import org.jooq.test._.TestStatisticsListener;
@ -874,12 +876,26 @@ public abstract class jOOQAbstractTest<
.withDefaultSchema(defaultSchema));
DSLContext create = create(settings);
create.configuration().getExecuteListeners().add(new TestStatisticsListener());
create.configuration().getExecuteListeners().add(new PrettyPrinter());
create.configuration().getExecuteListeners().add(new LifecycleWatcherListener());
addListeners(create.configuration(),
new TestStatisticsListener(),
new PrettyPrinter(),
new LifecycleWatcherListener());
return create;
}
protected final List<ExecuteListener> getListeners(org.jooq.Configuration configuration) {
// Most test cases run with the DefaultExecuteListenerProvider,
// which (inofficially) exposes a mutable List
DefaultExecuteListenerProvider provider = (DefaultExecuteListenerProvider) configuration.getExecuteListenerProvider();
return provider.provide();
}
protected final void addListeners(org.jooq.Configuration configuration, ExecuteListener... listeners) {
getListeners(configuration).addAll(Arrays.asList(listeners));
}
protected final SQLDialect getDialect() {
return create().configuration().getDialect();
}

View File

@ -36,7 +36,6 @@
package org.jooq;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import org.jooq.conf.Settings;
@ -147,10 +146,12 @@ public interface Configuration extends Serializable {
Object setData(Object key, Object value);
/**
* Get the configured <code>ExecuteListeners</code> from this configuration.
* Get the configured <code>ExecuteListenerProvider</code> from this
* configuration.
* <p>
* This method allows for retrieving the configured
* <code>ExecuteListener</code> instances from this configuration. These
* <code>ExecuteListenerProvider</code> from this configuration. The
* provider will provide jOOQ with {@link ExecuteListener} instances. These
* instances receive execution lifecycle notification events every time jOOQ
* executes queries. jOOQ makes no assumptions about the internal state of
* these listeners, i.e. listener instances may
@ -167,9 +168,56 @@ public interface Configuration extends Serializable {
* listeners will never be exposed through this method, though.
*
* @return The configured set of execute listeners.
* @see ExecuteListenerProvider
* @see ExecuteListener
* @see ExecuteContext
*/
List<ExecuteListener> getExecuteListeners();
ExecuteListenerProvider getExecuteListenerProvider();
/**
* Create a derived configuration from this one, without changing any
* properties.
*
* @return The derived configuration.
*/
Configuration derive();
/**
* Create a derived configuration from this one, with a new dialect.
*
* @param newDialect The new dialect to be contained in the derived
* configuration.
* @return The derived configuration.
*/
Configuration derive(SQLDialect newDialect);
/**
* Create a derived configuration from this one, with a new connection
* provider.
*
* @param newConnectionProvider The new connection provider to be contained
* in the derived configuration.
* @return The derived configuration.
*/
Configuration derive(ConnectionProvider newConnectionProvider);
/**
* Create a derived configuration from this one, with new settings.
*
* @param newSettings The new settings to be contained in the derived
* configuration.
* @return The derived configuration.
*/
Configuration derive(Settings newSettings);
/**
* Create a derived configuration from this one, with a new execute listener
* provider.
*
* @param newExecuteListenerProvider The new execute listener provider to be
* contained in the derived configuration.
* @return The derived configuration.
*/
Configuration derive(ExecuteListenerProvider newExecuteListenerProvider);
}

View File

@ -0,0 +1,65 @@
/**
* Copyright (c) 2009-2013, Lukas Eder, lukas.eder@gmail.com
* All rights reserved.
*
* This software is licensed to you under the Apache License, Version 2.0
* (the "License"); You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* . Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* . Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* . Neither the name "jOOQ" nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.jooq;
import java.util.List;
/**
* A provider for {@link ExecuteListener} instances.
* <p>
* In order to facilitate the lifecycle management of
* <code>ExecuteListener</code> instances that are provided to a jOOQ
* {@link Configuration}, clients can implement this API. To jOOQ, it is thus
* irrelevant, if execute listeners are stateful or stateless, local to an
* execution, or global to an application.
*
* @author Lukas Eder
* @see ExecuteListener
* @see Configuration
*/
public interface ExecuteListenerProvider {
/**
* Provide a list of <code>ExecuteListener</code> instances.
* <p>
* jOOQ will issue {@link ExecuteListener} notification events to each
* listener in the order of iteration of the returned list.
*
* @return A list of <code>ExecuteListener</code> instances.
* @see ExecuteListener
*/
List<ExecuteListener> provide();
}

View File

@ -49,6 +49,7 @@ import org.jooq.BatchBindStep;
import org.jooq.Configuration;
import org.jooq.DSLContext;
import org.jooq.ExecuteContext;
import org.jooq.ExecuteListener;
import org.jooq.Query;
import org.jooq.UpdatableRecord;
import org.jooq.exception.DataAccessException;
@ -95,55 +96,45 @@ class BatchCRUD implements Batch {
private final int[] executePrepared() {
Map<String, List<Query>> queries = new LinkedHashMap<String, List<Query>>();
Boolean executeLogging = configuration.getSettings().isExecuteLogging();
QueryCollector collector = new QueryCollector();
try {
// [#1537] Communicate with UpdatableRecordImpl
configuration.setData(Utils.DATA_OMIT_RETURNING_CLAUSE, true);
// Add the QueryCollector to intercept query execution after rendering
List<ExecuteListener> listeners = new ArrayList<ExecuteListener>(configuration.getExecuteListenerProvider().provide());
listeners.add(collector);
Configuration local = configuration.derive(new DefaultExecuteListenerProvider(listeners));
// Add the QueryCollector to intercept query execution after rendering
configuration.getExecuteListeners().add(collector);
// [#1537] Communicate with UpdatableRecordImpl
local.setData(Utils.DATA_OMIT_RETURNING_CLAUSE, true);
// [#1529] Avoid DEBUG logging of single INSERT / UPDATE statements
configuration.getSettings().setExecuteLogging(false);
// [#1529] Avoid DEBUG logging of single INSERT / UPDATE statements
local.getSettings().setExecuteLogging(false);
for (int i = 0; i < records.length; i++) {
Configuration previous = ((AttachableInternal) records[i]).getConfiguration();
for (int i = 0; i < records.length; i++) {
Configuration previous = ((AttachableInternal) records[i]).getConfiguration();
try {
records[i].attach(configuration);
executeAction(i);
}
catch (QueryCollectorException e) {
Query query = e.getQuery();
String sql = e.getSQL();
try {
records[i].attach(local);
executeAction(i);
}
catch (QueryCollectorException e) {
Query query = e.getQuery();
String sql = e.getSQL();
// Aggregate executable queries by identical SQL
if (query.isExecutable()) {
List<Query> list = queries.get(sql);
// Aggregate executable queries by identical SQL
if (query.isExecutable()) {
List<Query> list = queries.get(sql);
if (list == null) {
list = new ArrayList<Query>();
queries.put(sql, list);
}
list.add(query);
if (list == null) {
list = new ArrayList<Query>();
queries.put(sql, list);
}
}
finally {
records[i].attach(previous);
list.add(query);
}
}
}
// Restore the original factory
finally {
configuration.getData().remove(Utils.DATA_OMIT_RETURNING_CLAUSE);
configuration.getExecuteListeners().remove(collector);
configuration.getSettings().setExecuteLogging(executeLogging);
finally {
records[i].attach(previous);
}
}
// Execute one batch statement for each identical SQL statement. Every
@ -176,32 +167,27 @@ class BatchCRUD implements Batch {
List<Query> queries = new ArrayList<Query>();
QueryCollector collector = new QueryCollector();
try {
configuration.getExecuteListeners().add(collector);
List<ExecuteListener> listeners = new ArrayList<ExecuteListener>(configuration.getExecuteListenerProvider().provide());
listeners.add(collector);
Configuration local = configuration.derive(new DefaultExecuteListenerProvider(listeners));
for (int i = 0; i < records.length; i++) {
Configuration previous = ((AttachableInternal) records[i]).getConfiguration();
for (int i = 0; i < records.length; i++) {
Configuration previous = ((AttachableInternal) records[i]).getConfiguration();
try {
records[i].attach(configuration);
executeAction(i);
}
catch (QueryCollectorException e) {
Query query = e.getQuery();
try {
records[i].attach(local);
executeAction(i);
}
catch (QueryCollectorException e) {
Query query = e.getQuery();
if (query.isExecutable()) {
queries.add(query);
}
}
finally {
records[i].attach(previous);
if (query.isExecutable()) {
queries.add(query);
}
}
}
// Restore the original factory
finally {
configuration.getExecuteListeners().remove(collector);
finally {
records[i].attach(previous);
}
}
// Resulting statements can be batch executed in their requested order

View File

@ -82,8 +82,8 @@ import org.jooq.BindContext;
import org.jooq.Condition;
import org.jooq.Configuration;
import org.jooq.ConnectionProvider;
import org.jooq.DSLContext;
import org.jooq.Cursor;
import org.jooq.DSLContext;
import org.jooq.DataType;
import org.jooq.DeleteQuery;
import org.jooq.DeleteWhereStep;
@ -215,7 +215,7 @@ class DSLContextImpl implements DSLContext, Serializable {
}
DSLContextImpl(SQLDialect dialect, Settings settings) {
this(new DefaultConfiguration(new NoConnectionProvider(), dialect, settings, null));
this(new DefaultConfiguration(new NoConnectionProvider(), null, dialect, settings, null));
}
DSLContextImpl(Connection connection, SQLDialect dialect) {
@ -223,7 +223,7 @@ class DSLContextImpl implements DSLContext, Serializable {
}
DSLContextImpl(Connection connection, SQLDialect dialect, Settings settings) {
this(new DefaultConfiguration(new DefaultConnectionProvider(connection), dialect, settings, null));
this(new DefaultConfiguration(new DefaultConnectionProvider(connection), null, dialect, settings, null));
}
DSLContextImpl(DataSource datasource, SQLDialect dialect) {
@ -231,7 +231,7 @@ class DSLContextImpl implements DSLContext, Serializable {
}
DSLContextImpl(DataSource datasource, SQLDialect dialect, Settings settings) {
this(new DefaultConfiguration(new DataSourceConnectionProvider(datasource), dialect, settings, null));
this(new DefaultConfiguration(new DataSourceConnectionProvider(datasource), null, dialect, settings, null));
}
DSLContextImpl(ConnectionProvider connectionProvider, SQLDialect dialect) {
@ -239,7 +239,7 @@ class DSLContextImpl implements DSLContext, Serializable {
}
DSLContextImpl(ConnectionProvider connectionProvider, SQLDialect dialect, Settings settings) {
this(new DefaultConfiguration(connectionProvider, dialect, settings, null));
this(new DefaultConfiguration(connectionProvider, null, dialect, settings, null));
}
DSLContextImpl(Configuration configuration) {

View File

@ -37,9 +37,11 @@ package org.jooq.impl;
import static org.jooq.SQLDialect.SQL99;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@ -48,7 +50,7 @@ import javax.xml.bind.JAXB;
import org.jooq.Configuration;
import org.jooq.ConnectionProvider;
import org.jooq.DSLContext;
import org.jooq.ExecuteListener;
import org.jooq.ExecuteListenerProvider;
import org.jooq.SQLDialect;
import org.jooq.conf.Settings;
import org.jooq.conf.SettingsTools;
@ -61,6 +63,7 @@ import org.jooq.conf.SettingsTools;
*
* @author Lukas Eder
*/
@SuppressWarnings("deprecation")
public class DefaultConfiguration implements Configuration {
/**
@ -68,39 +71,136 @@ public class DefaultConfiguration implements Configuration {
*/
private static final long serialVersionUID = 8193158984283234708L;
private final ConnectionProvider connectionProvider;
// Configuration objects
private final SQLDialect dialect;
@SuppressWarnings("deprecation")
private final org.jooq.SchemaMapping mapping;
private final Settings settings;
private final ConcurrentHashMap<Object, Object> data;
private final List<ExecuteListener> listeners;
@SuppressWarnings("deprecation")
// Non-serializable Configuration objects
private transient ConnectionProvider connectionProvider;
private transient ExecuteListenerProvider listenerProvider;
// Derived objects
private final org.jooq.SchemaMapping mapping;
// -------------------------------------------------------------------------
// XXX: Constructors
// -------------------------------------------------------------------------
/**
* Create a new "empty" configuration object.
* <p>
* This can be used as is, as a "dummy" configuration object, or as a base
* implementation for creating more sophisticated "derived" configurations
* through the various <code>derive()</code> methods.
*/
public DefaultConfiguration() {
this(new NoConnectionProvider(), SQL99, SettingsTools.defaultSettings(), null);
this(
new NoConnectionProvider(),
new DefaultExecuteListenerProvider(),
SQL99,
SettingsTools.defaultSettings(),
null);
}
public DefaultConfiguration(Configuration configuration) {
/**
* Create a new "derived" configuration object from a pre-existing one.
* <p>
* This copies all properties from a pre-existing configuration into a new,
* derived one.
*
* @param configuration The pre-existing configuration.
*/
DefaultConfiguration(Configuration configuration) {
this(
configuration.getConnectionProvider(),
configuration.getExecuteListenerProvider(),
configuration.getDialect(),
configuration.getSettings(),
configuration.getData()
);
}
@SuppressWarnings("deprecation")
public DefaultConfiguration(ConnectionProvider connectionProvider, SQLDialect dialect, Settings settings, Map<Object, Object> data) {
/**
* Create the actual configuration object.
* <p>
* This constructor has been made package-private to allow for adding new
* configuration properties in the future, without breaking client code.
* Consider creating a configuration by chaining calls to various
* <code>derive()</code> methods.
*/
DefaultConfiguration(
ConnectionProvider connectionProvider,
ExecuteListenerProvider listenerProvider,
SQLDialect dialect,
Settings settings,
Map<Object, Object> data)
{
this.connectionProvider = connectionProvider;
this.listenerProvider = listenerProvider != null
? listenerProvider
: new DefaultExecuteListenerProvider();
this.dialect = dialect;
this.settings = settings != null ? settings : SettingsTools.defaultSettings();
this.settings = settings != null
? SettingsTools.clone(settings)
: SettingsTools.defaultSettings();
this.data = data != null
? new ConcurrentHashMap<Object, Object>(data)
: new ConcurrentHashMap<Object, Object>();
this.mapping = new org.jooq.SchemaMapping(this);
this.data = data != null ? new ConcurrentHashMap<Object, Object>(data) : new ConcurrentHashMap<Object, Object>();
this.listeners = new ArrayList<ExecuteListener>();
}
// -------------------------------------------------------------------------
// XXX: Deriving configurations
// -------------------------------------------------------------------------
/**
* {@inheritDoc}
*/
@Override
public final Configuration derive() {
return new DefaultConfiguration(this);
}
/**
* {@inheritDoc}
*/
@Override
public final Configuration derive(SQLDialect newDialect) {
return new DefaultConfiguration(connectionProvider, listenerProvider, newDialect, settings, data);
}
/**
* {@inheritDoc}
*/
@Override
public final Configuration derive(ConnectionProvider newConnectionProvider) {
return new DefaultConfiguration(newConnectionProvider, listenerProvider, dialect, settings, data);
}
/**
* {@inheritDoc}
*/
@Override
public final Configuration derive(Settings newSettings) {
return new DefaultConfiguration(connectionProvider, listenerProvider, dialect, newSettings, data);
}
/**
* {@inheritDoc}
*/
@Override
public final Configuration derive(ExecuteListenerProvider newExecuteListenerProvider) {
return new DefaultConfiguration(connectionProvider, newExecuteListenerProvider, dialect, settings, data);
}
// -------------------------------------------------------------------------
// XXX: Getters
// -------------------------------------------------------------------------
/**
* {@inheritDoc}
*/
@ -162,19 +262,8 @@ public class DefaultConfiguration implements Configuration {
* {@inheritDoc}
*/
@Override
public final List<ExecuteListener> getExecuteListeners() {
return listeners;
}
/**
* Set the execute listeners onto this configuration.
*/
public final void setExecuteListeners(List<ExecuteListener> listeners) {
this.listeners.clear();
if (listeners != null) {
listeners.addAll(listeners);
}
public final ExecuteListenerProvider getExecuteListenerProvider() {
return listenerProvider;
}
@Override
@ -186,5 +275,29 @@ public class DefaultConfiguration implements Configuration {
",\n\tdialect=" + dialect +
",\n\tdata=" + data +
",\n\tsettings=\n\t\t" + writer.toString().trim().replace("\n", "\n\t\t") +
"\n]"; }
"\n]";
}
// -------------------------------------------------------------------------
// XXX: Serialisation
// -------------------------------------------------------------------------
private void writeObject(ObjectOutputStream oos) throws IOException {
oos.defaultWriteObject();
// Allow these objects to be non-serializable
oos.writeObject(connectionProvider instanceof Serializable
? connectionProvider
: null);
oos.writeObject(listenerProvider instanceof Serializable
? listenerProvider
: null);
}
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
ois.defaultReadObject();
connectionProvider = (ConnectionProvider) ois.readObject();
listenerProvider = (ExecuteListenerProvider) ois.readObject();
}
}

View File

@ -0,0 +1,97 @@
/**
* Copyright (c) 2009-2013, Lukas Eder, lukas.eder@gmail.com
* All rights reserved.
*
* This software is licensed to you under the Apache License, Version 2.0
* (the "License"); You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* . Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* . Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* . Neither the name "jOOQ" nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.jooq.impl;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import org.jooq.ExecuteListener;
import org.jooq.ExecuteListenerProvider;
/**
* A default implementation for {@link ExecuteListenerProvider}.
* <p>
* This implementation just wraps a <code>List</code> of {@link ExecuteListener}
* instances, always providing the same.
*
* @author Lukas Eder
*/
public class DefaultExecuteListenerProvider implements ExecuteListenerProvider, Serializable {
/**
* Generated UID.
*/
private static final long serialVersionUID = -2122007794302549679L;
/**
* The delegate list.
*/
private List<ExecuteListener> listeners;
/**
* Create a new provider instance with an empty <code>ArrayList</code>
* argument.
*/
public DefaultExecuteListenerProvider() {
this(new ArrayList<ExecuteListener>());
}
/**
* Create a new provider instance from an argument <code>List</code>.
*
* @param listeners The argument list.
*/
public DefaultExecuteListenerProvider(List<ExecuteListener> listeners) {
this.listeners = listeners;
}
/**
* {@inheritDoc}
*/
@Override
public final List<ExecuteListener> provide() {
return listeners;
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
return "" + listeners;
}
}

View File

@ -38,11 +38,11 @@ package org.jooq.impl;
import static java.lang.Boolean.FALSE;
import static org.jooq.SQLDialect.CUBRID;
import static org.jooq.SQLDialect.POSTGRES;
import static org.jooq.impl.DefaultExecuteContext.localConnection;
import static org.jooq.impl.DSL.escape;
import static org.jooq.impl.DSL.getDataType;
import static org.jooq.impl.DSL.nullSafe;
import static org.jooq.impl.DSL.val;
import static org.jooq.impl.DefaultExecuteContext.localConnection;
import static org.jooq.tools.jdbc.JDBCUtils.safeFree;
import static org.jooq.tools.jdbc.JDBCUtils.wasNull;
import static org.jooq.tools.reflect.Reflect.accessible;
@ -86,13 +86,14 @@ import org.jooq.Attachable;
import org.jooq.AttachableInternal;
import org.jooq.BindContext;
import org.jooq.Configuration;
import org.jooq.DSLContext;
import org.jooq.Converter;
import org.jooq.Cursor;
import org.jooq.DSLContext;
import org.jooq.DataType;
import org.jooq.EnumType;
import org.jooq.ExecuteContext;
import org.jooq.ExecuteListener;
import org.jooq.ExecuteListenerProvider;
import org.jooq.Field;
import org.jooq.Param;
import org.jooq.QueryPart;
@ -1095,13 +1096,16 @@ final class Utils {
*/
static final List<ExecuteListener> getListeners(ExecuteContext ctx) {
List<ExecuteListener> result = new ArrayList<ExecuteListener>();
if (!FALSE.equals(ctx.configuration().getSettings().isExecuteLogging())) {
result.add(new StopWatchListener());
result.add(new LoggerListener());
}
result.addAll(ctx.configuration().getExecuteListeners());
ExecuteListenerProvider provider = ctx.configuration().getExecuteListenerProvider();
if (provider != null) {
result.addAll(provider.provide());
}
return result;
}