Deployment of custom MBean causes java.net.MalformedURLException: Unsupported protocol: remote+http in JBoss EAP 7.3.0 and later
Environment
- Red Hat JBoss Enterprise Application Platform (EAP)
- 7.3
- 7.4
- 8.0
Issue
When deploying the following custom MBean code, deployment succeeds up to JBoss EAP 7.2.9 but fails for 7.3.0 and later (including 7.4).
public class ConfigService extends ServiceMBeanSupport implements ConfigServiceMBean {
private static final String JMX_URL = "service:jmx:remote+http://127.0.0.1:9990";
@Override
protected void startService() throws Exception {
JMXServiceURL serviceURL = new JMXServiceURL(JMX_URL);
try (JMXConnector jmxConnector = JMXConnectorFactory.connect(serviceURL, null)) { // java.net.MalformedURLException: Unsupported protocol: remote+http on JBoss EAP 7.3.0 or later, but it works up to 7.2.9
MBeanServerConnection connection = jmxConnector.getMBeanServerConnection();
...
Log of reproduction:
16:12:11,980 WARN [org.jboss.example.mbean.support.ConfigService] (MSC service thread 1-4) WFLYSYSJMX0006: Starting failed jboss.support:name=ConfigBean: java.net.MalformedURLException: Unsupported protocol: remote+http
at java.management/javax.management.remote.JMXConnectorFactory.newJMXConnector(JMXConnectorFactory.java:366)
at java.management/javax.management.remote.JMXConnectorFactory.connect(JMXConnectorFactory.java:269)
at deployment.SampleMBean.sar//org.jboss.example.mbean.support.ConfigService.startService(ConfigService.java:22)
at org.jboss.as.system-jmx@7.4.13.GA-redhat-00001//org.jboss.system.ServiceMBeanSupport.jbossInternalStart(ServiceMBeanSupport.java:255)
...
Resolution
This is a known issue This content is not included.JBEAP-25937 and is expected to be fixed in a future cumulative patch to JBoss EAP 7.4.z and 8.0.z. There are several workarounds.
Option#1. Use ManagementFactory.getPlatformMBeanServer() instead of remote-jmx
import org.jboss.system.ServiceMBeanSupport;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import java.lang.management.ManagementFactory;
public class SampleService extends ServiceMBeanSupport implements SampleServiceMBean {
@Override
protected void startService() throws Exception {
MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
ObjectName objectName = ObjectName.getInstance("jboss.as:management-root=server");
String attributeName = "serverState";
Object result = mBeanServer.getAttribute(objectName, attributeName);
System.out.println("serverState = " + result);
}
}
Option#2. Temporarily replace thread's context class loader to application modules's classloader
ClassLoader old = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
JMXServiceURL serviceURL = new JMXServiceURL(JMX_URL);
try (JMXConnector jmxConnector = JMXConnectorFactory.connect(serviceURL, null)) {
MBeanServerConnection connection = jmxConnector.getMBeanServerConnection();
ObjectName objectName = ObjectName.getInstance("jboss.as:management-root=server");
String attributeName = "serverState";
Object result = connection.getAttribute(objectName, attributeName);
System.out.println("serverState = " + result);
}
} finally {
Thread.currentThread().setContextClassLoader(old);
}
This workaround requires the following jboss-deployment-structure.xml for *.sar deployment
resources/META-INF/jboss-deployment-structure.xml
<?xml version="1.0" encoding="UTF-8"?>
<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.2">
<deployment>
<dependencies>
<module name="org.jboss.remoting-jmx" services="import"/>
</deployment>
</jboss-deployment-structure>
Option#3. Use singleton-session-bean instead of ServiceMBeanSupport
The JBoss Service Archive (sar) deployment is not part of the Java EE specification. It is now recommended to rewrite to singleton-session-bean covered by Java EE spec. For more details, please check Are service archives (sar), jboss-service.xml, JBoss MBeans, jboss-beans.xml recommended in JBoss EAP 6+. In ejb-jar/war deployments, Thread's context classloader is always the classloader of the application module.
Root Cause
The implementation of sar deployment has been moved from org.jboss.as.jmx to org.jboss.as.sar module by This content is not included.WFCORE-4179 and This content is not included.WFLY-11239 fixed in JBoss EAP 7.3.0. As of JBoss EAP 7.2.9 and earlier, the thread context classloader for ServiceMBeanSupport is org.jboss.as.jmx, not application deployment module. But org.jboss.as.jmx module depended on org.jboss.remoting-jmx. Consequently, before JBoss EAP 7.2.9, remote JMX calls are available from custom MBeans with ServiceMBeanSupport.
This solution is part of Red Hat’s fast-track publication program, providing a huge library of solutions that Red Hat engineers have created while supporting our customers. To give you the knowledge you need the instant it becomes available, these articles may be presented in a raw and unedited form.