From c3883d2b9252cb0ac53bd8b7435caf6573df712f Mon Sep 17 00:00:00 2001 From: Lukas Eder Date: Sun, 7 Apr 2013 16:57:23 +0200 Subject: [PATCH] [#2388] Replace Configuration's List with an ExecuteListenerProvider to simplify correct and thread-safe client implementations --- jOOQ-test/src/org/jooq/test/BaseTest.java | 15 +- .../jooq/test/_/testcases/BenchmarkTests.java | 8 +- .../_/testcases/ExecuteListenerTests.java | 14 +- .../jooq/test/_/testcases/GeneralTests.java | 2 +- .../jooq/test/_/testcases/StatementTests.java | 4 +- .../src/org/jooq/test/jOOQAbstractTest.java | 22 ++- .../src/main/java/org/jooq/Configuration.java | 56 +++++- .../org/jooq/ExecuteListenerProvider.java | 65 +++++++ .../main/java/org/jooq/impl/BatchCRUD.java | 104 +++++------ .../java/org/jooq/impl/DSLContextImpl.java | 10 +- .../org/jooq/impl/DefaultConfiguration.java | 173 +++++++++++++++--- .../impl/DefaultExecuteListenerProvider.java | 97 ++++++++++ jOOQ/src/main/java/org/jooq/impl/Utils.java | 12 +- 13 files changed, 459 insertions(+), 123 deletions(-) create mode 100644 jOOQ/src/main/java/org/jooq/ExecuteListenerProvider.java create mode 100644 jOOQ/src/main/java/org/jooq/impl/DefaultExecuteListenerProvider.java diff --git a/jOOQ-test/src/org/jooq/test/BaseTest.java b/jOOQ-test/src/org/jooq/test/BaseTest.java index 696dbbc3c2..d8d7b4c6ed 100644 --- a/jOOQ-test/src/org/jooq/test/BaseTest.java +++ b/jOOQ-test/src/org/jooq/test/BaseTest.java @@ -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 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(); } diff --git a/jOOQ-test/src/org/jooq/test/_/testcases/BenchmarkTests.java b/jOOQ-test/src/org/jooq/test/_/testcases/BenchmarkTests.java index 54eeb288f4..58db0aecdd 100644 --- a/jOOQ-test/src/org/jooq/test/_/testcases/BenchmarkTests.java +++ b/jOOQ-test/src/org/jooq/test/_/testcases/BenchmarkTests.java @@ -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()); + getListeners(configuration).clear(); DSLContext create = create(configuration); // Dry-run to avoid side-effects diff --git a/jOOQ-test/src/org/jooq/test/_/testcases/ExecuteListenerTests.java b/jOOQ-test/src/org/jooq/test/_/testcases/ExecuteListenerTests.java index 368b09de5a..caa8f53fb5 100644 --- a/jOOQ-test/src/org/jooq/test/_/testcases/ExecuteListenerTests.java +++ b/jOOQ-test/src/org/jooq/test/_/testcases/ExecuteListenerTests.java @@ -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 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(); } diff --git a/jOOQ/src/main/java/org/jooq/Configuration.java b/jOOQ/src/main/java/org/jooq/Configuration.java index 462ac3ea47..3759f95540 100644 --- a/jOOQ/src/main/java/org/jooq/Configuration.java +++ b/jOOQ/src/main/java/org/jooq/Configuration.java @@ -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 ExecuteListeners from this configuration. + * Get the configured ExecuteListenerProvider from this + * configuration. *

* This method allows for retrieving the configured - * ExecuteListener instances from this configuration. These + * ExecuteListenerProvider 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 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); } diff --git a/jOOQ/src/main/java/org/jooq/ExecuteListenerProvider.java b/jOOQ/src/main/java/org/jooq/ExecuteListenerProvider.java new file mode 100644 index 0000000000..16fe61cef9 --- /dev/null +++ b/jOOQ/src/main/java/org/jooq/ExecuteListenerProvider.java @@ -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. + *

+ * In order to facilitate the lifecycle management of + * ExecuteListener 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 ExecuteListener instances. + *

+ * jOOQ will issue {@link ExecuteListener} notification events to each + * listener in the order of iteration of the returned list. + * + * @return A list of ExecuteListener instances. + * @see ExecuteListener + */ + List provide(); +} diff --git a/jOOQ/src/main/java/org/jooq/impl/BatchCRUD.java b/jOOQ/src/main/java/org/jooq/impl/BatchCRUD.java index b69782b70a..af5db4a36a 100644 --- a/jOOQ/src/main/java/org/jooq/impl/BatchCRUD.java +++ b/jOOQ/src/main/java/org/jooq/impl/BatchCRUD.java @@ -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> queries = new LinkedHashMap>(); - - 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 listeners = new ArrayList(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 list = queries.get(sql); + // Aggregate executable queries by identical SQL + if (query.isExecutable()) { + List list = queries.get(sql); - if (list == null) { - list = new ArrayList(); - queries.put(sql, list); - } - - list.add(query); + if (list == null) { + list = new ArrayList(); + 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 queries = new ArrayList(); QueryCollector collector = new QueryCollector(); - try { - configuration.getExecuteListeners().add(collector); + List listeners = new ArrayList(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 diff --git a/jOOQ/src/main/java/org/jooq/impl/DSLContextImpl.java b/jOOQ/src/main/java/org/jooq/impl/DSLContextImpl.java index b5edc7cf02..0416e11cfc 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DSLContextImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/DSLContextImpl.java @@ -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) { diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultConfiguration.java b/jOOQ/src/main/java/org/jooq/impl/DefaultConfiguration.java index b86c632aa8..0f3c901519 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DefaultConfiguration.java +++ b/jOOQ/src/main/java/org/jooq/impl/DefaultConfiguration.java @@ -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 data; - private final List 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. + *

+ * 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 derive() 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. + *

+ * 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 data) { + /** + * Create the actual configuration object. + *

+ * 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 + * derive() methods. + */ + DefaultConfiguration( + ConnectionProvider connectionProvider, + ExecuteListenerProvider listenerProvider, + SQLDialect dialect, + Settings settings, + Map 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(data) + : new ConcurrentHashMap(); + this.mapping = new org.jooq.SchemaMapping(this); - this.data = data != null ? new ConcurrentHashMap(data) : new ConcurrentHashMap(); - this.listeners = new ArrayList(); } + // ------------------------------------------------------------------------- + // 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 getExecuteListeners() { - return listeners; - } - - /** - * Set the execute listeners onto this configuration. - */ - public final void setExecuteListeners(List 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(); + } } \ No newline at end of file diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultExecuteListenerProvider.java b/jOOQ/src/main/java/org/jooq/impl/DefaultExecuteListenerProvider.java new file mode 100644 index 0000000000..e02cf9ae6d --- /dev/null +++ b/jOOQ/src/main/java/org/jooq/impl/DefaultExecuteListenerProvider.java @@ -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}. + *

+ * This implementation just wraps a List 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 listeners; + + /** + * Create a new provider instance with an empty ArrayList + * argument. + */ + public DefaultExecuteListenerProvider() { + this(new ArrayList()); + } + + /** + * Create a new provider instance from an argument List. + * + * @param listeners The argument list. + */ + public DefaultExecuteListenerProvider(List listeners) { + this.listeners = listeners; + } + + /** + * {@inheritDoc} + */ + @Override + public final List provide() { + return listeners; + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return "" + listeners; + } +} diff --git a/jOOQ/src/main/java/org/jooq/impl/Utils.java b/jOOQ/src/main/java/org/jooq/impl/Utils.java index 01d1a9b51b..967579755e 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Utils.java +++ b/jOOQ/src/main/java/org/jooq/impl/Utils.java @@ -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 getListeners(ExecuteContext ctx) { List result = new ArrayList(); - 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; }