Skip to content

Commit fc148fd

Browse files
HTTP Pool data added to JMX management (#793)
* Add HTTP connection pool info to JMX Issue:104837 * Call creation and destruction of mbeans * Various fixes * Better positioning of beans in monitoring console * Check used connections every 30 seconds * Shutdown runnable when no longer needed * Revert "Check used connections every 30 seconds" This reverts commit a15eaa7. * Set difference to find closed connections * Destroy connection pool manager after cleanup * Identify each http route by an unique id * Various fixes * Remove usage of custom connection pool * Manage JMX operation in a single separate thread * Remove usage of IdentifiableHttpRoute and prevent concurrency exception * Use apache logger instead of system.out
1 parent 62b3c40 commit fc148fd

6 files changed

Lines changed: 381 additions & 294 deletions

File tree

java/src/main/java/com/genexus/internet/HttpClientJavaLib.java

Lines changed: 47 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,17 @@
1111
import java.security.UnrecoverableKeyException;
1212
import java.security.cert.CertificateException;
1313
import java.util.*;
14-
import com.genexus.ModelContext;
15-
import com.genexus.util.IniFile;
14+
import java.net.URI;
15+
import java.util.concurrent.ExecutorService;
16+
import java.util.concurrent.Executors;
17+
import javax.net.ssl.SSLContext;
18+
1619
import org.apache.http.*;
17-
import com.genexus.CommonUtil;
18-
import com.genexus.specific.java.*;
1920
import org.apache.http.HttpResponse;
2021
import org.apache.http.client.config.CookieSpecs;
22+
import org.apache.http.conn.routing.HttpRoute;
2123
import org.apache.http.conn.ssl.NoopHostnameVerifier;
24+
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
2225
import org.apache.http.protocol.HttpContext;
2326
import org.apache.http.auth.AuthSchemeProvider;
2427
import org.apache.http.auth.AuthScope;
@@ -43,17 +46,21 @@
4346
import org.apache.http.impl.auth.SPNegoSchemeFactory;
4447
import org.apache.http.impl.client.*;
4548
import org.apache.http.impl.conn.DefaultProxyRoutePlanner;
46-
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
4749
import org.apache.http.message.BasicHeaderElementIterator;
4850
import org.apache.http.protocol.HTTP;
4951
import org.apache.http.ssl.SSLContextBuilder;
5052
import org.apache.http.ssl.SSLContexts;
5153
import org.apache.http.util.EntityUtils;
5254
import org.apache.logging.log4j.Logger;
53-
import com.genexus.webpanels.HttpContextWeb;
54-
import java.net.URI;
5555

56-
import javax.net.ssl.SSLContext;
56+
import com.genexus.webpanels.HttpContextWeb;
57+
import com.genexus.ModelContext;
58+
import com.genexus.management.HTTPConnectionJMX;
59+
import com.genexus.management.HTTPPoolJMX;
60+
import com.genexus.util.IniFile;
61+
import com.genexus.Application;
62+
import com.genexus.CommonUtil;
63+
import com.genexus.specific.java.*;
5764

5865
public class HttpClientJavaLib extends GXHttpClient {
5966

@@ -75,12 +82,21 @@ private static void getPoolInstance() {
7582
connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
7683
connManager.setMaxTotal((int) CommonUtil.val(clientCfg.getProperty("Client", "HTTPCLIENT_MAX_SIZE", "1000")));
7784
connManager.setDefaultMaxPerRoute((int) CommonUtil.val(clientCfg.getProperty("Client", "HTTPCLIENT_MAX_PER_ROUTE", "1000")));
85+
86+
if (Application.isJMXEnabled())
87+
HTTPPoolJMX.CreateHTTPPoolJMX(connManager);
7888
}
7989
else {
8090
connManager.closeExpiredConnections();
8191
}
8292
}
8393

94+
@Override
95+
protected void finalize() {
96+
this.closeOpenedStreams();
97+
executor.shutdown();
98+
}
99+
84100
private ConnectionKeepAliveStrategy generateKeepAliveStrategy() {
85101
return new ConnectionKeepAliveStrategy() {
86102
@Override
@@ -110,7 +126,6 @@ public void setTimeout(int timeout)
110126
}
111127

112128
private static Logger logger = org.apache.logging.log4j.LogManager.getLogger(HttpClientJavaLib.class);
113-
114129
private static PoolingHttpClientConnectionManager connManager = null;
115130
private Integer statusCode = 0;
116131
private String reasonLine = "";
@@ -127,8 +142,9 @@ public void setTimeout(int timeout)
127142
private static IniFile clientCfg = new ModelContext(ModelContext.getModelContextPackageClass()).getPreferences().getIniFile();
128143
private static final String SET_COOKIE = "Set-Cookie";
129144
private static final String COOKIE = "Cookie";
130-
131145
private java.util.Vector<InputStream> streamsToClose;
146+
private static HashSet<HttpRoute> storedRoutes = new HashSet<>();
147+
132148

133149
private void closeOpenedStreams()
134150
{
@@ -599,8 +615,12 @@ public void execute(String method, String url) {
599615
this.reasonLine = "";
600616
}
601617
finally {
602-
if (getIsURL())
603-
{
618+
if (Application.isJMXEnabled()){
619+
if (executor.isShutdown())
620+
executor = Executors.newSingleThreadExecutor();
621+
executor.submit(this::displayHTTPConnections);
622+
}
623+
if (getIsURL()) {
604624
this.setHost(getPrevURLhost());
605625
this.setBaseURL(getPrevURLbaseURL());
606626
this.setPort(getPrevURLport());
@@ -611,6 +631,21 @@ public void execute(String method, String url) {
611631
}
612632
}
613633

634+
private static ExecutorService executor = Executors.newSingleThreadExecutor();
635+
private synchronized void displayHTTPConnections(){
636+
Iterator<HttpRoute> iterator = storedRoutes.iterator();
637+
while (iterator.hasNext()) {
638+
HttpRoute route = iterator.next();
639+
HTTPConnectionJMX.DestroyHTTPConnectionJMX(route);
640+
iterator.remove();
641+
}
642+
643+
for (HttpRoute route : connManager.getRoutes()){
644+
HTTPConnectionJMX.CreateHTTPConnectionJMX(route);
645+
storedRoutes.add(route);
646+
}
647+
}
648+
614649
public int getStatusCode() {
615650
return statusCode;
616651
}
@@ -738,10 +773,4 @@ public void cleanup() {
738773
resetErrorsAndConnParams();
739774
}
740775

741-
@Override
742-
protected void finalize()
743-
{
744-
this.closeOpenedStreams();
745-
}
746-
747776
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package com.genexus.management;
2+
3+
import org.apache.http.conn.routing.HttpRoute;
4+
import org.apache.logging.log4j.Logger;
5+
6+
public class HTTPConnectionJMX implements HTTPConnectionJMXBean{
7+
8+
private static Logger log = org.apache.logging.log4j.LogManager.getLogger(HTTPConnectionJMX.class);
9+
10+
HttpRoute httpRoute;
11+
12+
public HTTPConnectionJMX(HttpRoute httpRoute) {
13+
this.httpRoute = httpRoute;
14+
}
15+
16+
static public void CreateHTTPConnectionJMX(HttpRoute connection) {
17+
try {
18+
MBeanUtils.createMBean(connection);
19+
}
20+
catch (Exception e) {
21+
log.error("Failed to register HTTP connection MBean.", e);
22+
}
23+
}
24+
25+
static public void DestroyHTTPConnectionJMX(HttpRoute connection) {
26+
try {
27+
MBeanUtils.destroyMBean(connection);
28+
}
29+
catch (Exception e) {
30+
log.error("Failed to destroy HTTP connection MBean.", e);
31+
}
32+
}
33+
34+
public int getPort() {
35+
return httpRoute.getTargetHost().getPort();
36+
}
37+
38+
public String getHost() {
39+
return httpRoute.getTargetHost().getHostName();
40+
}
41+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package com.genexus.management;
2+
3+
public interface HTTPConnectionJMXBean {
4+
int getPort();
5+
String getHost();
6+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package com.genexus.management;
2+
3+
import javax.management.MBeanNotificationInfo;
4+
import javax.management.Notification;
5+
import javax.management.NotificationBroadcasterSupport;
6+
7+
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
8+
import org.apache.logging.log4j.Logger;
9+
public class HTTPPoolJMX extends NotificationBroadcasterSupport implements HTTPPoolJMXMBean{
10+
11+
private long sequenceNumber=0;
12+
PoolingHttpClientConnectionManager connectionPool;
13+
private long lastUserWaitingForLongTimeNotif = 0L;
14+
private long lastPoollsFullNotif = 0L;
15+
private static Logger log = org.apache.logging.log4j.LogManager.getLogger(HTTPPoolJMX.class);
16+
17+
public HTTPPoolJMX(PoolingHttpClientConnectionManager connectionPool) {
18+
this.connectionPool = connectionPool;
19+
}
20+
21+
static public void CreateHTTPPoolJMX(PoolingHttpClientConnectionManager httpConnectionPool) {
22+
try {
23+
MBeanUtils.createMBean(httpConnectionPool);
24+
}
25+
catch(Exception e) {
26+
log.error("Failed to register HTTP connection pool MBean.", e);
27+
}
28+
}
29+
30+
public int getNumberOfConnectionsInUse(){
31+
return connectionPool.getTotalStats().getLeased();
32+
}
33+
34+
public int getNumberOfRequestsWaiting(){
35+
return connectionPool.getTotalStats().getPending();
36+
}
37+
38+
public int getNumberOfAvailableConnections(){
39+
return connectionPool.getTotalStats().getAvailable();
40+
}
41+
42+
public int getMaxNumberOfConnections(){
43+
return connectionPool.getTotalStats().getMax();
44+
}
45+
46+
public MBeanNotificationInfo[] getNotificationInfo() {
47+
String[] types = new String[] {"com.genexus.managment.fullpool"};
48+
String name = Notification.class.getName();
49+
String description = "The Connection Pool does not have available connections ";
50+
MBeanNotificationInfo info = new MBeanNotificationInfo(types, name, description);
51+
52+
types = new String[] {"com.genexus.managment.longtimeuserwaiting"};
53+
description = "User waiting a connection for a long time";
54+
MBeanNotificationInfo info1 = new MBeanNotificationInfo(types, name, description);
55+
56+
return new MBeanNotificationInfo[] {info, info1};
57+
}
58+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.genexus.management;
2+
3+
public interface HTTPPoolJMXMBean {
4+
int getNumberOfConnectionsInUse();
5+
int getNumberOfRequestsWaiting();
6+
int getNumberOfAvailableConnections();
7+
int getMaxNumberOfConnections();
8+
}

0 commit comments

Comments
 (0)