This is an automated email from the ASF dual-hosted git repository. vladimirsitnikov pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/jmeter.git
commit b15439e340b6c566fddc41874257d7a200455496 Author: Vladimir Sitnikov <[email protected]> AuthorDate: Thu May 25 11:13:44 2023 +0300 feat: use ServiceLoader for loading jmeter.gui.action.Command --- .../org/apache/jmeter/gui/action/ActionRouter.java | 72 +++++----------------- .../java/org/apache/jmeter/gui/action/Command.java | 2 + 2 files changed, 17 insertions(+), 57 deletions(-) diff --git a/src/core/src/main/java/org/apache/jmeter/gui/action/ActionRouter.java b/src/core/src/main/java/org/apache/jmeter/gui/action/ActionRouter.java index 24536f7ec7..af91e3b52a 100644 --- a/src/core/src/main/java/org/apache/jmeter/gui/action/ActionRouter.java +++ b/src/core/src/main/java/org/apache/jmeter/gui/action/ActionRouter.java @@ -20,17 +20,13 @@ package org.apache.jmeter.gui.action; import java.awt.HeadlessException; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.io.File; -import java.io.IOException; -import java.net.URISyntaxException; -import java.net.URL; -import java.security.CodeSource; import java.util.Arrays; +import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Optional; +import java.util.ServiceLoader; import java.util.Set; import javax.swing.SwingUtilities; @@ -38,7 +34,7 @@ import javax.swing.SwingUtilities; import org.apache.jmeter.exceptions.IllegalUserActionException; import org.apache.jmeter.gui.GuiPackage; import org.apache.jmeter.util.JMeterUtils; -import org.apache.jorphan.reflect.ClassFinder; +import org.apache.jorphan.reflect.LogAndIgnoreServiceLoadExceptionHandler; import org.apache.jorphan.util.JMeterError; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -309,35 +305,6 @@ public final class ActionRouter implements ActionListener { } } - @SuppressWarnings("deprecation") - private static List<String> findClassesThatExtend(String className, String excluding, String[] searchPath) throws IOException, ClassNotFoundException { - - return ClassFinder.findClassesThatExtend( - searchPath, // strPathsOrJars - pathNames or jar files to search for classes - new Class[] { Class.forName(className) }, - false, // innerClasses - should we include inner classes? - null, // contains - className should contain this string - // Ignore the classes which are specific to the reporting tool - excluding, // notContains - className should not contain this string - false); // annotations - true if classNames are annotations - } - - private static Optional<String[]> getCodeSourceSearchPath() { - CodeSource codeSource = ActionRouter.class.getProtectionDomain().getCodeSource(); - if (codeSource != null) { - try { - URL ownLocation = codeSource.getLocation(); - File ownPath = new File(ownLocation.toURI()); - if (ownPath.exists()) { - return Optional.of(new String[] { ownPath.getAbsolutePath() }); - } - } catch (URISyntaxException ex) { - log.debug("Can't get location for class sources", ex); - } - } - return Optional.empty(); - } - /** * Only for use by the JMeter.startGui. * This method must not be called by getInstance() as was done previously. @@ -348,28 +315,19 @@ public final class ActionRouter implements ActionListener { return; // already done } try { - List<String> listClasses = findClassesThatExtend("org.apache.jmeter.gui.action.Command", // $NON-NLS-1$ - "org.apache.jmeter.report.gui", // $NON-NLS-1$ - JMeterUtils.getSearchPaths()); - - if (listClasses.isEmpty()) { - //fallback - Optional<String[]> codeSourceSearchPath = getCodeSourceSearchPath(); - if (codeSourceSearchPath.isPresent()) { - log.info("Using fallback search path"); - listClasses = findClassesThatExtend("org.apache.jmeter.gui.action.Command", // $NON-NLS-1$ - "org.apache.jmeter.report.gui", // $NON-NLS-1$ - codeSourceSearchPath.get()); - } - } - - if (listClasses.isEmpty()) { - log.error("!!!!!Uh-oh, didn't find any action handlers!!!!!"); - throw new JMeterError("No action handlers found - check JMeterHome and libraries"); + Collection<Command> commandServices = JMeterUtils.loadServicesAndScanJars( + Command.class, + ServiceLoader.load(Command.class), + Thread.currentThread().getContextClassLoader(), + new LogAndIgnoreServiceLoadExceptionHandler(log) + ); + + if (commandServices.isEmpty()) { + String message = "No implementations of " + Command.class + " found. Please ensure the classpath contains JMeter commands"; + log.error(message); + throw new JMeterError(message); } - for (String strClassName : listClasses) { - Class<?> commandClass = Class.forName(strClassName); - Command command = (Command) commandClass.getDeclaredConstructor().newInstance(); + for (Command command : commandServices) { for (String commandName : command.getActionNames()) { Set<Command> commandObjects = commands.computeIfAbsent(commandName, k -> new HashSet<>()); commandObjects.add(command); diff --git a/src/core/src/main/java/org/apache/jmeter/gui/action/Command.java b/src/core/src/main/java/org/apache/jmeter/gui/action/Command.java index 97dcd1e70b..e7284f8fec 100644 --- a/src/core/src/main/java/org/apache/jmeter/gui/action/Command.java +++ b/src/core/src/main/java/org/apache/jmeter/gui/action/Command.java @@ -21,7 +21,9 @@ import java.awt.event.ActionEvent; import java.util.Set; import org.apache.jmeter.exceptions.IllegalUserActionException; +import org.apache.jorphan.reflect.JMeterService; +@JMeterService public interface Command { void doAction(ActionEvent e) throws IllegalUserActionException;
