From 627cde74e34f489b3e2ea6a4eccccfd1f0b8ca58 Mon Sep 17 00:00:00 2001 From: Guus der Kinderen Date: Sat, 2 Nov 2024 19:30:43 +0100 Subject: [PATCH] Fixes #12: Compatibility with Openfire 4.8.0 This commit disables the CoreThreadPoolEvaluator, which isn't compatible any more since the switch from MINA to Netty. A new ticket has been created to restore this functionality in a future version (#16). --- changelog.html | 2 + pom.xml | 2 +- .../jasper/runtime/JspSourceImports.java | 31 ---------- .../plugin/threaddump/ThreadDumpPlugin.java | 6 +- .../evaluator/CoreThreadPoolsEvaluator.java | 60 ++++++++++++------- .../DatabaseConnectionPoolEvaluator.java | 8 +-- src/main/web/threaddump.jsp | 7 ++- src/plugin.xml | 2 +- src/readme.html | 19 +++--- 9 files changed, 64 insertions(+), 73 deletions(-) delete mode 100644 src/main/java/org/apache/jasper/runtime/JspSourceImports.java diff --git a/changelog.html b/changelog.html index df0c1a2..1f95feb 100644 --- a/changelog.html +++ b/changelog.html @@ -48,6 +48,8 @@

1.2.0 -- (tbd)

1.1.1 -- August 31, 2023

diff --git a/pom.xml b/pom.xml index a36afd7..589177c 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ plugins org.igniterealtime.openfire - 4.3.0 + 4.8.0 org.igniterealtime.openfire.plugins diff --git a/src/main/java/org/apache/jasper/runtime/JspSourceImports.java b/src/main/java/org/apache/jasper/runtime/JspSourceImports.java deleted file mode 100644 index cb9e441..0000000 --- a/src/main/java/org/apache/jasper/runtime/JspSourceImports.java +++ /dev/null @@ -1,31 +0,0 @@ -// This class is added to the sources of this plugin to make the plugin executable in Openfire versions prior to 4.3.0. -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jasper.runtime; - -import java.util.Set; - -/** - * The EL engine needs access to the imports used in the JSP page to configure - * the ELContext. The imports are available at compile time but the ELContext - * is created lazily per page. This interface exposes the imports at runtime so - * that they may be added to the ELContext when it is created. - */ -public interface JspSourceImports { - Set getPackageImports(); - Set getClassImports(); -} diff --git a/src/main/java/org/igniterealtime/openfire/plugin/threaddump/ThreadDumpPlugin.java b/src/main/java/org/igniterealtime/openfire/plugin/threaddump/ThreadDumpPlugin.java index ed8105a..f676d73 100644 --- a/src/main/java/org/igniterealtime/openfire/plugin/threaddump/ThreadDumpPlugin.java +++ b/src/main/java/org/igniterealtime/openfire/plugin/threaddump/ThreadDumpPlugin.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 Ignite Realtime Foundation. All rights reserved. + * Copyright (C) 2019-2024 Ignite Realtime Foundation. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -82,7 +82,7 @@ public synchronized void configMonitor() { try { - final Evaluator evaluator = evaluatorClass.newInstance(); + final Evaluator evaluator = evaluatorClass.getDeclaredConstructor().newInstance(); if (evaluator.isSupported()) { evaluators.add(evaluator); } else { @@ -98,7 +98,7 @@ public synchronized void configMonitor() if ( !evaluators.isEmpty() ) { final Duration backoff = Duration.of( backoffMS, ChronoUnit.MILLIS ); - Log.info( "Scheduling a check for thread dump necessity evaluation every {}ms (starting after a delay of {}ms. No more than one dump per {} will be generated.", new Object[] {intervalMS, delayMS, backoff} ); + Log.info( "Scheduling a check for thread dump necessity evaluation every {}ms (starting after a delay of {}ms. No more than one dump per {} will be generated.", intervalMS, delayMS, backoff); evaluators.forEach( evaluator -> Log.info( "Enabled evaluator {}, running every {}", evaluator.getClass().getCanonicalName(), evaluator.getInterval() ) ); task = new DumpCheckTimerTask( backoff ); evaluators.forEach(task::add); diff --git a/src/main/java/org/igniterealtime/openfire/plugin/threaddump/evaluator/CoreThreadPoolsEvaluator.java b/src/main/java/org/igniterealtime/openfire/plugin/threaddump/evaluator/CoreThreadPoolsEvaluator.java index c71cec4..e5edc39 100644 --- a/src/main/java/org/igniterealtime/openfire/plugin/threaddump/evaluator/CoreThreadPoolsEvaluator.java +++ b/src/main/java/org/igniterealtime/openfire/plugin/threaddump/evaluator/CoreThreadPoolsEvaluator.java @@ -1,11 +1,25 @@ +/* + * Copyright (C) 2019-2024 Ignite Realtime Foundation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.igniterealtime.openfire.plugin.threaddump.evaluator; -import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder; -import org.apache.mina.filter.executor.ExecutorFilter; -import org.apache.mina.transport.socket.nio.NioSocketAcceptor; import org.jivesoftware.openfire.XMPPServer; +import org.jivesoftware.openfire.spi.ConnectionAcceptor; import org.jivesoftware.openfire.spi.ConnectionListener; import org.jivesoftware.openfire.spi.ConnectionManagerImpl; +import org.jivesoftware.openfire.spi.NettyConnectionAcceptor; import org.jivesoftware.util.JiveGlobals; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -13,7 +27,6 @@ import java.time.Duration; import java.time.temporal.ChronoUnit; import java.util.Set; -import java.util.concurrent.ThreadPoolExecutor; public class CoreThreadPoolsEvaluator implements Evaluator { @@ -60,31 +73,38 @@ protected boolean checkPools() final Set listeners = ((ConnectionManagerImpl) XMPPServer.getInstance().getConnectionManager()).getListeners(); for ( ConnectionListener listener : listeners ) { - final NioSocketAcceptor socketAcceptor = listener.getSocketAcceptor(); + final ConnectionAcceptor socketAcceptor = listener.getConnectionAcceptor(); if ( socketAcceptor == null ) { continue; } - final DefaultIoFilterChainBuilder filterChain = socketAcceptor.getFilterChain(); - if ( filterChain == null ) + if (!(socketAcceptor instanceof NettyConnectionAcceptor)) { continue; } - if ( filterChain.contains( ConnectionManagerImpl.EXECUTOR_FILTER_NAME ) ) - { - final ExecutorFilter executorFilter = (ExecutorFilter) filterChain.get( ConnectionManagerImpl.EXECUTOR_FILTER_NAME ); - final int max = ((ThreadPoolExecutor) executorFilter.getExecutor()).getMaximumPoolSize(); - final int act = ((ThreadPoolExecutor) executorFilter.getExecutor()).getActiveCount(); - final int busyPercentage = (int) Math.round( act * 100.0 / max ); - - Log.trace( "{}% ({}/{}) thread running in pool {} {}. Threshold: {}%", new Object[] { busyPercentage, act, max, listener.getType(), listener.getTLSPolicy(), busyPercentageLimit }); - if ( busyPercentage > busyPercentageLimit ) - { - return true; - } - } +// FIXME: Replace the MINA-based implementation with one that is compatible with Netty. See https://github.com/igniterealtime/openfire-threaddump-plugin/issues/16 +// final EventLoopGroup childEventLoopGroup = ((NettyConnectionAcceptor) socketAcceptor)..getChildEventLoopGroup(); +// if (childEventLoopGroup == null) +// { +// continue; +// } +// +// childEventLoopGroup. +// if ( filterChain.contains( ConnectionManagerImpl.EXECUTOR_FILTER_NAME ) ) +// { +// final ExecutorFilter executorFilter = (ExecutorFilter) filterChain.get( ConnectionManagerImpl.EXECUTOR_FILTER_NAME ); +// final int max = ((ThreadPoolExecutor) executorFilter.getExecutor()).getMaximumPoolSize(); +// final int act = ((ThreadPoolExecutor) executorFilter.getExecutor()).getActiveCount(); +// final int busyPercentage = (int) Math.round( act * 100.0 / max ); +// +// Log.trace( "{}% ({}/{}) thread running in pool {} {}. Threshold: {}%", busyPercentage, act, max, listener.getType(), listener.getTLSPolicy(), busyPercentageLimit); +// if ( busyPercentage > busyPercentageLimit ) +// { +// return true; +// } +// } } return false; diff --git a/src/main/java/org/igniterealtime/openfire/plugin/threaddump/evaluator/DatabaseConnectionPoolEvaluator.java b/src/main/java/org/igniterealtime/openfire/plugin/threaddump/evaluator/DatabaseConnectionPoolEvaluator.java index ebc70c4..d928429 100755 --- a/src/main/java/org/igniterealtime/openfire/plugin/threaddump/evaluator/DatabaseConnectionPoolEvaluator.java +++ b/src/main/java/org/igniterealtime/openfire/plugin/threaddump/evaluator/DatabaseConnectionPoolEvaluator.java @@ -1,5 +1,5 @@ /* - * Copyright (C) Ignite Realtime Foundation. All rights reserved. + * Copyright (C) 2022-2024 Ignite Realtime Foundation. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,16 +18,12 @@ import org.jivesoftware.database.ConnectionProvider; import org.jivesoftware.database.DbConnectionManager; import org.jivesoftware.database.DefaultConnectionProvider; -import org.jivesoftware.database.EmbeddedConnectionProvider; import org.jivesoftware.util.JiveGlobals; -import org.jivesoftware.util.TaskEngine; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.lang.reflect.Field; import java.time.Duration; import java.time.temporal.ChronoUnit; -import java.util.concurrent.ThreadPoolExecutor; public class DatabaseConnectionPoolEvaluator implements Evaluator { @@ -78,7 +74,7 @@ protected boolean checkPool() final int activeConnections = defaultConnectionProvider.getActiveConnections(); final int maxConnections = defaultConnectionProvider.getMaxConnections(); final int busyPercentage = 100 * activeConnections / maxConnections; - Log.trace( "{}% ({}/{}) connections of database pool are currently active. Threshold: {}%", new Object[] { busyPercentage, activeConnections, maxConnections, busyPercentageLimit }); + Log.trace( "{}% ({}/{}) connections of database pool are currently active. Threshold: {}%", busyPercentage, activeConnections, maxConnections, busyPercentageLimit); return busyPercentage > busyPercentageLimit; } else { Log.debug("This server is using {} as the database connection provider for Openfire, which is not supported by this evaluator.", connectionProvider.getClass().getSimpleName()); diff --git a/src/main/web/threaddump.jsp b/src/main/web/threaddump.jsp index d13d514..7d2fc62 100644 --- a/src/main/web/threaddump.jsp +++ b/src/main/web/threaddump.jsp @@ -123,8 +123,11 @@ pageContext.setAttribute( "dump", new DefaultThreadDumpFormatter().format( dump ) ); pageContext.setAttribute( "plugin", plugin ); - pageContext.setAttribute( "isPoolEvaluatorEnabled", plugin.getTaskEvaluatorClasses().contains( CoreThreadPoolsEvaluator.class ) ); - pageContext.setAttribute( "isPoolEvaluatorSupported", new CoreThreadPoolsEvaluator().isSupported() ); +// pageContext.setAttribute( "isPoolEvaluatorEnabled", plugin.getTaskEvaluatorClasses().contains( CoreThreadPoolsEvaluator.class ) ); +// pageContext.setAttribute( "isPoolEvaluatorSupported", new CoreThreadPoolsEvaluator().isSupported() ); + pageContext.setAttribute( "isPoolEvaluatorEnabled", false ); // FIXME re-enable when issue #12 is fixed. + pageContext.setAttribute( "isPoolEvaluatorSupported", false ); // FIXME re-enable when issue #12 is fixed. + pageContext.setAttribute( "isDBPoolEvaluatorEnabled", plugin.getTaskEvaluatorClasses().contains( DatabaseConnectionPoolEvaluator.class ) ); pageContext.setAttribute( "isDBPoolEvaluatorSupported", new DatabaseConnectionPoolEvaluator().isSupported() ); pageContext.setAttribute( "isDeadlockEvaluatorEnabled", plugin.getTaskEvaluatorClasses().contains( DeadlockEvaluator.class ) ); diff --git a/src/plugin.xml b/src/plugin.xml index 6769b40..7ab0aac 100644 --- a/src/plugin.xml +++ b/src/plugin.xml @@ -6,7 +6,7 @@ ${project.description} Ignite Realtime ${project.version} - 2023-08-31 + 2024-11-02 4.8.0 diff --git a/src/readme.html b/src/readme.html index f4c63ef..9aa5327 100644 --- a/src/readme.html +++ b/src/readme.html @@ -102,15 +102,16 @@

Configuration

The following evaluator classes are available:

  • -

    org.igniterealtime.openfire.plugin.threaddump.evaluator.CoreThreadPoolsEvaluator

    -

    An evaluator that periodically checks the activity in the thread pools that power most network-related activity. - - - - -
    threaddump.evaluator.threadpools.intervalThe frequency (in milliseconds) of core network thread pool evaluation.
    threaddump.evaluator.threadpools.busy-percentage-maxThe percentage of threads in a pool that can be running at the same time that is considered 'busy'.
    threaddump.evaluator.threadpools.successive-hitsHow many successive evaluations must have detected excessive thread pool usage, for a thread dump to be created.
    -

    -
  • + + + + + + + + + +

    org.igniterealtime.openfire.plugin.threaddump.evaluator.DatabaseConnectionPoolEvaluator

    An evaluator that periodically checks the amount of active database connections in the pool that manages the total amount of available connections. This evaluator is only available when using the standard database connection provider. It does not support the embedded database.