From d8c946543805fd85a844e77fdabf5332164bb8a2 Mon Sep 17 00:00:00 2001 From: IvanM <87393011+Ivan-Montes@users.noreply.github.com> Date: Wed, 16 Apr 2025 10:01:21 +0200 Subject: [PATCH 1/2] Add `andThen` method to `ConnectionPoolListener` --- Related: #5159 **Motivation:** Add `andThen` method to `ConnectionPoolListener` to chain more than one listener **Modifications:** - In `ConnectionPoolListener`, add `andThen` method. - In `ConnectionPoolListenerTest`, add test **Result:** - Closes #5159 - Supersedes #5166 This PR replaces the changes proposed in #5166, which is now outdated. - Now, we could chain more than one listener --- .../client/ConnectionPoolListener.java | 30 ++++++ .../client/ConnectionPoolListenerTest.java | 100 ++++++++++++++++++ 2 files changed, 130 insertions(+) create mode 100644 core/src/test/java/com/linecorp/armeria/client/ConnectionPoolListenerTest.java diff --git a/core/src/main/java/com/linecorp/armeria/client/ConnectionPoolListener.java b/core/src/main/java/com/linecorp/armeria/client/ConnectionPoolListener.java index 87cf5fb150d..207f6cbcf14 100644 --- a/core/src/main/java/com/linecorp/armeria/client/ConnectionPoolListener.java +++ b/core/src/main/java/com/linecorp/armeria/client/ConnectionPoolListener.java @@ -15,6 +15,8 @@ */ package com.linecorp.armeria.client; +import static java.util.Objects.requireNonNull; + import java.net.InetSocketAddress; import com.linecorp.armeria.common.SessionProtocol; @@ -136,4 +138,32 @@ default ConnectionPoolListener unwrap() { default void close() { // Do nothing by default. } + + /** + * Returns a new {@link ConnectionPoolListener} which combines two {@link ConnectionPoolListener}s. + */ + default ConnectionPoolListener andThen(ConnectionPoolListener nextConnectionPoolListener) { + requireNonNull(nextConnectionPoolListener, "nextConnectionPoolListener"); + return new ConnectionPoolListener() { + @Override + public void connectionOpen(SessionProtocol protocol, InetSocketAddress remoteAddr, + InetSocketAddress localAddr, AttributeMap attrs) throws Exception { + try { + ConnectionPoolListener.this.connectionOpen(protocol, remoteAddr, localAddr, attrs); + } finally { + nextConnectionPoolListener.connectionOpen(protocol, remoteAddr,localAddr,attrs); + } + } + + @Override + public void connectionClosed(SessionProtocol protocol, InetSocketAddress remoteAddr, + InetSocketAddress localAddr, AttributeMap attrs) throws Exception { + try { + ConnectionPoolListener.this.connectionClosed(protocol, remoteAddr, localAddr, attrs); + } finally { + nextConnectionPoolListener.connectionClosed(protocol, remoteAddr,localAddr,attrs); + } + } + }; + } } diff --git a/core/src/test/java/com/linecorp/armeria/client/ConnectionPoolListenerTest.java b/core/src/test/java/com/linecorp/armeria/client/ConnectionPoolListenerTest.java new file mode 100644 index 00000000000..0579bacfb9b --- /dev/null +++ b/core/src/test/java/com/linecorp/armeria/client/ConnectionPoolListenerTest.java @@ -0,0 +1,100 @@ +/* + * Copyright 2025 LINE Corporation + * + * LINE Corporation 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 com.linecorp.armeria.client; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.mockito.Mockito.mock; + +import java.net.InetSocketAddress; + +import org.junit.jupiter.api.Test; + +import com.linecorp.armeria.common.SessionProtocol; + +import io.netty.util.AttributeMap; + +class ConnectionPoolListenerTest { + + @Test + void andThen_shouldFinishWithoutErrors() { + + final Integer[] counterArray = new Integer[6]; + + final ConnectionPoolListener cpl1 = new ConnectionPoolListener() { + @Override + public void connectionOpen(SessionProtocol protocol, InetSocketAddress remoteAddr, + InetSocketAddress localAddr, AttributeMap attrs) throws Exception { + counterArray[0] = 0; + } + + @Override + public void connectionClosed(SessionProtocol protocol, InetSocketAddress remoteAddr, + InetSocketAddress localAddr, AttributeMap attrs) throws Exception { + counterArray[3] = 30; + } + }; + + final ConnectionPoolListener cpl2 = new ConnectionPoolListener() { + @Override + public void connectionOpen(SessionProtocol protocol, InetSocketAddress remoteAddr, + InetSocketAddress localAddr, AttributeMap attrs) throws Exception { + counterArray[1] = 10; + } + + @Override + public void connectionClosed(SessionProtocol protocol, InetSocketAddress remoteAddr, + InetSocketAddress localAddr, AttributeMap attrs) throws Exception { + counterArray[4] = 40; + } + }; + + final ConnectionPoolListener cpl3 = new ConnectionPoolListener() { + @Override + public void connectionOpen(SessionProtocol protocol, InetSocketAddress remoteAddr, + InetSocketAddress localAddr, AttributeMap attrs) throws Exception { + counterArray[2] = 20; + } + + @Override + public void connectionClosed(SessionProtocol protocol, InetSocketAddress remoteAddr, + InetSocketAddress localAddr, AttributeMap attrs) throws Exception { + counterArray[5] = 50; + } + }; + + final SessionProtocol protocol = SessionProtocol.HTTP; + final InetSocketAddress remoteAddr = new InetSocketAddress("localhost", 8080); + final InetSocketAddress localAddr = new InetSocketAddress("localhost", 9090); + final AttributeMap attrs = mock(AttributeMap.class); + + final ConnectionPoolListener cplCombined = cpl1.andThen(cpl2).andThen(cpl3); + + try { + cplCombined.connectionOpen(protocol, remoteAddr, localAddr, attrs); + cplCombined.connectionClosed(protocol, remoteAddr, localAddr, attrs); + } catch (Exception e) { + throw new RuntimeException(e); + } + + assertThat(counterArray[0]).isEqualTo(0); + assertThat(counterArray[1]).isEqualTo(10); + assertThat(counterArray[2]).isEqualTo(20); + assertThat(counterArray[3]).isEqualTo(30); + assertThat(counterArray[4]).isEqualTo(40); + assertThat(counterArray[5]).isEqualTo(50); + } +} From 896c7a9d7a9b8033951a774d17238ce4f25fdb76 Mon Sep 17 00:00:00 2001 From: IvanM <87393011+Ivan-Montes@users.noreply.github.com> Date: Thu, 17 Apr 2025 08:37:15 +0200 Subject: [PATCH 2/2] feat: apply suggested changes from PR review **Modifications:** - In `ConnectionPoolListener`, implement `close` method within the `andThen` method. - In `ConnectionPoolListener`, annotate the `andThen` method with `@UnstableApi`. - In `ConnectionPoolListenerTest`, add `throws Exception` to the method signature --- .../armeria/client/ConnectionPoolListener.java | 10 ++++++++++ .../armeria/client/ConnectionPoolListenerTest.java | 11 ++++------- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/com/linecorp/armeria/client/ConnectionPoolListener.java b/core/src/main/java/com/linecorp/armeria/client/ConnectionPoolListener.java index 207f6cbcf14..598bc27e1a7 100644 --- a/core/src/main/java/com/linecorp/armeria/client/ConnectionPoolListener.java +++ b/core/src/main/java/com/linecorp/armeria/client/ConnectionPoolListener.java @@ -142,6 +142,7 @@ default void close() { /** * Returns a new {@link ConnectionPoolListener} which combines two {@link ConnectionPoolListener}s. */ + @UnstableApi default ConnectionPoolListener andThen(ConnectionPoolListener nextConnectionPoolListener) { requireNonNull(nextConnectionPoolListener, "nextConnectionPoolListener"); return new ConnectionPoolListener() { @@ -164,6 +165,15 @@ public void connectionClosed(SessionProtocol protocol, InetSocketAddress remoteA nextConnectionPoolListener.connectionClosed(protocol, remoteAddr,localAddr,attrs); } } + + @Override + public void close() { + try { + ConnectionPoolListener.super.close(); + } finally { + nextConnectionPoolListener.close(); + } + } }; } } diff --git a/core/src/test/java/com/linecorp/armeria/client/ConnectionPoolListenerTest.java b/core/src/test/java/com/linecorp/armeria/client/ConnectionPoolListenerTest.java index 0579bacfb9b..288709f0c80 100644 --- a/core/src/test/java/com/linecorp/armeria/client/ConnectionPoolListenerTest.java +++ b/core/src/test/java/com/linecorp/armeria/client/ConnectionPoolListenerTest.java @@ -30,7 +30,7 @@ class ConnectionPoolListenerTest { @Test - void andThen_shouldFinishWithoutErrors() { + void andThen_shouldFinishWithoutErrors() throws Exception { final Integer[] counterArray = new Integer[6]; @@ -83,12 +83,9 @@ public void connectionClosed(SessionProtocol protocol, InetSocketAddress remoteA final ConnectionPoolListener cplCombined = cpl1.andThen(cpl2).andThen(cpl3); - try { - cplCombined.connectionOpen(protocol, remoteAddr, localAddr, attrs); - cplCombined.connectionClosed(protocol, remoteAddr, localAddr, attrs); - } catch (Exception e) { - throw new RuntimeException(e); - } + cplCombined.connectionOpen(protocol, remoteAddr, localAddr, attrs); + cplCombined.connectionClosed(protocol, remoteAddr, localAddr, attrs); + cplCombined.close(); assertThat(counterArray[0]).isEqualTo(0); assertThat(counterArray[1]).isEqualTo(10);