This is an automated email from the ASF dual-hosted git repository. asf-gitbox-commits pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/cayenne.git
commit 24dfb1b0ac5639a39a7837625a709116b280942e Author: Andrus Adamchik <[email protected]> AuthorDate: Fri Jul 3 18:07:55 2026 -0400 CAY-2912 Compact SQL logger cleanup --- .../java/org/apache/cayenne/access/DataNode.java | 26 +++-- .../apache/cayenne/access/DataNodeQueryAction.java | 108 --------------------- .../org/apache/cayenne/access/LoggingObserver.java | 2 +- .../apache/cayenne/access/OperationObserver.java | 9 +- .../cayenne/access/OriginalQueryObserver.java | 93 ++++++++++++++++++ .../apache/cayenne/access/LoggingObserverTest.java | 10 +- .../org/apache/cayenne/access/MockDataNode.java | 6 +- .../unit/telemetry/TelemetricDataNodeFactory.java | 4 +- 8 files changed, 122 insertions(+), 136 deletions(-) diff --git a/cayenne/src/main/java/org/apache/cayenne/access/DataNode.java b/cayenne/src/main/java/org/apache/cayenne/access/DataNode.java index 4839aa59b..3351852e4 100644 --- a/cayenne/src/main/java/org/apache/cayenne/access/DataNode.java +++ b/cayenne/src/main/java/org/apache/cayenne/access/DataNode.java @@ -194,8 +194,7 @@ public class DataNode { } /** - * Returns DbAdapter object. This is a plugin that handles RDBMS - * vendor-specific features. + * Returns DbAdapter object. This is a plugin that handles RDBMS vendor-specific features. */ public DbAdapter getAdapter() { return adapter; @@ -222,26 +221,25 @@ public class DataNode { * * @since 1.1 */ - public void performQueries(Collection<? extends Query> queries, OperationObserver operationObserver) { + public void performQueries(Collection<? extends Query> queries, OperationObserver callback) { int listSize = queries.size(); if (listSize == 0) { return; } - if (operationObserver.isIteratedResult() && listSize > 1) { + if (callback.isIteratedResult() && listSize > 1) { throw new CayenneRuntimeException("Iterated queries are not allowed in a batch. Batch size: %d", listSize); } - // do this meaningless inexpensive operation to trigger AutoAdapter lazy initialization before opening a // connection. Otherwise, we may end up with two connections open simultaneously, possibly hitting connection // pool upper limit. getAdapter().getExtendedTypes(); - OperationObserver instrumentedObserver = sqlLogger.isEnabled() - ? new LoggingObserver(operationObserver, sqlLogger) - : operationObserver; + OperationObserver instrumentedCallback = sqlLogger.isEnabled() + ? new LoggingObserver(callback, sqlLogger) + : callback; Transaction tx = BaseTransaction.getThreadTransaction(); Connection connection; @@ -253,20 +251,20 @@ public class DataNode { tx.setRollbackOnly(); } - instrumentedObserver.nextGlobalException(globalEx); + instrumentedCallback.nextGlobalException(globalEx); return; } try { - DataNodeQueryAction queryRunner = new DataNodeQueryAction(this, instrumentedObserver); - for (Query nextQuery : queries) { // catch exceptions for each individual query try { - queryRunner.runQuery(connection, nextQuery); + getAdapter() + .getAction(nextQuery, this) + .performAction(connection, new OriginalQueryObserver(instrumentedCallback, nextQuery)); } catch (Exception queryEx) { - instrumentedObserver.nextQueryException(nextQuery, queryEx); + instrumentedCallback.nextQueryException(nextQuery, queryEx); if (tx != null) { tx.setRollbackOnly(); @@ -275,7 +273,7 @@ public class DataNode { } } - instrumentedObserver.afterLastStatement(); + instrumentedCallback.onSuccess(); } finally { try { connection.close(); diff --git a/cayenne/src/main/java/org/apache/cayenne/access/DataNodeQueryAction.java b/cayenne/src/main/java/org/apache/cayenne/access/DataNodeQueryAction.java deleted file mode 100644 index a952eb5ba..000000000 --- a/cayenne/src/main/java/org/apache/cayenne/access/DataNodeQueryAction.java +++ /dev/null @@ -1,108 +0,0 @@ -/***************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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 - * - * https://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 org.apache.cayenne.access; - -import org.apache.cayenne.ObjectId; -import org.apache.cayenne.ResultIterator; -import org.apache.cayenne.access.translator.TranslatedStatement; -import org.apache.cayenne.query.Query; -import org.apache.cayenne.query.SQLAction; - -import java.sql.Connection; -import java.util.List; - -/** - * A helper that executes a sequence of queries, providing correct mapping of the results - * to the original query. Note that this class is not thread-safe as it stores current - * query execution state. - * - * @since 1.2 - */ -class DataNodeQueryAction { - - final OperationObserver observer; - final DataNode node; - - public DataNodeQueryAction(DataNode node, OperationObserver observer) { - this.observer = observer; - this.node = node; - } - - public void runQuery(Connection connection, Query originalQuery) throws Exception { - - // wrap to ensure that the result is mapped back to the original query, even if - // the underlying SQLAction uses query substitute... - OperationObserver wrapper = new OperationObserver() { - - @Override - public void nextStatement(Query query, TranslatedStatement statement) { - observer.nextStatement(originalQuery, statement); - } - - @Override - public void afterLastStatement() { - observer.afterLastStatement(); - } - - @Override - public void nextBatchCount(Query query, int[] resultCount) { - observer.nextBatchCount(originalQuery, resultCount); - } - - @Override - public void nextCount(Query query, int resultCount) { - observer.nextCount(originalQuery, resultCount); - } - - @Override - public void nextRows(Query query, List<?> dataRows) { - observer.nextRows(originalQuery, dataRows); - } - - @Override - public void nextRows(Query q, ResultIterator<?> it) { - observer.nextRows(originalQuery, it); - } - - @Override - public void nextGeneratedRows(Query query, ResultIterator<?> keys, List<ObjectId> idsToUpdate) { - observer.nextGeneratedRows(originalQuery, keys, idsToUpdate); - } - - @Override - public void nextGlobalException(Exception ex) { - observer.nextGlobalException(ex); - } - - @Override - public void nextQueryException(Query query, Exception ex) { - observer.nextQueryException(originalQuery, ex); - } - - @Override - public boolean isIteratedResult() { - return observer.isIteratedResult(); - } - }; - - SQLAction action = node.getAdapter().getAction(originalQuery, node); - action.performAction(connection, wrapper); - } -} diff --git a/cayenne/src/main/java/org/apache/cayenne/access/LoggingObserver.java b/cayenne/src/main/java/org/apache/cayenne/access/LoggingObserver.java index e7435503a..204a938c1 100644 --- a/cayenne/src/main/java/org/apache/cayenne/access/LoggingObserver.java +++ b/cayenne/src/main/java/org/apache/cayenne/access/LoggingObserver.java @@ -90,7 +90,7 @@ class LoggingObserver implements OperationObserver { } @Override - public void afterLastStatement() { + public void onSuccess() { flushPending(); current = null; } diff --git a/cayenne/src/main/java/org/apache/cayenne/access/OperationObserver.java b/cayenne/src/main/java/org/apache/cayenne/access/OperationObserver.java index 63a5a691f..270577503 100644 --- a/cayenne/src/main/java/org/apache/cayenne/access/OperationObserver.java +++ b/cayenne/src/main/java/org/apache/cayenne/access/OperationObserver.java @@ -43,9 +43,11 @@ public interface OperationObserver extends OperationHints { } /** + * Called at the end of a multi-query DataNode operation. + * * @since 5.0 */ - default void afterLastStatement() { + default void onSuccess() { } /** @@ -60,7 +62,7 @@ public interface OperationObserver extends OperationHints { /** * Callback method invoked for each processed ResultSet. - * + * * @since 3.0 */ void nextRows(Query query, List<?> dataRows); @@ -69,13 +71,14 @@ public interface OperationObserver extends OperationHints { * Callback method invoked for each opened ResultIterator. If this observer requested * results to be returned as a ResultIterator, this method is invoked instead of * {@link #nextRows(Query, List)}. - * + * * @since 3.0 */ void nextRows(Query q, ResultIterator<?> it); /** * Callback method invoked after each batch of generated values is read during an update. + * * @since 4.2 */ void nextGeneratedRows(Query query, ResultIterator<?> keys, List<ObjectId> idsToUpdate); diff --git a/cayenne/src/main/java/org/apache/cayenne/access/OriginalQueryObserver.java b/cayenne/src/main/java/org/apache/cayenne/access/OriginalQueryObserver.java new file mode 100644 index 000000000..fc999bc57 --- /dev/null +++ b/cayenne/src/main/java/org/apache/cayenne/access/OriginalQueryObserver.java @@ -0,0 +1,93 @@ +/***************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 + * + * https://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 org.apache.cayenne.access; + +import org.apache.cayenne.ObjectId; +import org.apache.cayenne.ResultIterator; +import org.apache.cayenne.access.translator.TranslatedStatement; +import org.apache.cayenne.query.Query; + +import java.util.List; + +/** + * An {@link OperationObserver} decorator that reports all results against the original query, even when the underlying + * {@link org.apache.cayenne.query.SQLAction} executes a substitute query. All callbacks are delegated to the wrapped + * observer with the {@code query} argument replaced by the original query. + */ +class OriginalQueryObserver implements OperationObserver { + + private final OperationObserver delegate; + private final Query originalQuery; + + OriginalQueryObserver(OperationObserver delegate, Query originalQuery) { + this.delegate = delegate; + this.originalQuery = originalQuery; + } + + @Override + public void nextStatement(Query query, TranslatedStatement statement) { + delegate.nextStatement(originalQuery, statement); + } + + @Override + public void onSuccess() { + delegate.onSuccess(); + } + + @Override + public void nextCount(Query query, int resultCount) { + delegate.nextCount(originalQuery, resultCount); + } + + @Override + public void nextBatchCount(Query query, int[] resultCount) { + delegate.nextBatchCount(originalQuery, resultCount); + } + + @Override + public void nextRows(Query query, List<?> dataRows) { + delegate.nextRows(originalQuery, dataRows); + } + + @Override + public void nextRows(Query query, ResultIterator<?> it) { + delegate.nextRows(originalQuery, it); + } + + @Override + public void nextGeneratedRows(Query query, ResultIterator<?> keys, List<ObjectId> idsToUpdate) { + delegate.nextGeneratedRows(originalQuery, keys, idsToUpdate); + } + + @Override + public void nextQueryException(Query query, Exception ex) { + delegate.nextQueryException(originalQuery, ex); + } + + @Override + public void nextGlobalException(Exception ex) { + delegate.nextGlobalException(ex); + } + + @Override + public boolean isIteratedResult() { + return delegate.isIteratedResult(); + } +} diff --git a/cayenne/src/test/java/org/apache/cayenne/access/LoggingObserverTest.java b/cayenne/src/test/java/org/apache/cayenne/access/LoggingObserverTest.java index ed62645c3..5b3aca43a 100644 --- a/cayenne/src/test/java/org/apache/cayenne/access/LoggingObserverTest.java +++ b/cayenne/src/test/java/org/apache/cayenne/access/LoggingObserverTest.java @@ -117,7 +117,7 @@ public class LoggingObserverTest { observer.nextStatement(null, select()); observer.nextRows(null, asList(new Object(), new Object())); - observer.afterLastStatement(); + observer.onSuccess(); assertEquals(List.of("selected:2"), logger.calls); } @@ -131,7 +131,7 @@ public class LoggingObserverTest { observer.nextCount(null, 1); observer.nextCount(null, 1); observer.nextCount(null, 1); - observer.afterLastStatement(); + observer.onSuccess(); assertEquals(List.of("updated:3"), logger.calls); } @@ -145,7 +145,7 @@ public class LoggingObserverTest { observer.nextRows(null, List.of(new Object(), new Object(), new Object(), new Object(), new Object())); observer.nextCount(null, 10); observer.nextCount(null, 20); - observer.afterLastStatement(); + observer.onSuccess(); assertEquals(List.of("selected:5", "also updated:10", "also updated:20"), logger.calls); } @@ -159,7 +159,7 @@ public class LoggingObserverTest { observer.nextStatement(null, select()); observer.nextRows(null, asList(new Object(), new Object())); observer.nextBatchCount(null, new int[0]); - observer.afterLastStatement(); + observer.onSuccess(); assertEquals(List.of("selected:2"), logger.calls); } @@ -174,7 +174,7 @@ public class LoggingObserverTest { // a second batch statement should flush the first observer.nextStatement(null, batch()); observer.nextCount(null, 3); - observer.afterLastStatement(); + observer.onSuccess(); assertEquals(List.of("updated:2", "updated:3"), logger.calls); } diff --git a/cayenne/src/test/java/org/apache/cayenne/access/MockDataNode.java b/cayenne/src/test/java/org/apache/cayenne/access/MockDataNode.java index d669519fa..db5522043 100644 --- a/cayenne/src/test/java/org/apache/cayenne/access/MockDataNode.java +++ b/cayenne/src/test/java/org/apache/cayenne/access/MockDataNode.java @@ -78,14 +78,14 @@ public class MockDataNode extends DataNode { } @Override - public void performQueries(Collection queries, OperationObserver operationObserver) { + public void performQueries(Collection queries, OperationObserver callback) { runCount += queries.size(); if (replaceResults) { - initWithPresetResults(queries, operationObserver); + initWithPresetResults(queries, callback); } else { - node.performQueries(queries, operationObserver); + node.performQueries(queries, callback); } } diff --git a/cayenne/src/test/java/org/apache/cayenne/unit/telemetry/TelemetricDataNodeFactory.java b/cayenne/src/test/java/org/apache/cayenne/unit/telemetry/TelemetricDataNodeFactory.java index 8a49337d1..579ae7a2b 100644 --- a/cayenne/src/test/java/org/apache/cayenne/unit/telemetry/TelemetricDataNodeFactory.java +++ b/cayenne/src/test/java/org/apache/cayenne/unit/telemetry/TelemetricDataNodeFactory.java @@ -44,11 +44,11 @@ public class TelemetricDataNodeFactory extends DefaultDataNodeFactory { } @Override - public void performQueries(Collection<? extends Query> queries, OperationObserver operationObserver) { + public void performQueries(Collection<? extends Query> queries, OperationObserver callback) { if (blockingQueries) { Assertions.fail("Query is unexpected: " + queries); } - super.performQueries(queries, operationObserver); + super.performQueries(queries, callback); queryCounter.addAndGet(queries.size()); }
