From d10160b4ceb370a1728850d4c883e305b2ca5540 Mon Sep 17 00:00:00 2001 From: tomas-sexenian Date: Mon, 23 Oct 2023 17:53:02 -0300 Subject: [PATCH 01/15] Add HTTP connection pool info to JMX Issue:104837 --- ...tomPoolingHttpClientConnectionManager.java | 116 ++++++++++++++++++ .../genexus/internet/HttpClientJavaLib.java | 24 +++- .../genexus/internet/IConnectionObserver.java | 9 ++ .../genexus/management/HTTPConnectionJMX.java | 50 ++++++++ .../management/HTTPConnectionJMXBean.java | 6 + .../com/genexus/management/HTTPPoolJMX.java | 78 ++++++++++++ .../genexus/management/HTTPPoolJMXMBean.java | 8 ++ .../com/genexus/management/MBeanUtils.java | 50 +++++++- 8 files changed, 336 insertions(+), 5 deletions(-) create mode 100644 java/src/main/java/com/genexus/internet/CustomPoolingHttpClientConnectionManager.java create mode 100644 java/src/main/java/com/genexus/internet/IConnectionObserver.java create mode 100644 java/src/main/java/com/genexus/management/HTTPConnectionJMX.java create mode 100644 java/src/main/java/com/genexus/management/HTTPConnectionJMXBean.java create mode 100644 java/src/main/java/com/genexus/management/HTTPPoolJMX.java create mode 100644 java/src/main/java/com/genexus/management/HTTPPoolJMXMBean.java diff --git a/java/src/main/java/com/genexus/internet/CustomPoolingHttpClientConnectionManager.java b/java/src/main/java/com/genexus/internet/CustomPoolingHttpClientConnectionManager.java new file mode 100644 index 000000000..7223fd8b8 --- /dev/null +++ b/java/src/main/java/com/genexus/internet/CustomPoolingHttpClientConnectionManager.java @@ -0,0 +1,116 @@ +package com.genexus.internet; + +import org.apache.http.HttpClientConnection; +import org.apache.http.config.Registry; +import org.apache.http.conn.ConnectionPoolTimeoutException; +import org.apache.http.conn.ConnectionRequest; +import org.apache.http.conn.ManagedHttpClientConnection; +import org.apache.http.conn.routing.HttpRoute; +import org.apache.http.conn.socket.ConnectionSocketFactory; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.apache.http.pool.PoolEntry; +import org.apache.http.pool.PoolEntryCallback; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; + +public class CustomPoolingHttpClientConnectionManager extends PoolingHttpClientConnectionManager { + private final List observers = new ArrayList<>(); + + public CustomPoolingHttpClientConnectionManager(Registry socketFactoryRegistry){ + super(socketFactoryRegistry); + } + + public void addObserver(IConnectionObserver observer) { + observers.add(observer); + } + + @Override + public ConnectionRequest requestConnection(HttpRoute route, Object state) { + final ConnectionRequest originalRequest = super.requestConnection(route, state); + + return new ConnectionRequest() { + @Override + public boolean cancel() { + return originalRequest.cancel(); + } + + @Override + public HttpClientConnection get(long timeout, TimeUnit tunit) throws InterruptedException, ExecutionException, ConnectionPoolTimeoutException { + HttpClientConnection connection = originalRequest.get(timeout, tunit); + + if (connection != null && !connection.isOpen()) { + notifyConnectionCreated(route); + } + + return connection; + } + }; + } + + @Override + public void closeExpiredConnections() { + Set closedRoutes = new HashSet<>(); + + // Enumerate over all connections and collect routes of the expired ones + super.enumAvailable(new PoolEntryCallback() { + @Override + public void process(PoolEntry entry) { + if (entry.isExpired(System.currentTimeMillis())) { + closedRoutes.add(entry.getRoute()); + } + } + }); + + // Close the expired connections + super.closeExpiredConnections(); + + // Notify for each closed connection + for (HttpRoute route : closedRoutes) { + notifyConnectionDestroyed(route); + } + } + + @Override + public void closeIdleConnections(long idletime, TimeUnit tunit) { + Set closedRoutes = new HashSet<>(); + long idleTimeoutMillis = tunit.toMillis(idletime); + + // Enumerate over all connections and collect routes of the idle ones + super.enumAvailable(new PoolEntryCallback() { + @Override + public void process(PoolEntry entry) { + if (entry.getUpdated() + idleTimeoutMillis < System.currentTimeMillis()) { + closedRoutes.add(entry.getRoute()); + } + } + }); + + // Close the idle connections + super.closeIdleConnections(idletime, tunit); + + // Notify for each closed connection + for (HttpRoute route : closedRoutes) { + notifyConnectionDestroyed(route); + } + } + + + private void notifyConnectionCreated(HttpRoute route) { + for (IConnectionObserver observer : observers) { + observer.onConnectionCreated(route); + } + } + + private void notifyConnectionDestroyed(HttpRoute route) { + for (IConnectionObserver observer : observers) { + observer.onConnectionDestroyed(route); + } + } +} + + diff --git a/java/src/main/java/com/genexus/internet/HttpClientJavaLib.java b/java/src/main/java/com/genexus/internet/HttpClientJavaLib.java index d95d16ec6..6ca1bc0da 100644 --- a/java/src/main/java/com/genexus/internet/HttpClientJavaLib.java +++ b/java/src/main/java/com/genexus/internet/HttpClientJavaLib.java @@ -12,12 +12,15 @@ import java.security.cert.CertificateException; import java.util.*; import com.genexus.ModelContext; +import com.genexus.management.HTTPPoolJMX; import com.genexus.util.IniFile; +import com.genexus.Application; import org.apache.http.*; import com.genexus.CommonUtil; import com.genexus.specific.java.*; import org.apache.http.HttpResponse; import org.apache.http.client.config.CookieSpecs; +import org.apache.http.conn.routing.HttpRoute; import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.protocol.HttpContext; import org.apache.http.auth.AuthSchemeProvider; @@ -43,7 +46,6 @@ import org.apache.http.impl.auth.SPNegoSchemeFactory; import org.apache.http.impl.client.*; import org.apache.http.impl.conn.DefaultProxyRoutePlanner; -import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.message.BasicHeaderElementIterator; import org.apache.http.protocol.HTTP; import org.apache.http.ssl.SSLContextBuilder; @@ -55,7 +57,7 @@ import javax.net.ssl.SSLContext; -public class HttpClientJavaLib extends GXHttpClient { +public class HttpClientJavaLib extends GXHttpClient implements IConnectionObserver { public HttpClientJavaLib() { getPoolInstance(); @@ -64,6 +66,7 @@ public HttpClientJavaLib() { cookies = new BasicCookieStore(); logger.info("Using apache http client implementation"); streamsToClose = new Vector<>(); + connManager.addObserver(this); } private static void getPoolInstance() { @@ -72,15 +75,28 @@ private static void getPoolInstance() { RegistryBuilder.create() .register("http", PlainConnectionSocketFactory.INSTANCE).register("https", getSSLSecureInstance()) .build(); - connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry); + connManager = new CustomPoolingHttpClientConnectionManager(socketFactoryRegistry); connManager.setMaxTotal((int) CommonUtil.val(clientCfg.getProperty("Client", "HTTPCLIENT_MAX_SIZE", "1000"))); connManager.setDefaultMaxPerRoute((int) CommonUtil.val(clientCfg.getProperty("Client", "HTTPCLIENT_MAX_PER_ROUTE", "1000"))); + + if (Application.isJMXEnabled()) + HTTPPoolJMX.CreateHTTPPoolJMX(connManager); } else { connManager.closeExpiredConnections(); } } + @Override + public void onConnectionCreated(HttpRoute route) { + System.out.println("Connection created"); + } + + @Override + public void onConnectionDestroyed(HttpRoute route) { + System.out.println("Connection destroyed"); + } + private ConnectionKeepAliveStrategy generateKeepAliveStrategy() { return new ConnectionKeepAliveStrategy() { @Override @@ -111,7 +127,7 @@ public void setTimeout(int timeout) private static Logger logger = org.apache.logging.log4j.LogManager.getLogger(HttpClientJavaLib.class); - private static PoolingHttpClientConnectionManager connManager = null; + private static CustomPoolingHttpClientConnectionManager connManager = null; private Integer statusCode = 0; private String reasonLine = ""; private HttpClientBuilder httpClientBuilder; diff --git a/java/src/main/java/com/genexus/internet/IConnectionObserver.java b/java/src/main/java/com/genexus/internet/IConnectionObserver.java new file mode 100644 index 000000000..0704d3d73 --- /dev/null +++ b/java/src/main/java/com/genexus/internet/IConnectionObserver.java @@ -0,0 +1,9 @@ +package com.genexus.internet; + +import org.apache.http.conn.routing.HttpRoute; + +public interface IConnectionObserver { + void onConnectionCreated(HttpRoute route); + void onConnectionDestroyed(HttpRoute route); +} + diff --git a/java/src/main/java/com/genexus/management/HTTPConnectionJMX.java b/java/src/main/java/com/genexus/management/HTTPConnectionJMX.java new file mode 100644 index 000000000..b5a573778 --- /dev/null +++ b/java/src/main/java/com/genexus/management/HTTPConnectionJMX.java @@ -0,0 +1,50 @@ +package com.genexus.management; + +import org.apache.http.conn.routing.HttpRoute; +import org.apache.logging.log4j.Logger; + +public class HTTPConnectionJMX implements HTTPConnectionJMXBean{ + + private static Logger log = org.apache.logging.log4j.LogManager.getLogger(HTTPPoolJMX.class); + + HttpRoute connection; + + public HTTPConnectionJMX(HttpRoute connection) + { + this.connection = connection; + } + + static public void CreateHTTPConnectionJMX(HttpRoute connection) + { + try + { + MBeanUtils.createMBean(connection); + } + catch(Exception e) + { + log.error("Cannot register HTTP connection MBean.", e); + } + } + + static public void DestroyHTTPConnectionJMX(HttpRoute connection) + { + try + { + MBeanUtils.destroyMBean(connection); + } + catch(Exception e) + { + log.error("Cannot destroy connection MBean.", e); + } + } + + public int getPort() + { + return connection.getTargetHost().getPort(); + } + + public String getHost() + { + return connection.getTargetHost().getHostName(); + } +} diff --git a/java/src/main/java/com/genexus/management/HTTPConnectionJMXBean.java b/java/src/main/java/com/genexus/management/HTTPConnectionJMXBean.java new file mode 100644 index 000000000..5e20f7281 --- /dev/null +++ b/java/src/main/java/com/genexus/management/HTTPConnectionJMXBean.java @@ -0,0 +1,6 @@ +package com.genexus.management; + +public interface HTTPConnectionJMXBean { + int getPort(); + String getHost(); +} \ No newline at end of file diff --git a/java/src/main/java/com/genexus/management/HTTPPoolJMX.java b/java/src/main/java/com/genexus/management/HTTPPoolJMX.java new file mode 100644 index 000000000..c7f57122c --- /dev/null +++ b/java/src/main/java/com/genexus/management/HTTPPoolJMX.java @@ -0,0 +1,78 @@ +package com.genexus.management; + +import javax.management.MBeanNotificationInfo; +import javax.management.Notification; +import javax.management.NotificationBroadcasterSupport; + +import org.apache.logging.log4j.Logger; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; + +public class HTTPPoolJMX extends NotificationBroadcasterSupport implements HTTPPoolJMXMBean{ + + private long sequenceNumber=0; + PoolingHttpClientConnectionManager connectionPool; + private long lastUserWaitingForLongTimeNotif = 0L; + private long lastPoollsFullNotif = 0L; + private static Logger log = org.apache.logging.log4j.LogManager.getLogger(HTTPPoolJMX.class); + + public HTTPPoolJMX(PoolingHttpClientConnectionManager connectionPool) { + this.connectionPool = connectionPool; + } + + static public void CreateHTTPPoolJMX(PoolingHttpClientConnectionManager httpConnectionPool) { + try { + MBeanUtils.createMBean(httpConnectionPool); + } + catch(Exception e) { + log.error("Cannot register HTTP connection pool MBean.", e); + } + } + + public int getNumberOfConnectionsInUse(){ + return connectionPool.getTotalStats().getAvailable(); + } + + public int getNumberOfRequestsWaiting(){ + return connectionPool.getTotalStats().getPending(); + } + + public int getNumberOfAvailableConnections(){ + return connectionPool.getTotalStats().getAvailable(); + } + + public int getMaxNumberOfConnections(){ + return connectionPool.getTotalStats().getMax(); + } + + public void PoolIsFull() { + if (System.currentTimeMillis() - lastPoollsFullNotif > 1000L) { + lastPoollsFullNotif = System.currentTimeMillis(); + Notification n = new Notification("com.genexus.managment.fullpool",this,sequenceNumber++,System.currentTimeMillis(),"The Connection Pool does not have available connections "); + + sendNotification(n); + } + } + + public void UserWaitingForLongTime() { + if (System.currentTimeMillis() - lastUserWaitingForLongTimeNotif > 1000L) + { + lastUserWaitingForLongTimeNotif = System.currentTimeMillis(); + Notification n = new Notification("com.genexus.managment.longtimeuserwaiting",this,sequenceNumber++,System.currentTimeMillis(),"User waiting a connection for a long time"); + + sendNotification(n); + } + } + + public MBeanNotificationInfo[] getNotificationInfo() { + String[] types = new String[] {"com.genexus.managment.fullpool"}; + String name = Notification.class.getName(); + String description = "The Connection Pool does not have available connections "; + MBeanNotificationInfo info = new MBeanNotificationInfo(types, name, description); + + types = new String[] {"com.genexus.managment.longtimeuserwaiting"}; + description = "User waiting a connection for a long time"; + MBeanNotificationInfo info1 = new MBeanNotificationInfo(types, name, description); + + return new MBeanNotificationInfo[] {info, info1}; + } +} diff --git a/java/src/main/java/com/genexus/management/HTTPPoolJMXMBean.java b/java/src/main/java/com/genexus/management/HTTPPoolJMXMBean.java new file mode 100644 index 000000000..439805312 --- /dev/null +++ b/java/src/main/java/com/genexus/management/HTTPPoolJMXMBean.java @@ -0,0 +1,8 @@ +package com.genexus.management; + +public interface HTTPPoolJMXMBean { + int getNumberOfConnectionsInUse(); + int getNumberOfRequestsWaiting(); + int getNumberOfAvailableConnections(); + int getMaxNumberOfConnections(); +} \ No newline at end of file diff --git a/java/src/main/java/com/genexus/management/MBeanUtils.java b/java/src/main/java/com/genexus/management/MBeanUtils.java index ba4056d9f..9e8481d57 100644 --- a/java/src/main/java/com/genexus/management/MBeanUtils.java +++ b/java/src/main/java/com/genexus/management/MBeanUtils.java @@ -17,6 +17,9 @@ import com.genexus.db.driver.ConnectionPool; import com.genexus.db.driver.DataSource; import com.genexus.db.driver.GXConnection; +import json.org.json.HTTP; +import org.apache.http.conn.routing.HttpRoute; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; public class MBeanUtils { @@ -130,6 +133,24 @@ public static void createMBean(ConnectionPool connectionPool) ConnectionPoolJMX mbean = new ConnectionPoolJMX(connectionPool); registerBean(mbean, "com.genexus.management:type=GeneXusApplicationServer.ApplicationName.DataStore.ConnectionPool,ApplicationName=" + connectionPool.getDataSource().getNamespace() + ",DataStore=" + connectionPool.getDataSource().name + ",name=R/W pool"); } + + public static void createMBean(PoolingHttpClientConnectionManager connectionPool) + { + MBeanServer mbs = getMBeanServer(); + if (mbs == null) + return; + HTTPPoolJMX mbean = new HTTPPoolJMX(connectionPool); + registerBean(mbean, "com.genexus.management:type=GeneXusApplicationServer.ApplicationName.HTTPPool,ApplicationName=" + connectionPool.hashCode() + ",HttpPool=" + connectionPool.toString() + ",name=Http Connection pool"); + } + + public static void createMBean(HttpRoute httpConnection) + { + MBeanServer mbs = getMBeanServer(); + if (mbs == null) + return; + HTTPConnectionJMX mbean = new HTTPConnectionJMX(httpConnection); + registerBean(mbean, "com.genexus.management:type=GeneXusApplicationServer.ApplicationName.HTTPPool.HTTPConnection,ApplicationName=" + httpConnection.hashCode() + ",HttpConnection=" + httpConnection.toString() + ",name=Http Connection"); + } public static void createMBean(GXConnection connection) { @@ -241,6 +262,33 @@ public static void destroyMBean(GXConnection connection) System.out.println(e); } } + + public static void destroyMBean(HttpRoute httpConnection) + { + MBeanServer mbs = getMBeanServer(); + if (mbs == null) + return; + + try + { + ObjectName name = new ObjectName("com.genexus.management:type=GeneXusApplicationServer.ApplicationName.HTTPPool.HTTPConnection,ApplicationName=" + httpConnection.hashCode() + ",HttpConnection=" + httpConnection.toString() + ",name=Http Connection"); + registeredObjects.removeElement(name); + + mbs.unregisterMBean(name); + } + catch(javax.management.MalformedObjectNameException e) + { + System.out.println(e); + } + catch(javax.management.InstanceNotFoundException e) + { + System.out.println(e); + } + catch(javax.management.MBeanRegistrationException e) + { + System.out.println(e); + } + } public static void destroyMBeanCache() { @@ -314,5 +362,5 @@ public static void unregisterObjects() System.out.println(e); } mbs = null; - } + } } From cbf040883f645daab9aefe69901629b7bdbe3642 Mon Sep 17 00:00:00 2001 From: tomas-sexenian Date: Tue, 24 Oct 2023 11:00:04 -0300 Subject: [PATCH 02/15] Call creation and destruction of mbeans --- .../main/java/com/genexus/internet/HttpClientJavaLib.java | 7 +++++-- .../java/com/genexus/internet/IConnectionObserver.java | 3 +-- java/src/main/java/com/genexus/management/MBeanUtils.java | 6 +++--- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/java/src/main/java/com/genexus/internet/HttpClientJavaLib.java b/java/src/main/java/com/genexus/internet/HttpClientJavaLib.java index 6ca1bc0da..7f92ae9fe 100644 --- a/java/src/main/java/com/genexus/internet/HttpClientJavaLib.java +++ b/java/src/main/java/com/genexus/internet/HttpClientJavaLib.java @@ -13,6 +13,7 @@ import java.util.*; import com.genexus.ModelContext; import com.genexus.management.HTTPPoolJMX; +import com.genexus.management.MBeanUtils; import com.genexus.util.IniFile; import com.genexus.Application; import org.apache.http.*; @@ -89,12 +90,14 @@ private static void getPoolInstance() { @Override public void onConnectionCreated(HttpRoute route) { - System.out.println("Connection created"); + if (Application.isJMXEnabled()) + MBeanUtils.createMBean(route); } @Override public void onConnectionDestroyed(HttpRoute route) { - System.out.println("Connection destroyed"); + if (Application.isJMXEnabled()) + MBeanUtils.destroyMBean(route); } private ConnectionKeepAliveStrategy generateKeepAliveStrategy() { diff --git a/java/src/main/java/com/genexus/internet/IConnectionObserver.java b/java/src/main/java/com/genexus/internet/IConnectionObserver.java index 0704d3d73..e47b817f8 100644 --- a/java/src/main/java/com/genexus/internet/IConnectionObserver.java +++ b/java/src/main/java/com/genexus/internet/IConnectionObserver.java @@ -5,5 +5,4 @@ public interface IConnectionObserver { void onConnectionCreated(HttpRoute route); void onConnectionDestroyed(HttpRoute route); -} - +} \ No newline at end of file diff --git a/java/src/main/java/com/genexus/management/MBeanUtils.java b/java/src/main/java/com/genexus/management/MBeanUtils.java index 9e8481d57..f87aa34e0 100644 --- a/java/src/main/java/com/genexus/management/MBeanUtils.java +++ b/java/src/main/java/com/genexus/management/MBeanUtils.java @@ -143,13 +143,13 @@ public static void createMBean(PoolingHttpClientConnectionManager connectionPool registerBean(mbean, "com.genexus.management:type=GeneXusApplicationServer.ApplicationName.HTTPPool,ApplicationName=" + connectionPool.hashCode() + ",HttpPool=" + connectionPool.toString() + ",name=Http Connection pool"); } - public static void createMBean(HttpRoute httpConnection) + public static void createMBean(HttpRoute httpRoute) { MBeanServer mbs = getMBeanServer(); if (mbs == null) return; - HTTPConnectionJMX mbean = new HTTPConnectionJMX(httpConnection); - registerBean(mbean, "com.genexus.management:type=GeneXusApplicationServer.ApplicationName.HTTPPool.HTTPConnection,ApplicationName=" + httpConnection.hashCode() + ",HttpConnection=" + httpConnection.toString() + ",name=Http Connection"); + HTTPConnectionJMX mbean = new HTTPConnectionJMX(httpRoute); + registerBean(mbean, "com.genexus.management:type=GeneXusApplicationServer.ApplicationName.HTTPPool.HTTPConnection,ApplicationName=" + httpRoute.hashCode() + ",HttpConnection=" + httpRoute.toString() + ",name=Http Connection"); } public static void createMBean(GXConnection connection) From 1ed48e9d914855f366028cdd38ab0b9c4b338d63 Mon Sep 17 00:00:00 2001 From: tomas-sexenian Date: Tue, 24 Oct 2023 11:15:54 -0300 Subject: [PATCH 03/15] Various fixes --- .../main/java/com/genexus/internet/HttpClientJavaLib.java | 5 +++-- .../main/java/com/genexus/management/HTTPConnectionJMX.java | 2 +- java/src/main/java/com/genexus/management/MBeanUtils.java | 6 +++--- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/java/src/main/java/com/genexus/internet/HttpClientJavaLib.java b/java/src/main/java/com/genexus/internet/HttpClientJavaLib.java index 7f92ae9fe..56f029b6d 100644 --- a/java/src/main/java/com/genexus/internet/HttpClientJavaLib.java +++ b/java/src/main/java/com/genexus/internet/HttpClientJavaLib.java @@ -12,6 +12,7 @@ import java.security.cert.CertificateException; import java.util.*; import com.genexus.ModelContext; +import com.genexus.management.HTTPConnectionJMX; import com.genexus.management.HTTPPoolJMX; import com.genexus.management.MBeanUtils; import com.genexus.util.IniFile; @@ -91,13 +92,13 @@ private static void getPoolInstance() { @Override public void onConnectionCreated(HttpRoute route) { if (Application.isJMXEnabled()) - MBeanUtils.createMBean(route); + HTTPConnectionJMX.CreateHTTPConnectionJMX(route); } @Override public void onConnectionDestroyed(HttpRoute route) { if (Application.isJMXEnabled()) - MBeanUtils.destroyMBean(route); + HTTPConnectionJMX.DestroyHTTPConnectionJMX(route); } private ConnectionKeepAliveStrategy generateKeepAliveStrategy() { diff --git a/java/src/main/java/com/genexus/management/HTTPConnectionJMX.java b/java/src/main/java/com/genexus/management/HTTPConnectionJMX.java index b5a573778..f13586464 100644 --- a/java/src/main/java/com/genexus/management/HTTPConnectionJMX.java +++ b/java/src/main/java/com/genexus/management/HTTPConnectionJMX.java @@ -5,7 +5,7 @@ public class HTTPConnectionJMX implements HTTPConnectionJMXBean{ - private static Logger log = org.apache.logging.log4j.LogManager.getLogger(HTTPPoolJMX.class); + private static Logger log = org.apache.logging.log4j.LogManager.getLogger(HTTPConnectionJMX.class); HttpRoute connection; diff --git a/java/src/main/java/com/genexus/management/MBeanUtils.java b/java/src/main/java/com/genexus/management/MBeanUtils.java index f87aa34e0..e6579dfac 100644 --- a/java/src/main/java/com/genexus/management/MBeanUtils.java +++ b/java/src/main/java/com/genexus/management/MBeanUtils.java @@ -149,7 +149,7 @@ public static void createMBean(HttpRoute httpRoute) if (mbs == null) return; HTTPConnectionJMX mbean = new HTTPConnectionJMX(httpRoute); - registerBean(mbean, "com.genexus.management:type=GeneXusApplicationServer.ApplicationName.HTTPPool.HTTPConnection,ApplicationName=" + httpRoute.hashCode() + ",HttpConnection=" + httpRoute.toString() + ",name=Http Connection"); + registerBean(mbean, "com.genexus.management:type=GeneXusApplicationServer.ApplicationName.HTTPPool.HTTPConnection,ApplicationName=" + httpRoute.getTargetHost().getHostName() + ",Port=" + httpRoute.getTargetHost().getPort()+ ",name=http connection"); } public static void createMBean(GXConnection connection) @@ -263,7 +263,7 @@ public static void destroyMBean(GXConnection connection) } } - public static void destroyMBean(HttpRoute httpConnection) + public static void destroyMBean(HttpRoute httpRoute) { MBeanServer mbs = getMBeanServer(); if (mbs == null) @@ -271,7 +271,7 @@ public static void destroyMBean(HttpRoute httpConnection) try { - ObjectName name = new ObjectName("com.genexus.management:type=GeneXusApplicationServer.ApplicationName.HTTPPool.HTTPConnection,ApplicationName=" + httpConnection.hashCode() + ",HttpConnection=" + httpConnection.toString() + ",name=Http Connection"); + ObjectName name = new ObjectName("com.genexus.management:type=GeneXusApplicationServer.ApplicationName.HTTPPool.HTTPConnection,ApplicationName=" + httpRoute.getTargetHost().getHostName() + ",Port=" + httpRoute.getTargetHost().getPort() + ",name=http connection"); registeredObjects.removeElement(name); mbs.unregisterMBean(name); From f8a78eb120ca6bcd9123b6d0c155b7b7bf8a966b Mon Sep 17 00:00:00 2001 From: tomas-sexenian Date: Wed, 25 Oct 2023 15:04:51 -0300 Subject: [PATCH 04/15] Better positioning of beans in monitoring console --- ...tomPoolingHttpClientConnectionManager.java | 55 +++++++------------ .../genexus/internet/HttpClientJavaLib.java | 20 +++---- .../genexus/management/HTTPConnectionJMX.java | 39 +++++-------- .../com/genexus/management/MBeanUtils.java | 28 ++++------ 4 files changed, 53 insertions(+), 89 deletions(-) diff --git a/java/src/main/java/com/genexus/internet/CustomPoolingHttpClientConnectionManager.java b/java/src/main/java/com/genexus/internet/CustomPoolingHttpClientConnectionManager.java index 7223fd8b8..760f3c473 100644 --- a/java/src/main/java/com/genexus/internet/CustomPoolingHttpClientConnectionManager.java +++ b/java/src/main/java/com/genexus/internet/CustomPoolingHttpClientConnectionManager.java @@ -4,12 +4,9 @@ import org.apache.http.config.Registry; import org.apache.http.conn.ConnectionPoolTimeoutException; import org.apache.http.conn.ConnectionRequest; -import org.apache.http.conn.ManagedHttpClientConnection; import org.apache.http.conn.routing.HttpRoute; import org.apache.http.conn.socket.ConnectionSocketFactory; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; -import org.apache.http.pool.PoolEntry; -import org.apache.http.pool.PoolEntryCallback; import java.util.ArrayList; import java.util.HashSet; @@ -43,9 +40,8 @@ public boolean cancel() { public HttpClientConnection get(long timeout, TimeUnit tunit) throws InterruptedException, ExecutionException, ConnectionPoolTimeoutException { HttpClientConnection connection = originalRequest.get(timeout, tunit); - if (connection != null && !connection.isOpen()) { + if (connection != null && !connection.isOpen()) notifyConnectionCreated(route); - } return connection; } @@ -54,62 +50,49 @@ public HttpClientConnection get(long timeout, TimeUnit tunit) throws Interrupted @Override public void closeExpiredConnections() { - Set closedRoutes = new HashSet<>(); + Set beforeClosing = new HashSet<>(); + Set afterClosing = new HashSet<>(); - // Enumerate over all connections and collect routes of the expired ones - super.enumAvailable(new PoolEntryCallback() { - @Override - public void process(PoolEntry entry) { - if (entry.isExpired(System.currentTimeMillis())) { - closedRoutes.add(entry.getRoute()); - } + super.enumAvailable(entry -> { + if (entry.isExpired(System.currentTimeMillis())) { + beforeClosing.add(entry.getRoute()); } }); - - // Close the expired connections super.closeExpiredConnections(); + super.enumAvailable(entry -> afterClosing.add(entry.getRoute())); + beforeClosing.removeAll(afterClosing); - // Notify for each closed connection - for (HttpRoute route : closedRoutes) { + for (HttpRoute route : beforeClosing) notifyConnectionDestroyed(route); - } } @Override public void closeIdleConnections(long idletime, TimeUnit tunit) { - Set closedRoutes = new HashSet<>(); + Set beforeClosing = new HashSet<>(); + Set afterClosing = new HashSet<>(); long idleTimeoutMillis = tunit.toMillis(idletime); - // Enumerate over all connections and collect routes of the idle ones - super.enumAvailable(new PoolEntryCallback() { - @Override - public void process(PoolEntry entry) { - if (entry.getUpdated() + idleTimeoutMillis < System.currentTimeMillis()) { - closedRoutes.add(entry.getRoute()); - } + super.enumAvailable(entry -> { + if (entry.getUpdated() + idleTimeoutMillis < System.currentTimeMillis()) { + beforeClosing.add(entry.getRoute()); } }); - - // Close the idle connections super.closeIdleConnections(idletime, tunit); + super.enumAvailable(entry -> afterClosing.add(entry.getRoute())); + beforeClosing.removeAll(afterClosing); - // Notify for each closed connection - for (HttpRoute route : closedRoutes) { + for (HttpRoute route : beforeClosing) notifyConnectionDestroyed(route); - } } - private void notifyConnectionCreated(HttpRoute route) { - for (IConnectionObserver observer : observers) { + for (IConnectionObserver observer : observers) observer.onConnectionCreated(route); - } } private void notifyConnectionDestroyed(HttpRoute route) { - for (IConnectionObserver observer : observers) { + for (IConnectionObserver observer : observers) observer.onConnectionDestroyed(route); - } } } diff --git a/java/src/main/java/com/genexus/internet/HttpClientJavaLib.java b/java/src/main/java/com/genexus/internet/HttpClientJavaLib.java index 56f029b6d..0974c0ceb 100644 --- a/java/src/main/java/com/genexus/internet/HttpClientJavaLib.java +++ b/java/src/main/java/com/genexus/internet/HttpClientJavaLib.java @@ -11,15 +11,9 @@ import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; import java.util.*; -import com.genexus.ModelContext; -import com.genexus.management.HTTPConnectionJMX; -import com.genexus.management.HTTPPoolJMX; -import com.genexus.management.MBeanUtils; -import com.genexus.util.IniFile; -import com.genexus.Application; +import java.net.URI; +import javax.net.ssl.SSLContext; import org.apache.http.*; -import com.genexus.CommonUtil; -import com.genexus.specific.java.*; import org.apache.http.HttpResponse; import org.apache.http.client.config.CookieSpecs; import org.apache.http.conn.routing.HttpRoute; @@ -55,9 +49,13 @@ import org.apache.http.util.EntityUtils; import org.apache.logging.log4j.Logger; import com.genexus.webpanels.HttpContextWeb; -import java.net.URI; - -import javax.net.ssl.SSLContext; +import com.genexus.ModelContext; +import com.genexus.management.HTTPConnectionJMX; +import com.genexus.management.HTTPPoolJMX; +import com.genexus.util.IniFile; +import com.genexus.Application; +import com.genexus.CommonUtil; +import com.genexus.specific.java.*; public class HttpClientJavaLib extends GXHttpClient implements IConnectionObserver { diff --git a/java/src/main/java/com/genexus/management/HTTPConnectionJMX.java b/java/src/main/java/com/genexus/management/HTTPConnectionJMX.java index f13586464..86662ef30 100644 --- a/java/src/main/java/com/genexus/management/HTTPConnectionJMX.java +++ b/java/src/main/java/com/genexus/management/HTTPConnectionJMX.java @@ -7,44 +7,35 @@ public class HTTPConnectionJMX implements HTTPConnectionJMXBean{ private static Logger log = org.apache.logging.log4j.LogManager.getLogger(HTTPConnectionJMX.class); - HttpRoute connection; + HttpRoute httpRoute; - public HTTPConnectionJMX(HttpRoute connection) - { - this.connection = connection; + public HTTPConnectionJMX(HttpRoute httpRoute) { + this.httpRoute = httpRoute; } - static public void CreateHTTPConnectionJMX(HttpRoute connection) - { - try - { + static public void CreateHTTPConnectionJMX(HttpRoute connection) { + try { MBeanUtils.createMBean(connection); } - catch(Exception e) - { - log.error("Cannot register HTTP connection MBean.", e); + catch(Exception e) { + log.error("Failed to register HTTP connection MBean.", e); } } - static public void DestroyHTTPConnectionJMX(HttpRoute connection) - { - try - { + static public void DestroyHTTPConnectionJMX(HttpRoute connection) { + try { MBeanUtils.destroyMBean(connection); } - catch(Exception e) - { - log.error("Cannot destroy connection MBean.", e); + catch(Exception e) { + log.error("Failed to destroy HTTP connection MBean.", e); } } - public int getPort() - { - return connection.getTargetHost().getPort(); + public int getPort() { + return httpRoute.getTargetHost().getPort(); } - public String getHost() - { - return connection.getTargetHost().getHostName(); + public String getHost() { + return httpRoute.getTargetHost().getHostName(); } } diff --git a/java/src/main/java/com/genexus/management/MBeanUtils.java b/java/src/main/java/com/genexus/management/MBeanUtils.java index e6579dfac..2e63b40e7 100644 --- a/java/src/main/java/com/genexus/management/MBeanUtils.java +++ b/java/src/main/java/com/genexus/management/MBeanUtils.java @@ -17,7 +17,6 @@ import com.genexus.db.driver.ConnectionPool; import com.genexus.db.driver.DataSource; import com.genexus.db.driver.GXConnection; -import json.org.json.HTTP; import org.apache.http.conn.routing.HttpRoute; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; @@ -134,22 +133,20 @@ public static void createMBean(ConnectionPool connectionPool) registerBean(mbean, "com.genexus.management:type=GeneXusApplicationServer.ApplicationName.DataStore.ConnectionPool,ApplicationName=" + connectionPool.getDataSource().getNamespace() + ",DataStore=" + connectionPool.getDataSource().name + ",name=R/W pool"); } - public static void createMBean(PoolingHttpClientConnectionManager connectionPool) - { + public static void createMBean(PoolingHttpClientConnectionManager connectionPool) { MBeanServer mbs = getMBeanServer(); if (mbs == null) return; HTTPPoolJMX mbean = new HTTPPoolJMX(connectionPool); - registerBean(mbean, "com.genexus.management:type=GeneXusApplicationServer.ApplicationName.HTTPPool,ApplicationName=" + connectionPool.hashCode() + ",HttpPool=" + connectionPool.toString() + ",name=Http Connection pool"); + registerBean(mbean, "com.genexus.management:type=GeneXusApplicationServer.HTTPPool,ApplicationName=Http connection pool"); } - public static void createMBean(HttpRoute httpRoute) - { + public static void createMBean(HttpRoute httpRoute) { MBeanServer mbs = getMBeanServer(); if (mbs == null) return; HTTPConnectionJMX mbean = new HTTPConnectionJMX(httpRoute); - registerBean(mbean, "com.genexus.management:type=GeneXusApplicationServer.ApplicationName.HTTPPool.HTTPConnection,ApplicationName=" + httpRoute.getTargetHost().getHostName() + ",Port=" + httpRoute.getTargetHost().getPort()+ ",name=http connection"); + registerBean(mbean, "com.genexus.management:type=GeneXusApplicationServer.HTTPPool.HTTPConnection,ApplicationName=" + httpRoute.getTargetHost().getHostName() + ",Port=" + httpRoute.getTargetHost().getPort() + ",name=http connection"); } public static void createMBean(GXConnection connection) @@ -263,29 +260,24 @@ public static void destroyMBean(GXConnection connection) } } - public static void destroyMBean(HttpRoute httpRoute) - { + public static void destroyMBean(HttpRoute httpRoute) { MBeanServer mbs = getMBeanServer(); if (mbs == null) return; - try - { - ObjectName name = new ObjectName("com.genexus.management:type=GeneXusApplicationServer.ApplicationName.HTTPPool.HTTPConnection,ApplicationName=" + httpRoute.getTargetHost().getHostName() + ",Port=" + httpRoute.getTargetHost().getPort() + ",name=http connection"); + try { + ObjectName name = new ObjectName("com.genexus.management:type=GeneXusApplicationServer.HTTPPool.HTTPConnection,ApplicationName=" + httpRoute.getTargetHost().getHostName() + ",Port=" + httpRoute.getTargetHost().getPort() + ",name=http connection"); registeredObjects.removeElement(name); mbs.unregisterMBean(name); } - catch(javax.management.MalformedObjectNameException e) - { + catch(javax.management.MalformedObjectNameException e) { System.out.println(e); } - catch(javax.management.InstanceNotFoundException e) - { + catch(javax.management.InstanceNotFoundException e) { System.out.println(e); } - catch(javax.management.MBeanRegistrationException e) - { + catch(javax.management.MBeanRegistrationException e) { System.out.println(e); } } From a15eaa7994cb9c94b767c4af58db6ecf6bb18a3c Mon Sep 17 00:00:00 2001 From: tomas-sexenian Date: Thu, 26 Oct 2023 12:12:01 -0300 Subject: [PATCH 05/15] Check used connections every 30 seconds --- ...tomPoolingHttpClientConnectionManager.java | 63 +++++++------------ .../genexus/internet/HttpClientJavaLib.java | 21 ++++--- .../com/genexus/management/HTTPPoolJMX.java | 11 +++- .../com/genexus/management/MBeanUtils.java | 27 +++++++- 4 files changed, 70 insertions(+), 52 deletions(-) diff --git a/java/src/main/java/com/genexus/internet/CustomPoolingHttpClientConnectionManager.java b/java/src/main/java/com/genexus/internet/CustomPoolingHttpClientConnectionManager.java index 760f3c473..7d70eba89 100644 --- a/java/src/main/java/com/genexus/internet/CustomPoolingHttpClientConnectionManager.java +++ b/java/src/main/java/com/genexus/internet/CustomPoolingHttpClientConnectionManager.java @@ -11,15 +11,35 @@ import java.util.ArrayList; import java.util.HashSet; import java.util.List; -import java.util.Set; import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class CustomPoolingHttpClientConnectionManager extends PoolingHttpClientConnectionManager { private final List observers = new ArrayList<>(); + private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); + + HashSet activeRoutes = new HashSet<>(this.getRoutes()); + public CustomPoolingHttpClientConnectionManager(Registry socketFactoryRegistry){ super(socketFactoryRegistry); + initializePeriodicPoolCheck(); + } + + private void initializePeriodicPoolCheck() { + Runnable task = () -> periodicPoolCheck(); + scheduler.scheduleAtFixedRate(task, 0, 30, TimeUnit.SECONDS); + } + + private void periodicPoolCheck() { + if (activeRoutes.size() > this.getRoutes().size()){ + activeRoutes.removeAll(this.getRoutes()); + for (HttpRoute route : activeRoutes) + notifyConnectionDestroyed(route); + } + activeRoutes = new HashSet<>(this.getRoutes()); } public void addObserver(IConnectionObserver observer) { @@ -40,51 +60,16 @@ public boolean cancel() { public HttpClientConnection get(long timeout, TimeUnit tunit) throws InterruptedException, ExecutionException, ConnectionPoolTimeoutException { HttpClientConnection connection = originalRequest.get(timeout, tunit); - if (connection != null && !connection.isOpen()) + if (connection != null && !connection.isOpen()){ notifyConnectionCreated(route); + activeRoutes.add(route); + } return connection; } }; } - @Override - public void closeExpiredConnections() { - Set beforeClosing = new HashSet<>(); - Set afterClosing = new HashSet<>(); - - super.enumAvailable(entry -> { - if (entry.isExpired(System.currentTimeMillis())) { - beforeClosing.add(entry.getRoute()); - } - }); - super.closeExpiredConnections(); - super.enumAvailable(entry -> afterClosing.add(entry.getRoute())); - beforeClosing.removeAll(afterClosing); - - for (HttpRoute route : beforeClosing) - notifyConnectionDestroyed(route); - } - - @Override - public void closeIdleConnections(long idletime, TimeUnit tunit) { - Set beforeClosing = new HashSet<>(); - Set afterClosing = new HashSet<>(); - long idleTimeoutMillis = tunit.toMillis(idletime); - - super.enumAvailable(entry -> { - if (entry.getUpdated() + idleTimeoutMillis < System.currentTimeMillis()) { - beforeClosing.add(entry.getRoute()); - } - }); - super.closeIdleConnections(idletime, tunit); - super.enumAvailable(entry -> afterClosing.add(entry.getRoute())); - beforeClosing.removeAll(afterClosing); - - for (HttpRoute route : beforeClosing) - notifyConnectionDestroyed(route); - } - private void notifyConnectionCreated(HttpRoute route) { for (IConnectionObserver observer : observers) observer.onConnectionCreated(route); diff --git a/java/src/main/java/com/genexus/internet/HttpClientJavaLib.java b/java/src/main/java/com/genexus/internet/HttpClientJavaLib.java index 0974c0ceb..a0b08bc85 100644 --- a/java/src/main/java/com/genexus/internet/HttpClientJavaLib.java +++ b/java/src/main/java/com/genexus/internet/HttpClientJavaLib.java @@ -2,6 +2,7 @@ import java.io.*; import java.net.InetAddress; +import java.net.URI; import java.net.URISyntaxException; import java.net.UnknownHostException; import java.nio.charset.StandardCharsets; @@ -11,7 +12,6 @@ import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; import java.util.*; -import java.net.URI; import javax.net.ssl.SSLContext; import org.apache.http.*; import org.apache.http.HttpResponse; @@ -99,6 +99,16 @@ public void onConnectionDestroyed(HttpRoute route) { HTTPConnectionJMX.DestroyHTTPConnectionJMX(route); } + @Override + protected void finalize() { + this.closeOpenedStreams(); + if (Application.isJMXEnabled()){ + for (HttpRoute route : connManager.getRoutes()) + HTTPConnectionJMX.DestroyHTTPConnectionJMX(route); + HTTPPoolJMX.DestroyHTTPPoolJMX(connManager); + } + } + private ConnectionKeepAliveStrategy generateKeepAliveStrategy() { return new ConnectionKeepAliveStrategy() { @Override @@ -145,7 +155,6 @@ public void setTimeout(int timeout) private static IniFile clientCfg = new ModelContext(ModelContext.getModelContextPackageClass()).getPreferences().getIniFile(); private static final String SET_COOKIE = "Set-Cookie"; private static final String COOKIE = "Cookie"; - private java.util.Vector streamsToClose; private void closeOpenedStreams() @@ -303,7 +312,7 @@ private CookieStore setAllStoredCookies() { CookieStore cookiesToSend = new BasicCookieStore(); if (!ModelContext.getModelContext().isNullHttpContext()) { // Caso de ejecucion de varias instancia de HttpClientJavaLib, por lo que se obtienen cookies desde sesion web del browser - String selfWebCookie = ((HttpContextWeb) ModelContext.getModelContext().getHttpContext()).getCookie(SET_COOKIE); + String selfWebCookie = ((HttpContextWeb) ModelContext.getModelContext().getHttpContext()).getCookie("Set-Cookie"); if (!selfWebCookie.isEmpty()) this.addHeader(COOKIE, selfWebCookie.replace("+",";")); @@ -756,10 +765,4 @@ public void cleanup() { resetErrorsAndConnParams(); } - @Override - protected void finalize() - { - this.closeOpenedStreams(); - } - } \ No newline at end of file diff --git a/java/src/main/java/com/genexus/management/HTTPPoolJMX.java b/java/src/main/java/com/genexus/management/HTTPPoolJMX.java index c7f57122c..fbf4afb2b 100644 --- a/java/src/main/java/com/genexus/management/HTTPPoolJMX.java +++ b/java/src/main/java/com/genexus/management/HTTPPoolJMX.java @@ -28,8 +28,17 @@ static public void CreateHTTPPoolJMX(PoolingHttpClientConnectionManager httpConn } } + static public void DestroyHTTPPoolJMX(PoolingHttpClientConnectionManager httpConnectionPool) { + try { + MBeanUtils.destroyMBean(httpConnectionPool); + } + catch(Exception e) { + log.error("Cannot register HTTP connection pool MBean.", e); + } + } + public int getNumberOfConnectionsInUse(){ - return connectionPool.getTotalStats().getAvailable(); + return connectionPool.getTotalStats().getLeased(); } public int getNumberOfRequestsWaiting(){ diff --git a/java/src/main/java/com/genexus/management/MBeanUtils.java b/java/src/main/java/com/genexus/management/MBeanUtils.java index 2e63b40e7..bfd644b65 100644 --- a/java/src/main/java/com/genexus/management/MBeanUtils.java +++ b/java/src/main/java/com/genexus/management/MBeanUtils.java @@ -23,10 +23,9 @@ public class MBeanUtils { private static MBeanServer mbs = null; - private static Vector registeredObjects = new Vector(); + private static Vector registeredObjects = new Vector<>(); - public MBeanUtils() { - } + public MBeanUtils() {} private static MBeanServer getMBeanServer() { @@ -281,6 +280,28 @@ public static void destroyMBean(HttpRoute httpRoute) { System.out.println(e); } } + + public static void destroyMBean(PoolingHttpClientConnectionManager httpConnectionPool) { + MBeanServer mbs = getMBeanServer(); + if (mbs == null) + return; + + try { + ObjectName name = new ObjectName("com.genexus.management:type=GeneXusApplicationServer.HTTPPool,ApplicationName=Http connection pool"); + registeredObjects.removeElement(name); + + mbs.unregisterMBean(name); + } + catch(javax.management.MalformedObjectNameException e) { + System.out.println(e); + } + catch(javax.management.InstanceNotFoundException e) { + System.out.println(e); + } + catch(javax.management.MBeanRegistrationException e) { + System.out.println(e); + } + } public static void destroyMBeanCache() { From 2a396b95a19fd5f97ab41e7c013e4bdd43ade8ff Mon Sep 17 00:00:00 2001 From: tomas-sexenian Date: Thu, 26 Oct 2023 14:00:57 -0300 Subject: [PATCH 06/15] Shutdown runnable when no longer needed --- .../internet/CustomPoolingHttpClientConnectionManager.java | 6 ++++++ java/src/main/java/com/genexus/management/MBeanUtils.java | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/java/src/main/java/com/genexus/internet/CustomPoolingHttpClientConnectionManager.java b/java/src/main/java/com/genexus/internet/CustomPoolingHttpClientConnectionManager.java index 7d70eba89..12db5cc30 100644 --- a/java/src/main/java/com/genexus/internet/CustomPoolingHttpClientConnectionManager.java +++ b/java/src/main/java/com/genexus/internet/CustomPoolingHttpClientConnectionManager.java @@ -79,6 +79,12 @@ private void notifyConnectionDestroyed(HttpRoute route) { for (IConnectionObserver observer : observers) observer.onConnectionDestroyed(route); } + + @Override + protected void finalize() throws Throwable { + super.finalize(); + scheduler.shutdown(); + } } diff --git a/java/src/main/java/com/genexus/management/MBeanUtils.java b/java/src/main/java/com/genexus/management/MBeanUtils.java index bfd644b65..c3baae29a 100644 --- a/java/src/main/java/com/genexus/management/MBeanUtils.java +++ b/java/src/main/java/com/genexus/management/MBeanUtils.java @@ -145,7 +145,7 @@ public static void createMBean(HttpRoute httpRoute) { if (mbs == null) return; HTTPConnectionJMX mbean = new HTTPConnectionJMX(httpRoute); - registerBean(mbean, "com.genexus.management:type=GeneXusApplicationServer.HTTPPool.HTTPConnection,ApplicationName=" + httpRoute.getTargetHost().getHostName() + ",Port=" + httpRoute.getTargetHost().getPort() + ",name=http connection"); + registerBean(mbean, "com.genexus.management:type=GeneXusApplicationServer.HTTPPool.HTTPConnection,ApplicationName=" + httpRoute.getTargetHost().getHostName() + ",Port=" + httpRoute.getTargetHost().getPort() + ",name=Http connection"); } public static void createMBean(GXConnection connection) @@ -265,7 +265,7 @@ public static void destroyMBean(HttpRoute httpRoute) { return; try { - ObjectName name = new ObjectName("com.genexus.management:type=GeneXusApplicationServer.HTTPPool.HTTPConnection,ApplicationName=" + httpRoute.getTargetHost().getHostName() + ",Port=" + httpRoute.getTargetHost().getPort() + ",name=http connection"); + ObjectName name = new ObjectName("com.genexus.management:type=GeneXusApplicationServer.HTTPPool.HTTPConnection,ApplicationName=" + httpRoute.getTargetHost().getHostName() + ",Port=" + httpRoute.getTargetHost().getPort() + ",name=Http connection"); registeredObjects.removeElement(name); mbs.unregisterMBean(name); From 5d8ba14b89c67cbf2a2c2dc51761412dbccd497f Mon Sep 17 00:00:00 2001 From: tomas-sexenian Date: Fri, 27 Oct 2023 10:16:20 -0300 Subject: [PATCH 07/15] Revert "Check used connections every 30 seconds" This reverts commit a15eaa7994cb9c94b767c4af58db6ecf6bb18a3c. --- ...tomPoolingHttpClientConnectionManager.java | 63 ++++++++++++------- .../genexus/internet/HttpClientJavaLib.java | 21 +++---- .../com/genexus/management/HTTPPoolJMX.java | 11 +--- .../com/genexus/management/MBeanUtils.java | 27 +------- 4 files changed, 52 insertions(+), 70 deletions(-) diff --git a/java/src/main/java/com/genexus/internet/CustomPoolingHttpClientConnectionManager.java b/java/src/main/java/com/genexus/internet/CustomPoolingHttpClientConnectionManager.java index 12db5cc30..cbd56d579 100644 --- a/java/src/main/java/com/genexus/internet/CustomPoolingHttpClientConnectionManager.java +++ b/java/src/main/java/com/genexus/internet/CustomPoolingHttpClientConnectionManager.java @@ -11,35 +11,15 @@ import java.util.ArrayList; import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.concurrent.ExecutionException; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class CustomPoolingHttpClientConnectionManager extends PoolingHttpClientConnectionManager { private final List observers = new ArrayList<>(); - private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); - - HashSet activeRoutes = new HashSet<>(this.getRoutes()); - public CustomPoolingHttpClientConnectionManager(Registry socketFactoryRegistry){ super(socketFactoryRegistry); - initializePeriodicPoolCheck(); - } - - private void initializePeriodicPoolCheck() { - Runnable task = () -> periodicPoolCheck(); - scheduler.scheduleAtFixedRate(task, 0, 30, TimeUnit.SECONDS); - } - - private void periodicPoolCheck() { - if (activeRoutes.size() > this.getRoutes().size()){ - activeRoutes.removeAll(this.getRoutes()); - for (HttpRoute route : activeRoutes) - notifyConnectionDestroyed(route); - } - activeRoutes = new HashSet<>(this.getRoutes()); } public void addObserver(IConnectionObserver observer) { @@ -60,16 +40,51 @@ public boolean cancel() { public HttpClientConnection get(long timeout, TimeUnit tunit) throws InterruptedException, ExecutionException, ConnectionPoolTimeoutException { HttpClientConnection connection = originalRequest.get(timeout, tunit); - if (connection != null && !connection.isOpen()){ + if (connection != null && !connection.isOpen()) notifyConnectionCreated(route); - activeRoutes.add(route); - } return connection; } }; } + @Override + public void closeExpiredConnections() { + Set beforeClosing = new HashSet<>(); + Set afterClosing = new HashSet<>(); + + super.enumAvailable(entry -> { + if (entry.isExpired(System.currentTimeMillis())) { + beforeClosing.add(entry.getRoute()); + } + }); + super.closeExpiredConnections(); + super.enumAvailable(entry -> afterClosing.add(entry.getRoute())); + beforeClosing.removeAll(afterClosing); + + for (HttpRoute route : beforeClosing) + notifyConnectionDestroyed(route); + } + + @Override + public void closeIdleConnections(long idletime, TimeUnit tunit) { + Set beforeClosing = new HashSet<>(); + Set afterClosing = new HashSet<>(); + long idleTimeoutMillis = tunit.toMillis(idletime); + + super.enumAvailable(entry -> { + if (entry.getUpdated() + idleTimeoutMillis < System.currentTimeMillis()) { + beforeClosing.add(entry.getRoute()); + } + }); + super.closeIdleConnections(idletime, tunit); + super.enumAvailable(entry -> afterClosing.add(entry.getRoute())); + beforeClosing.removeAll(afterClosing); + + for (HttpRoute route : beforeClosing) + notifyConnectionDestroyed(route); + } + private void notifyConnectionCreated(HttpRoute route) { for (IConnectionObserver observer : observers) observer.onConnectionCreated(route); diff --git a/java/src/main/java/com/genexus/internet/HttpClientJavaLib.java b/java/src/main/java/com/genexus/internet/HttpClientJavaLib.java index a0b08bc85..0974c0ceb 100644 --- a/java/src/main/java/com/genexus/internet/HttpClientJavaLib.java +++ b/java/src/main/java/com/genexus/internet/HttpClientJavaLib.java @@ -2,7 +2,6 @@ import java.io.*; import java.net.InetAddress; -import java.net.URI; import java.net.URISyntaxException; import java.net.UnknownHostException; import java.nio.charset.StandardCharsets; @@ -12,6 +11,7 @@ import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; import java.util.*; +import java.net.URI; import javax.net.ssl.SSLContext; import org.apache.http.*; import org.apache.http.HttpResponse; @@ -99,16 +99,6 @@ public void onConnectionDestroyed(HttpRoute route) { HTTPConnectionJMX.DestroyHTTPConnectionJMX(route); } - @Override - protected void finalize() { - this.closeOpenedStreams(); - if (Application.isJMXEnabled()){ - for (HttpRoute route : connManager.getRoutes()) - HTTPConnectionJMX.DestroyHTTPConnectionJMX(route); - HTTPPoolJMX.DestroyHTTPPoolJMX(connManager); - } - } - private ConnectionKeepAliveStrategy generateKeepAliveStrategy() { return new ConnectionKeepAliveStrategy() { @Override @@ -155,6 +145,7 @@ public void setTimeout(int timeout) private static IniFile clientCfg = new ModelContext(ModelContext.getModelContextPackageClass()).getPreferences().getIniFile(); private static final String SET_COOKIE = "Set-Cookie"; private static final String COOKIE = "Cookie"; + private java.util.Vector streamsToClose; private void closeOpenedStreams() @@ -312,7 +303,7 @@ private CookieStore setAllStoredCookies() { CookieStore cookiesToSend = new BasicCookieStore(); if (!ModelContext.getModelContext().isNullHttpContext()) { // Caso de ejecucion de varias instancia de HttpClientJavaLib, por lo que se obtienen cookies desde sesion web del browser - String selfWebCookie = ((HttpContextWeb) ModelContext.getModelContext().getHttpContext()).getCookie("Set-Cookie"); + String selfWebCookie = ((HttpContextWeb) ModelContext.getModelContext().getHttpContext()).getCookie(SET_COOKIE); if (!selfWebCookie.isEmpty()) this.addHeader(COOKIE, selfWebCookie.replace("+",";")); @@ -765,4 +756,10 @@ public void cleanup() { resetErrorsAndConnParams(); } + @Override + protected void finalize() + { + this.closeOpenedStreams(); + } + } \ No newline at end of file diff --git a/java/src/main/java/com/genexus/management/HTTPPoolJMX.java b/java/src/main/java/com/genexus/management/HTTPPoolJMX.java index fbf4afb2b..c7f57122c 100644 --- a/java/src/main/java/com/genexus/management/HTTPPoolJMX.java +++ b/java/src/main/java/com/genexus/management/HTTPPoolJMX.java @@ -28,17 +28,8 @@ static public void CreateHTTPPoolJMX(PoolingHttpClientConnectionManager httpConn } } - static public void DestroyHTTPPoolJMX(PoolingHttpClientConnectionManager httpConnectionPool) { - try { - MBeanUtils.destroyMBean(httpConnectionPool); - } - catch(Exception e) { - log.error("Cannot register HTTP connection pool MBean.", e); - } - } - public int getNumberOfConnectionsInUse(){ - return connectionPool.getTotalStats().getLeased(); + return connectionPool.getTotalStats().getAvailable(); } public int getNumberOfRequestsWaiting(){ diff --git a/java/src/main/java/com/genexus/management/MBeanUtils.java b/java/src/main/java/com/genexus/management/MBeanUtils.java index c3baae29a..0521d0f7f 100644 --- a/java/src/main/java/com/genexus/management/MBeanUtils.java +++ b/java/src/main/java/com/genexus/management/MBeanUtils.java @@ -23,9 +23,10 @@ public class MBeanUtils { private static MBeanServer mbs = null; - private static Vector registeredObjects = new Vector<>(); + private static Vector registeredObjects = new Vector(); - public MBeanUtils() {} + public MBeanUtils() { + } private static MBeanServer getMBeanServer() { @@ -280,28 +281,6 @@ public static void destroyMBean(HttpRoute httpRoute) { System.out.println(e); } } - - public static void destroyMBean(PoolingHttpClientConnectionManager httpConnectionPool) { - MBeanServer mbs = getMBeanServer(); - if (mbs == null) - return; - - try { - ObjectName name = new ObjectName("com.genexus.management:type=GeneXusApplicationServer.HTTPPool,ApplicationName=Http connection pool"); - registeredObjects.removeElement(name); - - mbs.unregisterMBean(name); - } - catch(javax.management.MalformedObjectNameException e) { - System.out.println(e); - } - catch(javax.management.InstanceNotFoundException e) { - System.out.println(e); - } - catch(javax.management.MBeanRegistrationException e) { - System.out.println(e); - } - } public static void destroyMBeanCache() { From f6a89a39f13cf2b2725521acccd4747d2fc919d6 Mon Sep 17 00:00:00 2001 From: tomas-sexenian Date: Fri, 27 Oct 2023 11:50:16 -0300 Subject: [PATCH 08/15] Set difference to find closed connections --- ...tomPoolingHttpClientConnectionManager.java | 39 +++++-------------- .../genexus/management/HTTPConnectionJMX.java | 4 +- .../com/genexus/management/MBeanUtils.java | 6 +-- 3 files changed, 14 insertions(+), 35 deletions(-) diff --git a/java/src/main/java/com/genexus/internet/CustomPoolingHttpClientConnectionManager.java b/java/src/main/java/com/genexus/internet/CustomPoolingHttpClientConnectionManager.java index cbd56d579..793573251 100644 --- a/java/src/main/java/com/genexus/internet/CustomPoolingHttpClientConnectionManager.java +++ b/java/src/main/java/com/genexus/internet/CustomPoolingHttpClientConnectionManager.java @@ -18,7 +18,7 @@ public class CustomPoolingHttpClientConnectionManager extends PoolingHttpClientConnectionManager { private final List observers = new ArrayList<>(); - public CustomPoolingHttpClientConnectionManager(Registry socketFactoryRegistry){ + public CustomPoolingHttpClientConnectionManager(Registry socketFactoryRegistry) { super(socketFactoryRegistry); } @@ -50,39 +50,24 @@ public HttpClientConnection get(long timeout, TimeUnit tunit) throws Interrupted @Override public void closeExpiredConnections() { - Set beforeClosing = new HashSet<>(); - Set afterClosing = new HashSet<>(); - - super.enumAvailable(entry -> { - if (entry.isExpired(System.currentTimeMillis())) { - beforeClosing.add(entry.getRoute()); - } - }); + Set beforeClosing = new HashSet<>(this.getRoutes()); super.closeExpiredConnections(); - super.enumAvailable(entry -> afterClosing.add(entry.getRoute())); - beforeClosing.removeAll(afterClosing); + Set afterClosing = this.getRoutes(); for (HttpRoute route : beforeClosing) - notifyConnectionDestroyed(route); + if (!afterClosing.contains(route)) + notifyConnectionDestroyed(route); } @Override public void closeIdleConnections(long idletime, TimeUnit tunit) { - Set beforeClosing = new HashSet<>(); - Set afterClosing = new HashSet<>(); - long idleTimeoutMillis = tunit.toMillis(idletime); - - super.enumAvailable(entry -> { - if (entry.getUpdated() + idleTimeoutMillis < System.currentTimeMillis()) { - beforeClosing.add(entry.getRoute()); - } - }); + Set beforeClosing = new HashSet<>(this.getRoutes()); super.closeIdleConnections(idletime, tunit); - super.enumAvailable(entry -> afterClosing.add(entry.getRoute())); - beforeClosing.removeAll(afterClosing); + Set afterClosing = this.getRoutes(); for (HttpRoute route : beforeClosing) - notifyConnectionDestroyed(route); + if (!afterClosing.contains(route)) + notifyConnectionDestroyed(route); } private void notifyConnectionCreated(HttpRoute route) { @@ -94,12 +79,6 @@ private void notifyConnectionDestroyed(HttpRoute route) { for (IConnectionObserver observer : observers) observer.onConnectionDestroyed(route); } - - @Override - protected void finalize() throws Throwable { - super.finalize(); - scheduler.shutdown(); - } } diff --git a/java/src/main/java/com/genexus/management/HTTPConnectionJMX.java b/java/src/main/java/com/genexus/management/HTTPConnectionJMX.java index 86662ef30..fd71f0b3a 100644 --- a/java/src/main/java/com/genexus/management/HTTPConnectionJMX.java +++ b/java/src/main/java/com/genexus/management/HTTPConnectionJMX.java @@ -17,7 +17,7 @@ static public void CreateHTTPConnectionJMX(HttpRoute connection) { try { MBeanUtils.createMBean(connection); } - catch(Exception e) { + catch (Exception e) { log.error("Failed to register HTTP connection MBean.", e); } } @@ -26,7 +26,7 @@ static public void DestroyHTTPConnectionJMX(HttpRoute connection) { try { MBeanUtils.destroyMBean(connection); } - catch(Exception e) { + catch (Exception e) { log.error("Failed to destroy HTTP connection MBean.", e); } } diff --git a/java/src/main/java/com/genexus/management/MBeanUtils.java b/java/src/main/java/com/genexus/management/MBeanUtils.java index 0521d0f7f..2a1fd335e 100644 --- a/java/src/main/java/com/genexus/management/MBeanUtils.java +++ b/java/src/main/java/com/genexus/management/MBeanUtils.java @@ -138,7 +138,7 @@ public static void createMBean(PoolingHttpClientConnectionManager connectionPool if (mbs == null) return; HTTPPoolJMX mbean = new HTTPPoolJMX(connectionPool); - registerBean(mbean, "com.genexus.management:type=GeneXusApplicationServer.HTTPPool,ApplicationName=Http connection pool"); + registerBean(mbean, "com.genexus.management:type=GeneXusApplicationServer.HTTPPool,ApplicationName=Http connection pool, Http connection pool id =" + connectionPool.hashCode()); } public static void createMBean(HttpRoute httpRoute) { @@ -146,7 +146,7 @@ public static void createMBean(HttpRoute httpRoute) { if (mbs == null) return; HTTPConnectionJMX mbean = new HTTPConnectionJMX(httpRoute); - registerBean(mbean, "com.genexus.management:type=GeneXusApplicationServer.HTTPPool.HTTPConnection,ApplicationName=" + httpRoute.getTargetHost().getHostName() + ",Port=" + httpRoute.getTargetHost().getPort() + ",name=Http connection"); + registerBean(mbean, "com.genexus.management:type=GeneXusApplicationServer.HTTPPool.HTTPConnection,ApplicationName=" + httpRoute.getTargetHost().getHostName() + ",Port=" + httpRoute.getTargetHost().getPort() + ",Http connection id=" + httpRoute.hashCode()); } public static void createMBean(GXConnection connection) @@ -266,7 +266,7 @@ public static void destroyMBean(HttpRoute httpRoute) { return; try { - ObjectName name = new ObjectName("com.genexus.management:type=GeneXusApplicationServer.HTTPPool.HTTPConnection,ApplicationName=" + httpRoute.getTargetHost().getHostName() + ",Port=" + httpRoute.getTargetHost().getPort() + ",name=Http connection"); + ObjectName name = new ObjectName("com.genexus.management:type=GeneXusApplicationServer.HTTPPool.HTTPConnection,ApplicationName=" + httpRoute.getTargetHost().getHostName() + ",Port=" + httpRoute.getTargetHost().getPort() + ",Http connection id=" + httpRoute.hashCode()); registeredObjects.removeElement(name); mbs.unregisterMBean(name); From e06257bda9dce39e1ca1323367f4796f246e4ff0 Mon Sep 17 00:00:00 2001 From: tomas-sexenian Date: Fri, 27 Oct 2023 14:51:59 -0300 Subject: [PATCH 09/15] Destroy connection pool manager after cleanup --- .../genexus/internet/HttpClientJavaLib.java | 5 ++- .../com/genexus/management/HTTPPoolJMX.java | 21 ++++++++---- .../com/genexus/management/MBeanUtils.java | 32 +++++++++++++++++-- 3 files changed, 47 insertions(+), 11 deletions(-) diff --git a/java/src/main/java/com/genexus/internet/HttpClientJavaLib.java b/java/src/main/java/com/genexus/internet/HttpClientJavaLib.java index 0974c0ceb..477668d80 100644 --- a/java/src/main/java/com/genexus/internet/HttpClientJavaLib.java +++ b/java/src/main/java/com/genexus/internet/HttpClientJavaLib.java @@ -13,6 +13,7 @@ import java.util.*; import java.net.URI; import javax.net.ssl.SSLContext; + import org.apache.http.*; import org.apache.http.HttpResponse; import org.apache.http.client.config.CookieSpecs; @@ -48,6 +49,7 @@ import org.apache.http.ssl.SSLContexts; import org.apache.http.util.EntityUtils; import org.apache.logging.log4j.Logger; + import com.genexus.webpanels.HttpContextWeb; import com.genexus.ModelContext; import com.genexus.management.HTTPConnectionJMX; @@ -128,7 +130,6 @@ public void setTimeout(int timeout) } private static Logger logger = org.apache.logging.log4j.LogManager.getLogger(HttpClientJavaLib.class); - private static CustomPoolingHttpClientConnectionManager connManager = null; private Integer statusCode = 0; private String reasonLine = ""; @@ -754,6 +755,8 @@ public void toFile(String fileName) { public void cleanup() { resetErrorsAndConnParams(); + if (Application.isJMXEnabled()) + HTTPPoolJMX.DestroyHTTPPoolJMX(connManager); } @Override diff --git a/java/src/main/java/com/genexus/management/HTTPPoolJMX.java b/java/src/main/java/com/genexus/management/HTTPPoolJMX.java index c7f57122c..faddad4d2 100644 --- a/java/src/main/java/com/genexus/management/HTTPPoolJMX.java +++ b/java/src/main/java/com/genexus/management/HTTPPoolJMX.java @@ -3,28 +3,35 @@ import javax.management.MBeanNotificationInfo; import javax.management.Notification; import javax.management.NotificationBroadcasterSupport; - import org.apache.logging.log4j.Logger; -import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; - +import com.genexus.internet.CustomPoolingHttpClientConnectionManager; public class HTTPPoolJMX extends NotificationBroadcasterSupport implements HTTPPoolJMXMBean{ private long sequenceNumber=0; - PoolingHttpClientConnectionManager connectionPool; + CustomPoolingHttpClientConnectionManager connectionPool; private long lastUserWaitingForLongTimeNotif = 0L; private long lastPoollsFullNotif = 0L; private static Logger log = org.apache.logging.log4j.LogManager.getLogger(HTTPPoolJMX.class); - public HTTPPoolJMX(PoolingHttpClientConnectionManager connectionPool) { + public HTTPPoolJMX(CustomPoolingHttpClientConnectionManager connectionPool) { this.connectionPool = connectionPool; } - static public void CreateHTTPPoolJMX(PoolingHttpClientConnectionManager httpConnectionPool) { + static public void CreateHTTPPoolJMX(CustomPoolingHttpClientConnectionManager httpConnectionPool) { try { MBeanUtils.createMBean(httpConnectionPool); } catch(Exception e) { - log.error("Cannot register HTTP connection pool MBean.", e); + log.error("Failed to register HTTP connection pool MBean.", e); + } + } + + static public void DestroyHTTPPoolJMX(CustomPoolingHttpClientConnectionManager httpConnectionPool) { + try { + MBeanUtils.destroyMBean(httpConnectionPool); + } + catch(Exception e) { + log.error("Failed to destroy HTTP connection pool MBean.", e); } } diff --git a/java/src/main/java/com/genexus/management/MBeanUtils.java b/java/src/main/java/com/genexus/management/MBeanUtils.java index 2a1fd335e..e916c984c 100644 --- a/java/src/main/java/com/genexus/management/MBeanUtils.java +++ b/java/src/main/java/com/genexus/management/MBeanUtils.java @@ -8,7 +8,6 @@ import javax.management.MBeanServerFactory; import javax.management.MalformedObjectNameException; import javax.management.ObjectName; - import com.genexus.db.CacheValue; import com.genexus.db.InProcessCache; import com.genexus.db.LocalUserInformation; @@ -17,8 +16,8 @@ import com.genexus.db.driver.ConnectionPool; import com.genexus.db.driver.DataSource; import com.genexus.db.driver.GXConnection; +import com.genexus.internet.CustomPoolingHttpClientConnectionManager; import org.apache.http.conn.routing.HttpRoute; -import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; public class MBeanUtils { @@ -133,7 +132,7 @@ public static void createMBean(ConnectionPool connectionPool) registerBean(mbean, "com.genexus.management:type=GeneXusApplicationServer.ApplicationName.DataStore.ConnectionPool,ApplicationName=" + connectionPool.getDataSource().getNamespace() + ",DataStore=" + connectionPool.getDataSource().name + ",name=R/W pool"); } - public static void createMBean(PoolingHttpClientConnectionManager connectionPool) { + public static void createMBean(CustomPoolingHttpClientConnectionManager connectionPool) { MBeanServer mbs = getMBeanServer(); if (mbs == null) return; @@ -260,6 +259,33 @@ public static void destroyMBean(GXConnection connection) } } + public static void destroyMBean(CustomPoolingHttpClientConnectionManager connectionPool) + { + MBeanServer mbs = getMBeanServer(); + if (mbs == null) + return; + + try + { + ObjectName name = new ObjectName("com.genexus.management:type=GeneXusApplicationServer.HTTPPool,ApplicationName=Http connection pool, Http connection pool id =" + connectionPool.hashCode()); + registeredObjects.removeElement(name); + + mbs.unregisterMBean(name); + } + catch(javax.management.MalformedObjectNameException e) + { + System.out.println(e); + } + catch(javax.management.InstanceNotFoundException e) + { + System.out.println(e); + } + catch(javax.management.MBeanRegistrationException e) + { + System.out.println(e); + } + } + public static void destroyMBean(HttpRoute httpRoute) { MBeanServer mbs = getMBeanServer(); if (mbs == null) From 2248d844e1443417c5700d2dee0d1d1fa8c74440 Mon Sep 17 00:00:00 2001 From: tomas-sexenian Date: Mon, 30 Oct 2023 12:01:38 -0300 Subject: [PATCH 10/15] Identify each http route by an unique id --- ...tomPoolingHttpClientConnectionManager.java | 59 +++++++++---------- .../genexus/internet/HttpClientJavaLib.java | 19 +++--- .../genexus/internet/IConnectionObserver.java | 5 +- .../internet/IdentifiableHttpRoute.java | 32 ++++++++++ .../genexus/management/HTTPConnectionJMX.java | 16 ++--- .../com/genexus/management/MBeanUtils.java | 13 ++-- 6 files changed, 86 insertions(+), 58 deletions(-) create mode 100644 java/src/main/java/com/genexus/internet/IdentifiableHttpRoute.java diff --git a/java/src/main/java/com/genexus/internet/CustomPoolingHttpClientConnectionManager.java b/java/src/main/java/com/genexus/internet/CustomPoolingHttpClientConnectionManager.java index 793573251..090d2ad15 100644 --- a/java/src/main/java/com/genexus/internet/CustomPoolingHttpClientConnectionManager.java +++ b/java/src/main/java/com/genexus/internet/CustomPoolingHttpClientConnectionManager.java @@ -1,23 +1,22 @@ package com.genexus.internet; -import org.apache.http.HttpClientConnection; import org.apache.http.config.Registry; -import org.apache.http.conn.ConnectionPoolTimeoutException; import org.apache.http.conn.ConnectionRequest; import org.apache.http.conn.routing.HttpRoute; import org.apache.http.conn.socket.ConnectionSocketFactory; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import java.util.ArrayList; -import java.util.HashSet; import java.util.List; import java.util.Set; -import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; public class CustomPoolingHttpClientConnectionManager extends PoolingHttpClientConnectionManager { private final List observers = new ArrayList<>(); + private Set storedRoutes = this.getRoutes().stream().map(r -> new IdentifiableHttpRoute(r)).collect(Collectors.toSet()); + public CustomPoolingHttpClientConnectionManager(Registry socketFactoryRegistry) { super(socketFactoryRegistry); } @@ -28,57 +27,57 @@ public void addObserver(IConnectionObserver observer) { @Override public ConnectionRequest requestConnection(HttpRoute route, Object state) { - final ConnectionRequest originalRequest = super.requestConnection(route, state); - - return new ConnectionRequest() { - @Override - public boolean cancel() { - return originalRequest.cancel(); - } - - @Override - public HttpClientConnection get(long timeout, TimeUnit tunit) throws InterruptedException, ExecutionException, ConnectionPoolTimeoutException { - HttpClientConnection connection = originalRequest.get(timeout, tunit); - - if (connection != null && !connection.isOpen()) - notifyConnectionCreated(route); - - return connection; - } - }; + ConnectionRequest originalRequest; + originalRequest = super.requestConnection(route, state); + if (originalRequest != null){ + IdentifiableHttpRoute identifiableHttpRoute = new IdentifiableHttpRoute(route); + storedRoutes.add(identifiableHttpRoute); + notifyConnectionCreated(identifiableHttpRoute); + } + return originalRequest; } @Override public void closeExpiredConnections() { - Set beforeClosing = new HashSet<>(this.getRoutes()); + Set beforeClosing = storedRoutes; super.closeExpiredConnections(); Set afterClosing = this.getRoutes(); - for (HttpRoute route : beforeClosing) - if (!afterClosing.contains(route)) + for (IdentifiableHttpRoute route : beforeClosing) + if (!afterClosing.contains(route.getHttpRoute())) notifyConnectionDestroyed(route); + + storedRoutes = afterClosing.stream().map(r -> new IdentifiableHttpRoute(r)).collect(Collectors.toSet()); } @Override public void closeIdleConnections(long idletime, TimeUnit tunit) { - Set beforeClosing = new HashSet<>(this.getRoutes()); + Set beforeClosing = storedRoutes; super.closeIdleConnections(idletime, tunit); Set afterClosing = this.getRoutes(); - for (HttpRoute route : beforeClosing) - if (!afterClosing.contains(route)) + for (IdentifiableHttpRoute route : beforeClosing) + if (!afterClosing.contains(route.getHttpRoute())) notifyConnectionDestroyed(route); + + storedRoutes = afterClosing.stream().map(r -> new IdentifiableHttpRoute(r)).collect(Collectors.toSet()); } - private void notifyConnectionCreated(HttpRoute route) { + private void notifyConnectionCreated(IdentifiableHttpRoute route) { for (IConnectionObserver observer : observers) observer.onConnectionCreated(route); } - private void notifyConnectionDestroyed(HttpRoute route) { + private void notifyConnectionDestroyed(IdentifiableHttpRoute route) { for (IConnectionObserver observer : observers) observer.onConnectionDestroyed(route); } + + protected void finalize() { + for (IdentifiableHttpRoute route : storedRoutes) + for (IConnectionObserver observer : observers) + observer.onConnectionDestroyed(route); + } } diff --git a/java/src/main/java/com/genexus/internet/HttpClientJavaLib.java b/java/src/main/java/com/genexus/internet/HttpClientJavaLib.java index 477668d80..e8494c7c5 100644 --- a/java/src/main/java/com/genexus/internet/HttpClientJavaLib.java +++ b/java/src/main/java/com/genexus/internet/HttpClientJavaLib.java @@ -90,17 +90,24 @@ private static void getPoolInstance() { } @Override - public void onConnectionCreated(HttpRoute route) { + public void onConnectionCreated(IdentifiableHttpRoute route) { if (Application.isJMXEnabled()) HTTPConnectionJMX.CreateHTTPConnectionJMX(route); } @Override - public void onConnectionDestroyed(HttpRoute route) { + public void onConnectionDestroyed(IdentifiableHttpRoute route) { if (Application.isJMXEnabled()) HTTPConnectionJMX.DestroyHTTPConnectionJMX(route); } + @Override + protected void finalize() { + this.closeOpenedStreams(); + if (Application.isJMXEnabled()) + HTTPPoolJMX.DestroyHTTPPoolJMX(connManager); + } + private ConnectionKeepAliveStrategy generateKeepAliveStrategy() { return new ConnectionKeepAliveStrategy() { @Override @@ -755,14 +762,6 @@ public void toFile(String fileName) { public void cleanup() { resetErrorsAndConnParams(); - if (Application.isJMXEnabled()) - HTTPPoolJMX.DestroyHTTPPoolJMX(connManager); - } - - @Override - protected void finalize() - { - this.closeOpenedStreams(); } } \ No newline at end of file diff --git a/java/src/main/java/com/genexus/internet/IConnectionObserver.java b/java/src/main/java/com/genexus/internet/IConnectionObserver.java index e47b817f8..5dd5fe549 100644 --- a/java/src/main/java/com/genexus/internet/IConnectionObserver.java +++ b/java/src/main/java/com/genexus/internet/IConnectionObserver.java @@ -1,8 +1,7 @@ package com.genexus.internet; -import org.apache.http.conn.routing.HttpRoute; public interface IConnectionObserver { - void onConnectionCreated(HttpRoute route); - void onConnectionDestroyed(HttpRoute route); + void onConnectionCreated(IdentifiableHttpRoute route); + void onConnectionDestroyed(IdentifiableHttpRoute route); } \ No newline at end of file diff --git a/java/src/main/java/com/genexus/internet/IdentifiableHttpRoute.java b/java/src/main/java/com/genexus/internet/IdentifiableHttpRoute.java new file mode 100644 index 000000000..511e6b1ca --- /dev/null +++ b/java/src/main/java/com/genexus/internet/IdentifiableHttpRoute.java @@ -0,0 +1,32 @@ +package com.genexus.internet; + +import org.apache.http.conn.routing.HttpRoute; + +public class IdentifiableHttpRoute { + private HttpRoute httpRoute; + private static int instanceCount = 0; + private int id; + + public IdentifiableHttpRoute(HttpRoute httpRoute) { + this.httpRoute = httpRoute; + this.id = instanceCount++;; + } + + public int getId() { + return id; + } + + public HttpRoute getHttpRoute() { + return httpRoute; + } + + public String toString() { + return "IdentifiableHttpRoute{" + + "target=" + httpRoute.getTargetHost() + + ", localAddress=" + httpRoute.getLocalAddress() + + ", instance id='" + id + '\'' + + '}'; + } +} + + diff --git a/java/src/main/java/com/genexus/management/HTTPConnectionJMX.java b/java/src/main/java/com/genexus/management/HTTPConnectionJMX.java index fd71f0b3a..8c3cdda72 100644 --- a/java/src/main/java/com/genexus/management/HTTPConnectionJMX.java +++ b/java/src/main/java/com/genexus/management/HTTPConnectionJMX.java @@ -1,19 +1,19 @@ package com.genexus.management; -import org.apache.http.conn.routing.HttpRoute; +import com.genexus.internet.IdentifiableHttpRoute; import org.apache.logging.log4j.Logger; public class HTTPConnectionJMX implements HTTPConnectionJMXBean{ private static Logger log = org.apache.logging.log4j.LogManager.getLogger(HTTPConnectionJMX.class); - HttpRoute httpRoute; + IdentifiableHttpRoute idableHttpRoute; - public HTTPConnectionJMX(HttpRoute httpRoute) { - this.httpRoute = httpRoute; + public HTTPConnectionJMX(IdentifiableHttpRoute httpRoute) { + this.idableHttpRoute = httpRoute; } - static public void CreateHTTPConnectionJMX(HttpRoute connection) { + static public void CreateHTTPConnectionJMX(IdentifiableHttpRoute connection) { try { MBeanUtils.createMBean(connection); } @@ -22,7 +22,7 @@ static public void CreateHTTPConnectionJMX(HttpRoute connection) { } } - static public void DestroyHTTPConnectionJMX(HttpRoute connection) { + static public void DestroyHTTPConnectionJMX(IdentifiableHttpRoute connection) { try { MBeanUtils.destroyMBean(connection); } @@ -32,10 +32,10 @@ static public void DestroyHTTPConnectionJMX(HttpRoute connection) { } public int getPort() { - return httpRoute.getTargetHost().getPort(); + return idableHttpRoute.getHttpRoute().getTargetHost().getPort(); } public String getHost() { - return httpRoute.getTargetHost().getHostName(); + return idableHttpRoute.getHttpRoute().getTargetHost().getHostName(); } } diff --git a/java/src/main/java/com/genexus/management/MBeanUtils.java b/java/src/main/java/com/genexus/management/MBeanUtils.java index e916c984c..c6069bf96 100644 --- a/java/src/main/java/com/genexus/management/MBeanUtils.java +++ b/java/src/main/java/com/genexus/management/MBeanUtils.java @@ -17,8 +17,7 @@ import com.genexus.db.driver.DataSource; import com.genexus.db.driver.GXConnection; import com.genexus.internet.CustomPoolingHttpClientConnectionManager; -import org.apache.http.conn.routing.HttpRoute; - +import com.genexus.internet.IdentifiableHttpRoute; public class MBeanUtils { private static MBeanServer mbs = null; @@ -140,12 +139,12 @@ public static void createMBean(CustomPoolingHttpClientConnectionManager connecti registerBean(mbean, "com.genexus.management:type=GeneXusApplicationServer.HTTPPool,ApplicationName=Http connection pool, Http connection pool id =" + connectionPool.hashCode()); } - public static void createMBean(HttpRoute httpRoute) { + public static void createMBean(IdentifiableHttpRoute idableHttpRoute) { MBeanServer mbs = getMBeanServer(); if (mbs == null) return; - HTTPConnectionJMX mbean = new HTTPConnectionJMX(httpRoute); - registerBean(mbean, "com.genexus.management:type=GeneXusApplicationServer.HTTPPool.HTTPConnection,ApplicationName=" + httpRoute.getTargetHost().getHostName() + ",Port=" + httpRoute.getTargetHost().getPort() + ",Http connection id=" + httpRoute.hashCode()); + HTTPConnectionJMX mbean = new HTTPConnectionJMX(idableHttpRoute); + registerBean(mbean, "com.genexus.management:type=GeneXusApplicationServer.HTTPPool.HTTPConnection,ApplicationName=" + idableHttpRoute.getHttpRoute().getTargetHost().getHostName() + ",Port=" + idableHttpRoute.getHttpRoute().getTargetHost().getPort() + ",Http connection id=" + idableHttpRoute.getId()); } public static void createMBean(GXConnection connection) @@ -286,13 +285,13 @@ public static void destroyMBean(CustomPoolingHttpClientConnectionManager connect } } - public static void destroyMBean(HttpRoute httpRoute) { + public static void destroyMBean(IdentifiableHttpRoute idableHttpRoute) { MBeanServer mbs = getMBeanServer(); if (mbs == null) return; try { - ObjectName name = new ObjectName("com.genexus.management:type=GeneXusApplicationServer.HTTPPool.HTTPConnection,ApplicationName=" + httpRoute.getTargetHost().getHostName() + ",Port=" + httpRoute.getTargetHost().getPort() + ",Http connection id=" + httpRoute.hashCode()); + ObjectName name = new ObjectName("com.genexus.management:type=GeneXusApplicationServer.HTTPPool.HTTPConnection,ApplicationName=" + idableHttpRoute.getHttpRoute().getTargetHost().getHostName() + ",Port=" + idableHttpRoute.getHttpRoute().getTargetHost().getPort() + ",Http connection id=" + idableHttpRoute.getId()); registeredObjects.removeElement(name); mbs.unregisterMBean(name); From ff70d63c234b33f6a630029eb6adf19e7ac9b48a Mon Sep 17 00:00:00 2001 From: tomas-sexenian Date: Wed, 1 Nov 2023 10:52:54 -0300 Subject: [PATCH 11/15] Various fixes --- ...tomPoolingHttpClientConnectionManager.java | 48 ++++++++++++++----- .../genexus/internet/HttpClientJavaLib.java | 13 ++--- .../internet/IdentifiableHttpRoute.java | 16 ++++++- .../genexus/management/HTTPConnectionJMX.java | 8 ++-- .../com/genexus/management/MBeanUtils.java | 3 +- 5 files changed, 61 insertions(+), 27 deletions(-) diff --git a/java/src/main/java/com/genexus/internet/CustomPoolingHttpClientConnectionManager.java b/java/src/main/java/com/genexus/internet/CustomPoolingHttpClientConnectionManager.java index 090d2ad15..d1ac4c366 100644 --- a/java/src/main/java/com/genexus/internet/CustomPoolingHttpClientConnectionManager.java +++ b/java/src/main/java/com/genexus/internet/CustomPoolingHttpClientConnectionManager.java @@ -5,8 +5,9 @@ import org.apache.http.conn.routing.HttpRoute; import org.apache.http.conn.socket.ConnectionSocketFactory; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; - +import org.apache.http.pool.PoolStats; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.TimeUnit; @@ -16,6 +17,7 @@ public class CustomPoolingHttpClientConnectionManager extends PoolingHttpClientC private final List observers = new ArrayList<>(); private Set storedRoutes = this.getRoutes().stream().map(r -> new IdentifiableHttpRoute(r)).collect(Collectors.toSet()); + PoolStats storedStats = this.getTotalStats(); public CustomPoolingHttpClientConnectionManager(Registry socketFactoryRegistry) { super(socketFactoryRegistry); @@ -27,40 +29,60 @@ public void addObserver(IConnectionObserver observer) { @Override public ConnectionRequest requestConnection(HttpRoute route, Object state) { - ConnectionRequest originalRequest; - originalRequest = super.requestConnection(route, state); - if (originalRequest != null){ + PoolStats statsBefore = storedStats; + ConnectionRequest connectionRequest = super.requestConnection(route, state); + PoolStats statsAfter = this.getTotalStats(); + if (statsBefore.getAvailable() < statsAfter.getAvailable() || statsBefore.getLeased() < statsAfter.getLeased()) { IdentifiableHttpRoute identifiableHttpRoute = new IdentifiableHttpRoute(route); storedRoutes.add(identifiableHttpRoute); notifyConnectionCreated(identifiableHttpRoute); + storedStats = statsAfter; } - return originalRequest; + return connectionRequest; } @Override public void closeExpiredConnections() { Set beforeClosing = storedRoutes; + Set commonRoutes = new HashSet<>(); super.closeExpiredConnections(); Set afterClosing = this.getRoutes(); - for (IdentifiableHttpRoute route : beforeClosing) - if (!afterClosing.contains(route.getHttpRoute())) - notifyConnectionDestroyed(route); + for (IdentifiableHttpRoute identifiableHttpRoute : beforeClosing){ + Boolean found = false; + for (HttpRoute httpRoute : afterClosing){ + if (identifiableHttpRoute.equals(httpRoute)){ + found = true; + commonRoutes.add(identifiableHttpRoute); + break; + } + } + if (!found) notifyConnectionDestroyed(identifiableHttpRoute); + } - storedRoutes = afterClosing.stream().map(r -> new IdentifiableHttpRoute(r)).collect(Collectors.toSet()); + storedRoutes = commonRoutes; } @Override public void closeIdleConnections(long idletime, TimeUnit tunit) { Set beforeClosing = storedRoutes; + Set commonRoutes = new HashSet<>(); super.closeIdleConnections(idletime, tunit); Set afterClosing = this.getRoutes(); - for (IdentifiableHttpRoute route : beforeClosing) - if (!afterClosing.contains(route.getHttpRoute())) - notifyConnectionDestroyed(route); + for (IdentifiableHttpRoute identifiableHttpRoute : beforeClosing){ + Boolean found = false; + for (HttpRoute httpRoute : afterClosing){ + if (identifiableHttpRoute.equals(httpRoute)){ + found = true; + commonRoutes.add(identifiableHttpRoute); + break; + } + } + if (!found) notifyConnectionDestroyed(identifiableHttpRoute); + } - storedRoutes = afterClosing.stream().map(r -> new IdentifiableHttpRoute(r)).collect(Collectors.toSet()); + storedRoutes = commonRoutes; } private void notifyConnectionCreated(IdentifiableHttpRoute route) { diff --git a/java/src/main/java/com/genexus/internet/HttpClientJavaLib.java b/java/src/main/java/com/genexus/internet/HttpClientJavaLib.java index e8494c7c5..e7e70915c 100644 --- a/java/src/main/java/com/genexus/internet/HttpClientJavaLib.java +++ b/java/src/main/java/com/genexus/internet/HttpClientJavaLib.java @@ -17,8 +17,8 @@ import org.apache.http.*; import org.apache.http.HttpResponse; import org.apache.http.client.config.CookieSpecs; -import org.apache.http.conn.routing.HttpRoute; import org.apache.http.conn.ssl.NoopHostnameVerifier; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.protocol.HttpContext; import org.apache.http.auth.AuthSchemeProvider; import org.apache.http.auth.AuthScope; @@ -68,7 +68,8 @@ public HttpClientJavaLib() { cookies = new BasicCookieStore(); logger.info("Using apache http client implementation"); streamsToClose = new Vector<>(); - connManager.addObserver(this); + if (Application.isJMXEnabled()) + ((CustomPoolingHttpClientConnectionManager) connManager).addObserver(this); } private static void getPoolInstance() { @@ -77,12 +78,12 @@ private static void getPoolInstance() { RegistryBuilder.create() .register("http", PlainConnectionSocketFactory.INSTANCE).register("https", getSSLSecureInstance()) .build(); - connManager = new CustomPoolingHttpClientConnectionManager(socketFactoryRegistry); + connManager = Application.isJMXEnabled() ? new CustomPoolingHttpClientConnectionManager(socketFactoryRegistry) : new PoolingHttpClientConnectionManager(socketFactoryRegistry); connManager.setMaxTotal((int) CommonUtil.val(clientCfg.getProperty("Client", "HTTPCLIENT_MAX_SIZE", "1000"))); connManager.setDefaultMaxPerRoute((int) CommonUtil.val(clientCfg.getProperty("Client", "HTTPCLIENT_MAX_PER_ROUTE", "1000"))); if (Application.isJMXEnabled()) - HTTPPoolJMX.CreateHTTPPoolJMX(connManager); + HTTPPoolJMX.CreateHTTPPoolJMX((CustomPoolingHttpClientConnectionManager) connManager); } else { connManager.closeExpiredConnections(); @@ -105,7 +106,7 @@ public void onConnectionDestroyed(IdentifiableHttpRoute route) { protected void finalize() { this.closeOpenedStreams(); if (Application.isJMXEnabled()) - HTTPPoolJMX.DestroyHTTPPoolJMX(connManager); + HTTPPoolJMX.DestroyHTTPPoolJMX((CustomPoolingHttpClientConnectionManager) connManager); } private ConnectionKeepAliveStrategy generateKeepAliveStrategy() { @@ -137,7 +138,7 @@ public void setTimeout(int timeout) } private static Logger logger = org.apache.logging.log4j.LogManager.getLogger(HttpClientJavaLib.class); - private static CustomPoolingHttpClientConnectionManager connManager = null; + private static PoolingHttpClientConnectionManager connManager = null; private Integer statusCode = 0; private String reasonLine = ""; private HttpClientBuilder httpClientBuilder; diff --git a/java/src/main/java/com/genexus/internet/IdentifiableHttpRoute.java b/java/src/main/java/com/genexus/internet/IdentifiableHttpRoute.java index 511e6b1ca..9a47ee97b 100644 --- a/java/src/main/java/com/genexus/internet/IdentifiableHttpRoute.java +++ b/java/src/main/java/com/genexus/internet/IdentifiableHttpRoute.java @@ -5,14 +5,14 @@ public class IdentifiableHttpRoute { private HttpRoute httpRoute; private static int instanceCount = 0; - private int id; + private long id; public IdentifiableHttpRoute(HttpRoute httpRoute) { this.httpRoute = httpRoute; this.id = instanceCount++;; } - public int getId() { + public long getId() { return id; } @@ -27,6 +27,18 @@ public String toString() { ", instance id='" + id + '\'' + '}'; } + + @Override + public final boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof HttpRoute)) + return false; + HttpRoute that = (HttpRoute) o; + Boolean sameHost = this.getHttpRoute().getTargetHost().getHostName().equals(that.getTargetHost().getHostName()); + Boolean samePort = this.getHttpRoute().getTargetHost().getPort() == that.getTargetHost().getPort(); + return sameHost && samePort; + } } diff --git a/java/src/main/java/com/genexus/management/HTTPConnectionJMX.java b/java/src/main/java/com/genexus/management/HTTPConnectionJMX.java index 8c3cdda72..bec91ea69 100644 --- a/java/src/main/java/com/genexus/management/HTTPConnectionJMX.java +++ b/java/src/main/java/com/genexus/management/HTTPConnectionJMX.java @@ -7,10 +7,10 @@ public class HTTPConnectionJMX implements HTTPConnectionJMXBean{ private static Logger log = org.apache.logging.log4j.LogManager.getLogger(HTTPConnectionJMX.class); - IdentifiableHttpRoute idableHttpRoute; + IdentifiableHttpRoute identifiableHttpRoute; public HTTPConnectionJMX(IdentifiableHttpRoute httpRoute) { - this.idableHttpRoute = httpRoute; + this.identifiableHttpRoute = httpRoute; } static public void CreateHTTPConnectionJMX(IdentifiableHttpRoute connection) { @@ -32,10 +32,10 @@ static public void DestroyHTTPConnectionJMX(IdentifiableHttpRoute connection) { } public int getPort() { - return idableHttpRoute.getHttpRoute().getTargetHost().getPort(); + return identifiableHttpRoute.getHttpRoute().getTargetHost().getPort(); } public String getHost() { - return idableHttpRoute.getHttpRoute().getTargetHost().getHostName(); + return identifiableHttpRoute.getHttpRoute().getTargetHost().getHostName(); } } diff --git a/java/src/main/java/com/genexus/management/MBeanUtils.java b/java/src/main/java/com/genexus/management/MBeanUtils.java index c6069bf96..f80ad43a6 100644 --- a/java/src/main/java/com/genexus/management/MBeanUtils.java +++ b/java/src/main/java/com/genexus/management/MBeanUtils.java @@ -293,14 +293,13 @@ public static void destroyMBean(IdentifiableHttpRoute idableHttpRoute) { try { ObjectName name = new ObjectName("com.genexus.management:type=GeneXusApplicationServer.HTTPPool.HTTPConnection,ApplicationName=" + idableHttpRoute.getHttpRoute().getTargetHost().getHostName() + ",Port=" + idableHttpRoute.getHttpRoute().getTargetHost().getPort() + ",Http connection id=" + idableHttpRoute.getId()); registeredObjects.removeElement(name); - mbs.unregisterMBean(name); } catch(javax.management.MalformedObjectNameException e) { System.out.println(e); } catch(javax.management.InstanceNotFoundException e) { - System.out.println(e); + // Intentionally left empty because PoolingHttpClientConnectionManager does not provide a concise way of knowing exactly which connections are being destroyed } catch(javax.management.MBeanRegistrationException e) { System.out.println(e); From 4a36b9f463b124266a9560adb480b8fc9b1761dd Mon Sep 17 00:00:00 2001 From: tomas-sexenian Date: Mon, 6 Nov 2023 12:18:29 -0300 Subject: [PATCH 12/15] Remove usage of custom connection pool --- ...tomPoolingHttpClientConnectionManager.java | 105 ------------------ .../genexus/internet/HttpClientJavaLib.java | 51 +++++---- .../genexus/internet/IConnectionObserver.java | 7 -- .../com/genexus/management/HTTPPoolJMX.java | 39 +------ .../com/genexus/management/MBeanUtils.java | 44 ++------ 5 files changed, 44 insertions(+), 202 deletions(-) delete mode 100644 java/src/main/java/com/genexus/internet/CustomPoolingHttpClientConnectionManager.java delete mode 100644 java/src/main/java/com/genexus/internet/IConnectionObserver.java diff --git a/java/src/main/java/com/genexus/internet/CustomPoolingHttpClientConnectionManager.java b/java/src/main/java/com/genexus/internet/CustomPoolingHttpClientConnectionManager.java deleted file mode 100644 index d1ac4c366..000000000 --- a/java/src/main/java/com/genexus/internet/CustomPoolingHttpClientConnectionManager.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.genexus.internet; - -import org.apache.http.config.Registry; -import org.apache.http.conn.ConnectionRequest; -import org.apache.http.conn.routing.HttpRoute; -import org.apache.http.conn.socket.ConnectionSocketFactory; -import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; -import org.apache.http.pool.PoolStats; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; - -public class CustomPoolingHttpClientConnectionManager extends PoolingHttpClientConnectionManager { - private final List observers = new ArrayList<>(); - - private Set storedRoutes = this.getRoutes().stream().map(r -> new IdentifiableHttpRoute(r)).collect(Collectors.toSet()); - PoolStats storedStats = this.getTotalStats(); - - public CustomPoolingHttpClientConnectionManager(Registry socketFactoryRegistry) { - super(socketFactoryRegistry); - } - - public void addObserver(IConnectionObserver observer) { - observers.add(observer); - } - - @Override - public ConnectionRequest requestConnection(HttpRoute route, Object state) { - PoolStats statsBefore = storedStats; - ConnectionRequest connectionRequest = super.requestConnection(route, state); - PoolStats statsAfter = this.getTotalStats(); - if (statsBefore.getAvailable() < statsAfter.getAvailable() || statsBefore.getLeased() < statsAfter.getLeased()) { - IdentifiableHttpRoute identifiableHttpRoute = new IdentifiableHttpRoute(route); - storedRoutes.add(identifiableHttpRoute); - notifyConnectionCreated(identifiableHttpRoute); - storedStats = statsAfter; - } - return connectionRequest; - } - - @Override - public void closeExpiredConnections() { - Set beforeClosing = storedRoutes; - Set commonRoutes = new HashSet<>(); - super.closeExpiredConnections(); - Set afterClosing = this.getRoutes(); - - for (IdentifiableHttpRoute identifiableHttpRoute : beforeClosing){ - Boolean found = false; - for (HttpRoute httpRoute : afterClosing){ - if (identifiableHttpRoute.equals(httpRoute)){ - found = true; - commonRoutes.add(identifiableHttpRoute); - break; - } - } - if (!found) notifyConnectionDestroyed(identifiableHttpRoute); - } - - storedRoutes = commonRoutes; - } - - @Override - public void closeIdleConnections(long idletime, TimeUnit tunit) { - Set beforeClosing = storedRoutes; - Set commonRoutes = new HashSet<>(); - super.closeIdleConnections(idletime, tunit); - Set afterClosing = this.getRoutes(); - - for (IdentifiableHttpRoute identifiableHttpRoute : beforeClosing){ - Boolean found = false; - for (HttpRoute httpRoute : afterClosing){ - if (identifiableHttpRoute.equals(httpRoute)){ - found = true; - commonRoutes.add(identifiableHttpRoute); - break; - } - } - if (!found) notifyConnectionDestroyed(identifiableHttpRoute); - } - - storedRoutes = commonRoutes; - } - - private void notifyConnectionCreated(IdentifiableHttpRoute route) { - for (IConnectionObserver observer : observers) - observer.onConnectionCreated(route); - } - - private void notifyConnectionDestroyed(IdentifiableHttpRoute route) { - for (IConnectionObserver observer : observers) - observer.onConnectionDestroyed(route); - } - - protected void finalize() { - for (IdentifiableHttpRoute route : storedRoutes) - for (IConnectionObserver observer : observers) - observer.onConnectionDestroyed(route); - } -} - - diff --git a/java/src/main/java/com/genexus/internet/HttpClientJavaLib.java b/java/src/main/java/com/genexus/internet/HttpClientJavaLib.java index e7e70915c..b53497e02 100644 --- a/java/src/main/java/com/genexus/internet/HttpClientJavaLib.java +++ b/java/src/main/java/com/genexus/internet/HttpClientJavaLib.java @@ -17,6 +17,7 @@ import org.apache.http.*; import org.apache.http.HttpResponse; import org.apache.http.client.config.CookieSpecs; +import org.apache.http.conn.routing.HttpRoute; import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.protocol.HttpContext; @@ -59,7 +60,7 @@ import com.genexus.CommonUtil; import com.genexus.specific.java.*; -public class HttpClientJavaLib extends GXHttpClient implements IConnectionObserver { +public class HttpClientJavaLib extends GXHttpClient { public HttpClientJavaLib() { getPoolInstance(); @@ -68,8 +69,6 @@ public HttpClientJavaLib() { cookies = new BasicCookieStore(); logger.info("Using apache http client implementation"); streamsToClose = new Vector<>(); - if (Application.isJMXEnabled()) - ((CustomPoolingHttpClientConnectionManager) connManager).addObserver(this); } private static void getPoolInstance() { @@ -78,35 +77,29 @@ private static void getPoolInstance() { RegistryBuilder.create() .register("http", PlainConnectionSocketFactory.INSTANCE).register("https", getSSLSecureInstance()) .build(); - connManager = Application.isJMXEnabled() ? new CustomPoolingHttpClientConnectionManager(socketFactoryRegistry) : new PoolingHttpClientConnectionManager(socketFactoryRegistry); + connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry); connManager.setMaxTotal((int) CommonUtil.val(clientCfg.getProperty("Client", "HTTPCLIENT_MAX_SIZE", "1000"))); connManager.setDefaultMaxPerRoute((int) CommonUtil.val(clientCfg.getProperty("Client", "HTTPCLIENT_MAX_PER_ROUTE", "1000"))); if (Application.isJMXEnabled()) - HTTPPoolJMX.CreateHTTPPoolJMX((CustomPoolingHttpClientConnectionManager) connManager); + HTTPPoolJMX.CreateHTTPPoolJMX(connManager); } else { connManager.closeExpiredConnections(); } } - @Override - public void onConnectionCreated(IdentifiableHttpRoute route) { - if (Application.isJMXEnabled()) - HTTPConnectionJMX.CreateHTTPConnectionJMX(route); - } - - @Override - public void onConnectionDestroyed(IdentifiableHttpRoute route) { - if (Application.isJMXEnabled()) - HTTPConnectionJMX.DestroyHTTPConnectionJMX(route); - } - @Override protected void finalize() { this.closeOpenedStreams(); - if (Application.isJMXEnabled()) - HTTPPoolJMX.DestroyHTTPPoolJMX((CustomPoolingHttpClientConnectionManager) connManager); + if (Application.isJMXEnabled()){ + Iterator iterator = storedRoutes.iterator(); + while (iterator.hasNext()) { + IdentifiableHttpRoute idRoute = iterator.next(); + HTTPConnectionJMX.DestroyHTTPConnectionJMX(idRoute); + iterator.remove(); + } + } } private ConnectionKeepAliveStrategy generateKeepAliveStrategy() { @@ -154,8 +147,9 @@ public void setTimeout(int timeout) private static IniFile clientCfg = new ModelContext(ModelContext.getModelContextPackageClass()).getPreferences().getIniFile(); private static final String SET_COOKIE = "Set-Cookie"; private static final String COOKIE = "Cookie"; - private java.util.Vector streamsToClose; + private HashSet storedRoutes = new HashSet<>(); + private void closeOpenedStreams() { @@ -626,8 +620,21 @@ public void execute(String method, String url) { this.reasonLine = ""; } finally { - if (getIsURL()) - { + if (Application.isJMXEnabled()){ + Iterator iterator = storedRoutes.iterator(); + while (iterator.hasNext()) { + IdentifiableHttpRoute idRoute = iterator.next(); + HTTPConnectionJMX.DestroyHTTPConnectionJMX(idRoute); + iterator.remove(); + } + + for (HttpRoute route : connManager.getRoutes()){ + IdentifiableHttpRoute idRoute = new IdentifiableHttpRoute(route); + HTTPConnectionJMX.CreateHTTPConnectionJMX(idRoute); + storedRoutes.add(idRoute); + } + } + if (getIsURL()) { this.setHost(getPrevURLhost()); this.setBaseURL(getPrevURLbaseURL()); this.setPort(getPrevURLport()); diff --git a/java/src/main/java/com/genexus/internet/IConnectionObserver.java b/java/src/main/java/com/genexus/internet/IConnectionObserver.java deleted file mode 100644 index 5dd5fe549..000000000 --- a/java/src/main/java/com/genexus/internet/IConnectionObserver.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.genexus.internet; - - -public interface IConnectionObserver { - void onConnectionCreated(IdentifiableHttpRoute route); - void onConnectionDestroyed(IdentifiableHttpRoute route); -} \ No newline at end of file diff --git a/java/src/main/java/com/genexus/management/HTTPPoolJMX.java b/java/src/main/java/com/genexus/management/HTTPPoolJMX.java index faddad4d2..b8ea980a8 100644 --- a/java/src/main/java/com/genexus/management/HTTPPoolJMX.java +++ b/java/src/main/java/com/genexus/management/HTTPPoolJMX.java @@ -3,21 +3,22 @@ import javax.management.MBeanNotificationInfo; import javax.management.Notification; import javax.management.NotificationBroadcasterSupport; + +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.logging.log4j.Logger; -import com.genexus.internet.CustomPoolingHttpClientConnectionManager; public class HTTPPoolJMX extends NotificationBroadcasterSupport implements HTTPPoolJMXMBean{ private long sequenceNumber=0; - CustomPoolingHttpClientConnectionManager connectionPool; + PoolingHttpClientConnectionManager connectionPool; private long lastUserWaitingForLongTimeNotif = 0L; private long lastPoollsFullNotif = 0L; private static Logger log = org.apache.logging.log4j.LogManager.getLogger(HTTPPoolJMX.class); - public HTTPPoolJMX(CustomPoolingHttpClientConnectionManager connectionPool) { + public HTTPPoolJMX(PoolingHttpClientConnectionManager connectionPool) { this.connectionPool = connectionPool; } - static public void CreateHTTPPoolJMX(CustomPoolingHttpClientConnectionManager httpConnectionPool) { + static public void CreateHTTPPoolJMX(PoolingHttpClientConnectionManager httpConnectionPool) { try { MBeanUtils.createMBean(httpConnectionPool); } @@ -26,17 +27,8 @@ static public void CreateHTTPPoolJMX(CustomPoolingHttpClientConnectionManager ht } } - static public void DestroyHTTPPoolJMX(CustomPoolingHttpClientConnectionManager httpConnectionPool) { - try { - MBeanUtils.destroyMBean(httpConnectionPool); - } - catch(Exception e) { - log.error("Failed to destroy HTTP connection pool MBean.", e); - } - } - public int getNumberOfConnectionsInUse(){ - return connectionPool.getTotalStats().getAvailable(); + return connectionPool.getTotalStats().getLeased(); } public int getNumberOfRequestsWaiting(){ @@ -51,25 +43,6 @@ public int getMaxNumberOfConnections(){ return connectionPool.getTotalStats().getMax(); } - public void PoolIsFull() { - if (System.currentTimeMillis() - lastPoollsFullNotif > 1000L) { - lastPoollsFullNotif = System.currentTimeMillis(); - Notification n = new Notification("com.genexus.managment.fullpool",this,sequenceNumber++,System.currentTimeMillis(),"The Connection Pool does not have available connections "); - - sendNotification(n); - } - } - - public void UserWaitingForLongTime() { - if (System.currentTimeMillis() - lastUserWaitingForLongTimeNotif > 1000L) - { - lastUserWaitingForLongTimeNotif = System.currentTimeMillis(); - Notification n = new Notification("com.genexus.managment.longtimeuserwaiting",this,sequenceNumber++,System.currentTimeMillis(),"User waiting a connection for a long time"); - - sendNotification(n); - } - } - public MBeanNotificationInfo[] getNotificationInfo() { String[] types = new String[] {"com.genexus.managment.fullpool"}; String name = Notification.class.getName(); diff --git a/java/src/main/java/com/genexus/management/MBeanUtils.java b/java/src/main/java/com/genexus/management/MBeanUtils.java index f80ad43a6..2554ecad5 100644 --- a/java/src/main/java/com/genexus/management/MBeanUtils.java +++ b/java/src/main/java/com/genexus/management/MBeanUtils.java @@ -16,8 +16,9 @@ import com.genexus.db.driver.ConnectionPool; import com.genexus.db.driver.DataSource; import com.genexus.db.driver.GXConnection; -import com.genexus.internet.CustomPoolingHttpClientConnectionManager; import com.genexus.internet.IdentifiableHttpRoute; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; + public class MBeanUtils { private static MBeanServer mbs = null; @@ -131,7 +132,7 @@ public static void createMBean(ConnectionPool connectionPool) registerBean(mbean, "com.genexus.management:type=GeneXusApplicationServer.ApplicationName.DataStore.ConnectionPool,ApplicationName=" + connectionPool.getDataSource().getNamespace() + ",DataStore=" + connectionPool.getDataSource().name + ",name=R/W pool"); } - public static void createMBean(CustomPoolingHttpClientConnectionManager connectionPool) { + public static void createMBean(PoolingHttpClientConnectionManager connectionPool) { MBeanServer mbs = getMBeanServer(); if (mbs == null) return; @@ -139,12 +140,12 @@ public static void createMBean(CustomPoolingHttpClientConnectionManager connecti registerBean(mbean, "com.genexus.management:type=GeneXusApplicationServer.HTTPPool,ApplicationName=Http connection pool, Http connection pool id =" + connectionPool.hashCode()); } - public static void createMBean(IdentifiableHttpRoute idableHttpRoute) { + public static void createMBean(IdentifiableHttpRoute idHttpRoute) { MBeanServer mbs = getMBeanServer(); if (mbs == null) return; - HTTPConnectionJMX mbean = new HTTPConnectionJMX(idableHttpRoute); - registerBean(mbean, "com.genexus.management:type=GeneXusApplicationServer.HTTPPool.HTTPConnection,ApplicationName=" + idableHttpRoute.getHttpRoute().getTargetHost().getHostName() + ",Port=" + idableHttpRoute.getHttpRoute().getTargetHost().getPort() + ",Http connection id=" + idableHttpRoute.getId()); + HTTPConnectionJMX mbean = new HTTPConnectionJMX(idHttpRoute); + registerBean(mbean, "com.genexus.management:type=GeneXusApplicationServer.HTTPPool.HTTPConnection,ApplicationName=" + idHttpRoute.getHttpRoute().getTargetHost().getHostName() + ",Port=" + idHttpRoute.getHttpRoute().getTargetHost().getPort() + ",Http connection id=" + idHttpRoute.getId()); } public static void createMBean(GXConnection connection) @@ -258,40 +259,13 @@ public static void destroyMBean(GXConnection connection) } } - public static void destroyMBean(CustomPoolingHttpClientConnectionManager connectionPool) - { - MBeanServer mbs = getMBeanServer(); - if (mbs == null) - return; - - try - { - ObjectName name = new ObjectName("com.genexus.management:type=GeneXusApplicationServer.HTTPPool,ApplicationName=Http connection pool, Http connection pool id =" + connectionPool.hashCode()); - registeredObjects.removeElement(name); - - mbs.unregisterMBean(name); - } - catch(javax.management.MalformedObjectNameException e) - { - System.out.println(e); - } - catch(javax.management.InstanceNotFoundException e) - { - System.out.println(e); - } - catch(javax.management.MBeanRegistrationException e) - { - System.out.println(e); - } - } - - public static void destroyMBean(IdentifiableHttpRoute idableHttpRoute) { + public static void destroyMBean(IdentifiableHttpRoute idHttpRoute) { MBeanServer mbs = getMBeanServer(); if (mbs == null) return; try { - ObjectName name = new ObjectName("com.genexus.management:type=GeneXusApplicationServer.HTTPPool.HTTPConnection,ApplicationName=" + idableHttpRoute.getHttpRoute().getTargetHost().getHostName() + ",Port=" + idableHttpRoute.getHttpRoute().getTargetHost().getPort() + ",Http connection id=" + idableHttpRoute.getId()); + ObjectName name = new ObjectName("com.genexus.management:type=GeneXusApplicationServer.HTTPPool.HTTPConnection,ApplicationName=" + idHttpRoute.getHttpRoute().getTargetHost().getHostName() + ",Port=" + idHttpRoute.getHttpRoute().getTargetHost().getPort() + ",Http connection id=" + idHttpRoute.getId()); registeredObjects.removeElement(name); mbs.unregisterMBean(name); } @@ -299,7 +273,7 @@ public static void destroyMBean(IdentifiableHttpRoute idableHttpRoute) { System.out.println(e); } catch(javax.management.InstanceNotFoundException e) { - // Intentionally left empty because PoolingHttpClientConnectionManager does not provide a concise way of knowing exactly which connections are being destroyed + System.out.println(e); } catch(javax.management.MBeanRegistrationException e) { System.out.println(e); From 80bf93705620316f4ef6abb3649ee96c3fad7e7d Mon Sep 17 00:00:00 2001 From: tomas-sexenian Date: Mon, 6 Nov 2023 13:56:21 -0300 Subject: [PATCH 13/15] Manage JMX operation in a single separate thread --- .../genexus/internet/HttpClientJavaLib.java | 45 +++++++++---------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/java/src/main/java/com/genexus/internet/HttpClientJavaLib.java b/java/src/main/java/com/genexus/internet/HttpClientJavaLib.java index b53497e02..e38a4ebf2 100644 --- a/java/src/main/java/com/genexus/internet/HttpClientJavaLib.java +++ b/java/src/main/java/com/genexus/internet/HttpClientJavaLib.java @@ -12,6 +12,8 @@ import java.security.cert.CertificateException; import java.util.*; import java.net.URI; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import javax.net.ssl.SSLContext; import org.apache.http.*; @@ -92,14 +94,7 @@ private static void getPoolInstance() { @Override protected void finalize() { this.closeOpenedStreams(); - if (Application.isJMXEnabled()){ - Iterator iterator = storedRoutes.iterator(); - while (iterator.hasNext()) { - IdentifiableHttpRoute idRoute = iterator.next(); - HTTPConnectionJMX.DestroyHTTPConnectionJMX(idRoute); - iterator.remove(); - } - } + executor.shutdown(); } private ConnectionKeepAliveStrategy generateKeepAliveStrategy() { @@ -148,7 +143,7 @@ public void setTimeout(int timeout) private static final String SET_COOKIE = "Set-Cookie"; private static final String COOKIE = "Cookie"; private java.util.Vector streamsToClose; - private HashSet storedRoutes = new HashSet<>(); + private static HashSet storedRoutes = new HashSet<>(); private void closeOpenedStreams() @@ -620,20 +615,8 @@ public void execute(String method, String url) { this.reasonLine = ""; } finally { - if (Application.isJMXEnabled()){ - Iterator iterator = storedRoutes.iterator(); - while (iterator.hasNext()) { - IdentifiableHttpRoute idRoute = iterator.next(); - HTTPConnectionJMX.DestroyHTTPConnectionJMX(idRoute); - iterator.remove(); - } - - for (HttpRoute route : connManager.getRoutes()){ - IdentifiableHttpRoute idRoute = new IdentifiableHttpRoute(route); - HTTPConnectionJMX.CreateHTTPConnectionJMX(idRoute); - storedRoutes.add(idRoute); - } - } + if (Application.isJMXEnabled()) + executor.submit(this::displayHTTPConnections); if (getIsURL()) { this.setHost(getPrevURLhost()); this.setBaseURL(getPrevURLbaseURL()); @@ -645,6 +628,22 @@ public void execute(String method, String url) { } } + private static ExecutorService executor = Executors.newSingleThreadExecutor(); + private synchronized void displayHTTPConnections(){ + Iterator iterator = storedRoutes.iterator(); + while (iterator.hasNext()) { + IdentifiableHttpRoute idRoute = iterator.next(); + HTTPConnectionJMX.DestroyHTTPConnectionJMX(idRoute); + iterator.remove(); + } + + for (HttpRoute route : connManager.getRoutes()){ + IdentifiableHttpRoute idRoute = new IdentifiableHttpRoute(route); + HTTPConnectionJMX.CreateHTTPConnectionJMX(idRoute); + storedRoutes.add(idRoute); + } + } + public int getStatusCode() { return statusCode; } From 421fd7692bc5c15bad089eccd487e92c21949943 Mon Sep 17 00:00:00 2001 From: tomas-sexenian Date: Tue, 7 Nov 2023 10:53:54 -0300 Subject: [PATCH 14/15] Remove usage of IdentifiableHttpRoute and prevent concurrency exception --- .../genexus/internet/HttpClientJavaLib.java | 18 ++++---- .../internet/IdentifiableHttpRoute.java | 44 ------------------- .../genexus/management/HTTPConnectionJMX.java | 16 +++---- .../com/genexus/management/MBeanUtils.java | 12 ++--- 4 files changed, 24 insertions(+), 66 deletions(-) delete mode 100644 java/src/main/java/com/genexus/internet/IdentifiableHttpRoute.java diff --git a/java/src/main/java/com/genexus/internet/HttpClientJavaLib.java b/java/src/main/java/com/genexus/internet/HttpClientJavaLib.java index e38a4ebf2..62008c4ee 100644 --- a/java/src/main/java/com/genexus/internet/HttpClientJavaLib.java +++ b/java/src/main/java/com/genexus/internet/HttpClientJavaLib.java @@ -143,7 +143,7 @@ public void setTimeout(int timeout) private static final String SET_COOKIE = "Set-Cookie"; private static final String COOKIE = "Cookie"; private java.util.Vector streamsToClose; - private static HashSet storedRoutes = new HashSet<>(); + private static HashSet storedRoutes = new HashSet<>(); private void closeOpenedStreams() @@ -615,8 +615,11 @@ public void execute(String method, String url) { this.reasonLine = ""; } finally { - if (Application.isJMXEnabled()) + if (Application.isJMXEnabled()){ + if (executor.isShutdown()) + executor = Executors.newSingleThreadExecutor(); executor.submit(this::displayHTTPConnections); + } if (getIsURL()) { this.setHost(getPrevURLhost()); this.setBaseURL(getPrevURLbaseURL()); @@ -630,17 +633,16 @@ public void execute(String method, String url) { private static ExecutorService executor = Executors.newSingleThreadExecutor(); private synchronized void displayHTTPConnections(){ - Iterator iterator = storedRoutes.iterator(); + Iterator iterator = storedRoutes.iterator(); while (iterator.hasNext()) { - IdentifiableHttpRoute idRoute = iterator.next(); - HTTPConnectionJMX.DestroyHTTPConnectionJMX(idRoute); + HttpRoute route = iterator.next(); + HTTPConnectionJMX.DestroyHTTPConnectionJMX(route); iterator.remove(); } for (HttpRoute route : connManager.getRoutes()){ - IdentifiableHttpRoute idRoute = new IdentifiableHttpRoute(route); - HTTPConnectionJMX.CreateHTTPConnectionJMX(idRoute); - storedRoutes.add(idRoute); + HTTPConnectionJMX.CreateHTTPConnectionJMX(route); + storedRoutes.add(route); } } diff --git a/java/src/main/java/com/genexus/internet/IdentifiableHttpRoute.java b/java/src/main/java/com/genexus/internet/IdentifiableHttpRoute.java deleted file mode 100644 index 9a47ee97b..000000000 --- a/java/src/main/java/com/genexus/internet/IdentifiableHttpRoute.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.genexus.internet; - -import org.apache.http.conn.routing.HttpRoute; - -public class IdentifiableHttpRoute { - private HttpRoute httpRoute; - private static int instanceCount = 0; - private long id; - - public IdentifiableHttpRoute(HttpRoute httpRoute) { - this.httpRoute = httpRoute; - this.id = instanceCount++;; - } - - public long getId() { - return id; - } - - public HttpRoute getHttpRoute() { - return httpRoute; - } - - public String toString() { - return "IdentifiableHttpRoute{" + - "target=" + httpRoute.getTargetHost() + - ", localAddress=" + httpRoute.getLocalAddress() + - ", instance id='" + id + '\'' + - '}'; - } - - @Override - public final boolean equals(Object o) { - if (o == this) - return true; - if (!(o instanceof HttpRoute)) - return false; - HttpRoute that = (HttpRoute) o; - Boolean sameHost = this.getHttpRoute().getTargetHost().getHostName().equals(that.getTargetHost().getHostName()); - Boolean samePort = this.getHttpRoute().getTargetHost().getPort() == that.getTargetHost().getPort(); - return sameHost && samePort; - } -} - - diff --git a/java/src/main/java/com/genexus/management/HTTPConnectionJMX.java b/java/src/main/java/com/genexus/management/HTTPConnectionJMX.java index bec91ea69..fd71f0b3a 100644 --- a/java/src/main/java/com/genexus/management/HTTPConnectionJMX.java +++ b/java/src/main/java/com/genexus/management/HTTPConnectionJMX.java @@ -1,19 +1,19 @@ package com.genexus.management; -import com.genexus.internet.IdentifiableHttpRoute; +import org.apache.http.conn.routing.HttpRoute; import org.apache.logging.log4j.Logger; public class HTTPConnectionJMX implements HTTPConnectionJMXBean{ private static Logger log = org.apache.logging.log4j.LogManager.getLogger(HTTPConnectionJMX.class); - IdentifiableHttpRoute identifiableHttpRoute; + HttpRoute httpRoute; - public HTTPConnectionJMX(IdentifiableHttpRoute httpRoute) { - this.identifiableHttpRoute = httpRoute; + public HTTPConnectionJMX(HttpRoute httpRoute) { + this.httpRoute = httpRoute; } - static public void CreateHTTPConnectionJMX(IdentifiableHttpRoute connection) { + static public void CreateHTTPConnectionJMX(HttpRoute connection) { try { MBeanUtils.createMBean(connection); } @@ -22,7 +22,7 @@ static public void CreateHTTPConnectionJMX(IdentifiableHttpRoute connection) { } } - static public void DestroyHTTPConnectionJMX(IdentifiableHttpRoute connection) { + static public void DestroyHTTPConnectionJMX(HttpRoute connection) { try { MBeanUtils.destroyMBean(connection); } @@ -32,10 +32,10 @@ static public void DestroyHTTPConnectionJMX(IdentifiableHttpRoute connection) { } public int getPort() { - return identifiableHttpRoute.getHttpRoute().getTargetHost().getPort(); + return httpRoute.getTargetHost().getPort(); } public String getHost() { - return identifiableHttpRoute.getHttpRoute().getTargetHost().getHostName(); + return httpRoute.getTargetHost().getHostName(); } } diff --git a/java/src/main/java/com/genexus/management/MBeanUtils.java b/java/src/main/java/com/genexus/management/MBeanUtils.java index 2554ecad5..bdb4f2e66 100644 --- a/java/src/main/java/com/genexus/management/MBeanUtils.java +++ b/java/src/main/java/com/genexus/management/MBeanUtils.java @@ -16,7 +16,7 @@ import com.genexus.db.driver.ConnectionPool; import com.genexus.db.driver.DataSource; import com.genexus.db.driver.GXConnection; -import com.genexus.internet.IdentifiableHttpRoute; +import org.apache.http.conn.routing.HttpRoute; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; public class MBeanUtils { @@ -140,12 +140,12 @@ public static void createMBean(PoolingHttpClientConnectionManager connectionPool registerBean(mbean, "com.genexus.management:type=GeneXusApplicationServer.HTTPPool,ApplicationName=Http connection pool, Http connection pool id =" + connectionPool.hashCode()); } - public static void createMBean(IdentifiableHttpRoute idHttpRoute) { + public static void createMBean(HttpRoute httpRoute) { MBeanServer mbs = getMBeanServer(); if (mbs == null) return; - HTTPConnectionJMX mbean = new HTTPConnectionJMX(idHttpRoute); - registerBean(mbean, "com.genexus.management:type=GeneXusApplicationServer.HTTPPool.HTTPConnection,ApplicationName=" + idHttpRoute.getHttpRoute().getTargetHost().getHostName() + ",Port=" + idHttpRoute.getHttpRoute().getTargetHost().getPort() + ",Http connection id=" + idHttpRoute.getId()); + HTTPConnectionJMX mbean = new HTTPConnectionJMX(httpRoute); + registerBean(mbean, "com.genexus.management:type=GeneXusApplicationServer.HTTPPool.HTTPConnection,ApplicationName=" + httpRoute.getTargetHost().getHostName() + ",Port=" + httpRoute.getTargetHost().getPort() + ",Http connection id=" + System.identityHashCode(httpRoute)); } public static void createMBean(GXConnection connection) @@ -259,13 +259,13 @@ public static void destroyMBean(GXConnection connection) } } - public static void destroyMBean(IdentifiableHttpRoute idHttpRoute) { + public static void destroyMBean(HttpRoute httpRoute) { MBeanServer mbs = getMBeanServer(); if (mbs == null) return; try { - ObjectName name = new ObjectName("com.genexus.management:type=GeneXusApplicationServer.HTTPPool.HTTPConnection,ApplicationName=" + idHttpRoute.getHttpRoute().getTargetHost().getHostName() + ",Port=" + idHttpRoute.getHttpRoute().getTargetHost().getPort() + ",Http connection id=" + idHttpRoute.getId()); + ObjectName name = new ObjectName("com.genexus.management:type=GeneXusApplicationServer.HTTPPool.HTTPConnection,ApplicationName=" + httpRoute.getTargetHost().getHostName() + ",Port=" + httpRoute.getTargetHost().getPort() + ",Http connection id=" + System.identityHashCode(httpRoute)); registeredObjects.removeElement(name); mbs.unregisterMBean(name); } From 90add058eb02d36e38c3083f29cbd9d0be996f45 Mon Sep 17 00:00:00 2001 From: tomas-sexenian Date: Tue, 7 Nov 2023 12:30:12 -0300 Subject: [PATCH 15/15] Use apache logger instead of system.out --- .../com/genexus/management/MBeanUtils.java | 485 +++++++----------- 1 file changed, 196 insertions(+), 289 deletions(-) diff --git a/java/src/main/java/com/genexus/management/MBeanUtils.java b/java/src/main/java/com/genexus/management/MBeanUtils.java index bdb4f2e66..4f13c0bba 100644 --- a/java/src/main/java/com/genexus/management/MBeanUtils.java +++ b/java/src/main/java/com/genexus/management/MBeanUtils.java @@ -2,12 +2,12 @@ import java.util.ArrayList; import java.util.Vector; - import javax.management.InstanceNotFoundException; import javax.management.MBeanServer; import javax.management.MBeanServerFactory; import javax.management.MalformedObjectNameException; import javax.management.ObjectName; + import com.genexus.db.CacheValue; import com.genexus.db.InProcessCache; import com.genexus.db.LocalUserInformation; @@ -16,121 +16,95 @@ import com.genexus.db.driver.ConnectionPool; import com.genexus.db.driver.DataSource; import com.genexus.db.driver.GXConnection; + import org.apache.http.conn.routing.HttpRoute; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.apache.logging.log4j.Logger; public class MBeanUtils { - - private static MBeanServer mbs = null; - private static Vector registeredObjects = new Vector(); - - public MBeanUtils() { - } - - private static MBeanServer getMBeanServer() - { - if(mbs == null) - { - try - { - ArrayList list = MBeanServerFactory.findMBeanServer(null); - if (list.size() > 0) - mbs = (MBeanServer) list.get(0); - } - catch(Throwable t) - { - t.printStackTrace(System.out); - System.exit(1); + private static MBeanServer mbs = null; + private static Vector < ObjectName > registeredObjects = new Vector<>(); + private static Logger logger = org.apache.logging.log4j.LogManager.getLogger(MBeanUtils.class); + public MBeanUtils() {} + private static MBeanServer getMBeanServer() { + if (mbs == null) { + try { + ArrayList list = MBeanServerFactory.findMBeanServer(null); + if (list.size() > 0) + mbs = (MBeanServer) list.get(0); + } catch (Throwable t) { + logger.error(t); + System.exit(1); + } } + return mbs; } - return mbs; - } - - public static void registerBean(Object mbean, String sName) { - ObjectName name = null; - try { - name = new ObjectName(sName); - } catch (MalformedObjectNameException e1) { - System.out.println(e1); - } - if (name == null) - return; - - try { - mbs.getObjectInstance(name); - } catch (InstanceNotFoundException ex) { - try - { - mbs.registerMBean(mbean, name); - registeredObjects.addElement(name); - } - catch(javax.management.InstanceAlreadyExistsException e) - { - System.out.println(e); - } - catch(javax.management.MBeanRegistrationException e) - { - System.out.println(e); - } - catch(javax.management.NotCompliantMBeanException e) - { - System.out.println(e); - } - } - } - - public static void createMBean(Namespace namespace) - { - MBeanServer mbs = getMBeanServer(); - if (mbs == null) - return; - NamespaceJMX mbean = new NamespaceJMX(namespace); - registerBean(mbean, "com.genexus.management:type=GeneXusApplicationServer.ApplicationName,name= " + namespace.getName()); - } - - public static void createMBean(ServerUserInformation serverUserInfo, com.genexus.ModelContext context) - { - MBeanServer mbs = getMBeanServer(); - if (mbs == null) - return; + public static void registerBean(Object mbean, String sName) { + ObjectName name = null; + try { + name = new ObjectName(sName); + } catch (MalformedObjectNameException e1) { + logger.error(e1); + } + if (name == null) + return; + try { + mbs.getObjectInstance(name); + } catch (InstanceNotFoundException ex) { + try { + mbs.registerMBean(mbean, name); + registeredObjects.addElement(name); + } catch (javax.management.InstanceAlreadyExistsException e) { + logger.error(e); + } catch (javax.management.MBeanRegistrationException e) { + logger.error(e); + } catch (javax.management.NotCompliantMBeanException e) { + logger.error(e); + } + } + } - ServerUserInformationJMX mbean = new ServerUserInformationJMX(serverUserInfo, context); - registerBean(mbean, "com.genexus.management:type=GeneXusApplicationServer.ApplicationName.User,ApplicationName=" + serverUserInfo.getNamespace().getName() + ",name=User " + serverUserInfo.getHandle()); - } - - public static void createMBean(LocalUserInformation localUserInfo) - { - MBeanServer mbs = getMBeanServer(); - if (mbs == null) - return; + public static void createMBean(Namespace namespace) { + MBeanServer mbs = getMBeanServer(); + if (mbs == null) + return; + NamespaceJMX mbean = new NamespaceJMX(namespace); + registerBean(mbean, "com.genexus.management:type=GeneXusApplicationServer.ApplicationName,name= " + namespace.getName()); + } - - LocalUserInformationJMX mbean = new LocalUserInformationJMX(localUserInfo); + public static void createMBean(ServerUserInformation serverUserInfo, com.genexus.ModelContext context) { + MBeanServer mbs = getMBeanServer(); + if (mbs == null) + return; + ServerUserInformationJMX mbean = new ServerUserInformationJMX(serverUserInfo, context); + registerBean(mbean, "com.genexus.management:type=GeneXusApplicationServer.ApplicationName.User,ApplicationName=" + serverUserInfo.getNamespace().getName() + ",name=User " + serverUserInfo.getHandle()); + } - registerBean(mbean, "com.genexus.management:type=GeneXusApplicationServer.ApplicationName.User,ApplicationName=" + localUserInfo.getNamespace().getName() + ",name=User " + localUserInfo.getHandle()); + public static void createMBean(LocalUserInformation localUserInfo) { + MBeanServer mbs = getMBeanServer(); + if (mbs == null) + return; + LocalUserInformationJMX mbean = new LocalUserInformationJMX(localUserInfo); + registerBean(mbean, "com.genexus.management:type=GeneXusApplicationServer.ApplicationName.User,ApplicationName=" + localUserInfo.getNamespace().getName() + ",name=User " + localUserInfo.getHandle()); - } - - public static void createMBean(DataSource dataSource) - { - MBeanServer mbs = getMBeanServer(); - if (mbs == null) - return; + } + public static void createMBean(DataSource dataSource) { + MBeanServer mbs = getMBeanServer(); + if (mbs == null) + return; + DataSourceJMX mbean = new DataSourceJMX(dataSource); + registerBean(mbean, "com.genexus.management:type=GeneXusApplicationServer.ApplicationName.DataStore,ApplicationName=" + dataSource.getNamespace() + ",name=DataStore " + dataSource.name); + } - DataSourceJMX mbean = new DataSourceJMX(dataSource); - registerBean(mbean, "com.genexus.management:type=GeneXusApplicationServer.ApplicationName.DataStore,ApplicationName=" + dataSource.getNamespace() + ",name=DataStore " + dataSource.name); - } - - public static void createMBean(ConnectionPool connectionPool) - { - MBeanServer mbs = getMBeanServer(); - if (mbs == null) - return; - ConnectionPoolJMX mbean = new ConnectionPoolJMX(connectionPool); - registerBean(mbean, "com.genexus.management:type=GeneXusApplicationServer.ApplicationName.DataStore.ConnectionPool,ApplicationName=" + connectionPool.getDataSource().getNamespace() + ",DataStore=" + connectionPool.getDataSource().name + ",name=R/W pool"); - } + public static void createMBean(ConnectionPool connectionPool) { + MBeanServer mbs = getMBeanServer(); + if (mbs == null) + return; + ConnectionPoolJMX mbean = new ConnectionPoolJMX(connectionPool); + registerBean(mbean, "com.genexus.management:type=GeneXusApplicationServer.ApplicationName.DataStore.ConnectionPool,ApplicationName=" + connectionPool.getDataSource().getNamespace() + ",DataStore=" + connectionPool.getDataSource().name + ",name=R/W pool"); + } public static void createMBean(PoolingHttpClientConnectionManager connectionPool) { MBeanServer mbs = getMBeanServer(); @@ -147,210 +121,143 @@ public static void createMBean(HttpRoute httpRoute) { HTTPConnectionJMX mbean = new HTTPConnectionJMX(httpRoute); registerBean(mbean, "com.genexus.management:type=GeneXusApplicationServer.HTTPPool.HTTPConnection,ApplicationName=" + httpRoute.getTargetHost().getHostName() + ",Port=" + httpRoute.getTargetHost().getPort() + ",Http connection id=" + System.identityHashCode(httpRoute)); } - - public static void createMBean(GXConnection connection) - { - MBeanServer mbs = getMBeanServer(); - if (mbs == null) - return; - - ConnectionJMX mbean = new ConnectionJMX(connection); - registerBean(mbean, "com.genexus.management:type=GeneXusApplicationServer.ApplicationName.DataStore.ConnectionPool.Connection,ApplicationName=" + connection.getDataSource().getNamespace() + ",DataStore=" + connection.getDataSource().name +",ConnectionPool=R/W pool" +",name=" + connection.getId()); - } - - public static void createMBean(InProcessCache cache) - { - MBeanServer mbs = getMBeanServer(); - if (mbs == null) - return; - - - CacheJMX mbean = new CacheJMX(cache); - registerBean(mbean, "com.genexus.management:type=InProcessCache"); - } - - public static void createMBean(CacheValue cacheValue) - { - MBeanServer mbs = getMBeanServer(); - if (mbs == null) - return; - CacheItemJMX mbean = new CacheItemJMX(cacheValue); - registerBean(mbean, "com.genexus.management:type=InProcessCache.Item,name=" + cacheValue.hashCode()); - } - - public static void destroyMBean(ServerUserInformation serverUserInfo) - { - MBeanServer mbs = getMBeanServer(); - if (mbs == null) - return; - try - { - ObjectName name = new ObjectName("com.genexus.management:type=GeneXusApplicationServer.ApplicationName.User,ApplicationName=" + serverUserInfo.getNamespace().getName() + ",name=User " + serverUserInfo.getHandle()); - registeredObjects.removeElement(name); + public static void createMBean(GXConnection connection) { + MBeanServer mbs = getMBeanServer(); + if (mbs == null) + return; + ConnectionJMX mbean = new ConnectionJMX(connection); + registerBean(mbean, "com.genexus.management:type=GeneXusApplicationServer.ApplicationName.DataStore.ConnectionPool.Connection,ApplicationName=" + connection.getDataSource().getNamespace() + ",DataStore=" + connection.getDataSource().name + ",ConnectionPool=R/W pool" + ",name=" + connection.getId()); + } - mbs.unregisterMBean(name); - } - catch(javax.management.MalformedObjectNameException e) - { - System.out.println(e); - } - catch(javax.management.InstanceNotFoundException e) - { - System.out.println(e); - } - catch(javax.management.MBeanRegistrationException e) - { - System.out.println(e); - } - } - - public static void destroyMBean(LocalUserInformation localUserInfo) - { - MBeanServer mbs = getMBeanServer(); - if (mbs == null) - return; + public static void createMBean(InProcessCache cache) { + MBeanServer mbs = getMBeanServer(); + if (mbs == null) + return; + CacheJMX mbean = new CacheJMX(cache); + registerBean(mbean, "com.genexus.management:type=InProcessCache"); + } - try - { - ObjectName name = new ObjectName("com.genexus.management:type=GeneXusApplicationServer.ApplicationName.User,ApplicationName=" + localUserInfo.getNamespace().getName() + ",name=User " + localUserInfo.getHandle()); - registeredObjects.removeElement(name); + public static void createMBean(CacheValue cacheValue) { + MBeanServer mbs = getMBeanServer(); + if (mbs == null) + return; + CacheItemJMX mbean = new CacheItemJMX(cacheValue); + registerBean(mbean, "com.genexus.management:type=InProcessCache.Item,name=" + cacheValue.hashCode()); + } - mbs.unregisterMBean(name); - } - catch(javax.management.MalformedObjectNameException e) - { - System.out.println(e); - } - catch(javax.management.InstanceNotFoundException e) - { - System.out.println(e); - } - catch(javax.management.MBeanRegistrationException e) - { - System.out.println(e); - } - } - - public static void destroyMBean(GXConnection connection) - { - MBeanServer mbs = getMBeanServer(); - if (mbs == null) - return; + public static void destroyMBean(ServerUserInformation serverUserInfo) { + MBeanServer mbs = getMBeanServer(); + if (mbs == null) + return; + try { + ObjectName name = new ObjectName("com.genexus.management:type=GeneXusApplicationServer.ApplicationName.User,ApplicationName=" + serverUserInfo.getNamespace().getName() + ",name=User " + serverUserInfo.getHandle()); + registeredObjects.removeElement(name); + mbs.unregisterMBean(name); + } catch (javax.management.MalformedObjectNameException e) { + logger.error(e); + } catch (javax.management.InstanceNotFoundException e) { + logger.error(e); + } catch (javax.management.MBeanRegistrationException e) { + logger.error(e); + } + } - try - { - ObjectName name = new ObjectName("com.genexus.management:type=GeneXusApplicationServer.ApplicationName.DataStore.ConnectionPool.Connection,ApplicationName=" + connection.getDataSource().getNamespace() + ",DataStore=" + connection.getDataSource().name +",ConnectionPool=R/W pool" +",name=" + connection.getId()); - registeredObjects.removeElement(name); + public static void destroyMBean(LocalUserInformation localUserInfo) { + MBeanServer mbs = getMBeanServer(); + if (mbs == null) + return; + try { + ObjectName name = new ObjectName("com.genexus.management:type=GeneXusApplicationServer.ApplicationName.User,ApplicationName=" + localUserInfo.getNamespace().getName() + ",name=User " + localUserInfo.getHandle()); + registeredObjects.removeElement(name); + mbs.unregisterMBean(name); + } catch (javax.management.MalformedObjectNameException e) { + logger.error(e); + } catch (javax.management.InstanceNotFoundException e) { + logger.error(e); + } catch (javax.management.MBeanRegistrationException e) { + logger.error(e); + } + } - mbs.unregisterMBean(name); - } - catch(javax.management.MalformedObjectNameException e) - { - System.out.println(e); - } - catch(javax.management.InstanceNotFoundException e) - { - System.out.println(e); - } - catch(javax.management.MBeanRegistrationException e) - { - System.out.println(e); - } - } + public static void destroyMBean(GXConnection connection) { + MBeanServer mbs = getMBeanServer(); + if (mbs == null) + return; + try { + ObjectName name = new ObjectName("com.genexus.management:type=GeneXusApplicationServer.ApplicationName.DataStore.ConnectionPool.Connection,ApplicationName=" + connection.getDataSource().getNamespace() + ",DataStore=" + connection.getDataSource().name + ",ConnectionPool=R/W pool" + ",name=" + connection.getId()); + registeredObjects.removeElement(name); + mbs.unregisterMBean(name); + } catch (javax.management.MalformedObjectNameException e) { + logger.error(e); + } catch (javax.management.InstanceNotFoundException e) { + logger.error(e); + } catch (javax.management.MBeanRegistrationException e) { + logger.error(e); + } + } public static void destroyMBean(HttpRoute httpRoute) { MBeanServer mbs = getMBeanServer(); if (mbs == null) return; - try { ObjectName name = new ObjectName("com.genexus.management:type=GeneXusApplicationServer.HTTPPool.HTTPConnection,ApplicationName=" + httpRoute.getTargetHost().getHostName() + ",Port=" + httpRoute.getTargetHost().getPort() + ",Http connection id=" + System.identityHashCode(httpRoute)); registeredObjects.removeElement(name); mbs.unregisterMBean(name); - } - catch(javax.management.MalformedObjectNameException e) { - System.out.println(e); - } - catch(javax.management.InstanceNotFoundException e) { - System.out.println(e); - } - catch(javax.management.MBeanRegistrationException e) { - System.out.println(e); + } catch (javax.management.MalformedObjectNameException e) { + logger.error(e); + } catch (javax.management.InstanceNotFoundException e) { + logger.error(e); + } catch (javax.management.MBeanRegistrationException e) { + logger.error(e); } } - - public static void destroyMBeanCache() - { - MBeanServer mbs = getMBeanServer(); - if (mbs == null) - return; - try - { - ObjectName name = new ObjectName("com.genexus.management:type=InProcessCache"); - registeredObjects.removeElement(name); - - mbs.unregisterMBean(name); - } - catch(javax.management.MalformedObjectNameException e) - { - System.out.println(e); - } - catch(javax.management.InstanceNotFoundException e) - { - System.out.println(e); - } - catch(javax.management.MBeanRegistrationException e) - { - System.out.println(e); - } - } - - public static void destroyMBean(CacheValue cacheValue) - { - MBeanServer mbs = getMBeanServer(); - if (mbs == null) - return; + public static void destroyMBeanCache() { + MBeanServer mbs = getMBeanServer(); + if (mbs == null) + return; + try { + ObjectName name = new ObjectName("com.genexus.management:type=InProcessCache"); + registeredObjects.removeElement(name); + mbs.unregisterMBean(name); + } catch (javax.management.MalformedObjectNameException e) { + logger.error(e); + } catch (javax.management.InstanceNotFoundException e) { + logger.error(e); + } catch (javax.management.MBeanRegistrationException e) { + logger.error(e); + } + } - try - { - ObjectName name = new ObjectName("com.genexus.management:type=InProcessCache.Item,name=" + cacheValue.hashCode()); - registeredObjects.removeElement(name); + public static void destroyMBean(CacheValue cacheValue) { + MBeanServer mbs = getMBeanServer(); + if (mbs == null) + return; + try { + ObjectName name = new ObjectName("com.genexus.management:type=InProcessCache.Item,name=" + cacheValue.hashCode()); + registeredObjects.removeElement(name); + mbs.unregisterMBean(name); + } catch (javax.management.MalformedObjectNameException e) { + logger.error(e); + } catch (javax.management.InstanceNotFoundException e) { + logger.error(e); + } catch (javax.management.MBeanRegistrationException e) { + logger.error(e); + } + } - mbs.unregisterMBean(name); - } - catch(javax.management.MalformedObjectNameException e) - { - System.out.println(e); - } - catch(javax.management.InstanceNotFoundException e) - { - System.out.println(e); - } - catch(javax.management.MBeanRegistrationException e) - { - System.out.println(e); - } - } - - public static void unregisterObjects() - { - try - { - for (int i = 0; i < registeredObjects.size(); i++) - { - mbs.unregisterMBean((ObjectName) registeredObjects.elementAt(i)); + public static void unregisterObjects() { + try { + for (int i = 0; i < registeredObjects.size(); i++) { + mbs.unregisterMBean(registeredObjects.elementAt(i)); + } + } catch (javax.management.InstanceNotFoundException e) { + logger.error(e); + } catch (javax.management.MBeanRegistrationException e) { + logger.error(e); } - } - catch(javax.management.InstanceNotFoundException e) - { - System.out.println(e); - } - catch(javax.management.MBeanRegistrationException e) - { - System.out.println(e); - } - mbs = null; - } -} + mbs = null; + } +} \ No newline at end of file