diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml
index 422449a0536..75aac07d2a0 100644
--- a/.github/workflows/build-linux.yml
+++ b/.github/workflows/build-linux.yml
@@ -18,9 +18,43 @@ jobs:
- name: List ports
run: ss -tulpn
- name: Build with Maven
+ id: maven-build
# qa skips documentation - we check it on Jenkins CI
# We skip checkstyle too - we check it on Jenkins CI
- run: mvn -B -e -ntp install -Pstaging -Pqa '-Dcheckstyle.skip=true'
+ run: |
+ set -o pipefail
+ mvn -B -e -ntp install -Pstaging -Pqa '-Dcheckstyle.skip=true' 2>&1 | tee build.log
+ - name: Extract build failure info
+ if: failure() && steps.maven-build.outcome == 'failure'
+ run: |
+ echo "## Build Failure Summary" >> $GITHUB_STEP_SUMMARY
+ echo "### Last 100 lines of Maven output:" >> $GITHUB_STEP_SUMMARY
+ echo '```' >> $GITHUB_STEP_SUMMARY
+ tail -100 build.log >> $GITHUB_STEP_SUMMARY
+ echo '```' >> $GITHUB_STEP_SUMMARY
+
+ echo "### Error Analysis:" >> $GITHUB_STEP_SUMMARY
+ if grep -q "BUILD FAILURE" build.log; then
+ echo "- ❌ Maven build failed" >> $GITHUB_STEP_SUMMARY
+ # Extract the failure reason
+ echo "### Failure Reason:" >> $GITHUB_STEP_SUMMARY
+ echo '```' >> $GITHUB_STEP_SUMMARY
+ grep -A 10 "BUILD FAILURE" build.log | head -15 >> $GITHUB_STEP_SUMMARY
+ echo '```' >> $GITHUB_STEP_SUMMARY
+ fi
+ if grep -q "COMPILATION ERROR" build.log; then
+ echo "- ❌ Compilation errors detected" >> $GITHUB_STEP_SUMMARY
+ fi
+ if grep -q "Tests run:.*Failures: [1-9]" build.log; then
+ echo "- ❌ Test failures detected" >> $GITHUB_STEP_SUMMARY
+ fi
+ - name: Upload build log
+ uses: actions/upload-artifact@v4
+ if: failure()
+ with:
+ name: build-log
+ path: build.log
+ retention-days: 3
- name: Upload server logs
uses: actions/upload-artifact@v4
if: failure()
diff --git a/.github/workflows/build-macos.yml b/.github/workflows/build-macos.yml
index c203ba4a969..f27ad4e05e9 100644
--- a/.github/workflows/build-macos.yml
+++ b/.github/workflows/build-macos.yml
@@ -16,11 +16,48 @@ jobs:
distribution: 'temurin'
cache: maven
- name: Build with Maven
+ id: maven-build
# qa skips documentation - we check it on Jenkins CI
# We skip checkstyle too - we check it on Jenkins CI
- run: mvn -B -e -ntp install -Pstaging -Pqa '-Dcheckstyle.skip=true' -Pfastest
+ run: |
+ set -o pipefail
+ mvn -B -e -ntp install -Pstaging -Pqa '-Dcheckstyle.skip=true' -Pfastest 2>&1 | tee build.log
- name: Test Starts
- run: mvn -B -e -ntp install -Pstaging '-Dcheckstyle.skip=true' -pl :glassfish-itest-tools
+ id: test-starts
+ run: |
+ set -o pipefail
+ mvn -B -e -ntp install -Pstaging '-Dcheckstyle.skip=true' -pl :glassfish-itest-tools 2>&1 | tee -a build.log
+ - name: Extract build failure info
+ if: failure() && (steps.maven-build.outcome == 'failure' || steps.test-starts.outcome == 'failure')
+ run: |
+ echo "## Build Failure Summary" >> $GITHUB_STEP_SUMMARY
+ echo "### Last 100 lines of Maven output:" >> $GITHUB_STEP_SUMMARY
+ echo '```' >> $GITHUB_STEP_SUMMARY
+ tail -100 build.log >> $GITHUB_STEP_SUMMARY
+ echo '```' >> $GITHUB_STEP_SUMMARY
+
+ echo "### Error Analysis:" >> $GITHUB_STEP_SUMMARY
+ if grep -q "BUILD FAILURE" build.log; then
+ echo "- ❌ Maven build failed" >> $GITHUB_STEP_SUMMARY
+ # Extract the failure reason
+ echo "### Failure Reason:" >> $GITHUB_STEP_SUMMARY
+ echo '```' >> $GITHUB_STEP_SUMMARY
+ grep -A 10 "BUILD FAILURE" build.log | head -15 >> $GITHUB_STEP_SUMMARY
+ echo '```' >> $GITHUB_STEP_SUMMARY
+ fi
+ if grep -q "COMPILATION ERROR" build.log; then
+ echo "- ❌ Compilation errors detected" >> $GITHUB_STEP_SUMMARY
+ fi
+ if grep -q "Tests run:.*Failures: [1-9]" build.log; then
+ echo "- ❌ Test failures detected" >> $GITHUB_STEP_SUMMARY
+ fi
+ - name: Upload build log
+ uses: actions/upload-artifact@v4
+ if: failure()
+ with:
+ name: build-log
+ path: build.log
+ retention-days: 3
- name: Upload server logs
uses: actions/upload-artifact@v4
if: failure()
diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml
index 1e80a4c04fd..87bcd766b44 100644
--- a/.github/workflows/build-windows.yml
+++ b/.github/workflows/build-windows.yml
@@ -16,9 +16,44 @@ jobs:
distribution: 'temurin'
cache: maven
- name: Build with Maven
+ id: maven-build
# qa skips documentation - we check it on Jenkins CI
# We skip checkstyle too - we check it on Jenkins CI
- run: mvn -B -e -ntp install -Pstaging -Pqa '-Dcheckstyle.skip=true'
+ run: |
+ mvn -B -e -ntp install -Pstaging -Pqa '-Dcheckstyle.skip=true' 2>&1 | Tee-Object build.log
+ - name: Extract build failure info
+ if: failure() && steps.maven-build.outcome == 'failure'
+ shell: pwsh
+ run: |
+ echo "## Build Failure Summary" >> $env:GITHUB_STEP_SUMMARY
+ echo "### Last 100 lines of Maven output:" >> $env:GITHUB_STEP_SUMMARY
+ echo '```' >> $env:GITHUB_STEP_SUMMARY
+ Get-Content build.log -Tail 100 >> $env:GITHUB_STEP_SUMMARY
+ echo '```' >> $env:GITHUB_STEP_SUMMARY
+
+ echo "### Error Analysis:" >> $env:GITHUB_STEP_SUMMARY
+ $content = Get-Content build.log -Raw
+ if ($content -match "BUILD FAILURE") {
+ echo "- ❌ Maven build failed" >> $env:GITHUB_STEP_SUMMARY
+ # Extract the failure reason
+ echo "### Failure Reason:" >> $env:GITHUB_STEP_SUMMARY
+ echo '```' >> $env:GITHUB_STEP_SUMMARY
+ ($content | Select-String -Pattern "BUILD FAILURE" -Context 0,10).Context.PostContext[0..14] -join "`n" >> $env:GITHUB_STEP_SUMMARY
+ echo '```' >> $env:GITHUB_STEP_SUMMARY
+ }
+ if ($content -match "COMPILATION ERROR") {
+ echo "- ❌ Compilation errors detected" >> $env:GITHUB_STEP_SUMMARY
+ }
+ if ($content -match "Tests run:.*Failures: [1-9]") {
+ echo "- ❌ Test failures detected" >> $env:GITHUB_STEP_SUMMARY
+ }
+ - name: Upload build log
+ uses: actions/upload-artifact@v4
+ if: failure()
+ with:
+ name: build-log
+ path: build.log
+ retention-days: 3
- name: Upload server logs
uses: actions/upload-artifact@v4
if: failure()
diff --git a/appserver/admin/template/src/main/resources/config/domain.xml b/appserver/admin/template/src/main/resources/config/domain.xml
index c30fa534715..e1913bc4a58 100644
--- a/appserver/admin/template/src/main/resources/config/domain.xml
+++ b/appserver/admin/template/src/main/resources/config/domain.xml
@@ -223,6 +223,7 @@
--add-exports=java.naming/com.sun.jndi.ldap=ALL-UNNAMED
--add-exports=java.base/jdk.internal.vm.annotation=ALL-UNNAMED
--add-opens=java.base/jdk.internal.vm.annotation=ALL-UNNAMED
+ --add-exports=java.base/jdk.internal.loader=ALL-UNNAMED
-Djdk.attach.allowAttachSelf=true
@@ -421,6 +422,7 @@
--add-exports=java.naming/com.sun.jndi.ldap=ALL-UNNAMED
--add-exports=java.base/jdk.internal.vm.annotation=ALL-UNNAMED
--add-opens=java.base/jdk.internal.vm.annotation=ALL-UNNAMED
+ --add-exports=java.base/jdk.internal.loader=ALL-UNNAMED
-Djdk.attach.allowAttachSelf=true
diff --git a/appserver/extras/embedded/all/pom.xml b/appserver/extras/embedded/all/pom.xml
index 70bef2e780f..ffd5d797b10 100644
--- a/appserver/extras/embedded/all/pom.xml
+++ b/appserver/extras/embedded/all/pom.xml
@@ -127,6 +127,17 @@
+
+ org.codehaus.gmaven
+ groovy-maven-plugin
+
+
+ merge-manifest-values-to-properties
+ prepare-package
+
+
+
+
maven-assembly-plugin
@@ -166,8 +177,9 @@
true
org.glassfish.main.embedded.all
org.glassfish.runnablejar.UberMain
- java.base/java.lang java.base/java.io java.base/java.util java.base/sun.nio.fs java.base/sun.net.www.protocol.jrt java.naming/javax.naming.spi java.rmi/sun.rmi.transport jdk.management/com.sun.management.internal java.base/jdk.internal.vm.annotation
- java.naming/com.sun.jndi.ldap java.base/jdk.internal.vm.annotation
+ ${glassfish.embedded.add-opens}
+ ${glassfish.embedded.add-exports}
+ ${probe.provider.class.names}
diff --git a/appserver/extras/embedded/pom.xml b/appserver/extras/embedded/pom.xml
index 0e265f7c36d..8dd40eb9927 100644
--- a/appserver/extras/embedded/pom.xml
+++ b/appserver/extras/embedded/pom.xml
@@ -16,7 +16,6 @@
SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
-->
-
4.0.0
@@ -31,6 +30,11 @@
GlassFish Embedded modules
+
+ java.base/java.lang java.base/java.io java.base/java.util java.base/sun.nio.fs java.base/sun.net.www.protocol.jrt java.naming/javax.naming.spi java.rmi/sun.rmi.transport jdk.management/com.sun.management.internal java.base/jdk.internal.vm.annotation
+ java.naming/com.sun.jndi.ldap java.base/jdk.internal.vm.annotation java.base/jdk.internal.loader
+
+
common
all
@@ -52,4 +56,62 @@
+
+
+
+
+ org.codehaus.gmaven
+ groovy-maven-plugin
+
+
+
+ merge-manifest-values-to-properties
+
+ execute
+
+
+
+ import java.util.jar.JarFile
+ import java.util.jar.Manifest
+
+ def probeProviders = [] as Set
+
+ project.artifacts.each { artifact ->
+ if (artifact.type == 'jar') {
+ try {
+ def jar = new JarFile(artifact.file)
+ def manifest = jar.manifest
+ if (manifest) {
+ def probeValue = manifest.mainAttributes.getValue('probe-provider-class-names')
+ if (probeValue) {
+ probeProviders.add(probeValue)
+ }
+ }
+ jar.close()
+ } catch (Exception e) {
+ // Ignore invalid JARs
+ }
+ }
+ }
+
+ if (probeProviders) {
+ project.properties['probe.provider.class.names'] = probeProviders.join(',')
+ println "Found ${probeProviders.size()} probe providers in project dependencies"
+ } else {
+ println "No probe providers found in project dependencies"
+ }
+
+
+
+
+
+
+
+
+
diff --git a/appserver/extras/embedded/shell/glassfish-embedded-static-shell/pom.xml b/appserver/extras/embedded/shell/glassfish-embedded-static-shell/pom.xml
index 59d9311c990..2bc22191d43 100755
--- a/appserver/extras/embedded/shell/glassfish-embedded-static-shell/pom.xml
+++ b/appserver/extras/embedded/shell/glassfish-embedded-static-shell/pom.xml
@@ -1,7 +1,7 @@
-Djdk.attach.allowAttachSelf=true
@@ -342,6 +343,7 @@
--add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED
--add-opens=jdk.management/com.sun.management.internal=ALL-UNNAMED
--add-exports=java.naming/com.sun.jndi.ldap=ALL-UNNAMED
+ --add-exports=java.base/jdk.internal.loader=ALL-UNNAMED
-Djdk.attach.allowAttachSelf=true
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/GlassfishNetworkListener.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/GlassfishNetworkListener.java
index 5fa6c749962..353636f64ec 100644
--- a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/GlassfishNetworkListener.java
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/GlassfishNetworkListener.java
@@ -83,6 +83,11 @@ public NetworkListener getNetworkListener() {
@Override
public void stop() throws IOException {
+ stop(true);
+ }
+
+ @Override
+ public void stop(boolean lastOne) throws IOException {
ServiceLocator locator = grizzlyService.getServiceLocator();
IndexedFilter removeFilter = BuilderHelper.createNameAndContractFilter(Mapper.class.getName(),
(address.toString() + port));
@@ -94,7 +99,13 @@ public void stop() throws IOException {
config.commit();
- unregisterMonitoringStatsProviders();
+ // Do not call unregisterMonitoringStatsProviders()
+ // - providers are shared by all listeners, they would be removed also for other listeners.
+ // We could add a rule to unregister only if there are no other listeners.
+ if (lastOne) {
+ unregisterMonitoringStatsProviders();
+ }
+
super.stop();
}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/GrizzlyProxy.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/GrizzlyProxy.java
index 9a5d6013f18..2d173aa013f 100644
--- a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/GrizzlyProxy.java
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/GrizzlyProxy.java
@@ -143,6 +143,14 @@ public void stop() throws IOException {
grizzlyListener.stop();
}
+ /**
+ * Stops the Grizzly service and shared resources if last one.
+ */
+ @Override
+ public void stop(boolean lastOne) throws IOException {
+ grizzlyListener.stop(lastOne);
+ }
+
@Override
public void destroy() {
grizzlyListener.destroy();
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/GrizzlyService.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/GrizzlyService.java
index d4e52c5e4f2..dcb4ba51817 100644
--- a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/GrizzlyService.java
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/GrizzlyService.java
@@ -203,7 +203,8 @@ private NetworkProxy getNetworkProxy(String id) {
public boolean removeNetworkProxy(NetworkProxy proxy) {
if (proxy != null) {
try {
- proxy.stop();
+ boolean lastOne = proxies.size() == 1;
+ proxy.stop(lastOne);
} catch (IOException e) {
LOGGER.log(WARNING, KernelLoggerInfo.grizzlyStopProxy, e);
}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/NetworkProxy.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/NetworkProxy.java
index b31d525e817..2c31dccdeb8 100644
--- a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/NetworkProxy.java
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/NetworkProxy.java
@@ -42,6 +42,14 @@ public interface NetworkProxy extends EndpointMapper{
*/
void stop() throws IOException;
+ /**
+ * Stop the proxy and remove all shared resources if it's the last proxy.
+ * @param lastOne Whether it's the last proxy.
+ * {@code false} if other proxies still exist and depend on the shared resources
+ */
+ default void stop(boolean lastOne) throws IOException {
+ stop();
+ }
/**
* Start the proxy.
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/ThreadPoolMonitor.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/ThreadPoolMonitor.java
index d6f911f298b..3a26367be4a 100644
--- a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/ThreadPoolMonitor.java
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/ThreadPoolMonitor.java
@@ -17,6 +17,7 @@
package com.sun.enterprise.v3.services.impl.monitor;
import com.sun.enterprise.v3.services.impl.monitor.stats.ConnectionQueueStatsProvider;
+import com.sun.enterprise.v3.services.impl.monitor.stats.ThreadPoolStats;
import com.sun.enterprise.v3.services.impl.monitor.stats.ThreadPoolStatsProvider;
import org.glassfish.grizzly.threadpool.AbstractThreadPool;
@@ -30,17 +31,19 @@
public class ThreadPoolMonitor implements ThreadPoolProbe {
private final GrizzlyMonitoring grizzlyMonitoring;
private final String monitoringId;
+ private final ThreadPoolStats stats;
public ThreadPoolMonitor(GrizzlyMonitoring grizzlyMonitoring,
String monitoringId, ThreadPoolConfig config) {
this.grizzlyMonitoring = grizzlyMonitoring;
this.monitoringId = monitoringId;
+ this.stats = new ThreadPoolStats(config);
if (grizzlyMonitoring != null) {
final ThreadPoolStatsProvider threadPoolStatsProvider =
grizzlyMonitoring.getThreadPoolStatsProvider(monitoringId);
if (threadPoolStatsProvider != null) {
- threadPoolStatsProvider.setStatsObject(config);
+ threadPoolStatsProvider.setStatsObject(stats);
threadPoolStatsProvider.reset();
}
@@ -63,59 +66,97 @@ public void onThreadPoolStopEvent(AbstractThreadPool threadPool) {
@Override
public void onThreadAllocateEvent(AbstractThreadPool threadPool, Thread thread) {
+ stats.currentThreadCount = threadPool.getSize();
grizzlyMonitoring.getThreadPoolProbeProvider().threadAllocatedEvent(
monitoringId, threadPool.getConfig().getPoolName(),
thread.getId());
+ grizzlyMonitoring.getThreadPoolProbeProvider().setCurrentThreadCountEvent(
+ monitoringId, threadPool.getConfig().getPoolName(),
+ threadPool.getSize());
}
@Override
public void onThreadReleaseEvent(AbstractThreadPool threadPool, Thread thread) {
+ stats.currentThreadCount = threadPool.getSize();
grizzlyMonitoring.getThreadPoolProbeProvider().threadReleasedEvent(
monitoringId, threadPool.getConfig().getPoolName(),
thread.getId());
+ grizzlyMonitoring.getThreadPoolProbeProvider().setCurrentThreadCountEvent(
+ monitoringId, threadPool.getConfig().getPoolName(),
+ threadPool.getSize());
}
@Override
public void onMaxNumberOfThreadsEvent(AbstractThreadPool threadPool, int maxNumberOfThreads) {
+ stats.currentThreadCount = threadPool.getSize();
grizzlyMonitoring.getThreadPoolProbeProvider().maxNumberOfThreadsReachedEvent(
monitoringId, threadPool.getConfig().getPoolName(),
maxNumberOfThreads);
+ grizzlyMonitoring.getThreadPoolProbeProvider().setCurrentThreadCountEvent(
+ monitoringId, threadPool.getConfig().getPoolName(),
+ threadPool.getSize());
}
@Override
public void onTaskDequeueEvent(AbstractThreadPool threadPool, Runnable task) {
+ long currentBusyThreadCount = stats.currentBusyThreadCount.incrementAndGet();
+ stats.currentThreadCount = threadPool.getSize();
grizzlyMonitoring.getThreadPoolProbeProvider().threadDispatchedFromPoolEvent(
monitoringId, threadPool.getConfig().getPoolName(),
- Thread.currentThread().getId());
+ Thread.currentThread().getId(),
+ currentBusyThreadCount);
grizzlyMonitoring.getConnectionQueueProbeProvider().onTaskDequeuedEvent(
monitoringId, task.getClass().getName());
+ grizzlyMonitoring.getThreadPoolProbeProvider().setCurrentThreadCountEvent(
+ monitoringId, threadPool.getConfig().getPoolName(),
+ threadPool.getSize());
}
@Override
public void onTaskCancelEvent(AbstractThreadPool threadPool, Runnable task) {
+ long currentBusyThreadCount = stats.currentBusyThreadCount.decrementAndGet();
+ stats.currentThreadCount = threadPool.getSize();
// when dequeued task is cancelled - we have to "return" the thread, that
// we marked as dispatched from the pool
grizzlyMonitoring.getThreadPoolProbeProvider().threadReturnedToPoolEvent(
monitoringId, threadPool.getConfig().getPoolName(),
- Thread.currentThread().getId());
+ Thread.currentThread().getId(),
+ currentBusyThreadCount);
+ grizzlyMonitoring.getThreadPoolProbeProvider().setCurrentThreadCountEvent(
+ monitoringId, threadPool.getConfig().getPoolName(),
+ threadPool.getSize());
}
@Override
public void onTaskCompleteEvent(AbstractThreadPool threadPool, Runnable task) {
+ long currentBusyThreadCount = stats.currentBusyThreadCount.decrementAndGet();
+ stats.currentThreadCount = threadPool.getSize();
grizzlyMonitoring.getThreadPoolProbeProvider().threadReturnedToPoolEvent(
monitoringId, threadPool.getConfig().getPoolName(),
- Thread.currentThread().getId());
+ Thread.currentThread().getId(),
+ currentBusyThreadCount);
+ grizzlyMonitoring.getThreadPoolProbeProvider().setCurrentThreadCountEvent(
+ monitoringId, threadPool.getConfig().getPoolName(),
+ threadPool.getSize());
}
@Override
public void onTaskQueueEvent(AbstractThreadPool threadPool, Runnable task) {
+ stats.currentThreadCount = threadPool.getSize();
grizzlyMonitoring.getConnectionQueueProbeProvider().onTaskQueuedEvent(
monitoringId, task.getClass().getName());
+ grizzlyMonitoring.getThreadPoolProbeProvider().setCurrentThreadCountEvent(
+ monitoringId, threadPool.getConfig().getPoolName(),
+ threadPool.getSize());
}
@Override
public void onTaskQueueOverflowEvent(AbstractThreadPool threadPool) {
+ stats.currentThreadCount = threadPool.getSize();
grizzlyMonitoring.getConnectionQueueProbeProvider().onTaskQueueOverflowEvent(
monitoringId);
+ grizzlyMonitoring.getThreadPoolProbeProvider().setCurrentThreadCountEvent(
+ monitoringId, threadPool.getConfig().getPoolName(),
+ threadPool.getSize());
}
}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/probes/ThreadPoolProbeProvider.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/probes/ThreadPoolProbeProvider.java
index 33eeb947bc4..52feb47639a 100644
--- a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/probes/ThreadPoolProbeProvider.java
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/probes/ThreadPoolProbeProvider.java
@@ -68,12 +68,20 @@ public void maxNumberOfThreadsReachedEvent(
public void threadDispatchedFromPoolEvent(
@ProbeParam("monitoringId") String monitoringId,
@ProbeParam("threadPoolName") String threadPoolName,
- @ProbeParam("threadId") long threadId) {}
+ @ProbeParam("threadId") long threadId,
+ @ProbeParam("busyThreadCount") long busyThreadCount) {}
@Probe(name="threadReturnedToPoolEvent")
public void threadReturnedToPoolEvent(
@ProbeParam("monitoringId") String monitoringId,
@ProbeParam("threadPoolName") String threadPoolName,
- @ProbeParam("threadId") long threadId) {}
+ @ProbeParam("threadId") long threadId,
+ @ProbeParam("busyThreadCount") long busyThreadCount) {}
+
+ @Probe(name="setCurrentThreadCountEvent")
+ public void setCurrentThreadCountEvent(
+ @ProbeParam("monitoringId") String monitoringId,
+ @ProbeParam("threadPoolName") String threadPoolName,
+ @ProbeParam("currentThreadCount") int currentThreadCount) {}
}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/stats/ThreadPoolStats.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/stats/ThreadPoolStats.java
new file mode 100644
index 00000000000..83a0371f037
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/stats/ThreadPoolStats.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2025 Contributors to the Eclipse Foundation
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+package com.sun.enterprise.v3.services.impl.monitor.stats;
+
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.glassfish.grizzly.threadpool.ThreadPoolConfig;
+
+/**
+ * An object to hold thread pool statistics. Shared by ThreadPoolMonitor and stats providers (probe listeners),
+ * as some stats should be preserved even if the listeners is down.
+ * For example, thread counters, if there's no reliable way to find out the actual thread numbers from the thread pool (like busy threads).
+ *
+ * @author Ondro Mihalyi
+ */
+public class ThreadPoolStats {
+
+ public ThreadPoolConfig threadPoolConfig;
+
+ public volatile long currentThreadCount;
+
+ public AtomicLong currentBusyThreadCount = new AtomicLong();
+
+ public ThreadPoolStats(ThreadPoolConfig threadPoolConfig) {
+ this.threadPoolConfig = threadPoolConfig;
+ }
+
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/stats/ThreadPoolStatsProvider.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/stats/ThreadPoolStatsProvider.java
index d20b4e19cff..0d213ece593 100644
--- a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/stats/ThreadPoolStatsProvider.java
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/stats/ThreadPoolStatsProvider.java
@@ -25,7 +25,6 @@
import org.glassfish.gmbal.Description;
import org.glassfish.gmbal.ManagedAttribute;
import org.glassfish.gmbal.ManagedObject;
-import org.glassfish.grizzly.threadpool.ThreadPoolConfig;
/**
* Thread Pool statistics
@@ -45,7 +44,7 @@ public class ThreadPoolStatsProvider implements StatsProvider {
protected final CountStatisticImpl currentThreadCount = new CountStatisticImpl("CurrentThreadCount", "count", "Provides the number of request processing threads currently in the listener thread pool");
protected final CountStatisticImpl currentThreadsBusy = new CountStatisticImpl("CurrentThreadsBusy", "count", "Provides the number of request processing threads currently in use in the listener thread pool serving requests");
- protected volatile ThreadPoolConfig threadPoolConfig;
+ protected volatile ThreadPoolStats threadPoolStats;
public ThreadPoolStatsProvider(String name) {
this.name = name;
@@ -53,15 +52,15 @@ public ThreadPoolStatsProvider(String name) {
@Override
public Object getStatsObject() {
- return threadPoolConfig;
+ return threadPoolStats;
}
@Override
public void setStatsObject(Object object) {
- if (object instanceof ThreadPoolConfig) {
- threadPoolConfig = (ThreadPoolConfig) object;
+ if (object instanceof ThreadPoolStats) {
+ threadPoolStats = (ThreadPoolStats) object;
} else {
- threadPoolConfig = null;
+ threadPoolStats = null;
}
}
@@ -86,12 +85,18 @@ public CountStatistic getTotalExecutedTasksCount() {
@ManagedAttribute(id = "currentthreadcount")
@Description("Provides the number of request processing threads currently in the listener thread pool")
public CountStatistic getCurrentThreadCount() {
+ if (threadPoolStats != null) {
+ currentThreadCount.setCount(threadPoolStats.currentThreadCount);
+ }
return currentThreadCount;
}
@ManagedAttribute(id = "currentthreadsbusy")
@Description("Provides the number of request processing threads currently in use in the listener thread pool serving requests.")
public CountStatistic getCurrentThreadsBusy() {
+ if (threadPoolStats != null) {
+ currentThreadsBusy.setCount(threadPoolStats.currentBusyThreadCount.get());
+ }
return currentThreadsBusy;
}
@@ -143,10 +148,11 @@ public void threadReleasedEvent(
public void threadDispatchedFromPoolEvent(
@ProbeParam("monitoringId") String monitoringId,
@ProbeParam("threadPoolName") String threadPoolName,
- @ProbeParam("threadId") long threadId) {
+ @ProbeParam("threadId") long threadId,
+ @ProbeParam("busyThreadCount") long busyThreadCount) {
if (name.equals(monitoringId)) {
- currentThreadsBusy.increment();
+ currentThreadsBusy.setCount(busyThreadCount);
}
}
@@ -154,23 +160,35 @@ public void threadDispatchedFromPoolEvent(
public void threadReturnedToPoolEvent(
@ProbeParam("monitoringId") String monitoringId,
@ProbeParam("threadPoolName") String threadPoolName,
- @ProbeParam("threadId") long threadId) {
+ @ProbeParam("threadId") long threadId,
+ @ProbeParam("busyThreadCount") long busyThreadCount) {
if (name.equals(monitoringId)) {
totalExecutedTasksCount.increment();
- currentThreadsBusy.decrement();
+ currentThreadsBusy.setCount(busyThreadCount);
+ }
+ }
+
+ @ProbeListener("glassfish:kernel:thread-pool:setCurrentThreadCountEvent")
+ public void setCurrentThreadCountEvent(
+ @ProbeParam("monitoringId") String monitoringId,
+ @ProbeParam("threadPoolName") String threadPoolName,
+ @ProbeParam("currentThreadCount") int currentThreadCount) {
+ if (name.equals(monitoringId)) {
+ this.currentThreadCount.setCount(currentThreadCount);
}
}
@Reset
public void reset() {
- if (threadPoolConfig != null) {
- maxThreadsCount.setCount(threadPoolConfig.getMaxPoolSize());
- coreThreadsCount.setCount(threadPoolConfig.getCorePoolSize());
- currentThreadCount.setCount(0);
- currentThreadsBusy.setCount(0);
+ if (threadPoolStats != null) {
+ if (threadPoolStats.threadPoolConfig != null) {
+ maxThreadsCount.setCount(threadPoolStats.threadPoolConfig.getMaxPoolSize());
+ coreThreadsCount.setCount(threadPoolStats.threadPoolConfig.getCorePoolSize());
+ }
+ currentThreadCount.setCount(threadPoolStats.currentThreadCount);
+ currentThreadsBusy.setCount(threadPoolStats.currentBusyThreadCount.get());
}
-
totalExecutedTasksCount.setCount(0);
}
}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/stats/ThreadPoolStatsProviderGlobal.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/stats/ThreadPoolStatsProviderGlobal.java
index cee2c0c0460..a8e925d9074 100644
--- a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/stats/ThreadPoolStatsProviderGlobal.java
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/stats/ThreadPoolStatsProviderGlobal.java
@@ -76,19 +76,29 @@ public void threadReleasedEvent(
public void threadDispatchedFromPoolEvent(
@ProbeParam("monitoringId") String monitoringId,
@ProbeParam("threadPoolName") String threadPoolName,
- @ProbeParam("threadId") long threadId) {
+ @ProbeParam("threadId") long threadId,
+ @ProbeParam("busyThreadCount") long busyThreadCount) {
- currentThreadsBusy.increment();
+ currentThreadsBusy.setCount(busyThreadCount);
}
@ProbeListener("glassfish:kernel:thread-pool:threadReturnedToPoolEvent")
public void threadReturnedToPoolEvent(
@ProbeParam("monitoringId") String monitoringId,
@ProbeParam("threadPoolName") String threadPoolName,
- @ProbeParam("threadId") long threadId) {
+ @ProbeParam("threadId") long threadId,
+ @ProbeParam("busyThreadCount") long busyThreadCount) {
totalExecutedTasksCount.increment();
- currentThreadsBusy.decrement();
+ currentThreadsBusy.setCount(busyThreadCount);
+ }
+
+ @ProbeListener("glassfish:kernel:thread-pool:setCurrentThreadCountEvent")
+ public void setCurrentThreadCountEvent(
+ @ProbeParam("monitoringId") String monitoringId,
+ @ProbeParam("threadPoolName") String threadPoolName,
+ @ProbeParam("currentThreadCount") int currentThreadCount) {
+ this.currentThreadCount.setCount(currentThreadCount);
}
}
diff --git a/nucleus/core/kernel/src/main/java/org/glassfish/runnablejar/UberMain.java b/nucleus/core/kernel/src/main/java/org/glassfish/runnablejar/UberMain.java
index 7e78ffaf99c..675342b9240 100644
--- a/nucleus/core/kernel/src/main/java/org/glassfish/runnablejar/UberMain.java
+++ b/nucleus/core/kernel/src/main/java/org/glassfish/runnablejar/UberMain.java
@@ -40,6 +40,7 @@
import org.glassfish.runnablejar.commandline.CommandLineParser;
import static java.lang.System.exit;
+import static java.util.logging.Level.CONFIG;
import static java.util.logging.Level.FINE;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.SEVERE;
@@ -176,7 +177,7 @@ private void runCommandPromptLoop() throws GlassFishException {
}
private void executeCommandFromString(String stringCommand) {
- logger.log(FINE, () -> "Executing command: " + stringCommand);
+ logger.log(CONFIG, () -> "Executing command: " + stringCommand);
// Split according to empty space but not if empty space is escaped by \
String[] split = stringCommand.split("(?--add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED
--add-opens=java.naming/javax.naming.spi=org.glassfish.main.jdke
--add-exports=java.naming/com.sun.jndi.ldap=ALL-UNNAMED
+ --add-exports=java.base/jdk.internal.loader=ALL-UNNAMED
diff --git a/nucleus/flashlight/framework/src/main/java/org/glassfish/flashlight/FlashlightLoggerInfo.java b/nucleus/flashlight/framework/src/main/java/org/glassfish/flashlight/FlashlightLoggerInfo.java
index e261db84164..492a7faa018 100644
--- a/nucleus/flashlight/framework/src/main/java/org/glassfish/flashlight/FlashlightLoggerInfo.java
+++ b/nucleus/flashlight/framework/src/main/java/org/glassfish/flashlight/FlashlightLoggerInfo.java
@@ -132,11 +132,6 @@ public static Logger getLogger() {
level = "WARNING")
public static final String NO_ATTACH_API = LOGMSG_PREFIX + "-00510";
- @LogMessageInfo(
- message = "Error while getting Instrumentation object from ProbeAgentMain",
- level = "WARNING")
- public static final String NO_ATTACH_GET = LOGMSG_PREFIX + "-00511";
-
@LogMessageInfo(
message = "DTrace is not available.",
cause="This is caused if following are missing: \n1. JDK 7 is required to run DTrace\n2. glassfish-dtrace.jar value-add is required for DTrace",
diff --git a/nucleus/flashlight/framework/src/main/java/org/glassfish/flashlight/cli/EnableMonitoring.java b/nucleus/flashlight/framework/src/main/java/org/glassfish/flashlight/cli/EnableMonitoring.java
index 9d2bf7bc4b9..e7300b1dae0 100644
--- a/nucleus/flashlight/framework/src/main/java/org/glassfish/flashlight/cli/EnableMonitoring.java
+++ b/nucleus/flashlight/framework/src/main/java/org/glassfish/flashlight/cli/EnableMonitoring.java
@@ -126,7 +126,7 @@ public void execute(AdminCommandContext context) {
if (!AgentAttacher.attachAgent(pidInt, options)) {
ActionReport.MessagePart part = report.getTopMessagePart().addChild();
part.setMessage(localStrings.getLocalString("attach.agent.exception",
- "Can't attach the agent to the JVM."));
+ "Can't attach the monitoring agent to the JVM. Restart with the flashlight-agent.jar attached by the -javaagent command line parameter"));
report.setActionExitCode(ActionReport.ExitCode.FAILURE);
return;
}
diff --git a/nucleus/flashlight/framework/src/main/java/org/glassfish/flashlight/impl/client/AgentAttacher.java b/nucleus/flashlight/framework/src/main/java/org/glassfish/flashlight/impl/client/AgentAttacher.java
index 8cf08ae96b5..d080c203a08 100644
--- a/nucleus/flashlight/framework/src/main/java/org/glassfish/flashlight/impl/client/AgentAttacher.java
+++ b/nucleus/flashlight/framework/src/main/java/org/glassfish/flashlight/impl/client/AgentAttacher.java
@@ -13,26 +13,63 @@
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
*/
-
package org.glassfish.flashlight.impl.client;
+import java.lang.instrument.Instrumentation;
+import java.lang.reflect.Method;
+import java.util.Optional;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.glassfish.flashlight.FlashlightLoggerInfo;
+
+
/**
* created May 26, 2011
+ *
* @author Byron Nevins
*/
public final class AgentAttacher {
+
+ private static final String AGENT_CLASSNAME = "org.glassfish.flashlight.agent.ProbeAgentMain";
+
+ private static final Logger logger = FlashlightLoggerInfo.getLogger();
+
+ public static Optional getInstrumentation() {
+ try {
+ Class agentMainClass = null;
+ ClassLoader classLoader = ClassLoader.getSystemClassLoader();
+
+ try {
+ agentMainClass = classLoader.loadClass(AGENT_CLASSNAME);
+ } catch (Throwable t) {
+ // need throwable, not Exception - it may throw an Error!
+ // try one more time after attempting to attach.
+ AgentAttacher.attachAgent();
+ // might throw
+ agentMainClass = classLoader.loadClass(AGENT_CLASSNAME);
+ }
+
+ Method mthd = agentMainClass.getMethod("getInstrumentation", null);
+ return Optional.ofNullable((Instrumentation) mthd.invoke(null, null));
+ } catch (Throwable throwable) {
+ logger.log(Level.WARNING, "Error while getting Instrumentation object from ProbeAgentMain", throwable);
+ return Optional.empty();
+ }
+ }
+
public synchronized static boolean canAttach() {
return canAttach;
}
public synchronized static boolean isAttached() {
try {
- if (!canAttach)
+ if (!canAttach) {
return false;
+ }
return AgentAttacherInternal.isAttached();
- }
- catch (Throwable t) {
+ } catch (Throwable t) {
return false;
}
}
@@ -40,24 +77,24 @@ public synchronized static boolean isAttached() {
public synchronized static boolean attachAgent() {
try {
- if (!canAttach)
+ if (!canAttach) {
return false;
+ }
return attachAgent(-1, "");
- }
- catch (Throwable t) {
+ } catch (Throwable t) {
return false;
}
}
public synchronized static boolean attachAgent(int pid, String options) {
try {
- if (!canAttach)
+ if (!canAttach) {
return false;
+ }
return AgentAttacherInternal.attachAgent(pid, options);
- }
- catch (Throwable t) {
+ } catch (Throwable t) {
return false;
}
}
@@ -71,8 +108,7 @@ public synchronized static boolean attachAgent(int pid, String options) {
// this is a distinct possibility in embedded mode.
AgentAttacherInternal.isAttached();
b = true;
- }
- catch (Throwable t) {
+ } catch (Throwable t) {
b = false;
}
canAttach = b;
diff --git a/nucleus/flashlight/framework/src/main/java/org/glassfish/flashlight/impl/client/AgentAttacherInternal.java b/nucleus/flashlight/framework/src/main/java/org/glassfish/flashlight/impl/client/AgentAttacherInternal.java
index 56cdee4fd59..2b395d0e068 100644
--- a/nucleus/flashlight/framework/src/main/java/org/glassfish/flashlight/impl/client/AgentAttacherInternal.java
+++ b/nucleus/flashlight/framework/src/main/java/org/glassfish/flashlight/impl/client/AgentAttacherInternal.java
@@ -55,6 +55,12 @@ static boolean attachAgent(long pid, String options) {
}
if (pid < 0) {
+
+ if (AgentAttacher.getInstrumentation().isPresent()) {
+ isAttached = true;
+ return true;
+ }
+
pid = ProcessHandle.current().pid();
}
diff --git a/nucleus/flashlight/framework/src/main/java/org/glassfish/flashlight/impl/client/ProbeProviderClassFileTransformer.java b/nucleus/flashlight/framework/src/main/java/org/glassfish/flashlight/impl/client/ProbeProviderClassFileTransformer.java
index ba5c9383c66..cbb1c219e23 100644
--- a/nucleus/flashlight/framework/src/main/java/org/glassfish/flashlight/impl/client/ProbeProviderClassFileTransformer.java
+++ b/nucleus/flashlight/framework/src/main/java/org/glassfish/flashlight/impl/client/ProbeProviderClassFileTransformer.java
@@ -48,7 +48,6 @@
import static org.glassfish.embeddable.GlassFishVariable.INSTALL_ROOT;
import static org.glassfish.flashlight.FlashlightLoggerInfo.NO_ATTACH_API;
-import static org.glassfish.flashlight.FlashlightLoggerInfo.NO_ATTACH_GET;
import static org.glassfish.flashlight.FlashlightLoggerInfo.REGISTRATION_ERROR;
import static org.glassfish.flashlight.FlashlightLoggerInfo.RETRANSFORMATION_ERROR;
import static org.glassfish.flashlight.FlashlightLoggerInfo.WRITE_ERROR;
@@ -82,7 +81,6 @@ public class ProbeProviderClassFileTransformer implements ClassFileTransformer {
private static final Instrumentation instrumentation;
private static boolean _debug = Boolean.parseBoolean(Utility.getEnvOrProp("AS_DEBUG"));
private static boolean emittedAttachUnavailableMessageAlready = false;
- private static final String AGENT_CLASSNAME = "org.glassfish.flashlight.agent.ProbeAgentMain";
private static final Logger logger = FlashlightLoggerInfo.getLogger();
private ProbeProviderClassFileTransformer(Class providerClass) {
@@ -494,28 +492,7 @@ private Method getMethod(FlashlightProbe probe) throws NoSuchMethodException {
if (AgentAttacher.canAttach()) {
canAttach = true;
- try {
- ClassLoader classLoader = ClassLoader.getSystemClassLoader();
-
- try {
- agentMainClass = classLoader.loadClass(AGENT_CLASSNAME);
- }
- catch (Throwable t) {
- // need throwable, not Exception - it may throw an Error!
- // try one more time after attempting to attach.
- AgentAttacher.attachAgent();
- // might throw
- agentMainClass = classLoader.loadClass(AGENT_CLASSNAME);
- }
-
- Method mthd = agentMainClass.getMethod("getInstrumentation", null);
- nonFinalInstrumentation = (Instrumentation) mthd.invoke(null, null);
- }
- catch (Throwable t) {
- nonFinalInstrumentation = null;
- // save it for nice neat message code below
- throwable = t;
- }
+ nonFinalInstrumentation = AgentAttacher.getInstrumentation().orElse(null);
}
// set the final
instrumentation = nonFinalInstrumentation;
@@ -525,7 +502,7 @@ private Method getMethod(FlashlightProbe probe) throws NoSuchMethodException {
} else if (instrumentation != null) {
Log.info("yes.attach.api", instrumentation);
} else {
- logger.log(Level.WARNING, NO_ATTACH_GET, throwable);
+ logger.log(Level.WARNING, "Could not attach agent");
}
}
}
diff --git a/nucleus/flashlight/framework/src/main/java/org/glassfish/flashlight/provider/FlashlightProbe.java b/nucleus/flashlight/framework/src/main/java/org/glassfish/flashlight/provider/FlashlightProbe.java
index b13a57fb185..5dc37c30ac8 100644
--- a/nucleus/flashlight/framework/src/main/java/org/glassfish/flashlight/provider/FlashlightProbe.java
+++ b/nucleus/flashlight/framework/src/main/java/org/glassfish/flashlight/provider/FlashlightProbe.java
@@ -146,10 +146,9 @@ public void fireProbe(Object[] params) {
parent.fireProbe(params);
}
- int sz = invokerList.size();
+ List invokers = new ArrayList<>(invokerList);
- for (int i=0; i fireProbeBefore(Object[] params) {
probeInvokeStates.addAll(parentStates);
}
- int sz = invokerList.size();
+ List invokers = new ArrayList<>(invokerList);
- for (int i=0; i invokers = new ArrayList<>(invokerList);
int stateIndex = -1;
- for (int i=0; i= 0)
- invoker.invokeOnException(states.get(stateIndex).getState(), exceptionValue);
+ statefulInvoker.invokeOnException(states.get(stateIndex).getState(), exceptionValue);
}
}
}
diff --git a/nucleus/grizzly/config/src/main/java/org/glassfish/grizzly/config/GrizzlyListener.java b/nucleus/grizzly/config/src/main/java/org/glassfish/grizzly/config/GrizzlyListener.java
index e3ffd8474ad..0b969f08e0b 100644
--- a/nucleus/grizzly/config/src/main/java/org/glassfish/grizzly/config/GrizzlyListener.java
+++ b/nucleus/grizzly/config/src/main/java/org/glassfish/grizzly/config/GrizzlyListener.java
@@ -43,6 +43,10 @@ public interface GrizzlyListener {
void stop() throws IOException;
+ default void stop(boolean lastOne) throws IOException {
+ stop();
+ }
+
void destroy();
String getName();