From 3c12057de7583d3926a6d09c44a31857b0debcb2 Mon Sep 17 00:00:00 2001 From: Michael Christoff Date: Thu, 25 Jan 2024 21:43:44 -0500 Subject: [PATCH 1/5] make simplepool thread names generic (not related to http/1.1 or http/2 --- .../SimpleUndertowConnectionMaker.java | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/client/src/main/java/com/networknt/client/simplepool/undertow/SimpleUndertowConnectionMaker.java b/client/src/main/java/com/networknt/client/simplepool/undertow/SimpleUndertowConnectionMaker.java index 1184b8ccc5..c420f97ac5 100644 --- a/client/src/main/java/com/networknt/client/simplepool/undertow/SimpleUndertowConnectionMaker.java +++ b/client/src/main/java/com/networknt/client/simplepool/undertow/SimpleUndertowConnectionMaker.java @@ -69,8 +69,8 @@ public SimpleConnection makeConnection( final Set allCreatedConnections) throws RuntimeException { boolean isHttps = uri.getScheme().equalsIgnoreCase("https"); - XnioWorker worker = getWorker(isHttp2); - XnioSsl ssl = getSSL(isHttps, isHttp2); + XnioWorker worker = getWorker(); + XnioSsl ssl = getSSL(isHttps); OptionMap connectionOptions = getConnectionOptions(isHttp2); InetSocketAddress bindAddress = null; @@ -138,10 +138,9 @@ private static OptionMap getConnectionOptions(boolean isHttp2) { * WARNING: This is called by getSSL(). Therefore, this method must never * call getSSL(), or any method that transitively calls getSSL() * - * @param isHttp2 if true, sets worker thread names to show HTTP2 * @return new XnioWorker */ - private static XnioWorker getWorker(boolean isHttp2) + private static XnioWorker getWorker() { if(WORKER.get() != null) return WORKER.get(); @@ -151,7 +150,7 @@ private static XnioWorker getWorker(boolean isHttp2) Xnio xnio = Xnio.getInstance(Undertow.class.getClassLoader()); try { - WORKER.set(xnio.createWorker(null, getWorkerOptionMap(isHttp2))); + WORKER.set(xnio.createWorker(null, getWorkerOptionMap())); } catch (IOException e) { logger.error("Exception while creating new XnioWorker", e); throw new RuntimeException(e); @@ -160,13 +159,13 @@ private static XnioWorker getWorker(boolean isHttp2) return WORKER.get(); } - private static OptionMap getWorkerOptionMap(boolean isHttp2) + private static OptionMap getWorkerOptionMap() { OptionMap.Builder optionBuild = OptionMap.builder() .set(Options.WORKER_IO_THREADS, 8) .set(Options.TCP_NODELAY, true) .set(Options.KEEP_ALIVE, true) - .set(Options.WORKER_NAME, isHttp2 ? "Callback-HTTP2" : "Callback-HTTP11"); + .set(Options.WORKER_NAME, "simplepool"); return optionBuild.getMap(); } @@ -176,10 +175,9 @@ private static OptionMap getWorkerOptionMap(boolean isHttp2) * WARNING: This calls getWorker() * * @param isHttps true if this is an HTTPS connection - * @param isHttp2 if true, sets worker thread names to show HTTP2 * @return new XnioSSL */ - private static XnioSsl getSSL(boolean isHttps, boolean isHttp2) + private static XnioSsl getSSL(boolean isHttps) { if(!isHttps) return null; if(SSL.get() != null) return SSL.get(); @@ -189,7 +187,7 @@ private static XnioSsl getSSL(boolean isHttps, boolean isHttp2) if(SSL.get() != null) return SSL.get(); try { - SSL.set(new UndertowXnioSsl(getWorker(isHttp2).getXnio(), OptionMap.EMPTY, BUFFER_POOL, SimpleSSLContextMaker.createSSLContext())); + SSL.set(new UndertowXnioSsl(getWorker().getXnio(), OptionMap.EMPTY, BUFFER_POOL, SimpleSSLContextMaker.createSSLContext())); } catch (Exception e) { logger.error("Exception while creating new shared UndertowXnioSsl used to create connections", e); throw new RuntimeException(e); From f01b77228b4910b8a52e7d68e49c775c78795686 Mon Sep 17 00:00:00 2001 From: Michael Christoff Date: Thu, 14 Mar 2024 12:49:02 -0400 Subject: [PATCH 2/5] new custom exceptions --- .../exceptions/SimplePoolConnectionClosureException.java | 6 ++++++ .../exceptions/SimplePoolConnectionFailureException.java | 6 ++++++ .../SimplePoolConnectionLimitReachedException.java | 6 ++++++ 3 files changed, 18 insertions(+) create mode 100644 client/src/main/java/com/networknt/client/simplepool/exceptions/SimplePoolConnectionClosureException.java create mode 100644 client/src/main/java/com/networknt/client/simplepool/exceptions/SimplePoolConnectionFailureException.java create mode 100644 client/src/main/java/com/networknt/client/simplepool/exceptions/SimplePoolConnectionLimitReachedException.java diff --git a/client/src/main/java/com/networknt/client/simplepool/exceptions/SimplePoolConnectionClosureException.java b/client/src/main/java/com/networknt/client/simplepool/exceptions/SimplePoolConnectionClosureException.java new file mode 100644 index 0000000000..4b6215fbe9 --- /dev/null +++ b/client/src/main/java/com/networknt/client/simplepool/exceptions/SimplePoolConnectionClosureException.java @@ -0,0 +1,6 @@ +package com.networknt.client.simplepool.exceptions; + +public class SimplePoolConnectionClosureException extends RuntimeException { + public SimplePoolConnectionClosureException(String message) { super(message); } + public SimplePoolConnectionClosureException(String message, Exception e) { super(message, e); } +} diff --git a/client/src/main/java/com/networknt/client/simplepool/exceptions/SimplePoolConnectionFailureException.java b/client/src/main/java/com/networknt/client/simplepool/exceptions/SimplePoolConnectionFailureException.java new file mode 100644 index 0000000000..2bf2c6eb8f --- /dev/null +++ b/client/src/main/java/com/networknt/client/simplepool/exceptions/SimplePoolConnectionFailureException.java @@ -0,0 +1,6 @@ +package com.networknt.client.simplepool.exceptions; + +public class SimplePoolConnectionFailureException extends RuntimeException { + public SimplePoolConnectionFailureException(String message) { super(message); } + public SimplePoolConnectionFailureException(String message, Exception e) { super(message, e); } +} diff --git a/client/src/main/java/com/networknt/client/simplepool/exceptions/SimplePoolConnectionLimitReachedException.java b/client/src/main/java/com/networknt/client/simplepool/exceptions/SimplePoolConnectionLimitReachedException.java new file mode 100644 index 0000000000..175f369c17 --- /dev/null +++ b/client/src/main/java/com/networknt/client/simplepool/exceptions/SimplePoolConnectionLimitReachedException.java @@ -0,0 +1,6 @@ +package com.networknt.client.simplepool.exceptions; + +public class SimplePoolConnectionLimitReachedException extends RuntimeException { + public SimplePoolConnectionLimitReachedException(String message) { super(message); } + public SimplePoolConnectionLimitReachedException(String message, Exception e) { super(message, e); } +} From 9499b166e6c2d1dff82d5189cde46e01e7ac0bcb Mon Sep 17 00:00:00 2001 From: Michael Christoff Date: Thu, 14 Mar 2024 12:49:51 -0400 Subject: [PATCH 3/5] update to use new custom exceptions --- .../networknt/client/simplepool/SimpleConnectionState.java | 7 ++++--- .../client/simplepool/SimpleURIConnectionPool.java | 5 +++-- .../client/simplepool/mock/TestConnectionMaker.java | 4 ++-- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/client/src/main/java/com/networknt/client/simplepool/SimpleConnectionState.java b/client/src/main/java/com/networknt/client/simplepool/SimpleConnectionState.java index dcf91cd703..c1091f8e9e 100644 --- a/client/src/main/java/com/networknt/client/simplepool/SimpleConnectionState.java +++ b/client/src/main/java/com/networknt/client/simplepool/SimpleConnectionState.java @@ -26,6 +26,7 @@ import java.util.List; import java.util.ArrayList; import java.util.concurrent.ConcurrentHashMap; +import com.networknt.client.simplepool.exceptions.*; /*** * A SimpleConnectionState is a simplified interface for a connection, that also keeps track of the connection's state. @@ -160,7 +161,7 @@ public SimpleConnectionState( // throw exception if connection creation failed if(!connection.isOpen()) { if(logger.isDebugEnabled()) logger.debug("{} closed connection", logLabel(connection, now)); - throw new RuntimeException("[" + port(connection) + "] Error creating connection to " + uri.toString()); + throw new SimplePoolConnectionFailureException("[" + port(connection) + "] Error creating connection to " + uri.toString()); // start life-timer and determine connection type } else { @@ -206,7 +207,7 @@ public synchronized ConnectionToken borrow(long now) throws RuntimeException, Il if(borrowable(now)) { if(closed()) - throw new RuntimeException("Connection was unexpectedly closed"); + throw new SimplePoolConnectionClosureException("Connection was unexpectedly closed"); // add connectionToken to the Set of borrowed tokens borrowedTokens.add( (connectionToken = new ConnectionToken(connection)) ); @@ -218,7 +219,7 @@ public synchronized ConnectionToken borrow(long now) throws RuntimeException, Il } else { if(closed()) - throw new RuntimeException("Connection was unexpectedly closed"); + throw new SimplePoolConnectionClosureException("Connection was unexpectedly closed"); else throw new IllegalStateException("Attempt made to borrow connection outside of BORROWABLE state"); } diff --git a/client/src/main/java/com/networknt/client/simplepool/SimpleURIConnectionPool.java b/client/src/main/java/com/networknt/client/simplepool/SimpleURIConnectionPool.java index 0afcfe000f..b523a61659 100644 --- a/client/src/main/java/com/networknt/client/simplepool/SimpleURIConnectionPool.java +++ b/client/src/main/java/com/networknt/client/simplepool/SimpleURIConnectionPool.java @@ -21,11 +21,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import java.net.URI; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ThreadLocalRandom; +import com.networknt.client.simplepool.exceptions.*; /*** SimpleURIConnectionPool is a connection pool for a single URI, which means that it manages a pool of reusable @@ -108,7 +108,8 @@ public synchronized SimpleConnectionState.ConnectionToken borrow(long createConn connectionState = new SimpleConnectionState(EXPIRY_TIME, createConnectionTimeout, isHttp2, uri, allCreatedConnections, connectionMaker); trackedConnections.add(connectionState); } else - throw new RuntimeException("An attempt was made to exceed the maximum size of the " + uri.toString() + " connection pool"); + throw new SimplePoolConnectionLimitReachedException( + "An attempt was made to exceed the maximum size of the " + uri.toString() + " connection pool"); } SimpleConnectionState.ConnectionToken connectionToken = connectionState.borrow(now); diff --git a/client/src/main/java/com/networknt/client/simplepool/mock/TestConnectionMaker.java b/client/src/main/java/com/networknt/client/simplepool/mock/TestConnectionMaker.java index f2604a3824..e85e133edc 100644 --- a/client/src/main/java/com/networknt/client/simplepool/mock/TestConnectionMaker.java +++ b/client/src/main/java/com/networknt/client/simplepool/mock/TestConnectionMaker.java @@ -21,9 +21,9 @@ import com.networknt.client.simplepool.SimpleConnection; import com.networknt.client.simplepool.SimpleConnectionMaker; +import com.networknt.client.simplepool.exceptions.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import java.lang.reflect.Constructor; import java.net.URI; import java.util.Set; @@ -63,7 +63,7 @@ private SimpleConnection instantiateConnection(long createConnectionTimeout, fin try { connection = future.get(createConnectionTimeout, TimeUnit.SECONDS); } catch(Exception e) { - throw new RuntimeException("Connection creation timed-out"); + throw new SimplePoolConnectionFailureException("Connection creation timed-out"); } return connection; } From 0e74bc5eb36fda0c9eca70791f2f203deae4b3c0 Mon Sep 17 00:00:00 2001 From: Michael Christoff Date: Thu, 14 Mar 2024 12:51:17 -0400 Subject: [PATCH 4/5] correctly classify connection-creation timeouts by checking all future statuses (only WAITING means a timeout). Also update to use new custom exceptions --- .../SimpleUndertowConnectionMaker.java | 45 ++++++++++++++----- 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/client/src/main/java/com/networknt/client/simplepool/undertow/SimpleUndertowConnectionMaker.java b/client/src/main/java/com/networknt/client/simplepool/undertow/SimpleUndertowConnectionMaker.java index c420f97ac5..f2652e7839 100644 --- a/client/src/main/java/com/networknt/client/simplepool/undertow/SimpleUndertowConnectionMaker.java +++ b/client/src/main/java/com/networknt/client/simplepool/undertow/SimpleUndertowConnectionMaker.java @@ -22,6 +22,7 @@ import com.networknt.client.ClientConfig; import com.networknt.client.simplepool.SimpleConnection; import com.networknt.client.simplepool.SimpleConnectionMaker; +import com.networknt.client.simplepool.exceptions.*; import io.undertow.Undertow; import io.undertow.UndertowOptions; import io.undertow.client.ClientCallback; @@ -88,7 +89,7 @@ public void completed(ClientConnection connection) { @Override public void failed(IOException e) { - if(logger.isDebugEnabled()) logger.debug("Failed to establish new connection for uri: {}", uri); + logger.error("Failed to establish new connection for uri {}: {}", uri, exceptionDetails(e)); result.setException(e); } }; @@ -105,25 +106,34 @@ public void failed(IOException e) { /*** * Never returns null * - * @param timeoutSeconds - * @param future - * @return + * @param timeoutSeconds connection timeout in seconds + * @param future contains future response containing new connection + * @return the new Undertow connection wrapped in a SimpleConnection + * @throws RuntimeException if connection fails */ - private static SimpleConnection safeConnect(long timeoutSeconds, IoFuture future) + private static SimpleConnection safeConnect(long timeoutSeconds, IoFuture future) throws RuntimeException { - SimpleConnection connection = null; - - if(future.await(timeoutSeconds, TimeUnit.SECONDS) != org.xnio.IoFuture.Status.DONE) - throw new RuntimeException("Connection establishment timed out"); + switch(future.await(timeoutSeconds, TimeUnit.SECONDS)) { + case DONE: + break; + case WAITING: + throw new SimplePoolConnectionFailureException("Connection establishment timed out after " + timeoutSeconds + " second(s)"); + case FAILED: + Exception e = future.getException(); + throw new SimplePoolConnectionFailureException("Connection establishment failed: " + exceptionDetails(e), e); + default: + throw new SimplePoolConnectionFailureException("Connection establishment failed"); + } + SimpleConnection connection = null; try { connection = future.get(); } catch (IOException e) { - throw new RuntimeException("Connection establishment generated I/O exception", e); + throw new SimplePoolConnectionFailureException("Connection establishment generated I/O exception: " + exceptionDetails(e), e); } if(connection == null) - throw new RuntimeException("Connection establishment failed (null) - Full connection terminated"); + throw new SimplePoolConnectionFailureException("Connection establishment failed (null) - Full connection terminated"); return connection; } @@ -196,6 +206,19 @@ private static XnioSsl getSSL(boolean isHttps) return SSL.get(); } + /*** + * Handles empty Exception messages for printing in logs (to avoid having "null" in logs for empty Exception messages) + * + * @param e Exception to look for a detail message in + * @return the Exception message, or "" if the Exception does not contain a message + */ + public static String exceptionDetails(Exception e) { + if(e == null || e.getMessage() == null) + return ""; + else + return e.getMessage(); + } + public static String port(ClientConnection connection) { if(connection == null) return "NULL"; String url = connection.getLocalAddress().toString(); From c949c5d352605f04165399d98d610fd1a36ee519 Mon Sep 17 00:00:00 2001 From: Michael Christoff Date: Tue, 19 Mar 2024 02:54:25 -0400 Subject: [PATCH 5/5] add attributions and license --- .../SimplePoolConnectionClosureException.java | 20 +++++++++++++++++++ .../SimplePoolConnectionFailureException.java | 20 +++++++++++++++++++ ...lePoolConnectionLimitReachedException.java | 20 +++++++++++++++++++ 3 files changed, 60 insertions(+) diff --git a/client/src/main/java/com/networknt/client/simplepool/exceptions/SimplePoolConnectionClosureException.java b/client/src/main/java/com/networknt/client/simplepool/exceptions/SimplePoolConnectionClosureException.java index 4b6215fbe9..c331e67f81 100644 --- a/client/src/main/java/com/networknt/client/simplepool/exceptions/SimplePoolConnectionClosureException.java +++ b/client/src/main/java/com/networknt/client/simplepool/exceptions/SimplePoolConnectionClosureException.java @@ -1,3 +1,23 @@ +/* + * Licensed 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 + * + * http://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. + * + * @author miklish Michael N. Christoff + * + * testing / QA + * AkashWorkGit + * jaydeepparekh1311 + */ + package com.networknt.client.simplepool.exceptions; public class SimplePoolConnectionClosureException extends RuntimeException { diff --git a/client/src/main/java/com/networknt/client/simplepool/exceptions/SimplePoolConnectionFailureException.java b/client/src/main/java/com/networknt/client/simplepool/exceptions/SimplePoolConnectionFailureException.java index 2bf2c6eb8f..8a23bbc076 100644 --- a/client/src/main/java/com/networknt/client/simplepool/exceptions/SimplePoolConnectionFailureException.java +++ b/client/src/main/java/com/networknt/client/simplepool/exceptions/SimplePoolConnectionFailureException.java @@ -1,3 +1,23 @@ +/* + * Licensed 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 + * + * http://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. + * + * @author miklish Michael N. Christoff + * + * testing / QA + * AkashWorkGit + * jaydeepparekh1311 + */ + package com.networknt.client.simplepool.exceptions; public class SimplePoolConnectionFailureException extends RuntimeException { diff --git a/client/src/main/java/com/networknt/client/simplepool/exceptions/SimplePoolConnectionLimitReachedException.java b/client/src/main/java/com/networknt/client/simplepool/exceptions/SimplePoolConnectionLimitReachedException.java index 175f369c17..a6d3fef9e1 100644 --- a/client/src/main/java/com/networknt/client/simplepool/exceptions/SimplePoolConnectionLimitReachedException.java +++ b/client/src/main/java/com/networknt/client/simplepool/exceptions/SimplePoolConnectionLimitReachedException.java @@ -1,3 +1,23 @@ +/* + * Licensed 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 + * + * http://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. + * + * @author miklish Michael N. Christoff + * + * testing / QA + * AkashWorkGit + * jaydeepparekh1311 + */ + package com.networknt.client.simplepool.exceptions; public class SimplePoolConnectionLimitReachedException extends RuntimeException {