You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by re...@apache.org on 2026/09/29 18:27:44 UTC
(tomcat) 10/15: Close the JMX connection owned by a task or condition when no reference is used to share it
This is an automated email from the ASF dual-hosted git repository.
rmaucher pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit 768e3b82989e6034a7dfe4dc2c18d95df267d617
Author: opencode <re...@apache.org>
AuthorDate: Tue Sep 29 19:26:31 2026 +0200
Close the JMX connection owned by a task or condition when no reference is used to share it
---
.../catalina/ant/jmx/JMXAccessorConditionBase.java | 37 +++++++++-
.../apache/catalina/ant/jmx/JMXAccessorTask.java | 82 +++++++++++++++++-----
2 files changed, 98 insertions(+), 21 deletions(-)
diff --git a/java/org/apache/catalina/ant/jmx/JMXAccessorConditionBase.java b/java/org/apache/catalina/ant/jmx/JMXAccessorConditionBase.java
index 6d08cd478e..084daf5b03 100644
--- a/java/org/apache/catalina/ant/jmx/JMXAccessorConditionBase.java
+++ b/java/org/apache/catalina/ant/jmx/JMXAccessorConditionBase.java
@@ -21,6 +21,7 @@ import java.net.MalformedURLException;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
+import javax.management.remote.JMXConnector;
import org.apache.tools.ant.ProjectComponent;
import org.apache.tools.ant.taskdefs.condition.Condition;
@@ -46,6 +47,12 @@ public abstract class JMXAccessorConditionBase extends ProjectComponent implemen
private String value;
private String ref = "jmx.server";
+ /*
+ * Connector created for the current evaluation when the connection is not shared through a project reference. It
+ * is closed once the value has been read so repeated waitfor evaluations do not accumulate connections.
+ */
+ private JMXConnector jmxConnector;
+
/**
* Get the attribute name.
*
@@ -217,8 +224,29 @@ public abstract class JMXAccessorConditionBase extends ProjectComponent implemen
* @throws IOException Connection error
*/
protected MBeanServerConnection getJMXConnection() throws MalformedURLException, IOException {
- return JMXAccessorTask.accessJMXConnection(getProject(), getUrl(), getHost(), getPort(), getUsername(),
- getPassword(), ref);
+ if (ref != null && !ref.isEmpty() && getProject() != null) {
+ // Reuse or establish a shared connection stored in the project reference; this condition does not own it.
+ return JMXAccessorTask.accessJMXConnection(getProject(), getUrl(), getHost(), getPort(), getUsername(),
+ getPassword(), ref);
+ }
+ // No reference to store it in: this condition owns the connection and closes it after the evaluation.
+ jmxConnector = JMXAccessorTask.createJMXConnector(getUrl(), getHost(), getPort(), getUsername(), getPassword());
+ return jmxConnector.getMBeanServerConnection();
+ }
+
+ /**
+ * Close the JMX connection owned by this condition, if any. Connections shared through a project reference are
+ * left open for reuse.
+ */
+ private void closeJMXConnector() {
+ if (jmxConnector != null) {
+ try {
+ jmxConnector.close();
+ } catch (IOException e) {
+ // Ignore errors while closing
+ }
+ jmxConnector = null;
+ }
}
/**
@@ -228,7 +256,8 @@ public abstract class JMXAccessorConditionBase extends ProjectComponent implemen
*/
protected String accessJMXValue() {
try {
- Object result = getJMXConnection().getAttribute(new ObjectName(name), attribute);
+ MBeanServerConnection jmxServerConnection = getJMXConnection();
+ Object result = jmxServerConnection.getAttribute(new ObjectName(name), attribute);
if (result != null) {
return result.toString();
}
@@ -237,6 +266,8 @@ public abstract class JMXAccessorConditionBase extends ProjectComponent implemen
* Exceptions are ignored for compatibility with the waitFor task when waiting for the server to start. If
* the exception was thrown the build task would fail rather than wait.
*/
+ } finally {
+ closeJMXConnector();
}
return null;
}
diff --git a/java/org/apache/catalina/ant/jmx/JMXAccessorTask.java b/java/org/apache/catalina/ant/jmx/JMXAccessorTask.java
index 91d66c4ef8..4a80078fde 100644
--- a/java/org/apache/catalina/ant/jmx/JMXAccessorTask.java
+++ b/java/org/apache/catalina/ant/jmx/JMXAccessorTask.java
@@ -125,6 +125,12 @@ public class JMXAccessorTask extends BaseRedirectorHelperTask {
private final Properties properties = new Properties();
+ /*
+ * Connector owned by this task for the duration of a single execution. Only set when the connection was created
+ * by this task and is not shared via a project reference, so it can be closed when the task completes.
+ */
+ private JMXConnector jmxConnector;
+
// ------------------------------------------------------------- Properties
/**
@@ -398,6 +404,7 @@ public class JMXAccessorTask extends BaseRedirectorHelperTask {
handleErrorOutput(e.getMessage());
}
} finally {
+ closeJMXConnector();
closeRedirector();
}
}
@@ -420,6 +427,29 @@ public class JMXAccessorTask extends BaseRedirectorHelperTask {
*/
public static MBeanServerConnection createJMXConnection(String url, String host, String port, String username,
String password) throws MalformedURLException, IOException {
+ return createJMXConnector(url, host, port, username, password).getMBeanServerConnection();
+ }
+
+ /**
+ * Create a new JMX Connection with auth when username and password is set. The caller is responsible for closing
+ * the returned connector.
+ *
+ * @param url URL to be used for the JMX connection (if specified, it is a complete URL so host and port will
+ * not be used)
+ * @param host Host name of the JMX server
+ * @param port Port number for the JMX server
+ * @param username User name for the connection
+ * @param password Credentials corresponding to the specified user
+ *
+ * @throws MalformedURLException Invalid URL specified
+ * @throws IOException Other connection error
+ *
+ * @return the JMX connector
+ *
+ * @since 12.0.x
+ */
+ public static JMXConnector createJMXConnector(String url, String host, String port, String username,
+ String password) throws MalformedURLException, IOException {
String urlForJMX;
if (url != null) {
urlForJMX = url;
@@ -434,9 +464,7 @@ public class JMXAccessorTask extends BaseRedirectorHelperTask {
environment = new HashMap<>();
environment.put(JMXConnector.CREDENTIALS, credentials);
}
- // FIXME: Referencing JMXConnector instead of MBeanServerConnection is needed to close the connection
- return JMXConnectorFactory.connect(new JMXServiceURL(urlForJMX), environment).getMBeanServerConnection();
-
+ return JMXConnectorFactory.connect(new JMXServiceURL(urlForJMX), environment);
}
/**
@@ -515,30 +543,48 @@ public class JMXAccessorTask extends BaseRedirectorHelperTask {
*/
protected MBeanServerConnection getJMXConnection() throws MalformedURLException, IOException {
MBeanServerConnection jmxServerConnection = null;
- if (isUseRef()) {
- Object pref;
- if (getProject() != null) {
- pref = getProject().getReference(getRef());
- if (pref != null) {
- try {
- jmxServerConnection = (MBeanServerConnection) pref;
- } catch (ClassCastException cce) {
- getProject().log("Wrong object reference " + getRef() + " - " + pref.getClass());
- return null;
- }
+ boolean refAvailable = isUseRef() && getProject() != null;
+ if (refAvailable) {
+ Object pref = getProject().getReference(getRef());
+ if (pref != null) {
+ try {
+ jmxServerConnection = (MBeanServerConnection) pref;
+ } catch (ClassCastException cce) {
+ getProject().log("Wrong object reference " + getRef() + " - " + pref.getClass());
+ return null;
}
}
- if (jmxServerConnection == null) {
+ }
+ if (jmxServerConnection == null) {
+ if (refAvailable) {
+ // A reference is available: the connection is stored in the project for reuse by later tasks in
+ // the same build and is intentionally left open, so this task does not own it.
jmxServerConnection = accessJMXConnection(getProject(), getUrl(), getHost(), getPort(), getUsername(),
getPassword(), getRef());
+ } else {
+ // No reference to store it in: this task owns the connection and closes it when it completes.
+ jmxConnector = createJMXConnector(getUrl(), getHost(), getPort(), getUsername(), getPassword());
+ jmxServerConnection = jmxConnector.getMBeanServerConnection();
}
- } else {
- jmxServerConnection = accessJMXConnection(getProject(), getUrl(), getHost(), getPort(), getUsername(),
- getPassword(), null);
}
return jmxServerConnection;
}
+ /**
+ * Close the JMX connection owned by this task, if any. Connections shared through a project reference are not
+ * owned by this task and are left open for reuse.
+ */
+ private void closeJMXConnector() {
+ if (jmxConnector != null) {
+ try {
+ jmxConnector.close();
+ } catch (IOException e) {
+ // Ignore errors while closing
+ }
+ jmxConnector = null;
+ }
+ }
+
/**
* Execute the specified command, based on the configured properties.
*
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org