This is an automated email from the ASF dual-hosted git repository.

rmaucher pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit f99f34a5fcbbf45f26f704d4b619d4c452feefa7
Merge: ae8680275a 2d9abd701b
Author: remm <[email protected]>
AuthorDate: Wed Oct 28 23:44:49 2026 +0100

    Merge branch 'main' of [email protected]:apache/tomcat.git into main

 .../org/apache/tomcat/jdbc/pool/jmx/ConnectionPool.java |  2 +-
 .../interceptor/TestResetAbandonedTimerStreaming.java   |  1 +
 .../jdbc/pool/interceptor/TestSlowQueryEviction.java    |  2 +-
 .../pool/interceptor/TestSlowQueryJmxMBeanSurface.java  |  6 +++---
 .../pool/interceptor/TestSlowQueryJmxNotifications.java | 10 +++++-----
 .../interceptor/TestStatementCacheJmxCacheSize.java     |  4 ++--
 .../pool/interceptor/TestStatementCacheReconnect.java   | 17 +++++++----------
 .../TestStatementCacheStaleEntryResurrection.java       |  7 +++----
 .../interceptor/TestStatementDecoratorIdentity.java     |  6 +++++-
 .../jdbc/pool/jmx/TestJmxNotificationTypeContract.java  |  2 +-
 10 files changed, 29 insertions(+), 28 deletions(-)

diff --cc 
modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/pool/interceptor/TestResetAbandonedTimerStreaming.java
index 6945021cf6,b21c2116e0..21601ef56f
--- 
a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/pool/interceptor/TestResetAbandonedTimerStreaming.java
+++ 
b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/pool/interceptor/TestResetAbandonedTimerStreaming.java
@@@ -248,11 -247,13 +248,12 @@@ class TestResetAbandonedTimerStreaming 
      @Test
      void resultSetsOnEveryAccessPathStayUsableAndHandleStable() throws 
Exception {
          awaitSessions(0);
 -        assertResultSetHandlesCompose(true);
 -        assertResultSetHandlesCompose(false);
 +        assertResultSetHandlesCompose();
      }
  
+     @SuppressWarnings("unlikely-arg-type") // Use of unlikely arg-type is 
deliberate
 -    private void assertResultSetHandlesCompose(boolean useStatementFacade) 
throws SQLException {
 -        DataSource ds = streamingPool(useStatementFacade);
 +    private void assertResultSetHandlesCompose() throws SQLException {
 +        DataSource ds = streamingPool();
          Connection con = ds.getConnection();
          String table = uniqueTable();
          try (Statement st = con.createStatement()) {
diff --cc 
modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/pool/interceptor/TestStatementDecoratorIdentity.java
index f02daedea9,dcf90537cb..553bcd81d0
--- 
a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/pool/interceptor/TestStatementDecoratorIdentity.java
+++ 
b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/pool/interceptor/TestStatementDecoratorIdentity.java
@@@ -61,153 -59,105 +61,156 @@@ class TestStatementDecoratorIdentity ex
          return ds;
      }
  
 +    /* The interceptor's own statement handle behind the facade's. */
 +    private static Statement statementBehindFacade(Statement facadeHandle)
 +            throws ReflectiveOperationException {
 +        return (Statement) proxiedObject(facadeHandle);
 +    }
 +
 +    /* The interceptor's own result set handle behind the facade's. */
 +    private static ResultSet resultSetBehindFacade(ResultSet facadeHandle)
 +            throws ReflectiveOperationException {
 +        return (ResultSet) proxiedObject(facadeHandle);
 +    }
 +
 +    /* The contract of an open statement handle, for one layer. */
 +    private static void assertOpenStatementHandle(Statement handle,
 +            Statement other, Connection pooled, String layer) {
 +        Assertions.assertTrue(handle.equals(handle),
 +                layer + ": a statement handle must be equal to itself");
 +        Assertions.assertFalse(handle.equals(null),
 +                layer + ": a statement handle is not equal to null");
 +        Assertions.assertFalse(handle.equals(pooled),
 +                layer + ": a statement handle is not equal to its 
connection");
 +        Assertions.assertFalse(handle.equals(other),
 +                layer + ": two statements are two handles");
 +        Assertions.assertFalse(other.equals(handle),
 +                layer + ": and not in the other direction either");
 +        int hash = handle.hashCode();
 +        Assertions.assertEquals(hash, handle.hashCode(),
 +                layer + ": hashCode must be a stable value of the handle 
itself");
 +        Set<Statement> seen = new HashSet<>();
 +        seen.add(handle);
 +        Assertions.assertTrue(seen.contains(handle),
 +                layer + ": hashCode must agree with equals");
 +    }
 +
 +    /* The contract of a closed statement handle, for one layer. */
 +    private static void assertClosedStatementHandle(Statement handle,
 +            int hashBeforeClose, Connection pooled, String layer) {
 +        // Neither method declares a checked exception, so a throwing handler
 +        // cannot reach the application as a SQLException - the proxy layer
 +        // wraps it. Both answers must simply be values.
 +        Assertions.assertDoesNotThrow(handle::hashCode,
 +                layer + ": hashCode on a closed handle must return, not 
throw");
 +        Assertions.assertEquals(hashBeforeClose, handle.hashCode(),
 +                layer + ": closing must not change the identity of a handle");
 +        Assertions.assertTrue(handle.equals(handle),
 +                layer + ": closing must not break reflexivity of a handle");
 +        Assertions.assertFalse(handle.equals(pooled),
 +                layer + ": a closed handle is still equal to nothing but 
itself");
 +        try {
 +            handle.hashCode();
 +        } catch (UndeclaredThrowableException e) {
 +            Assertions.fail(layer + ": hashCode on a closed handle must not "
 +                    + "surface as UndeclaredThrowableException: " + 
e.getCause());
 +        }
 +    }
 +
+     @SuppressWarnings("unlikely-arg-type") // Use of unlikely arg-type is 
deliberate
      @Test
      void aStatementHandleIsEqualOnlyToItselfWhileOpen() throws Exception {
 -        DataSource ds = decoratorPool(false);
 +        DataSource ds = decoratorPool();
          try (Connection pooled = ds.getConnection()) {
 -            try (Statement st = pooled.createStatement()) {
 -                Assertions.assertTrue(st.equals(st),
 -                        "a statement handle must be equal to itself");
 -                Assertions.assertFalse(st.equals(null),
 -                        "a statement handle is not equal to null");
 -                Assertions.assertFalse(st.equals(pooled),
 -                        "a statement handle is not equal to its connection");
 -                try (Statement other = pooled.createStatement()) {
 -                    Assertions.assertFalse(st.equals(other),
 -                            "two statements are two handles");
 -                    Assertions.assertFalse(other.equals(st));
 -                }
 -                int hash = st.hashCode();
 -                Assertions.assertEquals(hash, st.hashCode(),
 -                        "hashCode must be a stable value of the handle 
itself");
 -                Set<Statement> seen = new HashSet<>();
 -                seen.add(st);
 -                Assertions.assertTrue(seen.contains(st),
 -                        "hashCode must agree with equals");
 +            try (Statement st = pooled.createStatement();
 +                    Statement other = pooled.createStatement()) {
 +                assertOpenStatementHandle(st, other, pooled, "the statement 
facade");
 +                assertOpenStatementHandle(statementBehindFacade(st),
 +                        statementBehindFacade(other), pooled,
 +                        "the decorator's own proxy");
              }
          }
      }
  
+     @SuppressWarnings("unlikely-arg-type") // Use of unlikely arg-type is 
deliberate
      @Test
      void aClosedStatementHandleKeepsAnsweringWithItsOwnIdentity() throws 
Exception {
 -        DataSource ds = decoratorPool(false);
 -        Connection pooled = ds.getConnection();
 -        try {
 +        DataSource ds = decoratorPool();
 +        try (Connection pooled = ds.getConnection()) {
              Statement st = pooled.createStatement();
 -            int hash = st.hashCode();
 +            // The decorator's proxy is reached while the handle is still
 +            // open; it is the layer this test was written for.
 +            Statement decoratorHandle = statementBehindFacade(st);
 +            int facadeHash = st.hashCode();
 +            int decoratorHash = decoratorHandle.hashCode();
              st.close();
  
 -            // Neither method declares a checked exception, so a throwing
 -            // handler cannot reach the application as a SQLException - the
 -            // proxy layer wraps it. Both answers must simply be values.
 -            Assertions.assertDoesNotThrow(st::hashCode,
 -                    "hashCode on a closed handle must return, not throw");
 -            Assertions.assertEquals(hash, st.hashCode(),
 -                    "closing must not change the identity of a handle");
 -            Assertions.assertTrue(st.equals(st),
 -                    "closing must not break reflexivity of a handle");
 -            Assertions.assertFalse(st.equals(pooled),
 -                    "a closed handle is still equal to nothing but itself");
 -            try {
 -                st.hashCode();
 -            } catch (UndeclaredThrowableException e) {
 -                Assertions.fail("hashCode on a closed handle must not surface 
as "
 -                        + "UndeclaredThrowableException: " + e.getCause());
 -            }
 -        } finally {
 -            pooled.close();
 +            assertClosedStatementHandle(st, facadeHash, pooled, "the 
statement facade");
 +            assertClosedStatementHandle(decoratorHandle, decoratorHash, 
pooled,
 +                    "the decorator's proxy");
          }
      }
  
+     @SuppressWarnings("unlikely-arg-type") // Use of unlikely arg-type is 
deliberate
      @Test
      void aResultSetHandleIsAnHonestHandleOpenAndClosed() throws Exception {
 -        DataSource ds = decoratorPool(false);
 +        DataSource ds = decoratorPool();
          try (Connection pooled = ds.getConnection()) {
 -            try (Statement st = pooled.createStatement()) {
 -                ResultSet rs = st.executeQuery("SELECT 1");
 -                Assertions.assertTrue(rs.next());
 +            Statement st = pooled.createStatement();
 +            ResultSet rs = st.executeQuery("SELECT 1");
 +            Assertions.assertTrue(rs.next());
 +            Statement decoratorSt = statementBehindFacade(st);
 +            ResultSet decoratorRs = resultSetBehindFacade(rs);
  
 -                Assertions.assertTrue(rs.equals(rs),
 -                        "a result set handle must be equal to itself");
 -                Assertions.assertFalse(rs.equals(null),
 -                        "a result set handle is not equal to null");
 -                Assertions.assertFalse(rs.equals(st),
 -                        "a result set handle is not equal to its statement");
 -                Assertions.assertFalse(rs.equals(new Object()),
 -                        "a result set handle is not equal to a foreign 
object");
 -                int hash = rs.hashCode();
 -                Assertions.assertEquals(hash, rs.hashCode(),
 -                        "hashCode must be a stable value of the handle 
itself");
 +            ResultSet facadeRs = rs;
 +            for (int layer = 0; layer < 2; layer++) {
 +                String name = layer == 0 ? "the statement facade"
 +                        : "the decorator's own proxies";
 +                Statement stHandle = layer == 0 ? st : decoratorSt;
 +                ResultSet rsHandle = layer == 0 ? facadeRs : decoratorRs;
 +
 +                Assertions.assertTrue(rsHandle.equals(rsHandle),
 +                        name + ": a result set handle must be equal to 
itself");
 +                Assertions.assertFalse(rsHandle.equals(null),
 +                        name + ": a result set handle is not equal to null");
 +                Assertions.assertFalse(rsHandle.equals(stHandle),
 +                        name + ": a result set handle is not equal to its 
statement");
 +                Assertions.assertFalse(rsHandle.equals(new Object()),
 +                        name + ": a result set handle is not equal to a 
foreign object");
 +                int hash = rsHandle.hashCode();
 +                Assertions.assertEquals(hash, rsHandle.hashCode(),
 +                        name + ": hashCode must be a stable value of the 
handle itself");
                  // the handle a result set reports must answer to the
 -                // statement handle the application holds
 -                Assertions.assertSame(st, rs.getStatement());
 -                Assertions.assertTrue(rs.getStatement().equals(st),
 -                        "the reported statement must be equal to the held 
handle");
 +                // statement handle of the same layer
 +                Assertions.assertSame(stHandle, rsHandle.getStatement(),
 +                        name + ": the statement behind the result set must be 
"
 +                                + "the handle of the same layer");
 +                
Assertions.assertTrue(rsHandle.getStatement().equals(stHandle),
 +                        name + ": the reported statement must be equal to the 
held handle");
                  // toString is answered by the proxy, not forwarded to the
                  // driver's cursor
 -                
Assertions.assertTrue(rs.toString().contains("ResultSetProxy"),
 -                        "the handle must describe itself, was: " + rs);
 -
 -                rs.close();
 -                st.close();
 -
 -                Assertions.assertTrue(rs.equals(rs),
 -                        "a closed result set handle must still be equal to 
itself");
 -                Assertions.assertEquals(hash, rs.hashCode(),
 -                        "closing must not change the identity of a handle");
 -                Assertions.assertDoesNotThrow(() -> 
Boolean.valueOf(rs.equals(rs)),
 -                        "equals on a closed handle must return, not throw");
 +                
Assertions.assertTrue(rsHandle.toString().contains("ResultSetProxy"),
 +                        name + ": the handle must describe itself, was: " + 
rsHandle);
 +            }
 +
 +            int facadeRsHash = facadeRs.hashCode();
 +            int decoratorRsHash = decoratorRs.hashCode();
 +            // Close through the application's handles; both layers see it.
 +            facadeRs.close();
 +            st.close();
 +
 +            for (int layer = 0; layer < 2; layer++) {
 +                String name = layer == 0 ? "the statement facade"
 +                        : "the decorator's proxy";
 +                ResultSet rsHandle = layer == 0 ? facadeRs : decoratorRs;
 +                int hash = layer == 0 ? facadeRsHash : decoratorRsHash;
 +
 +                Assertions.assertTrue(rsHandle.equals(rsHandle),
 +                        name + ": a closed result set handle must still be 
equal to itself");
 +                Assertions.assertEquals(hash, rsHandle.hashCode(),
 +                        name + ": closing must not change the identity of a 
handle");
-                 Assertions.assertDoesNotThrow(() -> rsHandle.equals(rsHandle),
++                Assertions.assertDoesNotThrow(() -> 
Boolean.valueOf(rsHandle.equals(rsHandle)),
 +                        name + ": equals on a closed handle must return, not 
throw");
              }
          }
      }
@@@ -263,60 -200,47 +266,61 @@@
      }
  
      /*
 -     * The facade absorbs the Object methods from outside the decorator, so
 -     * the configuration switch must not change any answer the application
 -     * gets.
 +     * The facade answers the Object methods from outside the decorator, and
 +     * since it is always there the application can never be routed around
 +     * it - but the decorator's proxies stay live underneath, and the answers
 +     * both layers give must obey the same contract.
       */
+     @SuppressWarnings("unlikely-arg-type") // Use of unlikely arg-type is 
deliberate
      @Test
 -    void bothConfigurationsAnswerTheSameWay() throws Exception {
 -        for (boolean facade : new boolean[] { false, true }) {
 -            String config = facade ? "with" : "without";
 -            DataSource ds = decoratorPool(facade);
 -            try (Connection pooled = ds.getConnection()) {
 -                Statement st = pooled.createStatement();
 -                ResultSet rs = st.executeQuery("SELECT 1");
 -                Assertions.assertTrue(rs.next(), config + " the facade");
 -
 -                Assertions.assertTrue(st.equals(st),
 -                        config + " the facade a statement handle is equal to 
itself");
 -                Assertions.assertFalse(st.equals(null),
 -                        config + " the facade equals(null) is false");
 -                Assertions.assertFalse(st.equals(rs),
 -                        config + " the facade a statement is not its result 
set");
 -                Assertions.assertTrue(rs.equals(rs),
 -                        config + " the facade a result set handle is equal to 
itself");
 -                Assertions.assertFalse(rs.equals(st),
 -                        config + " the facade a result set is not its 
statement");
 -                Assertions.assertTrue(rs.getStatement().equals(st),
 -                        config + " the facade the reported statement answers 
to the held handle");
 -
 -                int stHash = st.hashCode();
 -                int rsHash = rs.hashCode();
 -                rs.close();
 -                st.close();
 -
 -                Assertions.assertTrue(st.equals(st),
 -                        config + " the facade a closed statement stays equal 
to itself");
 -                Assertions.assertTrue(rs.equals(rs),
 -                        config + " the facade a closed result set stays equal 
to itself");
 -                Assertions.assertEquals(stHash, st.hashCode(),
 -                        config + " the facade the statement hash survives the 
close");
 -                Assertions.assertEquals(rsHash, rs.hashCode(),
 -                        config + " the facade the result set hash survives 
the close");
 +    void facadeHandleAndDecoratorHandleObeyTheSameContract() throws Exception 
{
 +        DataSource ds = decoratorPool();
 +        try (Connection pooled = ds.getConnection()) {
 +            Statement st = pooled.createStatement();
 +            ResultSet rs = st.executeQuery("SELECT 1");
 +            Assertions.assertTrue(rs.next());
 +            Statement[] statements = { st, statementBehindFacade(st) };
 +            ResultSet[] resultSets = { rs, resultSetBehindFacade(rs) };
 +
 +            for (int layer = 0; layer < 2; layer++) {
 +                String name = layer == 0 ? "the statement facade"
 +                        : "the decorator's own proxies";
 +                Statement s = statements[layer];
 +                ResultSet r = resultSets[layer];
 +
 +                Assertions.assertTrue(s.equals(s),
 +                        name + ": a statement handle is equal to itself");
 +                Assertions.assertFalse(s.equals(null),
 +                        name + ": equals(null) is false");
 +                Assertions.assertFalse(s.equals(r),
 +                        name + ": a statement is not its result set");
 +                Assertions.assertTrue(r.equals(r),
 +                        name + ": a result set handle is equal to itself");
 +                Assertions.assertFalse(r.equals(s),
 +                        name + ": a result set is not its statement");
 +                Assertions.assertTrue(r.getStatement().equals(s),
 +                        name + ": the reported statement answers to the held 
handle");
 +            }
 +
 +            int[] stHashes = { statements[0].hashCode(), 
statements[1].hashCode() };
 +            int[] rsHashes = { resultSets[0].hashCode(), 
resultSets[1].hashCode() };
 +            // Close through the application's handles; both layers then face
 +            // the same closed state.
 +            resultSets[0].close();
 +            statements[0].close();
 +
 +            for (int layer = 0; layer < 2; layer++) {
 +                String name = layer == 0 ? "the statement facade"
 +                        : "the decorator's own proxies";
 +
 +                
Assertions.assertTrue(statements[layer].equals(statements[layer]),
 +                        name + ": a closed statement stays equal to itself");
 +                
Assertions.assertTrue(resultSets[layer].equals(resultSets[layer]),
 +                        name + ": a closed result set stays equal to itself");
 +                Assertions.assertEquals(stHashes[layer], 
statements[layer].hashCode(),
 +                        name + ": the statement hash survives the close");
 +                Assertions.assertEquals(rsHashes[layer], 
resultSets[layer].hashCode(),
 +                        name + ": the result set hash survives the close");
              }
          }
      }


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to