Skip to content

Commit 6c3eff8

Browse files
committed
Test for monitoring of Embedded GlassFish via JMX
1 parent da7c941 commit 6c3eff8

File tree

2 files changed

+165
-0
lines changed

2 files changed

+165
-0
lines changed

appserver/tests/embedded/runnable/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@
5151
<groupId>org.glassfish.main.extras</groupId>
5252
<artifactId>glassfish-embedded-web</artifactId>
5353
</dependency>
54+
<dependency>
55+
<groupId>org.glassfish.main.flashlight</groupId>
56+
<artifactId>flashlight-agent</artifactId>
57+
<version>${project.version}</version>
58+
</dependency>
5459
</dependencies>
5560

5661
<build>
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
/*
2+
* Copyright (c) 2025 Contributors to the Eclipse Foundation
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the Eclipse Public License v. 2.0, which is available at
6+
* http://www.eclipse.org/legal/epl-2.0.
7+
*
8+
* This Source Code may also be made available under the following Secondary
9+
* Licenses when the conditions for such availability set forth in the
10+
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
11+
* version 2 with the GNU Classpath Exception, which is available at
12+
* https://www.gnu.org/software/classpath/license.html.
13+
*
14+
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15+
*/
16+
package org.glassfish.tests.embedded.runnable;
17+
18+
import java.io.File;
19+
import java.io.IOException;
20+
import java.util.ArrayList;
21+
import java.util.List;
22+
import java.util.Optional;
23+
import java.util.Set;
24+
import java.util.concurrent.TimeUnit;
25+
import java.util.logging.Logger;
26+
27+
import javax.management.MBeanServerConnection;
28+
import javax.management.ObjectName;
29+
import javax.management.remote.JMXConnector;
30+
import javax.management.remote.JMXConnectorFactory;
31+
import javax.management.remote.JMXServiceURL;
32+
33+
import org.glassfish.tests.embedded.runnable.TestArgumentProviders.GfEmbeddedJarNameProvider;
34+
import org.junit.jupiter.params.ParameterizedTest;
35+
import org.junit.jupiter.params.provider.ArgumentsSource;
36+
37+
import static org.junit.jupiter.api.Assertions.assertNotNull;
38+
import static org.junit.jupiter.api.Assertions.assertTrue;
39+
40+
/**
41+
* @author Ondro Mihalyi
42+
*/
43+
public class MonitoringTest {
44+
45+
private static final Logger LOG = Logger.getLogger(MonitoringTest.class.getName());
46+
private static final int JMX_PORT = 8686;
47+
private static final int WAIT_SECONDS = 10;
48+
49+
@ParameterizedTest
50+
@ArgumentsSource(GfEmbeddedJarNameProvider.class)
51+
void testJmxMonitoringWithFlashlightAgent(String gfEmbeddedJarName) throws Exception {
52+
Process gfEmbeddedProcess = null;
53+
JMXConnector jmxConnector = null;
54+
try {
55+
gfEmbeddedProcess = startGlassFishWithJmx(gfEmbeddedJarName);
56+
57+
jmxConnector = connectToJmx();
58+
MBeanServerConnection mbsc = jmxConnector.getMBeanServerConnection();
59+
60+
bootAmxAndWait(mbsc);
61+
62+
verifyMonitoringMBeans(mbsc);
63+
64+
} finally {
65+
cleanup(jmxConnector, gfEmbeddedProcess);
66+
}
67+
}
68+
69+
private File createMonitoringPropertiesFile() throws Exception {
70+
File propertiesFile = File.createTempFile("monitoring", ".properties");
71+
java.nio.file.Files.write(propertiesFile.toPath(), List.of(
72+
"configs.config.server-config.monitoring-service.module-monitoring-levels.http-service=HIGH",
73+
"configs.config.server-config.monitoring-service.module-monitoring-levels.thread-pool=HIGH"
74+
));
75+
return propertiesFile;
76+
}
77+
78+
private Process startGlassFishWithJmx(String gfEmbeddedJarName) throws IOException {
79+
List<String> arguments = new ArrayList<>();
80+
arguments.add(ProcessHandle.current().info().command().get());
81+
arguments.addAll(List.of(
82+
"-javaagent:flashlight-agent.jar",
83+
"-Dcom.sun.management.jmxremote",
84+
"-Dcom.sun.management.jmxremote.port=" + JMX_PORT,
85+
"-Dcom.sun.management.jmxremote.authenticate=false",
86+
"-Dcom.sun.management.jmxremote.ssl=false",
87+
"-jar", gfEmbeddedJarName,
88+
"--noPort",
89+
"enable-monitoring --modules http-service"
90+
));
91+
92+
return new ProcessBuilder()
93+
.redirectOutput(ProcessBuilder.Redirect.PIPE)
94+
.redirectError(ProcessBuilder.Redirect.PIPE)
95+
.command(arguments)
96+
.start();
97+
}
98+
99+
private JMXConnector connectToJmx() throws Exception {
100+
JMXServiceURL serviceURL = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:" + JMX_PORT + "/jmxrmi");
101+
102+
for (int i = 0; i < WAIT_SECONDS * 2; i++) {
103+
try {
104+
return JMXConnectorFactory.connect(serviceURL, null);
105+
} catch (Exception e) {
106+
Thread.sleep(500);
107+
}
108+
}
109+
throw new IllegalStateException("Could not connect to JMX in " + WAIT_SECONDS + " seconds");
110+
}
111+
112+
private void bootAmxAndWait(MBeanServerConnection mbsc) throws Exception {
113+
ObjectName bootAMXObjectName = new ObjectName("amx-support:type=boot-amx");
114+
115+
for (int i = 0; i < WAIT_SECONDS * 2; i++) {
116+
if (mbsc.isRegistered(bootAMXObjectName)) {
117+
break;
118+
}
119+
Thread.sleep(500);
120+
}
121+
122+
123+
assertTrue(mbsc.isRegistered(bootAMXObjectName), "bootAMX is registered");
124+
125+
mbsc.invoke(bootAMXObjectName, "bootAMX", null, null);
126+
127+
// Wait for AMX runtime to be available
128+
for (int i = 0; i < WAIT_SECONDS * 2; i++) {
129+
Set<ObjectName> runtimeBeans = mbsc.queryNames(new ObjectName("amx:pp=/,type=runtime"), null);
130+
if (!runtimeBeans.isEmpty()) {
131+
return;
132+
}
133+
Thread.sleep(500);
134+
}
135+
throw new IllegalStateException("AMX runtime not available after " + WAIT_SECONDS + " seconds");
136+
}
137+
138+
private void verifyMonitoringMBeans(MBeanServerConnection mbsc) throws Exception {
139+
Set<ObjectName> requestBeans = mbsc.queryNames(new ObjectName("amx:type=request-mon,*"), null);
140+
assertTrue(!requestBeans.isEmpty(), "Request monitoring MBean should be present");
141+
142+
// Verify we can read monitoring data
143+
ObjectName requestBean = requestBeans.iterator().next();
144+
assertNotNull(mbsc.getAttribute(requestBean, "countrequests"), "Should be able to read request count");
145+
}
146+
147+
private void cleanup(JMXConnector jmxConnector, Process process) throws InterruptedException {
148+
if (jmxConnector != null) try { jmxConnector.close(); } catch (Exception ignored) {}
149+
if (process != null && process.isAlive()) {
150+
process.destroyForcibly();
151+
process.waitFor(5, TimeUnit.SECONDS);
152+
}
153+
}
154+
155+
private void cleanupFiles(File... files) {
156+
for (File file : files) {
157+
Optional.ofNullable(file).ifPresent(File::delete);
158+
}
159+
}
160+
}

0 commit comments

Comments
 (0)