├── src ├── test │ ├── resources │ │ ├── dummy.jar │ │ ├── serializedRepo │ │ ├── check-descriptors.sh │ │ ├── installed2.json │ │ ├── broken.json │ │ ├── lib_update.json │ │ ├── installed.json │ │ ├── suggest.json │ │ ├── check-descriptors.py │ │ ├── testVirtualPlugin.json │ │ ├── self_npe.json │ │ ├── lib_for_delete │ │ ├── lib_versions.json │ │ ├── plugins-map.jmx │ │ ├── http2_libs.json │ │ └── testplan.xml │ └── java │ │ └── org │ │ └── jmeterplugins │ │ └── repository │ │ ├── logging │ │ ├── LoggingConfiguratorTest.java │ │ ├── LoggingHookerTest.java │ │ ├── LoggerPanelWrappingTest.java │ │ └── LoggerAppenderTest.java │ │ ├── JARSourceEmul.java │ │ ├── exception │ │ └── DownloadExceptionTest.java │ │ ├── plugins │ │ ├── SuggestDialogTest.java │ │ ├── TestPlanAnalyzerTest.java │ │ └── PluginSuggesterTest.java │ │ ├── PluginCheckboxTest.java │ │ ├── PluginManagerMenuCreatorTest.java │ │ ├── cache │ │ └── PluginsRepoTest.java │ │ ├── http │ │ ├── HttpRetryStrategyTest.java │ │ └── StatsReporterTest.java │ │ ├── LibraryTest.java │ │ ├── PluginMock.java │ │ ├── ChangesMakerTest.java │ │ ├── PluginManagerDialogTest.java │ │ ├── PluginTest.java │ │ ├── PluginsListTest.java │ │ ├── PluginManagerCMDTest.java │ │ └── RepoTest.java └── main │ ├── resources │ └── org │ │ └── jmeterplugins │ │ ├── logo.png │ │ ├── logo22.png │ │ ├── logoUpdate.png │ │ ├── logo22Update.png │ │ ├── repository │ │ ├── PluginsManagerCMD.bat │ │ └── PluginsManagerCMD.sh │ │ ├── logo.svg │ │ └── logoUpdate.svg │ └── java │ └── org │ ├── jmeterplugins │ └── repository │ │ ├── GenericCallback.java │ │ ├── exception │ │ └── DownloadException.java │ │ ├── PluginCheckbox.java │ │ ├── logging │ │ ├── LoggerPanelWrapping.java │ │ ├── LoggingConfigurator.java │ │ ├── LoggingHooker.java │ │ └── LoggerAppender.java │ │ ├── util │ │ ├── PlaceholderTextField.java │ │ └── ComponentFinder.java │ │ ├── http │ │ ├── StatsReporter.java │ │ └── HttpRetryStrategy.java │ │ ├── JARSource.java │ │ ├── PluginUpgradesList.java │ │ ├── PluginManagerCMDInstaller.java │ │ ├── PluginManagerMenuCreator.java │ │ ├── JARSourceFilesystem.java │ │ ├── PluginIcon.java │ │ ├── cache │ │ └── PluginsRepo.java │ │ ├── CheckBoxList.java │ │ ├── plugins │ │ ├── PluginSuggester.java │ │ ├── SuggestDialog.java │ │ └── TestPlanAnalyzer.java │ │ ├── Library.java │ │ ├── PluginManagerMenuItem.java │ │ ├── SafeDeleter.java │ │ ├── PluginManagerCMD.java │ │ └── ChangesMaker.java │ └── apache │ ├── log │ ├── LogTarget.java │ ├── LogEvent.java │ ├── Priority.java │ ├── ContextMap.java │ └── Logger.java │ └── jorphan │ └── logging │ ├── Slf4jLogkitLogger.java │ └── LoggingManager.java ├── .gitignore ├── README.md ├── .travis.yml └── pom.xml /src/test/resources/dummy.jar: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea/ 2 | /target/ 3 | *.iml 4 | /dependency-reduced-pom.xml 5 | *.log -------------------------------------------------------------------------------- /src/test/resources/serializedRepo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Blazemeter/jmeter-plugins-manager/master/src/test/resources/serializedRepo -------------------------------------------------------------------------------- /src/main/resources/org/jmeterplugins/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Blazemeter/jmeter-plugins-manager/master/src/main/resources/org/jmeterplugins/logo.png -------------------------------------------------------------------------------- /src/main/resources/org/jmeterplugins/logo22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Blazemeter/jmeter-plugins-manager/master/src/main/resources/org/jmeterplugins/logo22.png -------------------------------------------------------------------------------- /src/main/resources/org/jmeterplugins/logoUpdate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Blazemeter/jmeter-plugins-manager/master/src/main/resources/org/jmeterplugins/logoUpdate.png -------------------------------------------------------------------------------- /src/main/resources/org/jmeterplugins/logo22Update.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Blazemeter/jmeter-plugins-manager/master/src/main/resources/org/jmeterplugins/logo22Update.png -------------------------------------------------------------------------------- /src/main/java/org/jmeterplugins/repository/GenericCallback.java: -------------------------------------------------------------------------------- 1 | package org.jmeterplugins.repository; 2 | 3 | public interface GenericCallback { 4 | void notify(T t); 5 | } -------------------------------------------------------------------------------- /src/test/resources/check-descriptors.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -xe 2 | jmeter -t $(dirname $0)/plugins-map.jmx -n 3 | python check-descriptors.py jmeter.log ~/Sources/JMeter/jmeter-plugins/site/dat/repo/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Plugins Manager for Apache JMeter 2 | 3 | [Official Website](https://jmeter-plugins.org/wiki/PluginsManager/) 4 | 5 | ![pmgr screenshot](https://jmeter-plugins.org/img/wiki/pmgr/pmgr_dialog.png) -------------------------------------------------------------------------------- /src/main/resources/org/jmeterplugins/repository/PluginsManagerCMD.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | java %JVM_ARGS% -jar "%~dp0\..\lib\cmdrunner-2.3.jar" --tool org.jmeterplugins.repository.PluginManagerCMD %* 4 | -------------------------------------------------------------------------------- /src/main/resources/org/jmeterplugins/repository/PluginsManagerCMD.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | java -Djava.awt.headless=true $JVM_ARGS -jar $(dirname $0)/../lib/cmdrunner-2.3.jar --tool org.jmeterplugins.repository.PluginManagerCMD "$@" 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false # to use new infrastructure 2 | language: java 3 | install: "mvn -Dmaven.test.skip=true clean install --batch-mode" 4 | script: "mvn -Djava.awt.headless=true -Dmaven.test.redirectTestOutputToFile=true --fail-at-end --batch-mode org.jacoco:jacoco-maven-plugin:prepare-agent test org.jacoco:jacoco-maven-plugin:report" 5 | after_success: 6 | - bash <(curl -s https://codecov.io/bash) -------------------------------------------------------------------------------- /src/main/java/org/jmeterplugins/repository/exception/DownloadException.java: -------------------------------------------------------------------------------- 1 | package org.jmeterplugins.repository.exception; 2 | 3 | /** 4 | * Throws when there are any errors in downloading 5 | */ 6 | public class DownloadException extends RuntimeException { 7 | public DownloadException() { 8 | } 9 | 10 | public DownloadException(String message) { 11 | super(message); 12 | } 13 | 14 | public DownloadException(String message, Throwable cause) { 15 | super(message, cause); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/test/java/org/jmeterplugins/repository/logging/LoggingConfiguratorTest.java: -------------------------------------------------------------------------------- 1 | package org.jmeterplugins.repository.logging; 2 | 3 | import org.junit.Test; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import static org.junit.Assert.assertNotNull; 8 | 9 | public class LoggingConfiguratorTest { 10 | 11 | @Test 12 | public void testFlow() throws Exception { 13 | LoggingConfigurator configurator = new LoggingConfigurator(); 14 | Logger log = LoggerFactory.getLogger(LoggingConfiguratorTest.class); 15 | log.info("Hi, logger"); 16 | assertNotNull(configurator); 17 | } 18 | } -------------------------------------------------------------------------------- /src/test/java/org/jmeterplugins/repository/JARSourceEmul.java: -------------------------------------------------------------------------------- 1 | package org.jmeterplugins.repository; 2 | 3 | import net.sf.json.JSON; 4 | 5 | import java.io.IOException; 6 | 7 | public class JARSourceEmul extends JARSource { 8 | @Override 9 | public JSON getRepo() throws IOException { 10 | return null; 11 | } 12 | 13 | @Override 14 | public void reportStats(String[] usageStats) throws IOException { 15 | // NOOP 16 | } 17 | 18 | @Override 19 | public void setTimeout(int timeout) { 20 | // NOOP 21 | } 22 | 23 | @Override 24 | public DownloadResult getJAR(String id, String location, GenericCallback statusChanged) throws IOException { 25 | return null; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/test/resources/installed2.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "jpgc-plugin1", 4 | "name": "Dependency plugin1", 5 | "description": "", 6 | "screenshotUrl": "https://jmeter-plugins.org/img/wiki/response_times_over_time.png", 7 | "helpUrl": "https://jmeter-plugins.org/wiki/ResponseTimesOverTime/", 8 | "vendor": "JMeter-Plugins.org", 9 | "markerClass": "org.jmeterplugins.repository.PluginManagerTest", 10 | "versions": { 11 | "0.0.0-STOCK": { 12 | "downloadUrl": "dummy.jar", 13 | "libs": { 14 | "commons-codec" : "commons-codec-0.4.jar", 15 | "q1w2e3>=2.2" : "q1w2e3-2.2.jar" 16 | } 17 | } 18 | } 19 | } 20 | ] -------------------------------------------------------------------------------- /src/test/java/org/jmeterplugins/repository/exception/DownloadExceptionTest.java: -------------------------------------------------------------------------------- 1 | package org.jmeterplugins.repository.exception; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | 8 | 9 | public class DownloadExceptionTest { 10 | 11 | @Test 12 | public void test() throws Exception { 13 | DownloadException exception = new DownloadException(); 14 | assertNull(exception.getMessage()); 15 | exception = new DownloadException("Message"); 16 | assertEquals("Message", exception.getMessage()); 17 | exception = new DownloadException("Message", new RuntimeException("Cause")); 18 | assertEquals("Message", exception.getMessage()); 19 | assertNotNull(exception.getCause() instanceof RuntimeException); 20 | assertEquals("Cause", exception.getCause().getMessage()); 21 | } 22 | } -------------------------------------------------------------------------------- /src/test/resources/broken.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "id": "installed", 3 | "name": "installed", 4 | "description": "Low-level HTTP request, solves memory problem for huge file upload/download case. Also ships Raw Data Source preprocessor.", 5 | "screenshotUrl": "https://jmeter-plugins.org/img/wiki/rawrequest.png", 6 | "helpUrl": "https://jmeter-plugins.org/wiki/RawRequest/", 7 | "vendor": "JMeter-Plugins.org", 8 | "markerClass": "kg.apc.jmeter.samplers.HTTPRawSampler", 9 | "versions": { 10 | "0.1": { 11 | "downloadUrl": "https://search.maven.org/remotecontent?filepath=kg/apc/jmeter-plugins-httpraw/0.1/jmeter-plugins-httpraw-0.1.jar", 12 | "libs": { 13 | "bsf>=99.8" : "lib-99.8.jar", 14 | "commons-jexl>=0.1" : "lib2-0.1.jar", 15 | "commons-codec" : "lib3.jar", 16 | "commons-jexl" : "lib4.jar" 17 | } 18 | } 19 | } 20 | } 21 | ] -------------------------------------------------------------------------------- /src/test/java/org/jmeterplugins/repository/plugins/SuggestDialogTest.java: -------------------------------------------------------------------------------- 1 | package org.jmeterplugins.repository.plugins; 2 | 3 | import kg.apc.emulators.TestJMeterUtils; 4 | import org.jmeterplugins.repository.PluginManager; 5 | import org.junit.BeforeClass; 6 | import org.junit.Test; 7 | 8 | import java.awt.*; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | public class SuggestDialogTest { 13 | 14 | @BeforeClass 15 | public static void setup() { 16 | TestJMeterUtils.createJmeterEnv(); 17 | } 18 | 19 | @Test 20 | public void testComponent() throws Exception { 21 | if (!GraphicsEnvironment.getLocalGraphicsEnvironment().isHeadlessInstance()) { 22 | PluginManager pmgr = new PluginManager(); 23 | SuggestDialog suggestDialog = new SuggestDialog(null, pmgr, pmgr.getAvailablePlugins(), "path"); 24 | suggestDialog.setVisible(true); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/main/java/org/jmeterplugins/repository/PluginCheckbox.java: -------------------------------------------------------------------------------- 1 | package org.jmeterplugins.repository; 2 | 3 | import javax.swing.JCheckBox; 4 | 5 | 6 | class PluginCheckbox extends JCheckBox { 7 | 8 | /** 9 | * 10 | */ 11 | private static final long serialVersionUID = 3604852617806921883L; 12 | private Plugin plugin; 13 | 14 | public PluginCheckbox(String name) { 15 | super(name); 16 | } 17 | 18 | public void setPlugin(Plugin plugin) { 19 | this.plugin = plugin; 20 | if (!plugin.canUninstall()) { 21 | super.setEnabled(false); 22 | } 23 | } 24 | 25 | public Plugin getPlugin() { 26 | return plugin; 27 | } 28 | 29 | @Override 30 | public void setEnabled(boolean b) { 31 | if (!plugin.canUninstall()) { 32 | super.setEnabled(false); 33 | } else { 34 | super.setEnabled(b); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/org/jmeterplugins/repository/logging/LoggerPanelWrapping.java: -------------------------------------------------------------------------------- 1 | package org.jmeterplugins.repository.logging; 2 | 3 | import org.apache.jmeter.gui.LoggerPanel; 4 | import org.apache.log.LogEvent; 5 | import org.jmeterplugins.repository.PluginManager; 6 | import org.jmeterplugins.repository.plugins.PluginSuggester; 7 | 8 | public class LoggerPanelWrapping extends LoggerPanel { 9 | 10 | protected PluginSuggester suggester; 11 | 12 | public LoggerPanelWrapping(PluginManager mgr) { 13 | super(); 14 | this.suggester = new PluginSuggester(mgr); 15 | } 16 | 17 | @Override 18 | public void processEvent(LogEvent logEvent) { 19 | if (logEvent.getCategory().contains("SaveService")) { 20 | suggester.checkAndSuggest(logEvent.getMessage()); 21 | } 22 | } 23 | 24 | public PluginSuggester getSuggester() { 25 | return suggester; 26 | } 27 | 28 | public void setSuggester(PluginSuggester suggester) { 29 | this.suggester = suggester; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/test/java/org/jmeterplugins/repository/PluginCheckboxTest.java: -------------------------------------------------------------------------------- 1 | package org.jmeterplugins.repository; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | public class PluginCheckboxTest { 8 | 9 | @Test 10 | public void testFlow() throws Exception { 11 | Plugin plugin = new Plugin("id"); 12 | plugin.name = "plugin-name"; 13 | plugin.canUninstall = true; 14 | PluginCheckbox checkbox = new PluginCheckbox(plugin.getName()); 15 | checkbox.setPlugin(plugin); 16 | 17 | assertTrue(checkbox.isEnabled()); 18 | checkbox.setEnabled(false); 19 | assertFalse(checkbox.isEnabled()); 20 | checkbox.setEnabled(true); 21 | assertTrue(checkbox.isEnabled()); 22 | 23 | plugin.canUninstall = false; 24 | checkbox.setPlugin(plugin); 25 | assertFalse(checkbox.isEnabled()); 26 | checkbox.setEnabled(true); 27 | assertFalse(checkbox.isEnabled()); 28 | 29 | assertEquals(plugin, checkbox.getPlugin()); 30 | } 31 | } -------------------------------------------------------------------------------- /src/main/java/org/jmeterplugins/repository/util/PlaceholderTextField.java: -------------------------------------------------------------------------------- 1 | package org.jmeterplugins.repository.util; 2 | 3 | import javax.swing.*; 4 | import java.awt.*; 5 | 6 | public class PlaceholderTextField extends JTextField { 7 | 8 | private String placeholder; 9 | 10 | @Override 11 | protected void paintComponent(final Graphics pG) { 12 | super.paintComponent(pG); 13 | 14 | if (placeholder.length() == 0 || getText().length() > 0) { 15 | return; 16 | } 17 | 18 | final Graphics2D g = (Graphics2D) pG; 19 | g.setRenderingHint( 20 | RenderingHints.KEY_ANTIALIASING, 21 | RenderingHints.VALUE_ANTIALIAS_ON); 22 | g.setColor(getDisabledTextColor()); 23 | g.drawString(placeholder, getInsets().left, pG.getFontMetrics() 24 | .getMaxAscent() + getInsets().top); 25 | } 26 | 27 | public void setPlaceholder(final String s) { 28 | placeholder = s; 29 | } 30 | 31 | public String getPlaceholder() { 32 | return placeholder; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/test/java/org/jmeterplugins/repository/logging/LoggingHookerTest.java: -------------------------------------------------------------------------------- 1 | package org.jmeterplugins.repository.logging; 2 | 3 | import kg.apc.emulators.TestJMeterUtils; 4 | import org.apache.jmeter.util.JMeterUtils; 5 | import org.jmeterplugins.repository.PluginManager; 6 | import org.jmeterplugins.repository.PluginManagerTest; 7 | import org.junit.BeforeClass; 8 | import org.junit.Test; 9 | 10 | import java.net.URL; 11 | 12 | import static org.junit.Assert.assertFalse; 13 | 14 | public class LoggingHookerTest { 15 | 16 | @BeforeClass 17 | public static void setup() { 18 | TestJMeterUtils.createJmeterEnv(); 19 | URL url = PluginManagerTest.class.getResource("/testVirtualPlugin.json"); 20 | JMeterUtils.setProperty("jpgc.repo.address", url.getFile()); 21 | } 22 | 23 | /** 24 | * For logging in JMeter 2.13-3.1 25 | */ 26 | @Test 27 | public void testFlowOld() throws Exception { 28 | LoggingHooker hooker = new LoggingHooker(new PluginManager()); 29 | hooker.hook(); 30 | assertFalse(hooker.isJMeter32orLater()); 31 | } 32 | 33 | 34 | } -------------------------------------------------------------------------------- /src/main/java/org/jmeterplugins/repository/util/ComponentFinder.java: -------------------------------------------------------------------------------- 1 | package org.jmeterplugins.repository.util; 2 | 3 | 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import java.awt.*; 8 | 9 | public class ComponentFinder { 10 | private static final Logger log = LoggerFactory.getLogger(ComponentFinder.class); 11 | 12 | private final Class search; 13 | 14 | public ComponentFinder(Class cls) { 15 | search = cls; 16 | } 17 | 18 | public T findComponentIn(Container container) { 19 | log.debug("Searching in " + container); 20 | for (Component a : container.getComponents()) { 21 | if (search.isAssignableFrom(a.getClass())) { 22 | log.debug("Found " + a); 23 | return (T) a; 24 | } 25 | 26 | if (a instanceof Container) { 27 | T res = findComponentIn((Container) a); 28 | if (res != null) { 29 | return res; 30 | } 31 | } 32 | } 33 | 34 | return null; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/test/java/org/jmeterplugins/repository/PluginManagerMenuCreatorTest.java: -------------------------------------------------------------------------------- 1 | package org.jmeterplugins.repository; 2 | 3 | import kg.apc.emulators.TestJMeterUtils; 4 | import org.apache.jmeter.gui.plugin.MenuCreator; 5 | import org.junit.BeforeClass; 6 | import org.junit.Test; 7 | 8 | import javax.swing.*; 9 | 10 | import static org.junit.Assert.assertEquals; 11 | 12 | 13 | public class PluginManagerMenuCreatorTest { 14 | @BeforeClass 15 | public static void setup() { 16 | TestJMeterUtils.createJmeterEnv(); 17 | } 18 | 19 | @Test 20 | public void getMenuItemsAtLocation() throws Exception { 21 | PluginManagerMenuCreator creator = new PluginManagerMenuCreator(); 22 | assertEquals(0, creator.getTopLevelMenus().length); 23 | creator.localeChanged(); 24 | JMenuItem[] menuItemsAtLocation = creator.getMenuItemsAtLocation(MenuCreator.MENU_LOCATION.OPTIONS); 25 | assertEquals(1, menuItemsAtLocation.length); 26 | assertEquals(0, creator.getMenuItemsAtLocation(MenuCreator.MENU_LOCATION.RUN).length); 27 | creator.localeChanged(menuItemsAtLocation[0]); 28 | } 29 | 30 | } -------------------------------------------------------------------------------- /src/main/java/org/jmeterplugins/repository/http/StatsReporter.java: -------------------------------------------------------------------------------- 1 | package org.jmeterplugins.repository.http; 2 | 3 | import org.jmeterplugins.repository.JARSource; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import java.io.IOException; 8 | 9 | public class StatsReporter extends Thread { 10 | private static final Logger log = LoggerFactory.getLogger(StatsReporter.class); 11 | 12 | private final JARSource jarSource; 13 | private final String[] usageStats; 14 | 15 | public StatsReporter(JARSource jarSource, String[] usageStats) throws CloneNotSupportedException { 16 | this.jarSource = (JARSource) jarSource.clone(); 17 | this.usageStats = usageStats; 18 | setDaemon(true); 19 | } 20 | 21 | @Override 22 | public void run() { 23 | try { 24 | jarSource.reportStats(usageStats); 25 | log.debug("Finished send repo stats"); 26 | } catch (IOException e) { 27 | log.warn("Failed to send repo stats", e); 28 | } 29 | } 30 | 31 | protected JARSource getJarSource() { 32 | return jarSource; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/test/java/org/jmeterplugins/repository/plugins/TestPlanAnalyzerTest.java: -------------------------------------------------------------------------------- 1 | package org.jmeterplugins.repository.plugins; 2 | 3 | import kg.apc.emulators.TestJMeterUtils; 4 | import org.junit.BeforeClass; 5 | import org.junit.Test; 6 | 7 | import java.util.Set; 8 | 9 | import static org.junit.Assert.*; 10 | 11 | 12 | public class TestPlanAnalyzerTest { 13 | 14 | @BeforeClass 15 | public static void setup() { 16 | TestJMeterUtils.createJmeterEnv(); 17 | } 18 | 19 | @Test 20 | public void test() throws Exception { 21 | String path = getClass().getResource("/testplan.xml").getPath(); 22 | TestPlanAnalyzer analyzer = new TestPlanAnalyzer(); 23 | Set classes = analyzer.analyze(path); 24 | 25 | assertEquals(4, classes.size()); 26 | assertTrue(classes.contains("kg.apc.jmeter.vizualizers.ResponseTimesOverTimeGui")); 27 | assertTrue(classes.contains("kg.apc.jmeter.samplers.DummySampler")); 28 | assertTrue(classes.contains("kg.apc.jmeter.vizualizers.CorrectedResultCollector")); 29 | assertTrue(classes.contains("kg.apc.jmeter.samplers.DummySamplerGui")); 30 | } 31 | } -------------------------------------------------------------------------------- /src/main/java/org/jmeterplugins/repository/JARSource.java: -------------------------------------------------------------------------------- 1 | package org.jmeterplugins.repository; 2 | 3 | import java.io.IOException; 4 | 5 | import net.sf.json.JSON; 6 | 7 | abstract public class JARSource implements Cloneable { 8 | public abstract JSON getRepo() throws IOException; 9 | 10 | public abstract void reportStats(String[] usageStats) throws IOException; 11 | 12 | public abstract void setTimeout(int timeout); 13 | 14 | public abstract DownloadResult getJAR(String id, String location, GenericCallback statusChanged) throws IOException; 15 | 16 | public class DownloadResult { 17 | private final String tmpFile; 18 | private final String filename; 19 | 20 | public DownloadResult(String tmpFile, String filename) { 21 | this.tmpFile = tmpFile; 22 | this.filename = filename; 23 | } 24 | 25 | public String getTmpFile() { 26 | return tmpFile; 27 | } 28 | 29 | public String getFilename() { 30 | return filename; 31 | } 32 | } 33 | 34 | @Override 35 | public Object clone() throws CloneNotSupportedException { 36 | return super.clone(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/test/resources/lib_update.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "plugin-for-update", 4 | "name": "plugin-for-update", 5 | "description": "A number of additional JMeter functions that cover more of typical needs.", 6 | "screenshotUrl": "", 7 | "helpUrl": "https://jmeter-plugins.org/wiki/Functions/", 8 | "vendor": "JMeter-Plugins.org", 9 | "markerClass": "kg.apc.jmeter.functions.Base64Decode", 10 | "versions": { 11 | "0.1": { 12 | "downloadUrl": "https://search.maven.org/remotecontent?filepath=kg/apc/jmeter-plugins-functions/2.0/jmeter-plugins-functions-2.0.jar", 13 | "libs": { 14 | "cmdrunner" : "cmdrunner-0.7.jar", 15 | "commons-codec" : "commons-codec-0.4.jar", 16 | "commons-lang3" : "commons-lang3.jar" 17 | } 18 | }, 19 | "0.2": { 20 | "downloadUrl": "https://search.maven.org/remotecontent?filepath=kg/apc/jmeter-plugins-functions/2.0/jmeter-plugins-functions-2.0.jar", 21 | "libs": { 22 | "cmdrunner>=9999.8" : "cmdrunner-9999.8.jar", 23 | "commons-codec>=999.5" : "commons-codec-999.5.jar", 24 | "commons-lang3" : "commons-lang3.jar" 25 | } 26 | } 27 | } 28 | } 29 | ] -------------------------------------------------------------------------------- /src/test/java/org/jmeterplugins/repository/cache/PluginsRepoTest.java: -------------------------------------------------------------------------------- 1 | package org.jmeterplugins.repository.cache; 2 | 3 | import org.junit.Test; 4 | 5 | import java.io.File; 6 | 7 | import static org.junit.Assert.*; 8 | 9 | public class PluginsRepoTest { 10 | 11 | @Test 12 | public void testFlow() throws Exception { 13 | String serializedRepo = getClass().getResource("/serializedRepo").getFile(); 14 | File expected = new File(serializedRepo); 15 | PluginsRepo repo = PluginsRepo.fromFile(expected); 16 | assertNotNull(repo); 17 | assertEquals(124810, repo.getRepoJSON().length()); 18 | assertEquals(1526736963000L, repo.getExpirationTime()); 19 | File tempFile = File.createTempFile("tmp_cache", "serialized"); 20 | repo.saveToFile(tempFile); 21 | assertEquals(expected.length(), tempFile.length()); 22 | } 23 | 24 | @Test 25 | public void testFlow2() throws Exception { 26 | long l = System.currentTimeMillis(); 27 | PluginsRepo repo = new PluginsRepo("", l + 10000, l); 28 | assertTrue(repo.isActual()); 29 | 30 | repo = new PluginsRepo("", l - 10000, l); 31 | assertFalse(repo.isActual()); 32 | } 33 | } -------------------------------------------------------------------------------- /src/main/java/org/jmeterplugins/repository/PluginUpgradesList.java: -------------------------------------------------------------------------------- 1 | package org.jmeterplugins.repository; 2 | 3 | 4 | import javax.swing.event.ChangeListener; 5 | 6 | public class PluginUpgradesList extends PluginsList { 7 | /** 8 | * 9 | */ 10 | private static final long serialVersionUID = 525391154129274758L; 11 | 12 | public PluginUpgradesList(GenericCallback dialogRefresh) { 13 | super(dialogRefresh); 14 | } 15 | 16 | @Override 17 | protected PluginCheckbox getCheckboxItem(Plugin plugin, ChangeListener changeNotifier) { 18 | PluginCheckbox checkboxItem = super.getCheckboxItem(plugin, changeNotifier); 19 | plugin.setCandidateVersion(plugin.getMaxVersion()); 20 | checkboxItem.setSelected(true); 21 | return checkboxItem; 22 | } 23 | 24 | @Override 25 | protected void setUpVersionsList(PluginCheckbox cb) { 26 | super.setUpVersionsList(cb); 27 | version.setEnabled(false); 28 | } 29 | 30 | @Override 31 | protected String getCbVersion(PluginCheckbox cb) { 32 | if (cb.isSelected()) { 33 | return cb.getPlugin().getMaxVersion(); 34 | } else { 35 | return cb.getPlugin().getInstalledVersion(); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/test/resources/installed.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "jpgc-plugin1", 4 | "name": "Dependency plugin1", 5 | "description": "
  • Average Response Time
  • Active Threads
  • Successful/Failed Transactions
", 6 | "screenshotUrl": "https://jmeter-plugins.org/img/wiki/response_times_over_time.png", 7 | "helpUrl": "https://jmeter-plugins.org/wiki/ResponseTimesOverTime/", 8 | "vendor": "JMeter-Plugins.org", 9 | "markerClass": "org.jmeterplugins.repository.PluginManagerTest", 10 | "versions": { 11 | "2.0": { 12 | "downloadUrl": "dummy.jar", 13 | "libs": { 14 | "commons-codec" : "commons-codec-0.4.jar" 15 | } 16 | } 17 | } 18 | }, 19 | { 20 | "id": "jpgc-plugin2", 21 | "name": "Dependency plugin2", 22 | "description": "Dependency plugin for test ", 23 | "screenshotUrl": "https://jmeter-plugins.org/img/wiki/response_times_over_time.png", 24 | "helpUrl": "https://jmeter-plugins.org/wiki/ResponseTimesOverTime/", 25 | "vendor": "JMeter-Plugins.org", 26 | "markerClass": "8888888", 27 | "versions": { 28 | "2.0": { 29 | "downloadUrl": "dummy.jar", 30 | "libs": { 31 | "commons-codec>=99.99" : "commons-codec-99.99.jar" 32 | } 33 | } 34 | } 35 | } 36 | ] -------------------------------------------------------------------------------- /src/main/java/org/jmeterplugins/repository/PluginManagerCMDInstaller.java: -------------------------------------------------------------------------------- 1 | package org.jmeterplugins.repository; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | import java.net.URLDecoder; 7 | import java.nio.file.Files; 8 | import java.nio.file.StandardCopyOption; 9 | 10 | public class PluginManagerCMDInstaller { 11 | public static void main(String[] argv) throws IOException { 12 | writeOut("/org/jmeterplugins/repository/PluginsManagerCMD.bat", false); 13 | writeOut("/org/jmeterplugins/repository/PluginsManagerCMD.sh", true); 14 | } 15 | 16 | private static void writeOut(String resName, boolean executable) throws IOException { 17 | String path = PluginManagerCMDInstaller.class.getProtectionDomain().getCodeSource().getLocation().getFile(); 18 | File self = new File(URLDecoder.decode(path, "UTF-8")); 19 | File src = new File(resName); 20 | String home = self.getParentFile().getParentFile().getParent(); 21 | File dest = new File(home + File.separator + "bin" + File.separator + src.getName()); 22 | 23 | try (InputStream is = PluginManagerCMDInstaller.class.getResourceAsStream(resName);) { 24 | Files.copy(is, dest.toPath(), StandardCopyOption.REPLACE_EXISTING); 25 | dest.setExecutable(executable); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/org/jmeterplugins/repository/logging/LoggingConfigurator.java: -------------------------------------------------------------------------------- 1 | package org.jmeterplugins.repository.logging; 2 | 3 | import org.apache.logging.log4j.Level; 4 | import org.apache.logging.log4j.LogManager; 5 | import org.apache.logging.log4j.core.LoggerContext; 6 | import org.apache.logging.log4j.core.appender.ConsoleAppender; 7 | import org.apache.logging.log4j.core.config.Configuration; 8 | import org.apache.logging.log4j.core.config.LoggerConfig; 9 | import org.apache.logging.log4j.core.layout.PatternLayout; 10 | 11 | /** 12 | * Configure log4j logging for JMeter since 3.2 in PluginsManagerCMD 13 | */ 14 | public class LoggingConfigurator { 15 | 16 | 17 | 18 | public LoggingConfigurator() { 19 | configure(); 20 | } 21 | 22 | public void configure() { 23 | PatternLayout.Builder patternBuilder = PatternLayout.newBuilder(); 24 | patternBuilder.withPattern("%d %p %c{1.}: %m%n"); 25 | PatternLayout layout = patternBuilder.build(); 26 | 27 | ConsoleAppender consoleAppender = ConsoleAppender.createDefaultAppenderForLayout(layout); 28 | consoleAppender.start(); 29 | 30 | Configuration configuration = ((LoggerContext) LogManager.getContext(false)).getConfiguration(); 31 | 32 | LoggerConfig rootLogger = configuration.getRootLogger(); 33 | rootLogger.setLevel(Level.INFO); 34 | rootLogger.addAppender(consoleAppender, Level.INFO, null); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/org/jmeterplugins/repository/PluginManagerMenuCreator.java: -------------------------------------------------------------------------------- 1 | package org.jmeterplugins.repository; 2 | 3 | import org.apache.jmeter.gui.plugin.MenuCreator; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import javax.swing.*; 8 | 9 | public class PluginManagerMenuCreator implements MenuCreator { 10 | private static final Logger log = LoggerFactory.getLogger(PluginManagerMenuCreator.class); 11 | 12 | @Override 13 | public JMenuItem[] getMenuItemsAtLocation(MENU_LOCATION location) { 14 | if (location == MENU_LOCATION.OPTIONS) { 15 | try { 16 | PluginManagerCMDInstaller.main(new String[0]); 17 | } catch (Throwable e) { 18 | log.warn("Was unable to install pmgr cmdline tool", e); 19 | } 20 | 21 | try { 22 | return new JMenuItem[]{new PluginManagerMenuItem()}; 23 | } catch (Throwable e) { 24 | log.error("Failed to load Plugins Manager", e); 25 | return new JMenuItem[0]; 26 | } 27 | } else { 28 | return new JMenuItem[0]; 29 | } 30 | } 31 | 32 | @Override 33 | public javax.swing.JMenu[] getTopLevelMenus() { 34 | return new javax.swing.JMenu[0]; 35 | } 36 | 37 | @Override 38 | public boolean localeChanged(javax.swing.MenuElement menu) { 39 | return false; 40 | } 41 | 42 | @Override 43 | public void localeChanged() { 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/test/resources/suggest.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "jpgc-plugin1", 4 | "name": "Dependency plugin1", 5 | "description": "
  • Average Response Time
  • Active Threads
  • Successful/Failed Transactions
", 6 | "screenshotUrl": "https://jmeter-plugins.org/img/wiki/response_times_over_time.png", 7 | "helpUrl": "https://jmeter-plugins.org/wiki/ResponseTimesOverTime/", 8 | "vendor": "JMeter-Plugins.org", 9 | "markerClass": "777", 10 | "componentClasses" : [], 11 | "versions": { 12 | "2.0": { 13 | "downloadUrl": "dummy.jar", 14 | "libs": { 15 | "commons-codec" : "commons-codec-0.4.jar" 16 | } 17 | } 18 | } 19 | }, 20 | { 21 | "id": "jpgc-plugin2", 22 | "name": "Dependency plugin2", 23 | "description": "Dependency plugin for test ", 24 | "screenshotUrl": "https://jmeter-plugins.org/img/wiki/response_times_over_time.png", 25 | "helpUrl": "https://jmeter-plugins.org/wiki/ResponseTimesOverTime/", 26 | "vendor": "JMeter-Plugins.org", 27 | "markerClass": "8888888", 28 | "componentClasses" : [ 29 | "kg.apc.jmeter.samplers.DummySamplerGui", 30 | "kg.apc.jmeter.vizualizers.CorrectedResultCollector", 31 | "kg.apc.jmeter.samplers.DummySampler", 32 | "kg.apc.jmeter.vizualizers.ResponseTimesOverTimeGui" 33 | ], 34 | "versions": { 35 | "2.0": { 36 | "downloadUrl": "dummy.jar", 37 | "libs": { 38 | "commons-codec>=99.99" : "commons-codec-99.99.jar" 39 | } 40 | } 41 | } 42 | } 43 | ] -------------------------------------------------------------------------------- /src/test/resources/check-descriptors.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | 4 | import sys, logging 5 | 6 | if __name__ == "__main__": 7 | logging.basicConfig(level=logging.DEBUG) 8 | with open(sys.argv[1]) as fhd: 9 | lines = fhd.readlines() 10 | 11 | while lines: 12 | line = lines.pop(0) 13 | if "Plugin Components:" in line.strip(): 14 | logging.debug("Found start: %s", line) 15 | break 16 | 17 | plugins = {} 18 | while lines: 19 | line = lines.pop(0) 20 | #logging.debug(line) 21 | if not line.strip(): 22 | break 23 | 24 | plugins[line.strip()] = json.loads(lines.pop(0).strip()[len('"componentClasses":'):-1]) 25 | 26 | #logging.info("%s", plugins) 27 | 28 | for fname in os.listdir(sys.argv[2]): 29 | fname = os.path.join(sys.argv[2], fname) 30 | logging.info(fname) 31 | with open(fname) as fhd: 32 | fpls = json.loads(fhd.read()) 33 | 34 | for plugin in fpls: 35 | if plugin['id'] not in plugins or not plugin['markerClass']: 36 | logging.warning("Missing: %s", plugin['id']) 37 | continue 38 | 39 | if not 'componentClasses' in plugin: 40 | plugin['componentClasses'] = [] 41 | 42 | if set(plugin['componentClasses']) != set(plugins[plugin['id']]): 43 | diff = json.dumps(list(set(plugins[plugin['id']]) - set(plugin['componentClasses']))) 44 | logging.debug("Diff %s %s: %s", plugin['id'], diff, json.dumps(plugins[plugin['id']])) 45 | -------------------------------------------------------------------------------- /src/test/java/org/jmeterplugins/repository/logging/LoggerPanelWrappingTest.java: -------------------------------------------------------------------------------- 1 | package org.jmeterplugins.repository.logging; 2 | 3 | import kg.apc.emulators.TestJMeterUtils; 4 | import org.apache.jmeter.util.JMeterUtils; 5 | import org.apache.log.LogEvent; 6 | import org.jmeterplugins.repository.PluginManager; 7 | import org.jmeterplugins.repository.PluginManagerTest; 8 | import org.jmeterplugins.repository.plugins.PluginSuggester; 9 | import org.junit.BeforeClass; 10 | import org.junit.Test; 11 | 12 | import java.awt.*; 13 | import java.net.URL; 14 | 15 | import static org.junit.Assert.*; 16 | 17 | public class LoggerPanelWrappingTest { 18 | @BeforeClass 19 | public static void setup() { 20 | TestJMeterUtils.createJmeterEnv(); 21 | URL url = PluginManagerTest.class.getResource("/testVirtualPlugin.json"); 22 | JMeterUtils.setProperty("jpgc.repo.address", url.getFile()); 23 | } 24 | 25 | @Test 26 | public void testFlow() throws Exception { 27 | if (!GraphicsEnvironment.getLocalGraphicsEnvironment().isHeadlessInstance()) { 28 | PluginManager pmgr = new PluginManager(); 29 | LoggerPanelWrapping wrapping = new LoggerPanelWrapping(pmgr); 30 | PluginSuggester suggester = new PluginSuggester(pmgr); 31 | wrapping.setSuggester(suggester); 32 | assertEquals(suggester, wrapping.getSuggester()); 33 | LogEvent event = new LogEvent(); 34 | event.setCategory("SaveService"); 35 | event.setMessage("Save File"); 36 | wrapping.processEvent(event); 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /src/main/java/org/jmeterplugins/repository/JARSourceFilesystem.java: -------------------------------------------------------------------------------- 1 | package org.jmeterplugins.repository; 2 | 3 | 4 | import net.sf.json.JSON; 5 | import net.sf.json.JSONSerializer; 6 | import net.sf.json.JsonConfig; 7 | import org.apache.commons.io.FileUtils; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | 11 | import java.io.File; 12 | import java.io.IOException; 13 | 14 | public class JARSourceFilesystem extends JARSource { 15 | private static final Logger log = LoggerFactory.getLogger(JARSourceFilesystem.class); 16 | private final File base; 17 | private final File jsonFile; 18 | 19 | public JARSourceFilesystem(File jsonFile) { 20 | this.jsonFile = jsonFile; 21 | this.base = jsonFile.getParentFile(); 22 | } 23 | 24 | @Override 25 | public JSON getRepo() throws IOException { 26 | return JSONSerializer.toJSON(FileUtils.readFileToString(jsonFile), new JsonConfig()); 27 | } 28 | 29 | @Override 30 | public void reportStats(java.lang.String[] usageStats) throws IOException { 31 | log.debug("Not reporting stats"); 32 | } 33 | 34 | @Override 35 | public void setTimeout(int timeout) { 36 | log.debug("Filesystem does not care of timeout"); 37 | } 38 | 39 | @Override 40 | public DownloadResult getJAR(String id, String location, GenericCallback statusChanged) throws IOException { 41 | File orig = new File(base.getAbsolutePath() + File.separator + location); 42 | File tmp = File.createTempFile("jpgc-", ".jar"); 43 | FileUtils.copyFile(orig, tmp); 44 | return new DownloadResult(tmp.getAbsolutePath(), orig.getName()); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/test/java/org/jmeterplugins/repository/http/HttpRetryStrategyTest.java: -------------------------------------------------------------------------------- 1 | package org.jmeterplugins.repository.http; 2 | 3 | import org.apache.http.HttpResponse; 4 | import org.apache.http.ProtocolVersion; 5 | import org.apache.http.message.BasicHttpResponse; 6 | import org.apache.http.message.BasicStatusLine; 7 | import org.junit.Test; 8 | 9 | import static org.junit.Assert.*; 10 | 11 | public class HttpRetryStrategyTest { 12 | 13 | @Test 14 | public void testFlow() throws Exception { 15 | HttpRetryStrategy strategy = new HttpRetryStrategy(); 16 | HttpResponse response = new BasicHttpResponse(new BasicStatusLine(new ProtocolVersion("HTTP",1,1), 200, "")); 17 | assertFalse(strategy.retryRequest(response, 1, null)); 18 | 19 | strategy = new HttpRetryStrategy(2, 3333); 20 | response = new BasicHttpResponse(new BasicStatusLine(new ProtocolVersion("HTTP",1,1), 301, "")); 21 | assertTrue(strategy.retryRequest(response, 1, null)); 22 | assertFalse(strategy.retryRequest(response, 4, null)); 23 | 24 | assertEquals(2, strategy.getMaxRetries()); 25 | assertEquals(3333, strategy.getRetryInterval()); 26 | 27 | try { 28 | new HttpRetryStrategy(-1, 2222); 29 | fail(); 30 | } catch (IllegalArgumentException ex) { 31 | assertEquals("MaxRetries must be greater than 1", ex.getMessage()); 32 | } 33 | 34 | 35 | try { 36 | new HttpRetryStrategy(2, -1); 37 | fail(); 38 | } catch (IllegalArgumentException ex) { 39 | assertEquals("Retry interval must be greater than 1", ex.getMessage()); 40 | } 41 | 42 | 43 | } 44 | } -------------------------------------------------------------------------------- /src/main/java/org/apache/log/LogTarget.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package org.apache.log; 19 | 20 | /** 21 | * LogTarget is a class to encapsulate outputting LogEvent's. 22 | * This provides the base for all output and filter targets. 23 | * 24 | * Warning: If performance becomes a problem then this 25 | * interface will be rewritten as a abstract class. 26 | * 27 | * @author Peter Donald 28 | * @deprecated Will be dropped in 3.3 29 | */ 30 | @Deprecated 31 | public interface LogTarget 32 | { 33 | /** 34 | * Process a log event. 35 | * In NO case should this method ever throw an exception/error. 36 | * The reason is that logging is usually added for debugging/auditing 37 | * purposes and it would be unacceptable to have your debugging 38 | * code cause more errors. 39 | * 40 | * @param event the event 41 | */ 42 | void processEvent( LogEvent event ); 43 | } 44 | -------------------------------------------------------------------------------- /src/test/java/org/jmeterplugins/repository/LibraryTest.java: -------------------------------------------------------------------------------- 1 | package org.jmeterplugins.repository; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | public class LibraryTest { 8 | @Test 9 | public void testFlow() throws Exception { 10 | Library lib1 = new Library("name", "9.9.9", "LINK"); 11 | 12 | Library lib2 = new Library(); 13 | lib2.setName("name2"); 14 | lib2.setVersion("9.9.8"); 15 | assertEquals("name2>=9.9.8", lib2.getFullName()); 16 | 17 | lib2.setLink("LINK2"); 18 | 19 | assertEquals("name2", lib2.getName()); 20 | assertEquals("9.9.8", lib2.getVersion()); 21 | assertEquals("LINK2", lib2.getLink()); 22 | 23 | assertEquals(1, Library.versionComparator.compare(lib1, lib2)); 24 | 25 | lib2.setVersion("9.9.10"); 26 | assertEquals(-1, Library.versionComparator.compare(lib1, lib2)); 27 | 28 | lib1.setVersion("9.9"); 29 | assertEquals(-1, Library.versionComparator.compare(lib1, lib2)); 30 | 31 | lib1.setVersion("1.1"); 32 | lib2.setVersion("1.2"); 33 | assertEquals(-1, Library.versionComparator.compare(lib1, lib2)); 34 | 35 | lib2.setVersion("1.1"); 36 | assertEquals(0, Library.versionComparator.compare(lib1, lib2)); 37 | 38 | lib1.setVersion("1.1.v1"); 39 | lib2.setVersion("1.1.v2"); 40 | assertEquals(-1, Library.versionComparator.compare(lib1, lib2)); 41 | } 42 | 43 | @Test 44 | public void testStaticMethods() throws Exception { 45 | String fullName = "lib>=2.2"; 46 | assertEquals("lib", Library.getNameFromFullName(fullName)); 47 | assertEquals("2.2", Library.getVersionFromFullName(fullName)); 48 | } 49 | } -------------------------------------------------------------------------------- /src/test/java/org/jmeterplugins/repository/PluginMock.java: -------------------------------------------------------------------------------- 1 | package org.jmeterplugins.repository; 2 | 3 | import net.sf.json.JSONObject; 4 | import net.sf.json.JsonConfig; 5 | 6 | import java.util.HashMap; 7 | import java.util.HashSet; 8 | import java.util.Map; 9 | import java.util.Set; 10 | 11 | 12 | public class PluginMock extends Plugin { 13 | private Set depends = new HashSet<>(); 14 | private Map libs = new HashMap<>(); 15 | 16 | public PluginMock(String id, String iVer) { 17 | super(id); 18 | installedVersion = iVer; 19 | installedPath = iVer; 20 | versions = JSONObject.fromObject("{\"1.0\":null,\"0.1\":null,\"0.1.5\":null}", new JsonConfig()); 21 | candidateVersion = getMaxVersion(); 22 | } 23 | 24 | public PluginMock() { 25 | super("mock"); 26 | } 27 | 28 | public PluginMock(String id) { 29 | super(id); 30 | } 31 | 32 | @Override 33 | public Set getDepends() { 34 | return depends; 35 | } 36 | 37 | public void setDepends(Set depends) { 38 | this.depends = depends; 39 | } 40 | 41 | @Override 42 | public Map getLibs(String verStr) { 43 | return libs; 44 | } 45 | 46 | public void setLibs(Map libs) { 47 | this.libs = libs; 48 | } 49 | 50 | public void setVersions(JSONObject a) { 51 | versions = a; 52 | } 53 | 54 | public void setMarkerClass(String markerClass) { 55 | this.markerClass = markerClass; 56 | } 57 | 58 | public void setInstallerClass(String installerClass) { 59 | this.installerClass = installerClass; 60 | } 61 | 62 | public void setDestName(String destName) { 63 | this.destName = destName; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/test/resources/testVirtualPlugin.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "jpgc-dep1", 4 | "name": "Dependency plugin1", 5 | "description": "
  • Average Response Time
  • Active Threads
  • Successful/Failed Transactions
", 6 | "screenshotUrl": "https://jmeter-plugins.org/img/wiki/response_times_over_time.png", 7 | "helpUrl": "https://jmeter-plugins.org/wiki/ResponseTimesOverTime/", 8 | "vendor": "JMeter-Plugins.org", 9 | "markerClass": "org.jmeterplugins.repository.PluginManagerTest", 10 | "versions": { 11 | "2.0": { 12 | "downloadUrl": "dummy.jar", 13 | "libs": { 14 | "jmeter-plugins-cmn-jmeter": "dummy.jar" 15 | } 16 | } 17 | } 18 | }, 19 | { 20 | "id": "jpgc-dep2", 21 | "name": "Dependency plugin2", 22 | "description": "Dependency plugin for test ", 23 | "screenshotUrl": "https://jmeter-plugins.org/img/wiki/response_times_over_time.png", 24 | "helpUrl": "https://jmeter-plugins.org/wiki/ResponseTimesOverTime/", 25 | "vendor": "JMeter-Plugins.org", 26 | "markerClass": "org.jmeterplugins.repository.PluginManagerTest", 27 | "versions": { 28 | "2.0": { 29 | "downloadUrl": "dummy.jar", 30 | "libs": { 31 | "jmeter-plugins-cmn-jmeter": "dummy.jar" 32 | } 33 | } 34 | } 35 | }, 36 | { 37 | "id": "jpgc-standard", 38 | "name": "jpgc - Standard Set", 39 | "description": "Virtual package, select to install its dependencies", 40 | "screenshotUrl": "", 41 | "helpUrl": "", 42 | "vendor": "JMeter-Plugins.org", 43 | "markerClass": null, 44 | "versions": { 45 | "2.0": { 46 | "downloadUrl": null, 47 | "depends": [ 48 | "jpgc-dep1", 49 | "jpgc-dep2" 50 | ] 51 | } 52 | } 53 | } 54 | ] -------------------------------------------------------------------------------- /src/main/java/org/jmeterplugins/repository/http/HttpRetryStrategy.java: -------------------------------------------------------------------------------- 1 | package org.jmeterplugins.repository.http; 2 | 3 | import org.apache.http.HttpResponse; 4 | import org.apache.http.client.ServiceUnavailableRetryStrategy; 5 | import org.apache.http.protocol.HttpContext; 6 | 7 | public class HttpRetryStrategy implements ServiceUnavailableRetryStrategy { 8 | 9 | /** 10 | * Maximum number of allowed retries if the server responds with a HTTP code 11 | * in our retry code list. Default value is 1. 12 | */ 13 | private final int maxRetries; 14 | 15 | /** 16 | * Retry interval between subsequent requests, in milliseconds. Default 17 | * value is 1 second. 18 | */ 19 | private final long retryInterval; 20 | 21 | public HttpRetryStrategy(int maxRetries, int retryInterval) { 22 | super(); 23 | if (maxRetries < 1) { 24 | throw new IllegalArgumentException("MaxRetries must be greater than 1"); 25 | } 26 | if (retryInterval < 1) { 27 | throw new IllegalArgumentException("Retry interval must be greater than 1"); 28 | } 29 | this.maxRetries = maxRetries; 30 | this.retryInterval = retryInterval; 31 | } 32 | 33 | public HttpRetryStrategy() { 34 | this(1, 1000); 35 | } 36 | 37 | public boolean retryRequest(final HttpResponse response, int executionCount, final HttpContext context) { 38 | return executionCount <= maxRetries && 39 | !isSuccessStatusCode(response.getStatusLine().getStatusCode()); 40 | } 41 | 42 | private boolean isSuccessStatusCode(int code) { 43 | return code >= 200 && code < 300; 44 | } 45 | 46 | public long getRetryInterval() { 47 | return retryInterval; 48 | } 49 | 50 | public int getMaxRetries() { 51 | return maxRetries; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/test/resources/self_npe.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "jpgc-plugins-manager", 4 | "name": "Plugins Manager", 5 | "description": "Adds menu item into Options menu to access UI for installing/removing additional plugins", 6 | "screenshotUrl": "https://jmeter-plugins.org/img/wiki/pmgr/pmgr_menu_item.png", 7 | "helpUrl": "https://jmeter-plugins.org/wiki/PluginsManager/", 8 | "vendor": "JMeter-Plugins.org", 9 | "markerClass": "org.jmeterplugins.repository.PluginManager", 10 | "canUninstall": false, 11 | "versions": { 12 | "0.13": { 13 | "changes": "

- Fixed show empty plugins list;

- Retry JAR download after failed downloads;

- Inform on potential JAR conflicts;

- Re-enable manager after failed JAR downloads;

- Make stats UUID less sensitive + detect CI, clouds and OS;

- Version management for libs;

", 14 | "downloadUrl": "https://search.maven.org/remotecontent?filepath=kg/apc/jmeter-plugins-manager/0.13/jmeter-plugins-manager-0.13.jar", 15 | "libs": { 16 | "cmdbeginner": "https://search.maven.org/remotecontent?filepath=kg/apc/cmdrunner/2.0/cmdrunner-2.0.jar" 17 | } 18 | }, 19 | "0.14": { 20 | "changes": "

- Added Plugins Manager button on toolbar;

- Suggest to install missing plugins;

- Load last test plan file after restart JMeter;

- Fixed update lib;

- Opportunity to fix broken jmeter;

- Fixed load plugins list;

- Distinct gui/non-gui mode in stats;

- Added \"install-all-except\" command to cmd;

", 21 | "downloadUrl": "https://search.maven.org/remotecontent?filepath=kg/apc/jmeter-plugins-manager/0.14/jmeter-plugins-manager-0.14.jar", 22 | "libs": { 23 | "cmdbeginner": "https://search.maven.org/remotecontent?filepath=kg/apc/cmdrunner/2.0/cmdrunner-2.0.jar" 24 | } 25 | } 26 | } 27 | } 28 | ] -------------------------------------------------------------------------------- /src/main/java/org/jmeterplugins/repository/logging/LoggingHooker.java: -------------------------------------------------------------------------------- 1 | package org.jmeterplugins.repository.logging; 2 | 3 | import org.apache.log.LogTarget; 4 | import org.jmeterplugins.repository.PluginManager; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | import java.lang.reflect.Constructor; 9 | 10 | public class LoggingHooker { 11 | private static final org.slf4j.Logger log = LoggerFactory.getLogger(LoggingHooker.class); 12 | private final PluginManager mgr; 13 | 14 | public LoggingHooker(PluginManager mgr) { 15 | this.mgr = mgr; 16 | } 17 | 18 | public void hook() { 19 | try { 20 | if (!isJMeter32orLater()) { 21 | Logger logger = LoggerFactory.getLogger("jmeter.save.SaveService"); 22 | // FIXME: what to do? logger.setLogTargets(new LogTarget[]{new LoggerPanelWrapping(mgr)}); 23 | } else { 24 | Class cls = Class.forName("org.jmeterplugins.repository.logging.LoggerAppender"); 25 | Constructor constructor = cls.getConstructor(String.class, PluginManager.class); 26 | constructor.newInstance("pmgr-logging-appender", mgr); 27 | } 28 | } catch (Throwable ex) { 29 | log.error("Cannot hook into logging", ex); 30 | } 31 | } 32 | 33 | public static boolean isJMeter32orLater() { 34 | try { 35 | Class cls = LoggingHooker.class.getClassLoader().loadClass("org.apache.jmeter.gui.logging.GuiLogEventBus"); 36 | if (cls != null) { 37 | return true; 38 | } 39 | } catch (ClassNotFoundException ex) { 40 | log.debug("Class 'org.apache.jmeter.gui.logging.GuiLogEventBus' not found", ex); 41 | } catch (Throwable ex) { 42 | log.warn("Fail to detect JMeter version", ex); 43 | } 44 | return false; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/test/java/org/jmeterplugins/repository/logging/LoggerAppenderTest.java: -------------------------------------------------------------------------------- 1 | package org.jmeterplugins.repository.logging; 2 | 3 | 4 | import kg.apc.emulators.TestJMeterUtils; 5 | import org.apache.jmeter.util.JMeterUtils; 6 | import org.apache.logging.log4j.core.Filter; 7 | import org.apache.logging.log4j.core.impl.Log4jLogEvent; 8 | import org.apache.logging.log4j.message.MessageFormatMessage; 9 | import org.jmeterplugins.repository.PluginManager; 10 | import org.jmeterplugins.repository.PluginManagerTest; 11 | import org.jmeterplugins.repository.plugins.PluginSuggester; 12 | import org.junit.BeforeClass; 13 | import org.junit.Test; 14 | 15 | import java.net.URL; 16 | 17 | import static org.junit.Assert.assertEquals; 18 | 19 | public class LoggerAppenderTest { 20 | 21 | @BeforeClass 22 | public static void setup() { 23 | TestJMeterUtils.createJmeterEnv(); 24 | URL url = PluginManagerTest.class.getResource("/testVirtualPlugin.json"); 25 | JMeterUtils.setProperty("jpgc.repo.address", url.getFile()); 26 | } 27 | 28 | @Test 29 | public void testFlow() throws Exception { 30 | PluginManager pmgr = new PluginManager(); 31 | LoggerAppender appender = new LoggerAppender("test-appender", pmgr); 32 | PluginSuggester suggester = new PluginSuggester(pmgr); 33 | appender.setSuggester(suggester); 34 | assertEquals(suggester, appender.getSuggester()); 35 | 36 | Log4jLogEvent.Builder builder = Log4jLogEvent.newBuilder(); 37 | builder.setMessage(new MessageFormatMessage("Save file")); 38 | builder.setLoggerName("SaveService"); 39 | appender.append(builder.build()); 40 | 41 | LoggerAppender.SaveServiceFilter filter = new LoggerAppender.SaveServiceFilter(Filter.Result.ACCEPT, Filter.Result.DENY); 42 | assertEquals(Filter.Result.ACCEPT, filter.filter(builder.build())); 43 | builder.setLoggerName("SomeLogger"); 44 | assertEquals(Filter.Result.DENY, filter.filter(builder.build())); 45 | } 46 | } -------------------------------------------------------------------------------- /src/main/java/org/jmeterplugins/repository/logging/LoggerAppender.java: -------------------------------------------------------------------------------- 1 | package org.jmeterplugins.repository.logging; 2 | 3 | import org.apache.logging.log4j.Level; 4 | import org.apache.logging.log4j.LogManager; 5 | import org.apache.logging.log4j.core.Filter; 6 | import org.apache.logging.log4j.core.LogEvent; 7 | import org.apache.logging.log4j.core.LoggerContext; 8 | import org.apache.logging.log4j.core.appender.AbstractAppender; 9 | import org.apache.logging.log4j.core.config.Configuration; 10 | import org.apache.logging.log4j.core.config.plugins.Plugin; 11 | import org.apache.logging.log4j.core.filter.AbstractFilter; 12 | import org.apache.logging.log4j.core.layout.PatternLayout; 13 | import org.jmeterplugins.repository.PluginManager; 14 | import org.jmeterplugins.repository.plugins.PluginSuggester; 15 | 16 | 17 | //@Plugin(name = "Logger", category = "Core", elementType = "appender", printObject = true) 18 | public class LoggerAppender extends AbstractAppender { 19 | 20 | protected PluginSuggester suggester; 21 | 22 | public LoggerAppender(String name, PluginManager pmgr) { 23 | super(name, new SaveServiceFilter(Filter.Result.ACCEPT, Filter.Result.DENY), PatternLayout.createDefaultLayout()); 24 | start(); 25 | Configuration configuration = ((LoggerContext) LogManager.getContext(false)).getConfiguration(); 26 | configuration.getRootLogger().addAppender(this, Level.INFO, new SaveServiceFilter(Filter.Result.ACCEPT, Filter.Result.DENY)); 27 | this.suggester = new PluginSuggester(pmgr); 28 | } 29 | 30 | @Override 31 | public void append(LogEvent logEvent) { 32 | if (logEvent.getLoggerName().contains("SaveService")) { 33 | suggester.checkAndSuggest(logEvent.getMessage().getFormattedMessage()); 34 | } 35 | } 36 | 37 | public PluginSuggester getSuggester() { 38 | return suggester; 39 | } 40 | 41 | public void setSuggester(PluginSuggester suggester) { 42 | this.suggester = suggester; 43 | } 44 | 45 | public static class SaveServiceFilter extends AbstractFilter { 46 | public SaveServiceFilter(Result onMatch, Result onMismatch) { 47 | super(onMatch, onMismatch); 48 | } 49 | 50 | @Override 51 | public Result filter(LogEvent event) { 52 | return event.getLoggerName().contains("SaveService") ? onMatch : onMismatch; 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/org/jmeterplugins/repository/PluginIcon.java: -------------------------------------------------------------------------------- 1 | package org.jmeterplugins.repository; 2 | 3 | import javax.swing.*; 4 | import java.awt.*; 5 | 6 | public class PluginIcon { 7 | 8 | private static boolean SVG_AVAILABLE; 9 | private static boolean FRAME_ICON_API_AVAILABLE; 10 | 11 | static { 12 | try { 13 | Class.forName( "com.github.weisj.darklaf.icons.IconLoader" ); 14 | SVG_AVAILABLE = true; 15 | } catch (ClassNotFoundException e) { 16 | SVG_AVAILABLE = false; 17 | } 18 | if (SVG_AVAILABLE) { 19 | try { 20 | com.github.weisj.darklaf.icons.IconLoader.class.getDeclaredMethod("createFrameIcon", Icon.class, Window.class); 21 | FRAME_ICON_API_AVAILABLE = true; 22 | } catch (NoSuchMethodException e) { 23 | FRAME_ICON_API_AVAILABLE = false; 24 | } 25 | } 26 | } 27 | 28 | public static Image getPluginFrameIcon(boolean hasUpdates, Window window) { 29 | if (FRAME_ICON_API_AVAILABLE) { 30 | return com.github.weisj.darklaf.icons.IconLoader.createFrameIcon(getPluginsIcon(hasUpdates), window); 31 | } else { 32 | return getPluginImageIcon(hasUpdates, false).getImage(); 33 | } 34 | } 35 | 36 | public static Icon getIcon22Px(boolean hasUpdates) { 37 | if (SVG_AVAILABLE) { 38 | return getPluginsSVGIcon(hasUpdates, 22); 39 | } else { 40 | return getPluginImageIcon(hasUpdates, true); 41 | } 42 | } 43 | 44 | public static Icon getPluginsIcon(boolean hasUpdates) { 45 | if (SVG_AVAILABLE) { 46 | return getPluginsSVGIcon(hasUpdates, 16); 47 | } else { 48 | return getPluginImageIcon(hasUpdates, false); 49 | } 50 | } 51 | 52 | private static Icon getPluginsSVGIcon(boolean hasUpdates, int size) { 53 | if (hasUpdates) { 54 | return com.github.weisj.darklaf.icons.IconLoader.get().getIcon("org/jmeterplugins/logoUpdate.svg", size, size); 55 | } else { 56 | return com.github.weisj.darklaf.icons.IconLoader.get().getIcon("org/jmeterplugins/logo.svg", size, size); 57 | } 58 | } 59 | 60 | private static ImageIcon getPluginImageIcon(boolean hasUpdates, boolean large) { 61 | String path = "/org/jmeterplugins/logo"; 62 | if (large) path += "22"; 63 | if (hasUpdates) path += "Update"; 64 | path += ".png"; 65 | return new ImageIcon(PluginIcon.class.getResource(path)); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/org/jmeterplugins/repository/cache/PluginsRepo.java: -------------------------------------------------------------------------------- 1 | package org.jmeterplugins.repository.cache; 2 | 3 | import org.apache.commons.io.FileUtils; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import java.io.File; 8 | import java.io.FileInputStream; 9 | import java.io.FileOutputStream; 10 | import java.io.IOException; 11 | import java.io.ObjectInputStream; 12 | import java.io.ObjectOutputStream; 13 | import java.io.Serializable; 14 | 15 | public class PluginsRepo implements Serializable { 16 | private static final long serialVersionUID = 1L; 17 | private static final Logger log = LoggerFactory.getLogger(PluginsRepo.class); 18 | 19 | private final String repoJSON; 20 | private final long expirationTime; 21 | private final long lastModified; 22 | 23 | public PluginsRepo(String repoJSON, long expirationTime, long lastModified) { 24 | this.repoJSON = repoJSON; 25 | this.expirationTime = expirationTime; 26 | this.lastModified = lastModified; 27 | } 28 | 29 | public boolean isActual() { 30 | return expirationTime > System.currentTimeMillis(); 31 | } 32 | 33 | public boolean isActual(long lastModified) { 34 | return isActual() && lastModified <= this.lastModified; 35 | } 36 | 37 | public long getExpirationTime() { 38 | return expirationTime; 39 | } 40 | 41 | public String getRepoJSON() { 42 | return repoJSON; 43 | } 44 | 45 | public void saveToFile(File file) { 46 | log.debug("Saving repo to file: " + file.getAbsolutePath()); 47 | // Serialization 48 | try (FileOutputStream fout = new FileOutputStream(file); 49 | ObjectOutputStream out = new ObjectOutputStream(fout)) { 50 | FileUtils.touch(file); 51 | // Method for serialization of object 52 | out.writeObject(this); 53 | } catch (IOException ex) { 54 | log.warn("Failed for serialize repo", ex); 55 | } 56 | } 57 | 58 | public static PluginsRepo fromFile(File file) { 59 | log.debug("Loading repo from file: " + file.getAbsolutePath()); 60 | // Deserialization 61 | try (FileInputStream fis = new FileInputStream(file); 62 | ObjectInputStream in = new ObjectInputStream(fis);) { 63 | 64 | // Method for deserialization of object 65 | return (PluginsRepo) in.readObject(); 66 | } catch (IOException | ClassNotFoundException ex) { 67 | log.warn("Failed for deserialize repo", ex); 68 | return null; 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/test/resources/lib_for_delete: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "delete1", 4 | "name": "delete1", 5 | "description": "A number of additional JMeter functions that cover more of typical needs.", 6 | "screenshotUrl": "", 7 | "helpUrl": "https://jmeter-plugins.org/wiki/Functions/", 8 | "vendor": "JMeter-Plugins.org", 9 | "markerClass": "kg.apc.jmeter.functions.Base64Decode", 10 | "versions": { 11 | "0.1": { 12 | "downloadUrl": "https://search.maven.org/remotecontent?filepath=kg/apc/jmeter-plugins-functions/2.0/jmeter-plugins-functions-2.0.jar", 13 | "libs": { 14 | "cmdrunner>=0.8" : "lib-0.8.jar", 15 | "ApacheJMeter_core" : "lib2.jar", 16 | "bsf>=0.6" : "lib3-0.6.jar", 17 | "commons-codec" : "lib4.jar", 18 | "commons-lang3" : "lib7.jar" 19 | } 20 | } 21 | } 22 | }, 23 | { 24 | "id": "delete2", 25 | "name": "delete2", 26 | "description": "Low-level HTTP request, solves memory problem for huge file upload/download case. Also ships Raw Data Source preprocessor.", 27 | "screenshotUrl": "https://jmeter-plugins.org/img/wiki/rawrequest.png", 28 | "helpUrl": "https://jmeter-plugins.org/wiki/RawRequest/", 29 | "vendor": "JMeter-Plugins.org", 30 | "markerClass": "kg.apc.jmeter.samplers.HTTPRawSampler", 31 | "versions": { 32 | "0.1": { 33 | "downloadUrl": "https://search.maven.org/remotecontent?filepath=kg/apc/jmeter-plugins-httpraw/0.1/jmeter-plugins-httpraw-0.1.jar", 34 | "libs": { 35 | "cmdrunner" : "lib1.jar", 36 | "ApacheJMeter_core" : "lib2-0.8.jar", 37 | "bsf>=0.7" : "lib3-0.7.jar", 38 | "commons-jexl>=0.5" : "lib6-0.5.jar", 39 | "commons-httpclient>=0.8" : "lib8-0.8.jar" 40 | } 41 | } 42 | } 43 | }, 44 | { 45 | "id": "installed", 46 | "name": "installed", 47 | "description": "Low-level HTTP request, solves memory problem for huge file upload/download case. Also ships Raw Data Source preprocessor.", 48 | "screenshotUrl": "https://jmeter-plugins.org/img/wiki/rawrequest.png", 49 | "helpUrl": "https://jmeter-plugins.org/wiki/RawRequest/", 50 | "vendor": "JMeter-Plugins.org", 51 | "markerClass": "kg.apc.jmeter.samplers.HTTPRawSampler", 52 | "versions": { 53 | "0.1": { 54 | "downloadUrl": "https://search.maven.org/remotecontent?filepath=kg/apc/jmeter-plugins-httpraw/0.1/jmeter-plugins-httpraw-0.1.jar", 55 | "libs": { 56 | "cmdrunner" : "lib1.jar", 57 | "bsf>=0.8" : "lib3-0.8.jar", 58 | "commons-codec" : "lib4.jar", 59 | "commons-io>=0.8" : "lib5-0.8.jar", 60 | "commons-jexl" : "lib6.jar" 61 | } 62 | } 63 | } 64 | } 65 | ] 66 | -------------------------------------------------------------------------------- /src/test/resources/lib_versions.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "plugin1", 4 | "name": "plugin1", 5 | "description": "A number of additional JMeter functions that cover more of typical needs.", 6 | "screenshotUrl": "", 7 | "helpUrl": "https://jmeter-plugins.org/wiki/Functions/", 8 | "vendor": "JMeter-Plugins.org", 9 | "markerClass": "kg.apc.jmeter.functions.Base64Decode", 10 | "versions": { 11 | "2.0": { 12 | "downloadUrl": "https://search.maven.org/remotecontent?filepath=kg/apc/jmeter-plugins-functions/2.0/jmeter-plugins-functions-2.0.jar", 13 | "libs": { 14 | "jmeter-plugins-cmn-jmeter>=0.4": "jmeter-plugins-cmn-jmeter-0.4.jar", 15 | "kafka_2.8.2>=0.8": "kafka_2.8.2_v0.8.jar", 16 | "commons-io" : "commons-io.jar", 17 | "kafka_2.1.0" : "kafka_2.1.0.jar", 18 | "lib" : "lib.jar", 19 | "lib2" : "lib2.jar" 20 | } 21 | } 22 | } 23 | }, 24 | { 25 | "id": "plugin2", 26 | "name": "plugin2", 27 | "description": "Low-level HTTP request, solves memory problem for huge file upload/download case. Also ships Raw Data Source preprocessor.", 28 | "screenshotUrl": "https://jmeter-plugins.org/img/wiki/rawrequest.png", 29 | "helpUrl": "https://jmeter-plugins.org/wiki/RawRequest/", 30 | "vendor": "JMeter-Plugins.org", 31 | "markerClass": "kg.apc.jmeter.samplers.HTTPRawSampler", 32 | "versions": { 33 | "0.1": { 34 | "downloadUrl": "https://search.maven.org/remotecontent?filepath=kg/apc/jmeter-plugins-httpraw/0.1/jmeter-plugins-httpraw-0.1.jar", 35 | "libs": { 36 | "jmeter-plugins-cmn-jmeter>=0.3": "jmeter-plugins-cmn-jmeter-0.3.jar", 37 | "kafka_2.8.2": "kafka_2.8.2_v0.7.jar", 38 | "commons-io" : "commons-io.jar", 39 | "kafka_2.1.0>=0.1" : "kafka_2.1.0_v.0.1.jar", 40 | "lib>=0.7" : "lib-0.7.jar", 41 | "lib2" : "lib2.jar" 42 | } 43 | } 44 | } 45 | }, 46 | { 47 | "id": "plugin3", 48 | "name": "plugin3", 49 | "description": "Low-level HTTP request, solves memory problem for huge file upload/download case. Also ships Raw Data Source preprocessor.", 50 | "screenshotUrl": "https://jmeter-plugins.org/img/wiki/rawrequest.png", 51 | "helpUrl": "https://jmeter-plugins.org/wiki/RawRequest/", 52 | "vendor": "JMeter-Plugins.org", 53 | "markerClass": "kg.apc.jmeter.samplers.HTTPRawSampler", 54 | "versions": { 55 | "0.1": { 56 | "downloadUrl": "https://search.maven.org/remotecontent?filepath=kg/apc/jmeter-plugins-httpraw/0.1/jmeter-plugins-httpraw-0.1.jar", 57 | "libs": { 58 | "jmeter-plugins-cmn-jmeter": "jmeter-plugins-cmn-jmeter.jar", 59 | "kafka_2.8.2>=0.7": "kafka_2.8.2_v0.7.jar", 60 | "commons-io" : "commons-io.jar", 61 | "kafka_2.1.0" : "kafka_2.1.0.jar", 62 | "lib>=0.8" : "lib-0.8.jar", 63 | "lib2>=0.2" : "lib2-0.2.jar" 64 | } 65 | } 66 | } 67 | } 68 | ] 69 | -------------------------------------------------------------------------------- /src/test/java/org/jmeterplugins/repository/plugins/PluginSuggesterTest.java: -------------------------------------------------------------------------------- 1 | package org.jmeterplugins.repository.plugins; 2 | 3 | import kg.apc.emulators.TestJMeterUtils; 4 | import org.apache.jmeter.util.JMeterUtils; 5 | import org.jmeterplugins.repository.Plugin; 6 | import org.jmeterplugins.repository.PluginManager; 7 | import org.jmeterplugins.repository.PluginManagerTest; 8 | import org.junit.AfterClass; 9 | import org.junit.BeforeClass; 10 | import org.junit.Test; 11 | 12 | import java.awt.*; 13 | import java.net.URL; 14 | import java.util.HashSet; 15 | import java.util.Set; 16 | 17 | import static org.junit.Assert.assertEquals; 18 | import static org.junit.Assert.assertTrue; 19 | 20 | 21 | public class PluginSuggesterTest { 22 | @BeforeClass 23 | public static void setup() { 24 | TestJMeterUtils.createJmeterEnv(); 25 | } 26 | 27 | 28 | @Test 29 | public void testFlow() throws Throwable { 30 | if (!GraphicsEnvironment.getLocalGraphicsEnvironment().isHeadlessInstance()) { 31 | URL repo = PluginManagerTest.class.getResource("/suggest.json"); 32 | URL testPlan = PluginManagerTest.class.getResource("/testplan.xml"); 33 | 34 | JMeterUtils.setProperty("jpgc.repo.address", repo.getPath()); 35 | PluginManager pmgr = new PluginManager(); 36 | pmgr.load(); 37 | 38 | PluginSuggester suggester = new PluginSuggester(pmgr); 39 | suggester.checkAndSuggest("Loading file : " + testPlan.getPath()); 40 | } 41 | } 42 | 43 | @Test 44 | public void testSuggest() throws Throwable { 45 | URL repo = PluginManagerTest.class.getResource("/suggest.json"); 46 | JMeterUtils.setProperty("jpgc.repo.address", repo.getPath()); 47 | PluginManager pmgr = new PluginManager(); 48 | pmgr.load(); 49 | 50 | 51 | PluginSuggester suggester = new PluginSuggester(pmgr); 52 | TestPlanAnalyzer analyzer = new TestPlanAnalyzer(); 53 | suggester.setAnalyzer(analyzer); 54 | assertEquals(analyzer, suggester.getAnalyzer()); 55 | 56 | URL testPlan = PluginManagerTest.class.getResource("/testplan.xml"); 57 | Set plugins = suggester.findPluginsToInstall("Loading file : " + testPlan.getPath()); 58 | assertEquals(1, plugins.size()); 59 | assertEquals("jpgc-plugin2", plugins.toArray(new Plugin[1])[0].getID()); 60 | 61 | Set classes = new HashSet<>(); 62 | classes.add("kg.apc.jmeter.samplers.DummySamplerGui"); 63 | plugins = suggester.findPluginsFromClasses(classes); 64 | assertEquals(1, plugins.size()); 65 | assertEquals("jpgc-plugin2", plugins.toArray(new Plugin[1])[0].getID()); 66 | 67 | pmgr.togglePlugins(pmgr.getAvailablePlugins(), true); 68 | String msg = pmgr.getChangesAsText(); 69 | 70 | assertTrue(msg.contains("jpgc-plugin1")); 71 | assertTrue(msg.contains("jpgc-plugin2")); 72 | } 73 | 74 | @AfterClass 75 | public static void tearDown() throws Exception { 76 | JMeterUtils.getJMeterProperties().remove("jpgc.repo.address"); 77 | } 78 | } -------------------------------------------------------------------------------- /src/test/resources/plugins-map.jmx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | false 7 | false 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | continue 16 | 17 | false 18 | 1 19 | 20 | 1 21 | 1 22 | 1501670700000 23 | 1501670700000 24 | false 25 | 26 | 27 | 28 | 29 | 30 | false 31 | true 32 | false 33 | 34 | 35 | 36 | 37 | 38 | 39 | org.jmeterplugins.repository.PluginManager.getStaticManager().logPluginComponents(); 40 | groovy 41 | 42 | 43 | 44 | 45 | 46 | 47 | true 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /src/main/resources/org/jmeterplugins/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 9 | 11 | 13 | 15 | 16 | 17 | 18 | 21 | 23 | 25 | 27 | 29 | 30 | 31 | 34 | 36 | 38 | 40 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /src/main/java/org/jmeterplugins/repository/CheckBoxList.java: -------------------------------------------------------------------------------- 1 | package org.jmeterplugins.repository; 2 | 3 | // http://www.devx.com/tips/Tip/5342 4 | 5 | import java.awt.Component; 6 | import java.awt.Font; 7 | import java.awt.event.MouseAdapter; 8 | import java.awt.event.MouseEvent; 9 | 10 | import javax.swing.Icon; 11 | import javax.swing.JCheckBox; 12 | import javax.swing.JList; 13 | import javax.swing.ListCellRenderer; 14 | import javax.swing.ListSelectionModel; 15 | import javax.swing.UIManager; 16 | import javax.swing.border.Border; 17 | import javax.swing.border.EmptyBorder; 18 | 19 | public class CheckBoxList extends JList { 20 | protected static Border noFocusBorder = new EmptyBorder(1, 1, 1, 1); 21 | 22 | public CheckBoxList(final int xOffset) { 23 | setCellRenderer(new CellRenderer()); 24 | 25 | addMouseListener(new MouseAdapter() { 26 | public void mousePressed(MouseEvent e) { 27 | int index = locationToIndex(e.getPoint()); 28 | 29 | if (index != -1) { 30 | JCheckBox checkbox = getModel().getElementAt(index); 31 | Icon icon = UIManager.getIcon("CheckBox.icon"); 32 | if (icon != null) { 33 | if (e.getX() <= icon.getIconWidth() + xOffset) { 34 | if (checkbox.isEnabled()) { 35 | checkbox.setSelected(!checkbox.isSelected()); 36 | } 37 | } 38 | repaint(); 39 | } else { 40 | if (checkbox.isEnabled()) { 41 | checkbox.setSelected(!checkbox.isSelected()); 42 | } 43 | repaint(); 44 | } 45 | } 46 | } 47 | } 48 | ); 49 | 50 | setSelectionMode(ListSelectionModel.SINGLE_SELECTION); 51 | } 52 | 53 | protected class CellRenderer implements ListCellRenderer { 54 | @Override 55 | public Component getListCellRendererComponent(JList list, JCheckBox value, int index, boolean isSelected, boolean cellHasFocus) { 56 | value.setBackground(isSelected ? getSelectionBackground() : getBackground()); 57 | value.setForeground(isSelected ? getSelectionForeground() : getForeground()); 58 | value.setEnabled(isEnabled() && value.isEnabled()); 59 | value.setFont(getFont()); 60 | if (value instanceof PluginCheckbox) { 61 | Plugin p = ((PluginCheckbox) value).getPlugin(); 62 | if (p.isUpgradable()) { 63 | value.setFont(getFont().deriveFont(Font.ITALIC | Font.BOLD)); 64 | } 65 | } 66 | 67 | value.setFocusPainted(false); 68 | value.setBorderPainted(true); 69 | value.setBorder(isSelected ? UIManager.getBorder("List.focusCellHighlightBorder") : noFocusBorder); 70 | return value; 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/org/jmeterplugins/repository/plugins/PluginSuggester.java: -------------------------------------------------------------------------------- 1 | package org.jmeterplugins.repository.plugins; 2 | 3 | import org.apache.jmeter.gui.GuiPackage; 4 | import org.jmeterplugins.repository.Plugin; 5 | import org.jmeterplugins.repository.PluginManager; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | import java.awt.*; 10 | import java.util.Arrays; 11 | import java.util.Collections; 12 | import java.util.HashSet; 13 | import java.util.Set; 14 | 15 | public class PluginSuggester { 16 | private static final Logger log = LoggerFactory.getLogger(PluginSuggester.class); 17 | 18 | protected TestPlanAnalyzer analyzer; 19 | protected String testPlan; 20 | private final PluginManager pmgr; 21 | 22 | public PluginSuggester(PluginManager pmgr) { 23 | this.pmgr = pmgr; 24 | analyzer = new TestPlanAnalyzer(); 25 | } 26 | 27 | public void checkAndSuggest(String msg) { 28 | Set pluginsToInstall = findPluginsToInstall(msg); 29 | if (pluginsToInstall.size() > 0) { 30 | 31 | pmgr.togglePlugins(pluginsToInstall, true); 32 | 33 | Frame parent = (GuiPackage.getInstance() != null) ? GuiPackage.getInstance().getMainFrame() : null; 34 | SuggestDialog dialog = new SuggestDialog(parent, pmgr, pluginsToInstall, testPlan); 35 | dialog.setVisible(true); 36 | dialog.setAlwaysOnTop(true); 37 | } 38 | } 39 | 40 | protected Set findPluginsToInstall(String msg) { 41 | if (msg != null && msg.contains("Loading file")) { 42 | testPlan = msg.substring(msg.indexOf(": ") + 2); 43 | if (!"null".equals(testPlan)) { 44 | return analyzeTestPlan(testPlan); 45 | } 46 | } 47 | return Collections.emptySet(); 48 | } 49 | 50 | public Set analyzeTestPlan(String path) { 51 | Set nonExistentClasses = analyzer.analyze(path); 52 | if (nonExistentClasses.size() > 0) { 53 | return findPluginsFromClasses(nonExistentClasses); 54 | } 55 | return Collections.emptySet(); 56 | } 57 | 58 | 59 | protected Set findPluginsFromClasses(Set nonExistentClasses) { 60 | try { 61 | pmgr.load(); 62 | } catch (Throwable throwable) { 63 | log.warn("Cannot load plugins repo: ", throwable); 64 | return Collections.emptySet(); 65 | } 66 | final Set availablePlugins = pmgr.getAvailablePlugins(); 67 | final Set pluginsToInstall = new HashSet<>(); 68 | for (Plugin plugin : availablePlugins) { 69 | if (plugin.containsComponentClasses(nonExistentClasses)) { 70 | pluginsToInstall.add(plugin); 71 | } 72 | } 73 | 74 | if (pluginsToInstall.isEmpty()) { 75 | log.warn("Plugins Manager were unable to find plugins to satisfy Test Plan requirements. " + 76 | "To help improve, please report following list to https://jmeter-plugins.org/support/: " + 77 | Arrays.toString(nonExistentClasses.toArray())); 78 | } 79 | 80 | return pluginsToInstall; 81 | } 82 | 83 | public TestPlanAnalyzer getAnalyzer() { 84 | return analyzer; 85 | } 86 | 87 | public void setAnalyzer(TestPlanAnalyzer analyzer) { 88 | this.analyzer = analyzer; 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /src/main/resources/org/jmeterplugins/logoUpdate.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 10 | 12 | 14 | 16 | 17 | 18 | 20 | 22 | 24 | 26 | 28 | 31 | 32 | 33 | 36 | 38 | 40 | 42 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /src/test/java/org/jmeterplugins/repository/ChangesMakerTest.java: -------------------------------------------------------------------------------- 1 | package org.jmeterplugins.repository; 2 | 3 | 4 | import org.junit.Assert; 5 | import org.junit.Test; 6 | 7 | import java.io.File; 8 | import java.net.URLDecoder; 9 | import java.nio.charset.Charset; 10 | import java.nio.file.Files; 11 | import java.nio.file.Paths; 12 | import java.util.*; 13 | 14 | import static org.junit.Assert.assertTrue; 15 | 16 | public class ChangesMakerTest { 17 | @Test 18 | public void getProcessBuilder() throws Exception { 19 | Assert.assertEquals("a b", URLDecoder.decode("a%20b", "UTF-8")); 20 | } 21 | 22 | @Test 23 | public void getRestartFile() throws Exception { 24 | Map map = new HashMap<>(); 25 | ChangesMaker maker = new ChangesMaker(map); 26 | 27 | LinkedList options = new LinkedList<>(); 28 | options.add("-t"); 29 | options.add("testPlanFile"); 30 | 31 | File file = maker.getRestartFile(options); 32 | List lines = Files.readAllLines(Paths.get(file.toURI()), Charset.defaultCharset()); 33 | String fileContent = Arrays.toString(lines.toArray()); 34 | 35 | assertTrue(fileContent, fileContent.contains("ApacheJMeter.jar, -t, testPlanFile")); 36 | } 37 | 38 | @Test 39 | public void getInstallFile() throws Exception { 40 | Map map = new HashMap<>(); 41 | ChangesMaker obj = new ChangesMaker(map); 42 | Set plugins = new HashSet<>(); 43 | PluginMock p1 = new PluginMock("test", "test"); 44 | p1.setInstallerClass("test1"); 45 | p1.setDestName("plugin1"); 46 | Map libs1 = new HashMap<>(); 47 | libs1.put("lib_to_install1", "path..."); 48 | p1.setLibs(libs1); 49 | 50 | PluginMock p2 = new PluginMock("test", "test"); 51 | p2.setInstallerClass("test2"); 52 | p2.setDestName("plugin2"); 53 | Map libs2 = new HashMap<>(); 54 | libs2.put("jmeter-plugins-emulators", "path..."); 55 | p2.setLibs(libs2); 56 | 57 | plugins.add(p1); 58 | plugins.add(p2); 59 | 60 | HashSet installationInfos = new HashSet<>(); 61 | installationInfos.add(new Library.InstallationInfo("lib_to_install1", "tmp_path", "some_path_to_jar1")); 62 | File res = obj.getInstallFile(plugins, installationInfos); 63 | 64 | assertTrue(res.length() > 0); 65 | 66 | String installFirst = "some_path_to_jar1" + File.pathSeparator + "plugin1\ttest1"; 67 | String installSecond = "jmeter-plugins-emulators-0.2.jar" + File.pathSeparator + "plugin2\ttest2"; 68 | 69 | List lines = Files.readAllLines(Paths.get(res.toURI()), Charset.defaultCharset()); 70 | String fileContent = Arrays.toString(lines.toArray()); 71 | System.out.println(fileContent); 72 | 73 | assertTrue(fileContent, fileContent.contains(installFirst)); 74 | assertTrue(fileContent, fileContent.contains(installSecond)); 75 | 76 | File res2 = obj.getMovementsFile(plugins, plugins, new HashSet(), new HashSet()); 77 | assertTrue(res2.length() > 0); 78 | } 79 | 80 | @Test 81 | public void getMovementsFile() throws Exception { 82 | Map map = new HashMap<>(); 83 | ChangesMaker obj = new ChangesMaker(map); 84 | File file = File.createTempFile("tmp", ""); 85 | file.deleteOnExit(); 86 | obj.getProcessBuilder(file, file, file); 87 | } 88 | 89 | } -------------------------------------------------------------------------------- /src/test/java/org/jmeterplugins/repository/PluginManagerDialogTest.java: -------------------------------------------------------------------------------- 1 | package org.jmeterplugins.repository; 2 | 3 | import kg.apc.emulators.TestJMeterUtils; 4 | import net.sf.json.JSONObject; 5 | import net.sf.json.JsonConfig; 6 | import org.apache.jmeter.util.JMeterUtils; 7 | import org.jmeterplugins.repository.exception.DownloadException; 8 | import org.junit.BeforeClass; 9 | import org.junit.Test; 10 | 11 | import javax.swing.*; 12 | import java.awt.*; 13 | import java.net.URL; 14 | import java.util.*; 15 | import java.util.List; 16 | 17 | import static org.junit.Assert.assertTrue; 18 | 19 | public class PluginManagerDialogTest { 20 | @BeforeClass 21 | public static void setup() { 22 | TestJMeterUtils.createJmeterEnv(); 23 | } 24 | 25 | @Test 26 | public void displayGUI() throws Throwable { 27 | if (!GraphicsEnvironment.getLocalGraphicsEnvironment().isHeadlessInstance()) { 28 | // URL url = PluginManagerTest.class.getResource("/lib_versions.json"); 29 | // JMeterUtils.setProperty("jpgc.repo.address", url.getPath()); 30 | System.setProperty("http.proxyHost", "localhost"); 31 | System.setProperty("http.proxyPort", "81"); 32 | PluginManager aManager = new PluginManager(); 33 | aManager.load(); 34 | PluginManagerDialog frame = new PluginManagerDialog(aManager); 35 | 36 | frame.setPreferredSize(new Dimension(800, 600)); 37 | frame.setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE); 38 | frame.pack(); 39 | frame.setVisible(true); 40 | while (frame.isVisible()) { 41 | Thread.sleep(1000); 42 | } 43 | JMeterUtils.getJMeterProperties().remove("jpgc.repo.address"); 44 | } 45 | } 46 | 47 | 48 | 49 | @Test 50 | public void testFailDownload() throws Exception { 51 | if (!GraphicsEnvironment.getLocalGraphicsEnvironment().isHeadlessInstance()) { 52 | String addr = JMeterUtils.getPropDefault("jpgc.repo.address", "https://jmeter-plugins.org/repo/"); 53 | try { 54 | JMeterUtils.setProperty("jpgc.repo.address", "http://httpstat.us/500"); 55 | PluginManager aManager = new PluginManager(); 56 | PluginManagerDialog frame = new PluginManagerDialog(aManager); 57 | frame.componentShown(null); 58 | List panes = new ArrayList<>(); 59 | getJEditorPane(frame, panes); 60 | assertTrue(panes.size() > 0); 61 | boolean isOk = false; 62 | for (JEditorPane p : panes) { 63 | if (p.getText().contains("Failed to download plugins repository.")) { 64 | isOk = true; 65 | break; 66 | } 67 | } 68 | assertTrue(isOk); 69 | frame.actionPerformed(null); 70 | } finally { 71 | JMeterUtils.setProperty("jpgc.repo.address", addr); 72 | } 73 | } 74 | } 75 | 76 | private void getJEditorPane(Container component, List result) { 77 | Component[] components = component.getComponents(); 78 | for (Component component1 : components) { 79 | 80 | if (component1 instanceof JEditorPane) { 81 | result.add((JEditorPane) component1); 82 | } 83 | 84 | if (component1 instanceof Container) { 85 | getJEditorPane((Container) component1, result); 86 | } 87 | } 88 | } 89 | } -------------------------------------------------------------------------------- /src/main/java/org/jmeterplugins/repository/Library.java: -------------------------------------------------------------------------------- 1 | package org.jmeterplugins.repository; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import java.util.Comparator; 7 | 8 | public class Library { 9 | private static final Logger log = LoggerFactory.getLogger(Library.class); 10 | 11 | protected String name; 12 | protected String version; 13 | protected String link; 14 | 15 | public static final Comparator versionComparator = new Comparator() { 16 | @Override 17 | public int compare(Library lib1, Library lib2) { 18 | int code = 0; 19 | 20 | final String[] versions1 = lib1.getVersion().split("[.]"); 21 | final String[] versions2 = lib2.getVersion().split("[.]"); 22 | int length = Math.min(versions1.length, versions2.length); 23 | 24 | for (int i = 0; i < length; i++) { 25 | try { 26 | code = Integer.compare(Integer.parseInt(versions1[i]), Integer.parseInt(versions2[i])); 27 | } catch (NumberFormatException e) { 28 | log.debug("Cannot parse library version", e); 29 | code = versions1[i].compareTo(versions2[i]); 30 | } 31 | if (code != 0) { 32 | break; 33 | } 34 | } 35 | 36 | // if version1: 9.9 and version2: 9.9.1 37 | if (code == 0 && versions1.length != versions2.length) { 38 | code = Integer.compare(versions1.length, versions2.length); 39 | } 40 | 41 | return code; 42 | } 43 | }; 44 | 45 | 46 | public Library() { 47 | } 48 | 49 | public Library(String name, String version, String link) { 50 | this.name = name; 51 | this.version = version; 52 | this.link = link; 53 | } 54 | 55 | public Library(String name, String link) { 56 | this.name = name; 57 | this.link = link; 58 | } 59 | 60 | public String getName() { 61 | return name; 62 | } 63 | 64 | public void setName(String name) { 65 | this.name = name; 66 | } 67 | 68 | public String getVersion() { 69 | return version; 70 | } 71 | 72 | public void setVersion(String version) { 73 | this.version = version; 74 | } 75 | 76 | public String getLink() { 77 | return link; 78 | } 79 | 80 | public void setLink(String link) { 81 | this.link = link; 82 | } 83 | 84 | public String getFullName() { 85 | return name + ">=" + version; 86 | } 87 | 88 | public static String getVersionFromFullName(String fullName) { 89 | return fullName.substring(fullName.indexOf(">=") + 2); 90 | } 91 | 92 | public static String getNameFromFullName(String fullName) { 93 | return fullName.substring(0, fullName.indexOf(">=")); 94 | } 95 | 96 | public static class InstallationInfo { 97 | private final String name; 98 | private final String tmpPath; 99 | private final String destinationFileName; 100 | 101 | public InstallationInfo(String name, String tmpPath, String destinationFileName) { 102 | this.name = name; 103 | this.tmpPath = tmpPath; 104 | this.destinationFileName = destinationFileName; 105 | } 106 | 107 | public String getName() { 108 | return name; 109 | } 110 | 111 | public String getTmpPath() { 112 | return tmpPath; 113 | } 114 | 115 | public String getDestinationFileName() { 116 | return destinationFileName; 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/test/java/org/jmeterplugins/repository/http/StatsReporterTest.java: -------------------------------------------------------------------------------- 1 | package org.jmeterplugins.repository.http; 2 | 3 | import kg.apc.emulators.TestJMeterUtils; 4 | import org.apache.http.HttpResponse; 5 | import org.apache.http.ProtocolVersion; 6 | import org.apache.http.client.methods.HttpUriRequest; 7 | import org.apache.http.entity.BasicHttpEntity; 8 | import org.apache.http.impl.client.AbstractHttpClient; 9 | import org.apache.http.message.BasicHttpResponse; 10 | import org.apache.http.message.BasicStatusLine; 11 | import org.apache.http.protocol.HttpContext; 12 | import org.jmeterplugins.repository.JARSourceEmul; 13 | import org.jmeterplugins.repository.JARSourceFilesystem; 14 | import org.jmeterplugins.repository.JARSourceHTTP; 15 | import org.junit.BeforeClass; 16 | import org.junit.Test; 17 | 18 | import java.io.ByteArrayInputStream; 19 | import java.io.File; 20 | import java.io.InputStream; 21 | 22 | import static org.junit.Assert.*; 23 | 24 | public class StatsReporterTest { 25 | @BeforeClass 26 | public static void setup() { 27 | TestJMeterUtils.createJmeterEnv(); 28 | } 29 | 30 | @Test 31 | public void testFlow() throws Exception { 32 | final String[] stats = {"aaaa"}; 33 | JARSourceEmul emul = new JARSourceEmul() { 34 | @Override 35 | public void reportStats(String[] usageStats) { 36 | assertArrayEquals(stats, usageStats); 37 | } 38 | }; 39 | StatsReporter reporter = new StatsReporter(emul, stats); 40 | assertTrue(reporter.isDaemon()); 41 | reporter.start(); 42 | reporter.join(); 43 | } 44 | 45 | @Test 46 | public void testCloneable() throws Exception { 47 | JARSourceHTTPExt jarSource = new JARSourceHTTPExt("repo1;repo2"); 48 | final String[] stats = {"aaaa"}; 49 | StatsReporter reporter = new StatsReporter(jarSource, stats); 50 | assertNotNull(reporter.getJarSource()); 51 | assertNotSame(jarSource, reporter.getJarSource()); 52 | 53 | assertTrue(reporter.getJarSource() instanceof JARSourceHTTPExt); 54 | JARSourceHTTPExt actual = (JARSourceHTTPExt) reporter.getJarSource(); 55 | assertNotSame(jarSource.getHttpClient(), actual.getHttpClient()); 56 | 57 | } 58 | 59 | public static class JARSourceHTTPExt extends JARSourceHTTP { 60 | public JARSourceHTTPExt(String jmProp) { 61 | super(jmProp); 62 | } 63 | 64 | public AbstractHttpClient getHttpClient() { 65 | return httpClient; 66 | } 67 | 68 | @Override 69 | public HttpResponse execute(HttpUriRequest request, HttpContext context) { 70 | ProtocolVersion http = new ProtocolVersion("HTTP", 1, 1); 71 | BasicStatusLine accepted = new BasicStatusLine(http, 200, "OK"); 72 | BasicHttpResponse basicHttpResponse = new BasicHttpResponse(accepted); 73 | basicHttpResponse.addHeader("Last-Modified", JARSourceHTTP.dateFormat.format(System.currentTimeMillis() - 1000)); 74 | BasicHttpEntity entity = new BasicHttpEntity(); 75 | InputStream is=new ByteArrayInputStream("[]".getBytes()); 76 | entity.setContent(is); 77 | basicHttpResponse.setEntity(entity); 78 | return basicHttpResponse; 79 | } 80 | } 81 | 82 | @Test 83 | public void testCloneable1() throws Exception { 84 | JARSourceFilesystem filesystem = new JARSourceFilesystem(new File("")); 85 | final String[] stats = {"aaaa"}; 86 | StatsReporter reporter = new StatsReporter(filesystem, stats); 87 | assertNotNull(reporter.getJarSource()); 88 | assertNotSame(filesystem, reporter.getJarSource()); 89 | } 90 | 91 | @Test 92 | public void testFlow3() throws Exception { 93 | JARSourceHTTPExt jarSource = new JARSourceHTTPExt("repoStats"); 94 | jarSource.getRepo(); 95 | Thread.sleep(500); 96 | final String[] stats = {"aaaa"}; 97 | jarSource.reportStats(stats); 98 | } 99 | } -------------------------------------------------------------------------------- /src/test/java/org/jmeterplugins/repository/PluginTest.java: -------------------------------------------------------------------------------- 1 | package org.jmeterplugins.repository; 2 | 3 | import net.sf.json.JSONObject; 4 | import net.sf.json.JsonConfig; 5 | import org.apache.jmeter.engine.JMeterEngine; 6 | import org.junit.Test; 7 | 8 | import java.util.HashSet; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | public class PluginTest { 13 | @Test 14 | public void testVerFromPath() throws Exception { 15 | assertEquals("0.1", Plugin.getVersionFromPath("/tmp/plugins-manager-0.1.jar")); 16 | assertEquals("0.1-BETA", Plugin.getVersionFromPath("/tmp/plugins-manager-0.1-BETA.jar")); 17 | assertEquals("0.1-SNAPSHOT", Plugin.getVersionFromPath("/tmp/plugins-manager-0.1-SNAPSHOT.jar")); 18 | assertEquals("0.1.v20182206", Plugin.getVersionFromPath("/tmp/plugins-manager-0.1.v20182206.jar")); 19 | } 20 | 21 | @Test 22 | public void testLibInstallPath() throws Exception { 23 | assertNotNull(Plugin.getLibPath("hector-core", new String[]{"/tmp/hector-core-1.1-2.jar"})); 24 | assertNotNull(Plugin.getLibPath("kafka_2.8.2", new String[]{"/tmp/kafka_2.8.2-0.8.0.jar"})); 25 | assertNotNull(Plugin.getLibPath("websocket-api", new String[]{"/tmp/websocket-api-9.1.1.v20140108.jar"})); 26 | assertNotNull(Plugin.getLibPath("cglib-nodep", new String[]{"/tmp/cglib-nodep-2.1_3.jar"})); 27 | } 28 | 29 | @Test 30 | public void testVersionComparator() throws Exception { 31 | PluginMock obj = new PluginMock(); 32 | obj.setMarkerClass(JMeterEngine.class.getCanonicalName()); 33 | obj.detectInstalled(new HashSet()); 34 | assertEquals("2.13", obj.getCandidateVersion()); 35 | } 36 | 37 | @Test 38 | public void testVirtual() throws Exception { 39 | PluginMock obj = new PluginMock("virtual"); 40 | obj.setCandidateVersion("0"); 41 | obj.setVersions(JSONObject.fromObject("{\"0\": {\"downloadUrl\": null}}", new JsonConfig())); 42 | assertTrue(obj.isVirtual()); 43 | HashSet depends = new HashSet<>(); 44 | depends.add("mock"); 45 | obj.setDepends(depends); 46 | 47 | HashSet others = new HashSet<>(); 48 | PluginMock e = new PluginMock(); 49 | e.setMarkerClass(JMeterEngine.class.getCanonicalName()); 50 | e.detectInstalled(new HashSet()); 51 | others.add(e); 52 | obj.detectInstalled(others); 53 | assertTrue(obj.isInstalled()); 54 | 55 | obj.download(new JARSourceEmul(), new GenericCallback() { 56 | @Override 57 | public void notify(String s) { 58 | } 59 | }); 60 | } 61 | 62 | @Test 63 | public void testInstallerClass() { 64 | String str = "{\"id\": 0, \"markerClass\": 0, \"name\": 0, \"description\": 0, \"helpUrl\": 0, \"vendor\": 0, \"installerClass\": \"test\"}"; 65 | Plugin p = Plugin.fromJSON(JSONObject.fromObject(str, new JsonConfig())); 66 | assertEquals("test", p.getInstallerClass()); 67 | } 68 | 69 | @Test 70 | public void testVersionChanges() { 71 | String str = "{\"id\": 0, \"markerClass\": 0, \"name\": 0, \"description\": 0, \"helpUrl\": 0, \"vendor\": 0, \"installerClass\": \"test\", " + 72 | "\"versions\" : { \"0.1\" : { \"changes\": \"fix verified exception\" } }}"; 73 | Plugin p = Plugin.fromJSON(JSONObject.fromObject(str, new JsonConfig())); 74 | assertEquals("fix verified exception", p.getVersionChanges("0.1")); 75 | 76 | str = "{\"id\": 0, \"markerClass\": 0, \"name\": 0, \"description\": 0, \"helpUrl\": 0, \"vendor\": 0, \"installerClass\": \"test\", " + 77 | "\"versions\" : { \"0.1\" : { } }}"; 78 | p = Plugin.fromJSON(JSONObject.fromObject(str, new JsonConfig())); 79 | assertNull(p.getVersionChanges("0.1")); 80 | } 81 | 82 | @Test 83 | public void testAllData() { 84 | String str = "{\"id\": \"id\", \"markerClass\": \"class\", \"name\": \"name\", \"description\": \"description\"," + 85 | " \"helpUrl\": 0, \"vendor\": 0, \"installerClass\": \"test\"}"; 86 | Plugin p = Plugin.fromJSON(JSONObject.fromObject(str, new JsonConfig())); 87 | assertEquals("idnamedescriptionclass", p.getSearchIndexString()); 88 | } 89 | } -------------------------------------------------------------------------------- /src/main/java/org/jmeterplugins/repository/PluginManagerMenuItem.java: -------------------------------------------------------------------------------- 1 | package org.jmeterplugins.repository; 2 | 3 | import org.apache.jmeter.gui.GuiPackage; 4 | import org.apache.jmeter.gui.MainFrame; 5 | import org.apache.jmeter.gui.util.JMeterToolBar; 6 | import org.jmeterplugins.repository.logging.LoggingHooker; 7 | import org.jmeterplugins.repository.util.ComponentFinder; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | 11 | import javax.swing.*; 12 | import java.awt.*; 13 | import java.awt.event.ActionEvent; 14 | import java.awt.event.ActionListener; 15 | import java.util.Arrays; 16 | 17 | public class PluginManagerMenuItem extends JMenuItem implements ActionListener { 18 | private static final long serialVersionUID = -8708638472918746046L; 19 | private static final Logger log = LoggerFactory.getLogger(PluginManagerMenuItem.class); 20 | private static PluginManagerDialog dialog; 21 | private final PluginManager mgr; 22 | 23 | public PluginManagerMenuItem() { 24 | super("Plugins Manager"); 25 | addActionListener(this); 26 | 27 | mgr = new PluginManager(); // don't delay startup for longer that 1 second 28 | LoggingHooker hooker = new LoggingHooker(mgr); 29 | hooker.hook(); 30 | final JButton toolbarButton = getToolbarButton(); 31 | addToolbarIcon(toolbarButton); 32 | setIcon(PluginIcon.getPluginsIcon(false)); 33 | 34 | new Thread("repo-downloader-thread") { 35 | @Override 36 | public void run() { 37 | try { 38 | mgr.load(); 39 | } catch (Throwable e) { 40 | log.warn("Failed to load plugin updates info", e); 41 | } 42 | 43 | if (mgr.hasAnyUpdates()) { 44 | setText("Plugins Manager (has upgrades)"); 45 | log.info("Plugins Manager has upgrades: " + Arrays.toString(mgr.getUpgradablePlugins().toArray())); 46 | } 47 | 48 | boolean hasAnyUpdates = mgr.hasAnyUpdates(); 49 | setIcon(PluginIcon.getPluginsIcon(hasAnyUpdates)); 50 | toolbarButton.setIcon(PluginIcon.getIcon22Px(hasAnyUpdates)); 51 | toolbarButton.setToolTipText(hasAnyUpdates ? 52 | "Plugins Manager (has upgrades)" : 53 | "Plugins Manager" 54 | ); 55 | } 56 | }.start(); 57 | } 58 | 59 | private void addToolbarIcon(final Component toolbarButton) { 60 | GuiPackage instance = GuiPackage.getInstance(); 61 | if (instance != null) { 62 | final MainFrame mf = instance.getMainFrame(); 63 | final ComponentFinder finder = new ComponentFinder<>(JMeterToolBar.class); 64 | SwingUtilities.invokeLater(new Runnable() { 65 | @Override 66 | public void run() { 67 | JMeterToolBar toolbar = null; 68 | while (toolbar == null) { 69 | try { 70 | Thread.sleep(1000); 71 | } catch (InterruptedException e) { 72 | log.debug("Did not add btn to toolbar", e); 73 | } 74 | log.debug("Searching for toolbar"); 75 | toolbar = finder.findComponentIn(mf); 76 | } 77 | 78 | int pos = toolbar.getComponents().length - 1; 79 | toolbarButton.setSize(toolbar.getComponent(pos).getSize()); 80 | toolbar.add(toolbarButton, pos + 1); 81 | } 82 | }); 83 | } 84 | } 85 | 86 | private JButton getToolbarButton() { 87 | boolean hasAnyUpdates = mgr.hasAnyUpdates(); 88 | JButton button = new JButton(PluginIcon.getIcon22Px(hasAnyUpdates)); 89 | button.setToolTipText(hasAnyUpdates ? 90 | "Plugins Manager (has upgrades)" : 91 | "Plugins Manager" 92 | ); 93 | button.addActionListener(this); 94 | return button; 95 | } 96 | 97 | 98 | @Override 99 | public void actionPerformed(ActionEvent e) { 100 | if (dialog == null) { 101 | dialog = new PluginManagerDialog(mgr); 102 | } 103 | 104 | dialog.pack(); 105 | dialog.setVisible(true); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/test/java/org/jmeterplugins/repository/PluginsListTest.java: -------------------------------------------------------------------------------- 1 | package org.jmeterplugins.repository; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.junit.Assert.assertFalse; 5 | 6 | import java.awt.KeyboardFocusManager; 7 | import java.awt.event.KeyEvent; 8 | import java.io.File; 9 | import java.util.HashSet; 10 | import java.util.Set; 11 | 12 | import javax.swing.JComboBox; 13 | import javax.swing.JList; 14 | import javax.swing.JTextField; 15 | import javax.swing.ListModel; 16 | import javax.swing.event.ChangeListener; 17 | import javax.swing.event.ListSelectionEvent; 18 | 19 | import org.junit.Test; 20 | 21 | import net.sf.json.JSONObject; 22 | import net.sf.json.JsonConfig; 23 | 24 | public class PluginsListTest { 25 | 26 | private static final String EXPECTED_DESC_MAVEN = 27 | "Maven groupId: kg.apc, artifactId: jmeter-plugins-webdriver, version: 0.3"; 28 | private static final String EXPECTED_DESC_CHANGES = 29 | "What's new in version 0.3: fix verified exception1"; 30 | @Test 31 | public void testFlow() throws Exception { 32 | String imgPath = "file:///" + new File(".").getAbsolutePath() + "/target/classes/org/jmeterplugins/logo.png"; 33 | String str = "{\"id\": 0, \"markerClass\": \"" + PluginsListTest.class.getName() + "\"," + 34 | " \"screenshotUrl\": \"" + imgPath + "\", \"name\": 3, \"description\": 4, \"helpUrl\": 5, \"vendor\": 5, \"installerClass\": \"test\", " + 35 | "\"versions\" : { \"0.1\" : { \"changes\": \"fix verified exception1\", \"downloadUrl\": \"https://search.maven.org/remotecontent?filepath=kg/apc/jmeter-plugins-webdriver/0.3/jmeter-plugins-webdriver-0.1.jar\" }," + 36 | "\"0.2\" : { \"changes\": \"fix verified exception1\", \"downloadUrl\": \"https://search.maven.org/remotecontent?filepath=kg/apc/jmeter-plugins-webdriver/0.3/jmeter-plugins-webdriver-0.2.jar\"}," + 37 | "\"0.3\" : { \"changes\": \"fix verified exception1\", " + 38 | "\"downloadUrl\": \"https://search.maven.org/remotecontent?filepath=kg/apc/jmeter-plugins-webdriver/0.3/jmeter-plugins-webdriver-0.3.jar\"} }}"; 39 | Plugin p = Plugin.fromJSON(JSONObject.fromObject(str, new JsonConfig())); 40 | 41 | Set set = new HashSet<>(); 42 | set.add(p); 43 | 44 | PluginsListExt pluginsList = new PluginsListExt(set, null, null); 45 | pluginsList.getList().setSelectedIndex(0); 46 | 47 | ListSelectionEvent event = new ListSelectionEvent("0.2", 0, 2, false); 48 | pluginsList.valueChanged(event); 49 | 50 | p.setCandidateVersion("0.3"); 51 | assertEquals("0.3", pluginsList.getCbVersion(pluginsList.getCheckboxItem(p, null))); 52 | String desc = pluginsList.getDescriptionHTML(p); 53 | assertFalse(desc.indexOf(EXPECTED_DESC_MAVEN)<0); 54 | assertFalse(desc.indexOf(EXPECTED_DESC_CHANGES)<0); 55 | p.detectInstalled(null); 56 | assertEquals(Plugin.VER_STOCK, pluginsList.getCbVersion(pluginsList.getCheckboxItem(p, null))); 57 | 58 | pluginsList.setEnabled(false); 59 | assertFalse(pluginsList.getList().isEnabled()); 60 | assertFalse(pluginsList.getVersion().isEnabled()); 61 | assertFalse(pluginsList.getList().getModel().getElementAt(0).isEnabled()); 62 | 63 | JTextField searchField = pluginsList.searchField; 64 | ListModel model = pluginsList.getList().getModel(); 65 | searchField.setText("not found plugin"); 66 | KeyEvent keyEvent = new KeyEvent(pluginsList.searchField, KeyEvent.KEY_RELEASED, 20, 1, KeyEvent.VK_Z, 'z'); 67 | KeyboardFocusManager.getCurrentKeyboardFocusManager().redispatchEvent(searchField, keyEvent); 68 | searchField.dispatchEvent(keyEvent); 69 | assertEquals(0, pluginsList.getList().getModel().getSize()); 70 | assertFalse(model == pluginsList.getList().getModel()); 71 | 72 | searchField.setText(""); 73 | KeyboardFocusManager.getCurrentKeyboardFocusManager().redispatchEvent(searchField, keyEvent); 74 | searchField.dispatchEvent(keyEvent); 75 | assertEquals(1, pluginsList.getList().getModel().getSize()); 76 | assertEquals(model, pluginsList.getList().getModel()); 77 | } 78 | 79 | 80 | public static class PluginsListExt extends PluginsList { 81 | public PluginsListExt(Set plugins, ChangeListener checkboxNotifier, GenericCallback dialogRefresh) { 82 | super(dialogRefresh); 83 | setPlugins(plugins, checkboxNotifier); 84 | } 85 | 86 | public JList getList() { 87 | return list; 88 | } 89 | 90 | public JComboBox getVersion() { 91 | return version; 92 | } 93 | } 94 | } -------------------------------------------------------------------------------- /src/test/java/org/jmeterplugins/repository/PluginManagerCMDTest.java: -------------------------------------------------------------------------------- 1 | package org.jmeterplugins.repository; 2 | 3 | import kg.apc.emulators.TestJMeterUtils; 4 | import org.apache.jmeter.util.JMeterUtils; 5 | import org.junit.AfterClass; 6 | import org.junit.BeforeClass; 7 | import org.junit.Test; 8 | 9 | import java.net.URL; 10 | import java.util.LinkedList; 11 | 12 | import static junit.framework.Assert.assertEquals; 13 | import static junit.framework.TestCase.fail; 14 | 15 | public class PluginManagerCMDTest { 16 | @BeforeClass 17 | public static void setup() { 18 | TestJMeterUtils.createJmeterEnv(); 19 | URL url = PluginManagerTest.class.getResource("/testVirtualPlugin.json"); 20 | JMeterUtils.setProperty("jpgc.repo.address", url.getFile()); 21 | } 22 | 23 | @AfterClass 24 | public static void tearDown() throws Exception { 25 | JMeterUtils.getJMeterProperties().remove("jpgc.repo.address"); 26 | } 27 | 28 | @Test 29 | public void processParams_status() throws Exception { 30 | PluginManagerCMD cmd = new PluginManagerCMD(); 31 | LinkedList params = new LinkedList<>(); 32 | params.add("status"); 33 | cmd.processParams(params.listIterator()); 34 | } 35 | 36 | @Test 37 | public void processParams_install() throws Exception { 38 | PluginManagerCMD cmd = new PluginManagerCMD(); 39 | LinkedList params = new LinkedList<>(); 40 | params.add("install"); 41 | try { 42 | cmd.processParams(params.listIterator()); 43 | fail(); 44 | } catch (IllegalArgumentException ignored) { 45 | } 46 | params.add("jpgc-dep1,jpgc-dep2=2.0"); 47 | cmd.processParams(params.listIterator()); 48 | } 49 | 50 | @Test 51 | public void processParams_install_all() throws Exception { 52 | PluginManagerCMD cmd = new PluginManagerCMD(); 53 | LinkedList params = new LinkedList<>(); 54 | params.add("install-all-except"); 55 | cmd.processParams(params.listIterator()); 56 | params.add("jpgc-dep1,jpgc-dep2=2.0"); 57 | cmd.processParams(params.listIterator()); 58 | } 59 | 60 | @Test 61 | public void processParams_install_invalid() throws Exception { 62 | PluginManagerCMD cmd = new PluginManagerCMD(); 63 | LinkedList params = new LinkedList<>(); 64 | params.add("install"); 65 | params.add("jpgc-invalid"); 66 | try { 67 | cmd.processParams(params.listIterator()); 68 | fail(); 69 | } catch (RuntimeException ignored) { 70 | } 71 | } 72 | 73 | @Test 74 | public void processParams_uninstall() throws Exception { 75 | PluginManagerCMD cmd = new PluginManagerCMD(); 76 | LinkedList params = new LinkedList<>(); 77 | params.add("uninstall"); 78 | try { 79 | cmd.processParams(params.listIterator()); 80 | fail(); 81 | } catch (IllegalArgumentException ignored) { 82 | } 83 | params.add("jpgc-dep1,jpgc-dep2=2.0"); 84 | cmd.processParams(params.listIterator()); 85 | } 86 | 87 | 88 | @Test 89 | public void showHelp() throws Exception { 90 | PluginManagerCMD cmd = new PluginManagerCMD(); 91 | 92 | LinkedList params = new LinkedList<>(); 93 | params.add("help"); 94 | int code = cmd.processParams(params.listIterator()); 95 | assertEquals(0, code); 96 | 97 | params.clear(); 98 | params.add("help me pls"); 99 | try { 100 | cmd.processParams(params.listIterator()); 101 | } catch (Throwable ex) { 102 | // 103 | } 104 | 105 | params.clear(); 106 | try { 107 | cmd.processParams(params.listIterator()); 108 | } catch (IllegalArgumentException ex) { 109 | // 110 | } 111 | } 112 | 113 | @Test 114 | public void testAvailable() throws Exception { 115 | PluginManagerCMD cmd = new PluginManagerCMD(); 116 | LinkedList params = new LinkedList<>(); 117 | params.add("available"); 118 | int code = cmd.processParams(params.listIterator()); 119 | assertEquals(0, code); 120 | } 121 | 122 | @Test 123 | public void testUpgrades() throws Exception { 124 | PluginManagerCMD cmd = new PluginManagerCMD(); 125 | LinkedList params = new LinkedList<>(); 126 | params.add("upgrades"); 127 | int code = cmd.processParams(params.listIterator()); 128 | assertEquals(0, code); 129 | } 130 | 131 | @Test 132 | public void testInstallPluginsForJMX() throws Exception { 133 | JMeterUtils.getJMeterProperties().remove("jpgc.repo.address"); 134 | String path = getClass().getResource("/testplan.xml").getPath(); 135 | PluginManagerCMD cmd = new PluginManagerCMD(); 136 | LinkedList params = new LinkedList<>(); 137 | params.add("install-for-jmx"); 138 | params.add(path); 139 | int code = cmd.processParams(params.listIterator()); 140 | assertEquals(0, code); 141 | } 142 | } -------------------------------------------------------------------------------- /src/main/java/org/jmeterplugins/repository/plugins/SuggestDialog.java: -------------------------------------------------------------------------------- 1 | package org.jmeterplugins.repository.plugins; 2 | 3 | import org.apache.jmeter.gui.action.ActionNames; 4 | import org.apache.jmeter.gui.action.ActionRouter; 5 | import org.apache.jmeter.gui.util.EscapeDialog; 6 | import org.apache.jorphan.gui.ComponentUtil; 7 | import org.jmeterplugins.repository.GenericCallback; 8 | import org.jmeterplugins.repository.Plugin; 9 | import org.jmeterplugins.repository.PluginIcon; 10 | import org.jmeterplugins.repository.PluginManager; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | 14 | import javax.swing.*; 15 | import java.awt.*; 16 | import java.awt.event.ActionEvent; 17 | import java.awt.event.ActionListener; 18 | import java.util.LinkedList; 19 | import java.util.Set; 20 | 21 | import static org.jmeterplugins.repository.PluginManagerDialog.SPACING; 22 | 23 | public class SuggestDialog extends EscapeDialog implements GenericCallback { 24 | private static final Logger log = LoggerFactory.getLogger(SuggestDialog.class); 25 | private final PluginManager manager; 26 | private final JLabel titleLabel = new JLabel(""); 27 | private final JLabel statusLabel = new JLabel(""); 28 | 29 | public SuggestDialog(Frame parent, PluginManager manager, Set plugins, final String testPlan) { 30 | super(parent, "JMeter Plugins Manager", true); 31 | setLocationRelativeTo(parent); 32 | this.manager = manager; 33 | init(plugins, testPlan); 34 | } 35 | 36 | private void init(Set plugins, final String testPlan) { 37 | setLayout(new BorderLayout()); 38 | setIconImage(PluginIcon.getPluginFrameIcon(manager.hasAnyUpdates(), this)); 39 | ComponentUtil.centerComponentInWindow(this); 40 | 41 | JPanel mainPanel = new JPanel(new BorderLayout(0, 0)); 42 | mainPanel.setBorder(SPACING); 43 | 44 | final StringBuilder message = new StringBuilder("

Your test plan requires following plugins:

    "); 45 | for (Plugin plugin : plugins) { 46 | message.append("
  • ").append(plugin.getName()).append("
  • "); 47 | } 48 | message.append("
"); 49 | message.append("

"); 50 | message.append("

Plugins Manager can install it automatically. Following changes will be applied:

"); 51 | message.append(""); 52 | titleLabel.setText(message.toString()); 53 | mainPanel.add(titleLabel, BorderLayout.NORTH); 54 | 55 | mainPanel.add(getDetailsPanel(), BorderLayout.CENTER); 56 | 57 | mainPanel.add(getButtonsPanel(plugins, testPlan), BorderLayout.SOUTH); 58 | 59 | add(mainPanel, BorderLayout.CENTER); 60 | pack(); 61 | } 62 | 63 | private JPanel getButtonsPanel(final Set plugins, final String testPlan) { 64 | final JButton btnYes = new JButton("Yes, install it"); 65 | final JButton btnNo = new JButton("Cancel"); 66 | final SuggestDialog dialog = this; 67 | btnYes.addActionListener(new ActionListener() { 68 | public void actionPerformed(ActionEvent e) { 69 | btnYes.setEnabled(false); 70 | btnNo.setEnabled(false); 71 | 72 | new Thread() { 73 | @Override 74 | public void run() { 75 | LinkedList options = new LinkedList<>(); 76 | options.add("-t"); 77 | options.add(testPlan); 78 | manager.applyChanges(dialog, true, options); 79 | dispose(); 80 | ActionRouter.getInstance().actionPerformed(new ActionEvent(this, 0, ActionNames.EXIT)); 81 | } 82 | }.start(); 83 | } 84 | }); 85 | 86 | btnNo.addActionListener(new ActionListener() { 87 | public void actionPerformed(ActionEvent e) { 88 | manager.togglePlugins(plugins, false); 89 | dispose(); 90 | } 91 | }); 92 | 93 | JPanel buttons = new JPanel(new FlowLayout()); 94 | buttons.add(btnYes); 95 | buttons.add(btnNo); 96 | JPanel btnPanel = new JPanel(new BorderLayout()); 97 | btnPanel.setBorder(SPACING); 98 | btnPanel.add(buttons, BorderLayout.EAST); 99 | btnPanel.add(statusLabel, BorderLayout.WEST); 100 | return btnPanel; 101 | } 102 | 103 | private JPanel getDetailsPanel() { 104 | JTextArea messageLabel = new JTextArea(manager.getChangesAsText()); 105 | messageLabel.setEditable(false); 106 | 107 | JPanel messagePanel = new JPanel(new BorderLayout()); 108 | messagePanel.setBorder(SPACING); 109 | messagePanel.add(new JScrollPane(messageLabel)); 110 | 111 | return messagePanel; 112 | } 113 | 114 | @Override 115 | public void notify(final String s) { 116 | SwingUtilities.invokeLater( 117 | new Runnable() { 118 | 119 | @Override 120 | public void run() { 121 | statusLabel.setText(s); 122 | repaint(); 123 | } 124 | }); 125 | 126 | } 127 | } -------------------------------------------------------------------------------- /src/main/java/org/jmeterplugins/repository/plugins/TestPlanAnalyzer.java: -------------------------------------------------------------------------------- 1 | package org.jmeterplugins.repository.plugins; 2 | 3 | import org.apache.jmeter.save.SaveService; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import org.w3c.dom.Document; 7 | import org.w3c.dom.NamedNodeMap; 8 | import org.w3c.dom.Node; 9 | import org.w3c.dom.NodeList; 10 | 11 | import javax.xml.parsers.DocumentBuilder; 12 | import javax.xml.parsers.DocumentBuilderFactory; 13 | import javax.xml.parsers.ParserConfigurationException; 14 | import javax.xml.xpath.XPath; 15 | import javax.xml.xpath.XPathConstants; 16 | import javax.xml.xpath.XPathExpression; 17 | import javax.xml.xpath.XPathFactory; 18 | import java.io.ByteArrayInputStream; 19 | import java.io.File; 20 | import java.io.FileInputStream; 21 | import java.io.IOException; 22 | import java.util.Collections; 23 | import java.util.HashSet; 24 | import java.util.Set; 25 | 26 | public class TestPlanAnalyzer { 27 | 28 | private static final Logger log = LoggerFactory.getLogger(TestPlanAnalyzer.class); 29 | private static final byte[] XML_VERSION = "version=\"1.1\"".getBytes(); 30 | 31 | /** 32 | * @param path fo jmx file with test plan 33 | * @return set of classes, that does not exists or empty list if there are none 34 | */ 35 | public Set analyze(String path) { 36 | log.debug("Analyze test plan: " + path); 37 | final NodeList nodeList = getNodeListWithClassNames(path); 38 | 39 | if (nodeList != null) { 40 | final Set nonExistentClasses = new HashSet<>(); 41 | for (int i = 0; i < nodeList.getLength(); i++) { 42 | Node node = nodeList.item(i); 43 | NamedNodeMap attributes = node.getAttributes(); 44 | checkAttributeAndAdd(attributes, "guiclass", nonExistentClasses); 45 | checkAttributeAndAdd(attributes, "testclass", nonExistentClasses); 46 | } 47 | return nonExistentClasses; 48 | } 49 | return Collections.emptySet(); 50 | } 51 | 52 | private void checkAttributeAndAdd(NamedNodeMap attributes, final String attributeName, final Set nonExistentClasses) { 53 | Node node = attributes.getNamedItem(attributeName); 54 | if (node != null && !isClassExists(node.getTextContent())) { 55 | nonExistentClasses.add(node.getTextContent()); 56 | } 57 | } 58 | 59 | private static byte[] readBytesFromFile(String filePath) { 60 | FileInputStream fileInputStream = null; 61 | byte[] bytesArray = null; 62 | 63 | try { 64 | File file = new File(filePath); 65 | bytesArray = new byte[(int) file.length()]; 66 | 67 | //read file into bytes[] 68 | fileInputStream = new FileInputStream(file); 69 | fileInputStream.read(bytesArray); 70 | } catch (IOException e) { 71 | log.warn("Failed read jmx file", e); 72 | } finally { 73 | if (fileInputStream != null) { 74 | try { 75 | fileInputStream.close(); 76 | } catch (IOException e) { 77 | log.warn("Failed close jmx file input stream", e); 78 | } 79 | } 80 | } 81 | 82 | return bytesArray; 83 | } 84 | 85 | private byte[] overrideXmlVersion(byte[] bytes) { 86 | final int headerLength = 100; 87 | if (bytes != null && bytes.length > headerLength) { 88 | final byte[] line = new byte[headerLength]; 89 | System.arraycopy(bytes, 0, line, 0, headerLength); 90 | String header = new String(line); 91 | int index = header.indexOf("version="); 92 | if (index != -1) { 93 | System.arraycopy(XML_VERSION, 0, bytes, index, XML_VERSION.length); 94 | } else { 95 | log.debug("Did not find XML version in test plan"); 96 | } 97 | } 98 | return bytes; 99 | } 100 | 101 | 102 | private NodeList getNodeListWithClassNames(String path) { 103 | try { 104 | DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 105 | factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); 106 | factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); 107 | factory.setXIncludeAware(false); 108 | factory.setExpandEntityReferences(false); 109 | 110 | DocumentBuilder builder = factory.newDocumentBuilder(); 111 | byte[] bytes = overrideXmlVersion(readBytesFromFile(path)); 112 | Document doc = (bytes == null) ? builder.parse(path) : builder.parse(new ByteArrayInputStream(bytes)); 113 | XPathFactory xPathfactory = XPathFactory.newInstance(); 114 | XPath xpath = xPathfactory.newXPath(); 115 | XPathExpression expr = xpath.compile("//*[@guiclass|@testclass]"); 116 | return (NodeList) expr.evaluate(doc, XPathConstants.NODESET); 117 | } catch (ParserConfigurationException pex) { 118 | log.warn("Cannot set the required parser config", pex); 119 | return null; 120 | } catch (Exception ex) { 121 | log.warn("Cannot parse file: " + path, ex); 122 | return null; 123 | } 124 | } 125 | 126 | public static boolean isClassExists(String className) { 127 | try { 128 | Class.forName(SaveService.aliasToClass(className)); 129 | return true; 130 | } catch (ClassNotFoundException | NoClassDefFoundError e) { 131 | return false; 132 | } 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /src/main/java/org/apache/jorphan/logging/Slf4jLogkitLogger.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | */ 18 | 19 | package org.apache.jorphan.logging; 20 | 21 | import org.apache.log.Priority; 22 | import org.slf4j.Logger; 23 | import org.slf4j.LoggerFactory; 24 | 25 | /** 26 | * Wrapper, implementing org.apache.log.Logger and delegating to the internal SLF4J logger. 27 | */ 28 | @Deprecated // Logger & Priority will be dropped in 3.3; so will this class be 29 | class Slf4jLogkitLogger extends org.apache.log.Logger { 30 | 31 | private final Logger slf4jLogger; 32 | 33 | Slf4jLogkitLogger(final Logger slf4jLogger) { 34 | this.slf4jLogger = slf4jLogger; 35 | } 36 | 37 | @Override 38 | public boolean isDebugEnabled() { 39 | return slf4jLogger.isDebugEnabled(); 40 | } 41 | 42 | @Override 43 | public void debug(String message, Throwable throwable) { 44 | slf4jLogger.debug(message, throwable); 45 | } 46 | 47 | @Override 48 | public void debug(String message) { 49 | slf4jLogger.debug(message); 50 | } 51 | 52 | @Override 53 | public boolean isInfoEnabled() { 54 | return slf4jLogger.isInfoEnabled(); 55 | } 56 | 57 | @Override 58 | public void info(String message, Throwable throwable) { 59 | slf4jLogger.info(message, throwable); 60 | } 61 | 62 | @Override 63 | public void info(String message) { 64 | slf4jLogger.info(message); 65 | } 66 | 67 | @Override 68 | public boolean isWarnEnabled() { 69 | return slf4jLogger.isWarnEnabled(); 70 | } 71 | 72 | @Override 73 | public void warn(String message, Throwable throwable) { 74 | slf4jLogger.warn(message, throwable); 75 | } 76 | 77 | @Override 78 | public void warn(String message) { 79 | slf4jLogger.warn(message); 80 | } 81 | 82 | @Override 83 | public boolean isErrorEnabled() { 84 | return slf4jLogger.isErrorEnabled(); 85 | } 86 | 87 | @Override 88 | public void error(String message, Throwable throwable) { 89 | slf4jLogger.error(message, throwable); 90 | } 91 | 92 | @Override 93 | public void error(String message) { 94 | slf4jLogger.error(message); 95 | } 96 | 97 | @Override 98 | public boolean isFatalErrorEnabled() { 99 | return slf4jLogger.isErrorEnabled(); 100 | } 101 | 102 | @Override 103 | public void fatalError(String message, Throwable throwable) { 104 | slf4jLogger.error(message, throwable); 105 | } 106 | 107 | @Override 108 | public void fatalError(String message) { 109 | slf4jLogger.error(message); 110 | } 111 | 112 | @Override 113 | public boolean isPriorityEnabled(Priority priority) { 114 | if (priority == Priority.FATAL_ERROR) { 115 | return slf4jLogger.isErrorEnabled(); 116 | } else if (priority == Priority.ERROR) { 117 | return slf4jLogger.isErrorEnabled(); 118 | } else if (priority == Priority.WARN) { 119 | return slf4jLogger.isWarnEnabled(); 120 | } else if (priority == Priority.INFO) { 121 | return slf4jLogger.isInfoEnabled(); 122 | } else if (priority == Priority.DEBUG) { 123 | return slf4jLogger.isDebugEnabled(); 124 | } 125 | 126 | return false; 127 | } 128 | 129 | @Override 130 | public void log(Priority priority, String message, Throwable throwable) { 131 | if (priority == Priority.FATAL_ERROR) { 132 | slf4jLogger.error(message, throwable); 133 | } else if (priority == Priority.ERROR) { 134 | slf4jLogger.error(message, throwable); 135 | } else if (priority == Priority.WARN) { 136 | slf4jLogger.warn(message, throwable); 137 | } else if (priority == Priority.INFO) { 138 | slf4jLogger.info(message, throwable); 139 | } else if (priority == Priority.DEBUG) { 140 | slf4jLogger.debug(message, throwable); 141 | } 142 | } 143 | 144 | @Override 145 | public void log(Priority priority, String message) { 146 | if (priority == Priority.FATAL_ERROR) { 147 | slf4jLogger.error(message); 148 | } else if (priority == Priority.ERROR) { 149 | slf4jLogger.error(message); 150 | } else if (priority == Priority.WARN) { 151 | slf4jLogger.warn(message); 152 | } else if (priority == Priority.INFO) { 153 | slf4jLogger.info(message); 154 | } else if (priority == Priority.DEBUG) { 155 | slf4jLogger.debug(message); 156 | } 157 | } 158 | 159 | @Override 160 | public org.apache.log.Logger getChildLogger(String subCategory) { 161 | return new Slf4jLogkitLogger(LoggerFactory 162 | .getLogger(slf4jLogger.getName() + org.apache.log.Logger.CATEGORY_SEPARATOR + subCategory)); 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /src/main/java/org/jmeterplugins/repository/SafeDeleter.java: -------------------------------------------------------------------------------- 1 | package org.jmeterplugins.repository; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.File; 5 | import java.io.FileReader; 6 | import java.io.IOException; 7 | import java.nio.file.Files; 8 | import java.nio.file.StandardCopyOption; 9 | import java.util.ArrayList; 10 | import java.util.Arrays; 11 | import java.util.ListIterator; 12 | 13 | public class SafeDeleter { 14 | 15 | public static void main(String[] argsRaw) throws Throwable { 16 | ListIterator args = Arrays.asList(argsRaw).listIterator(); 17 | 18 | while (args.hasNext()) { 19 | String nextArg = args.next(); 20 | if (nextArg.equalsIgnoreCase("--move-list")) { 21 | if (!args.hasNext()) { 22 | throw new IllegalArgumentException("Missing delete list file name"); 23 | } 24 | 25 | File fCopy = new File(args.next()); 26 | moveFiles(fCopy); 27 | fCopy.delete(); 28 | } else if (nextArg.equalsIgnoreCase("--install-list")) { 29 | if (!args.hasNext()) { 30 | throw new IllegalArgumentException("Missing install list file"); 31 | } 32 | 33 | File file = new File(args.next()); 34 | installsFromFile(file); 35 | file.delete(); 36 | } else if (nextArg.equalsIgnoreCase("--restart-command")) { 37 | if (!args.hasNext()) { 38 | throw new IllegalArgumentException("Missing restart command file"); 39 | } 40 | 41 | File file = new File(args.next()); 42 | restartFromFile(file); 43 | file.delete(); 44 | } else { 45 | throw new IllegalArgumentException("Unknown option: " + nextArg); 46 | } 47 | } 48 | } 49 | 50 | private static void installsFromFile(File file) throws IOException { 51 | try (FileReader fr = new FileReader(file); 52 | BufferedReader br = new BufferedReader(fr)) { 53 | File log = File.createTempFile("jpgc-installers-", ".log"); 54 | String line; 55 | while ((line = br.readLine()) != null) { 56 | String[] parts = line.split("\t"); 57 | if (parts.length != 2) { 58 | System.out.println("Invalid line: " + line); 59 | continue; 60 | } 61 | 62 | String jar = parts[0]; 63 | String cls = parts[1]; 64 | 65 | final ArrayList command = new ArrayList<>(); 66 | command.add(getJVM()); 67 | command.add("-classpath"); 68 | command.add(jar); 69 | command.add(cls); 70 | 71 | final ProcessBuilder builder = new ProcessBuilder(command); 72 | System.out.print("Starting: " + command + "\n"); 73 | builder.redirectError(log); 74 | builder.redirectOutput(log); 75 | Process p = builder.start(); 76 | try { 77 | p.waitFor(); 78 | } catch (InterruptedException e) { 79 | e.printStackTrace(System.out); 80 | } 81 | } 82 | System.out.println("Done running installers"); 83 | } 84 | } 85 | 86 | private static void restartFromFile(File file) throws IOException { 87 | final ArrayList command = new ArrayList<>(); 88 | try (FileReader fr = new FileReader(file); 89 | BufferedReader br = new BufferedReader(fr)) { 90 | String line; 91 | while ((line = br.readLine()) != null) { 92 | command.add(line); 93 | } 94 | 95 | final ProcessBuilder builder = new ProcessBuilder(command); 96 | System.out.print("Starting: " + command + "\n"); 97 | File restarterLog = File.createTempFile("jpgc-restarter-", ".log"); 98 | builder.redirectError(restarterLog); 99 | builder.redirectOutput(restarterLog); 100 | builder.start(); 101 | } 102 | } 103 | 104 | private static void moveFiles(File list) throws IOException, InterruptedException { 105 | try (FileReader fr = new FileReader(list); 106 | BufferedReader br = new BufferedReader(fr)) { 107 | String line; 108 | while ((line = br.readLine()) != null) { 109 | String[] parts = line.split("\t"); 110 | if (parts.length != 2) { 111 | System.out.println("Invalid line: " + line); 112 | continue; 113 | } 114 | 115 | File src = new File(parts[0]); 116 | File dst = new File(parts[1]); 117 | 118 | System.out.println("Moving " + src + " to " + dst); 119 | 120 | if (!src.exists()) { 121 | System.out.println("Cannot move, file not exists: " + src); 122 | } 123 | 124 | try { 125 | Files.move(src.toPath(), dst.toPath(), StandardCopyOption.REPLACE_EXISTING); 126 | } catch (Exception e) { 127 | System.out.println("Cannot move " + src + " because of " + e.toString()); 128 | e.printStackTrace(System.out); 129 | } 130 | } 131 | System.out.println("Done moving files"); 132 | } 133 | } 134 | 135 | public static String getJVM() { 136 | String jvm_location; 137 | if (System.getProperty("os.name").startsWith("Win")) { 138 | jvm_location = System.getProperties().getProperty("java.home") + File.separator + "bin" + File.separator + "java.exe"; 139 | } else { 140 | jvm_location = System.getProperties().getProperty("java.home") + File.separator + "bin" + File.separator + "java"; 141 | } 142 | return jvm_location; 143 | } 144 | 145 | 146 | } 147 | -------------------------------------------------------------------------------- /src/main/java/org/apache/log/LogEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package org.apache.log; 19 | 20 | import java.io.ObjectStreamException; 21 | import java.io.Serializable; 22 | 23 | /** 24 | * This class encapsulates each individual log event. 25 | * LogEvents usually originate at a Logger and are routed 26 | * to LogTargets. 27 | * 28 | * @author Avalon Development Team 29 | * @author Peter Donald 30 | * @deprecated Will be dropped in 3.3 31 | */ 32 | @Deprecated 33 | public final class LogEvent 34 | implements Serializable 35 | { 36 | private static final long serialVersionUID = 1L; 37 | 38 | //A Constant used when retrieving time relative to start of application start 39 | private static final long START_TIME = System.currentTimeMillis(); 40 | 41 | ///The category that this LogEvent concerns. (Must not be null) 42 | private String m_category; 43 | 44 | ///The message to be logged. (Must not be null) 45 | private String m_message; 46 | 47 | ///The exception that caused LogEvent if any. (May be null) 48 | private Throwable m_throwable; 49 | 50 | ///The time in millis that LogEvent occurred 51 | private long m_time; 52 | 53 | ///The priority of LogEvent. (Must not be null) 54 | private Priority m_priority; 55 | 56 | ///The context map associated with LogEvent. (May be null). 57 | private ContextMap m_contextMap; 58 | 59 | /** 60 | * Get Priority for LogEvent. 61 | * 62 | * @return the LogEvent Priority 63 | */ 64 | public final Priority getPriority() 65 | { 66 | return m_priority; 67 | } 68 | 69 | /** 70 | * Set the priority of LogEvent. 71 | * 72 | * @param priority the new LogEvent priority 73 | */ 74 | public final void setPriority( final Priority priority ) 75 | { 76 | m_priority = priority; 77 | } 78 | 79 | /** 80 | * Get ContextMap associated with LogEvent 81 | * 82 | * @return the ContextMap 83 | */ 84 | public final ContextMap getContextMap() 85 | { 86 | return m_contextMap; 87 | } 88 | 89 | /** 90 | * Set the ContextMap for this LogEvent. 91 | * 92 | * @param contextMap the context map 93 | */ 94 | public final void setContextMap( final ContextMap contextMap ) 95 | { 96 | m_contextMap = contextMap; 97 | } 98 | 99 | /** 100 | * Get the category that LogEvent relates to. 101 | * 102 | * @return the name of category 103 | */ 104 | public final String getCategory() 105 | { 106 | return m_category; 107 | } 108 | 109 | /** 110 | * Get the message associated with event. 111 | * 112 | * @return the message 113 | */ 114 | public final String getMessage() 115 | { 116 | return m_message; 117 | } 118 | 119 | /** 120 | * Get throwable instance associated with event. 121 | * 122 | * @return the Throwable 123 | */ 124 | public final Throwable getThrowable() 125 | { 126 | return m_throwable; 127 | } 128 | 129 | /** 130 | * Get the absolute time of the log event. 131 | * 132 | * @return the absolute time 133 | */ 134 | public final long getTime() 135 | { 136 | return m_time; 137 | } 138 | 139 | /** 140 | * Get the time of the log event relative to start of application. 141 | * 142 | * @return the time 143 | */ 144 | public final long getRelativeTime() 145 | { 146 | return m_time - START_TIME; 147 | } 148 | 149 | /** 150 | * Set the LogEvent category. 151 | * 152 | * @param category the category 153 | */ 154 | public final void setCategory( final String category ) 155 | { 156 | m_category = category; 157 | } 158 | 159 | /** 160 | * Set the message for LogEvent. 161 | * 162 | * @param message the message 163 | */ 164 | public final void setMessage( final String message ) 165 | { 166 | m_message = message; 167 | } 168 | 169 | /** 170 | * Set the throwable for LogEvent. 171 | * 172 | * @param throwable the instance of Throwable 173 | */ 174 | public final void setThrowable( final Throwable throwable ) 175 | { 176 | m_throwable = throwable; 177 | } 178 | 179 | /** 180 | * Set the absolute time of LogEvent. 181 | * 182 | * @param time the time 183 | */ 184 | public final void setTime( final long time ) 185 | { 186 | m_time = time; 187 | } 188 | 189 | /** 190 | * Helper method that replaces deserialized priority with correct singleton. 191 | * 192 | * @return the singleton version of object 193 | * @exception ObjectStreamException if an error occurs 194 | */ 195 | private Object readResolve() 196 | throws ObjectStreamException 197 | { 198 | if( null == m_category ) 199 | { 200 | m_category = ""; 201 | } 202 | if( null == m_message ) 203 | { 204 | m_message = ""; 205 | } 206 | 207 | String priorityName = ""; 208 | if( null != m_priority ) 209 | { 210 | priorityName = m_priority.getName(); 211 | } 212 | 213 | m_priority = Priority.getPriorityForName( priorityName ); 214 | 215 | return this; 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /src/test/resources/http2_libs.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "bzm-http2", 4 | "name": "HTTP/2 Sampler", 5 | "description": "HTTP/2 protocol sampler", 6 | "helpUrl": "https://github.com/Blazemeter/jmeter-bzm-plugins/blob/master/http2/README.md", 7 | "screenshotUrl": "https://github.com/Blazemeter/jmeter-bzm-plugins/raw/master/http2/http2Sampler.png", 8 | "vendor": "BlazeMeter", 9 | "markerClass": "com.blazemeter.jmeter.http2.sampler.HTTP2Request", 10 | "componentClasses": [ 11 | "com.blazemeter.jmeter.http2.sampler.HTTP2Request", 12 | "com.blazemeter.jmeter.http2.sampler.gui.HTTP2RequestGui", 13 | "com.blazemeter.jmeter.http2.sampler.gui.Http2DefaultsGui", 14 | "com.blazemeter.jmeter.http2.visualizers.ResultCollector", 15 | "com.blazemeter.jmeter.http2.visualizers.SimpleDataWriter", 16 | "com.blazemeter.jmeter.http2.visualizers.ViewResultsFullVisualizer" 17 | ], 18 | "versions": { 19 | "1.0": { 20 | "downloadUrl": "https://github.com/Blazemeter/jmeter-bzm-plugins/releases/download/http2-1.0/jmeter-bzm-http2-1.0.jar", 21 | "libs": { 22 | "jmeter-plugins-cmn-jmeter": "https://search.maven.org/remotecontent?filepath=kg/apc/jmeter-plugins-cmn-jmeter/0.5/jmeter-plugins-cmn-jmeter-0.5.jar", 23 | "jetty-client": "http://search.maven.org/remotecontent?filepath=org/eclipse/jetty/jetty-client/9.4.0.v20161208/jetty-client-9.4.0.v20161208.jar", 24 | "jetty-util": "http://search.maven.org/remotecontent?filepath=org/eclipse/jetty/jetty-util/9.4.0.v20161208/jetty-util-9.4.0.v20161208.jar", 25 | "jetty-http": "http://search.maven.org/remotecontent?filepath=org/eclipse/jetty/jetty-http/9.4.0.v20161208/jetty-http-9.4.0.v20161208.jar", 26 | "jetty-io": "http://search.maven.org/remotecontent?filepath=org/eclipse/jetty/jetty-io/9.4.0.v20161208/jetty-io-9.4.0.v20161208.jar", 27 | "jetty-alpn-client": "http://search.maven.org/remotecontent?filepath=org/eclipse/jetty/jetty-alpn-client/9.4.0.v20161208/jetty-alpn-client-9.4.0.v20161208.jar", 28 | "http2-client": "http://search.maven.org/remotecontent?filepath=org/eclipse/jetty/http2/http2-client/9.4.0.v20161208/http2-client-9.4.0.v20161208.jar", 29 | "http2-common": "http://search.maven.org/remotecontent?filepath=org/eclipse/jetty/http2/http2-common/9.4.0.v20161208/http2-common-9.4.0.v20161208.jar", 30 | "http2-hpack": "http://search.maven.org/remotecontent?filepath=org/eclipse/jetty/http2/http2-hpack/9.4.0.v20161208/http2-hpack-9.4.0.v20161208.jar", 31 | "jetty-osgi-alpn": "http://search.maven.org/remotecontent?filepath=org/eclipse/jetty/osgi/jetty-osgi-alpn/9.4.0.v20161208/jetty-osgi-alpn-9.4.0.v20161208.jar" 32 | } 33 | }, 34 | "1.1": { 35 | "changes": "Fix memory leak and JTL output error", 36 | "downloadUrl": "https://search.maven.org/remotecontent?filepath=com/blazemeter/jmeter-bzm-http2/1.1/jmeter-bzm-http2-1.1.jar", 37 | "libs": { 38 | "jmeter-plugins-cmn-jmeter": "https://search.maven.org/remotecontent?filepath=kg/apc/jmeter-plugins-cmn-jmeter/0.5/jmeter-plugins-cmn-jmeter-0.5.jar", 39 | "jetty-client": "http://search.maven.org/remotecontent?filepath=org/eclipse/jetty/jetty-client/9.4.0.v20161208/jetty-client-9.4.0.v20161208.jar", 40 | "jetty-util": "http://search.maven.org/remotecontent?filepath=org/eclipse/jetty/jetty-util/9.4.0.v20161208/jetty-util-9.4.0.v20161208.jar", 41 | "jetty-http": "http://search.maven.org/remotecontent?filepath=org/eclipse/jetty/jetty-http/9.4.0.v20161208/jetty-http-9.4.0.v20161208.jar", 42 | "jetty-io": "http://search.maven.org/remotecontent?filepath=org/eclipse/jetty/jetty-io/9.4.0.v20161208/jetty-io-9.4.0.v20161208.jar", 43 | "jetty-alpn-client": "http://search.maven.org/remotecontent?filepath=org/eclipse/jetty/jetty-alpn-client/9.4.0.v20161208/jetty-alpn-client-9.4.0.v20161208.jar", 44 | "http2-client": "http://search.maven.org/remotecontent?filepath=org/eclipse/jetty/http2/http2-client/9.4.0.v20161208/http2-client-9.4.0.v20161208.jar", 45 | "http2-common": "http://search.maven.org/remotecontent?filepath=org/eclipse/jetty/http2/http2-common/9.4.0.v20161208/http2-common-9.4.0.v20161208.jar", 46 | "http2-hpack": "http://search.maven.org/remotecontent?filepath=org/eclipse/jetty/http2/http2-hpack/9.4.0.v20161208/http2-hpack-9.4.0.v20161208.jar", 47 | "jetty-osgi-alpn": "http://search.maven.org/remotecontent?filepath=org/eclipse/jetty/osgi/jetty-osgi-alpn/9.4.0.v20161208/jetty-osgi-alpn-9.4.0.v20161208.jar" 48 | } 49 | }, 50 | "1.2": { 51 | "changes": "Fix HTTP2 plugin POST support to include proper request and fix issue with callback handler", 52 | "downloadUrl": "https://search.maven.org/remotecontent?filepath=com/blazemeter/jmeter-bzm-http2/1.2/jmeter-bzm-http2-1.2.jar", 53 | "libs": { 54 | "http2-client>=9.4.9.v20180320": "http://search.maven.org/remotecontent?filepath=org/eclipse/jetty/http2/http2-client/9.4.9.v20180320/http2-client-9.4.9.v20180320.jar", 55 | "http2-common>=9.4.9.v20180320": "http://search.maven.org/remotecontent?filepath=org/eclipse/jetty/http2/http2-common/9.4.9.v20180320/http2-common-9.4.9.v20180320.jar", 56 | "http2-hpack>=9.4.9.v20180320": "http://search.maven.org/remotecontent?filepath=org/eclipse/jetty/http2/http2-hpack/9.4.9.v20180320/http2-hpack-9.4.9.v20180320.jar", 57 | "jetty-alpn-client>=9.4.9.v20180320": "http://search.maven.org/remotecontent?filepath=org/eclipse/jetty/jetty-alpn-client/9.4.9.v20180320/jetty-alpn-client-9.4.9.v20180320.jar", 58 | "jetty-alpn-openjdk8-client>=9.4.9.v20180320": "http://search.maven.org/remotecontent?filepath=org/eclipse/jetty/jetty-alpn-openjdk8-client/9.4.9.v20180320/jetty-alpn-openjdk8-client-9.4.9.v20180320.jar", 59 | "jetty-http>=9.4.9.v20180320": "http://search.maven.org/remotecontent?filepath=org/eclipse/jetty/jetty-http/9.4.9.v20180320/jetty-http-9.4.9.v20180320.jar", 60 | "jetty-io>=9.4.9.v20180320": "http://search.maven.org/remotecontent?filepath=org/eclipse/jetty/jetty-io/9.4.9.v20180320/jetty-io-9.4.9.v20180320.jar", 61 | "jetty-util>=9.4.9.v20180320": "http://search.maven.org/remotecontent?filepath=org/eclipse/jetty/jetty-util/9.4.9.v20180320/jetty-util-9.4.9.v20180320.jar" 62 | } 63 | } 64 | } 65 | } 66 | ] -------------------------------------------------------------------------------- /src/test/java/org/jmeterplugins/repository/RepoTest.java: -------------------------------------------------------------------------------- 1 | package org.jmeterplugins.repository; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.io.PrintWriter; 6 | import java.nio.file.Files; 7 | import java.nio.file.Paths; 8 | import java.util.ArrayList; 9 | import java.util.HashMap; 10 | import java.util.List; 11 | import java.util.Map; 12 | 13 | import junit.framework.AssertionFailedError; 14 | import net.sf.json.JSON; 15 | import net.sf.json.JSONArray; 16 | import net.sf.json.JSONObject; 17 | import net.sf.json.JSONSerializer; 18 | import net.sf.json.JsonConfig; 19 | 20 | import org.apache.commons.io.FileUtils; 21 | 22 | /** 23 | * @deprecated in favor of python-based builder 24 | */ 25 | public class RepoTest { 26 | private final Map cache = new HashMap<>(); 27 | private String s = File.separator; 28 | private File repo = new File(System.getProperty("project.build.directory", "target") + s + "jpgc-repo"); 29 | private File lib = new File(repo.getAbsolutePath() + s + "lib"); 30 | private File libExt = new File(lib.getAbsolutePath() + s + "ext"); 31 | private JARSource jarSource = new JARSourceHTTP("https://jmeter-plugins.org/repo/"); 32 | 33 | public RepoTest() { 34 | try { 35 | FileUtils.deleteDirectory(lib); 36 | } catch (IOException e) { 37 | e.printStackTrace(); 38 | } 39 | libExt.mkdirs(); 40 | } 41 | 42 | public void testAll() throws IOException { 43 | Map env = System.getenv(); 44 | if (env.containsKey("TRAVIS")) { 45 | System.out.println("Not running test inside Travis CI"); 46 | return; 47 | } 48 | 49 | List problems = new ArrayList<>(); 50 | File[] files = getRepoFiles(); 51 | 52 | JSONArray merged = new JSONArray(); 53 | for (File repoFile : files) { 54 | System.out.println("Checking repo: " + repoFile.getCanonicalPath()); 55 | String content = new String(Files.readAllBytes(Paths.get(repoFile.getAbsolutePath())), "UTF-8"); 56 | JSON json = JSONSerializer.toJSON(content, new JsonConfig()); 57 | JSONArray list = (JSONArray) json; 58 | for (Object item : list) { 59 | JSONObject spec = (JSONObject) item; 60 | checkPlugin(problems, repoFile, spec); 61 | merged.add(spec); 62 | } 63 | } 64 | 65 | if (problems.size() > 0) { 66 | throw new AssertionFailedError(problems.toString()); 67 | } 68 | 69 | try (PrintWriter out = new PrintWriter(new File(repo.getAbsolutePath() + s + "all.json"));) { 70 | out.print(merged.toString(1)); 71 | } 72 | } 73 | 74 | private File[] getRepoFiles() throws IOException { 75 | String path = getClass().getProtectionDomain().getCodeSource().getLocation().getFile(); 76 | String up = File.separator + ".."; 77 | String repos = path + up + up + up + File.separator + "site" + File.separator + "dat" + File.separator + "repo"; 78 | File dir = new File(repos); 79 | 80 | System.out.println("Working with " + dir.getCanonicalPath()); 81 | File[] files = dir.listFiles(); 82 | assert files != null; 83 | return files; 84 | } 85 | 86 | private void checkPlugin(List problems, File repoFile, JSONObject spec) { 87 | Plugin plugin = Plugin.fromJSON(spec); 88 | if (plugin.isVirtual()) { 89 | return; 90 | } 91 | 92 | String maxVersion = plugin.getMaxVersion(); 93 | JSONObject maxVerObject = spec.getJSONObject("versions").getJSONObject(maxVersion); 94 | 95 | JSONObject newVersions = new JSONObject(); 96 | newVersions.put(maxVersion, maxVerObject); 97 | 98 | try { 99 | System.out.println("Checking plugin: " + plugin); 100 | plugin.setCandidateVersion(maxVersion); 101 | plugin.download(jarSource, dummy); 102 | 103 | if (!plugin.isVersionFrozenToJMeter()) { 104 | File jar = new File(plugin.getTempName()); 105 | File dest = new File(plugin.getDestName()); 106 | File to = new File(libExt.getAbsolutePath() + File.separator + dest.getName()); 107 | jar.renameTo(to); 108 | 109 | maxVerObject.put("downloadUrl", "lib/ext/" + dest.getName()); 110 | } 111 | } catch (Throwable e) { 112 | problems.add(repoFile.getName() + ":" + plugin); 113 | System.err.println("Problem with " + plugin); 114 | e.printStackTrace(System.err); 115 | } 116 | 117 | checkLibs(problems, repoFile, plugin, maxVerObject); 118 | 119 | if (!maxVerObject.isEmpty()) { 120 | newVersions.put(maxVersion, maxVerObject); 121 | spec.put("versions", newVersions); 122 | } 123 | } 124 | 125 | private void checkLibs(List problems, File repoFile, Plugin plugin, JSONObject maxVerObject) { 126 | Map libs = plugin.getLibs(plugin.getCandidateVersion()); 127 | for (String id : libs.keySet()) { 128 | if (!cache.containsKey(libs.get(id))) { 129 | try { 130 | JARSource.DownloadResult dwn = jarSource.getJAR(id, libs.get(id), dummy); 131 | 132 | File jar = new File(dwn.getTmpFile()); 133 | File dest = new File(lib.getAbsolutePath() + File.separator + dwn.getFilename()); 134 | jar.renameTo(dest); 135 | 136 | cache.put(libs.get(id), dwn.getFilename()); 137 | } catch (Throwable e) { 138 | problems.add(repoFile.getName() + ":" + plugin + ":" + id); 139 | System.err.println("Problem with " + id); 140 | e.printStackTrace(System.err); 141 | } 142 | } 143 | 144 | maxVerObject.getJSONObject("libs").put(id, "lib/" + cache.get(libs.get(id))); 145 | } 146 | } 147 | 148 | private GenericCallback dummy = new GenericCallback() { 149 | @Override 150 | public void notify(String s) { 151 | } 152 | }; 153 | } 154 | -------------------------------------------------------------------------------- /src/main/java/org/apache/log/Priority.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package org.apache.log; 19 | 20 | import java.io.Serializable; 21 | 22 | /** 23 | * Class representing and holding constants for priority. 24 | * 25 | * @author Peter Donald 26 | * @deprecated Will be dropped in 3.3 27 | */ 28 | @Deprecated 29 | public final class Priority 30 | implements Serializable 31 | { 32 | private static final long serialVersionUID = 1L; 33 | 34 | /** 35 | * Developer orientated messages, usually used during development of product. 36 | */ 37 | public static final Priority DEBUG = new Priority( "DEBUG", 5 ); 38 | 39 | /** 40 | * Useful information messages such as state changes, client connection, user login etc. 41 | */ 42 | public static final Priority INFO = new Priority( "INFO", 10 ); 43 | 44 | /** 45 | * A problem or conflict has occurred but it may be recoverable, then 46 | * again it could be the start of the system failing. 47 | */ 48 | public static final Priority WARN = new Priority( "WARN", 15 ); 49 | 50 | /** 51 | * A problem has occurred but it is not fatal. The system will still function. 52 | */ 53 | public static final Priority ERROR = new Priority( "ERROR", 20 ); 54 | 55 | /** 56 | * Something caused whole system to fail. This indicates that an administrator 57 | * should restart the system and try to fix the problem that caused the failure. 58 | */ 59 | public static final Priority FATAL_ERROR = new Priority( "FATAL_ERROR", 25 ); 60 | 61 | /** 62 | * Do not log anything. 63 | */ 64 | public static final Priority NONE = new Priority( "NONE", Integer.MAX_VALUE ); 65 | 66 | private final String m_name; 67 | private final int m_priority; 68 | 69 | /** 70 | * Retrieve a Priority object for the name parameter. 71 | * 72 | * @param priority the priority name 73 | * @return the Priority for name 74 | */ 75 | public static Priority getPriorityForName( final String priority ) 76 | { 77 | if( Priority.DEBUG.getName().equals( priority ) ) 78 | { 79 | return Priority.DEBUG; 80 | } 81 | else if( Priority.INFO.getName().equals( priority ) ) 82 | { 83 | return Priority.INFO; 84 | } 85 | else if( Priority.WARN.getName().equals( priority ) ) 86 | { 87 | return Priority.WARN; 88 | } 89 | else if( Priority.ERROR.getName().equals( priority ) ) 90 | { 91 | return Priority.ERROR; 92 | } 93 | else if( Priority.FATAL_ERROR.getName().equals( priority ) ) 94 | { 95 | return Priority.FATAL_ERROR; 96 | } 97 | else if( Priority.NONE.getName().equals( priority ) ) 98 | { 99 | return Priority.NONE; 100 | } 101 | else 102 | { 103 | return Priority.DEBUG; 104 | } 105 | } 106 | 107 | /** 108 | * Private Constructor to block instantiation outside class. 109 | * 110 | * @param name the string name of priority 111 | * @param priority the numerical code of priority 112 | */ 113 | private Priority( final String name, final int priority ) 114 | { 115 | if( null == name ) 116 | { 117 | throw new NullPointerException( "name" ); 118 | } 119 | 120 | m_name = name; 121 | m_priority = priority; 122 | } 123 | 124 | /** 125 | * Overridden string to display Priority in human readable form. 126 | * 127 | * @return the string describing priority 128 | */ 129 | @Override 130 | public String toString() 131 | { 132 | return "Priority[" + getName() + "/" + getValue() + "]"; 133 | } 134 | 135 | /** 136 | * Get numerical value associated with priority. 137 | * 138 | * @return the numerical value 139 | */ 140 | public int getValue() 141 | { 142 | return m_priority; 143 | } 144 | 145 | /** 146 | * Get name of priority. 147 | * 148 | * @return the priorities name 149 | */ 150 | public String getName() 151 | { 152 | return m_name; 153 | } 154 | 155 | /** 156 | * Test whether this priority is greater than other priority. 157 | * 158 | * @param other the other Priority 159 | * @return TRUE if the priority is greater else FALSE 160 | */ 161 | public boolean isGreater( final Priority other ) 162 | { 163 | return m_priority > other.getValue(); 164 | } 165 | 166 | /** 167 | * Test whether this priority is lower than other priority. 168 | * 169 | * @param other the other Priority 170 | * @return TRUE if the priority is lower else FALSE 171 | */ 172 | public boolean isLower( final Priority other ) 173 | { 174 | return m_priority < other.getValue(); 175 | } 176 | 177 | /** 178 | * Test whether this priority is lower or equal to other priority. 179 | * 180 | * @param other the other Priority 181 | * @return TRUE if the priority is lower or equal else FALSE 182 | */ 183 | public boolean isLowerOrEqual( final Priority other ) 184 | { 185 | return m_priority <= other.getValue(); 186 | } 187 | 188 | /** 189 | * Helper method that replaces deserialized object with correct singleton. 190 | * 191 | * @return the singleton version of object 192 | */ 193 | private Object readResolve() 194 | { 195 | return getPriorityForName( m_name ); 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.blazemeter 8 | jmeter-plugins-manager 9 | 1.7 10 | jar 11 | 12 | JMeter Plugins Manager 13 | UI-based plugins management 14 | 15 | 16 | The Apache Software License, Version 2.0 17 | http://www.apache.org/licenses/LICENSE-2.0.txt 18 | repo 19 | 20 | 21 | http://jmeter-plugins.org/ 22 | 23 | https://github.com/Blazemeter/jmeter-plugins-manager 24 | https://github.com/Blazemeter/jmeter-plugins.git 25 | git@github.com:Blazemeter/jmeter-plugins.git 26 | 27 | 28 | 29 | team 30 | jmeter-plugins.org 31 | jmeter-plugins@googlegroups.com 32 | 33 | 34 | 35 | 36 | UTF-8 37 | 1.7 38 | 1.7 39 | 40 | 41 | 42 | 43 | org.apache.logging.log4j 44 | log4j-api 45 | 2.18.0 46 | 47 | 48 | org.apache.logging.log4j 49 | log4j-core 50 | 2.18.0 51 | 52 | 53 | org.apache.logging.log4j 54 | log4j-slf4j-impl 55 | 2.18.0 56 | 57 | 58 | commons-beanutils 59 | commons-beanutils 60 | 1.9.4 61 | 62 | 63 | com.github.weisj 64 | darklaf-property-loader 65 | 2.7.3 66 | provided 67 | 68 | 69 | 70 | org.apache.jmeter 71 | ApacheJMeter_core 72 | 2.13 73 | 74 | 75 | commons-math3 76 | commons-math3 77 | 78 | 79 | commons-pool2 80 | commons-pool2 81 | 82 | 83 | 84 | 85 | net.sf.json-lib 86 | json-lib 87 | 2.4 88 | jdk15 89 | 90 | 91 | 92 | org.apache.jmeter 93 | ApacheJMeter_http 94 | 2.13 95 | test 96 | 97 | 98 | commons-math3 99 | commons-math3 100 | 101 | 102 | commons-pool2 103 | commons-pool2 104 | 105 | 106 | 107 | 108 | kg.apc 109 | jmeter-plugins-emulators 110 | 0.2 111 | test 112 | 113 | 114 | kg.apc 115 | cmdrunner 116 | 2.3 117 | 118 | 119 | 120 | 121 | 122 | org.apache.maven.plugins 123 | maven-shade-plugin 124 | 2.1 125 | 126 | 127 | package 128 | 129 | shade 130 | 131 | 132 | 133 | 134 | net.sf.json-lib:json-lib 135 | commons-lang:commons-lang 136 | net.sf.ezmorph:ezmorph 137 | commons-beanutils:commons-beanutils 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | org.sonatype.plugins 146 | nexus-staging-maven-plugin 147 | 1.6.13 148 | true 149 | 150 | sonatype-nexus-staging 151 | https://oss.sonatype.org/ 152 | true 153 | 154 | 155 | 156 | 157 | -------------------------------------------------------------------------------- /src/main/java/org/apache/log/ContextMap.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.apache.log; 18 | 19 | import java.io.Serializable; 20 | import java.util.Hashtable; 21 | 22 | /** 23 | * The ContextMap contains non-hierarchical context information 24 | * relevant to a particular LogEvent. It may include information 25 | * such as; 26 | * 27 | *
    28 | *
  • user ->fred
  • 29 | *
  • hostname ->helm.realityforge.org
  • 30 | *
  • ipaddress ->1.2.3.4
  • 31 | *
  • interface ->127.0.0.1
  • 32 | *
  • caller ->com.biz.MyCaller.method(MyCaller.java:18)
  • 33 | *
  • source ->1.6.3.2:33
  • 34 | *
35 | * The context is bound to a thread (and inherited by sub-threads) but 36 | * it can also be added to by LogTargets. 37 | * 38 | * @author Avalon Development Team 39 | * @author Peter Donald 40 | * @deprecated Will be dropped in 3.3 41 | */ 42 | @Deprecated 43 | @SuppressWarnings({"unchecked","rawtypes"}) // will be dropped in 3.3 44 | public final class ContextMap 45 | implements Serializable 46 | { 47 | private static final long serialVersionUID = 1L; 48 | 49 | ///Thread local for holding instance of map associated with current thread 50 | private static final ThreadLocal c_localContext = new InheritableThreadLocal(); 51 | 52 | private final ContextMap m_parent; 53 | 54 | ///Container to hold map of elements 55 | private Hashtable m_map = new Hashtable(); 56 | 57 | ///Flag indicating whether this map should be readonly 58 | private transient boolean m_readOnly; 59 | 60 | /** 61 | * Get the Current ContextMap. 62 | * This method returns a ContextMap associated with current thread. If the 63 | * thread doesn't have a ContextMap associated with it then a new 64 | * ContextMap is created. 65 | * 66 | * @return the current ContextMap 67 | */ 68 | public static final ContextMap getCurrentContext() 69 | { 70 | return getCurrentContext( true ); 71 | } 72 | 73 | /** 74 | * Get the Current ContextMap. 75 | * This method returns a ContextMap associated with current thread. 76 | * If the thread doesn't have a ContextMap associated with it and 77 | * autocreate is true then a new ContextMap is created. 78 | * 79 | * @param autocreate true if a ContextMap is to be created if it doesn't exist 80 | * @return the current ContextMap 81 | */ 82 | public static final ContextMap getCurrentContext( final boolean autocreate ) 83 | { 84 | //Check security permission here??? 85 | ContextMap context = (ContextMap)c_localContext.get(); 86 | 87 | if( null == context && autocreate ) 88 | { 89 | context = new ContextMap(); 90 | c_localContext.set( context ); 91 | } 92 | 93 | return context; 94 | } 95 | 96 | /** 97 | * Bind a particular ContextMap to current thread. 98 | * 99 | * @param context the context map (may be null) 100 | */ 101 | public static final void bind( final ContextMap context ) 102 | { 103 | //Check security permission here?? 104 | c_localContext.set( context ); 105 | } 106 | 107 | /** 108 | * Default constructor. 109 | */ 110 | public ContextMap() 111 | { 112 | this( null ); 113 | } 114 | 115 | /** 116 | * Constructor that sets parent contextMap. 117 | * 118 | * @param parent the parent ContextMap 119 | */ 120 | public ContextMap( final ContextMap parent ) 121 | { 122 | m_parent = parent; 123 | } 124 | 125 | /** 126 | * Make the context read-only. 127 | * This makes it safe to allow untrusted code reference 128 | * to ContextMap. 129 | */ 130 | public void makeReadOnly() 131 | { 132 | m_readOnly = true; 133 | } 134 | 135 | /** 136 | * Determine if context is read-only. 137 | * 138 | * @return true if Context is read only, false otherwise 139 | */ 140 | public boolean isReadOnly() 141 | { 142 | return m_readOnly; 143 | } 144 | 145 | /** 146 | * Empty the context map. 147 | * 148 | */ 149 | public void clear() 150 | { 151 | checkReadable(); 152 | 153 | m_map.clear(); 154 | } 155 | 156 | /** 157 | * Get an entry from the context. 158 | * 159 | * @param key the key to map 160 | * @param defaultObject a default object to return if key does not exist 161 | * @return the object in context 162 | */ 163 | public Object get( final String key, final Object defaultObject ) 164 | { 165 | final Object object = get( key ); 166 | 167 | if( null != object ) 168 | { 169 | return object; 170 | } 171 | else 172 | { 173 | return defaultObject; 174 | } 175 | } 176 | 177 | /** 178 | * Get an entry from the context. 179 | * 180 | * @param key the key to map 181 | * @return the object in context or null if none with specified key 182 | */ 183 | public Object get( final String key ) 184 | { 185 | if( key == null ) 186 | { 187 | return null; 188 | } 189 | 190 | final Object result = m_map.get( key ); 191 | 192 | if( null == result && null != m_parent ) 193 | { 194 | return m_parent.get( key ); 195 | } 196 | 197 | return result; 198 | } 199 | 200 | /** 201 | * Set a value in context 202 | * 203 | * @param key the key 204 | * @param value the value (may be null) 205 | */ 206 | public void set( final String key, final Object value ) 207 | { 208 | checkReadable(); 209 | 210 | if( value == null ) 211 | { 212 | m_map.remove( key ); 213 | } 214 | else 215 | { 216 | m_map.put( key, value ); 217 | } 218 | } 219 | 220 | /** 221 | * Retrieve keys of entries into context map. 222 | * 223 | * @return the keys of items in context 224 | */ 225 | /* 226 | public String[] getKeys() 227 | { 228 | return (String[])m_map.keySet().toArray( new String[ 0 ] ); 229 | } 230 | */ 231 | 232 | /** 233 | * Get the number of contexts in map. 234 | * 235 | * @return the number of contexts in map 236 | */ 237 | public int getSize() 238 | { 239 | return m_map.size(); 240 | } 241 | 242 | /** 243 | * Helper method that sets context to read-only after de-serialization. 244 | * 245 | * @return the corrected object version 246 | */ 247 | private Object readResolve() 248 | { 249 | makeReadOnly(); 250 | return this; 251 | } 252 | 253 | /** 254 | * Utility method to verify that Context is read-only. 255 | */ 256 | private void checkReadable() 257 | { 258 | if( isReadOnly() ) 259 | { 260 | throw new IllegalStateException( "ContextMap is read only and can not be modified" ); 261 | } 262 | } 263 | } 264 | -------------------------------------------------------------------------------- /src/main/java/org/apache/jorphan/logging/LoggingManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | */ 18 | 19 | package org.apache.jorphan.logging; 20 | 21 | import java.util.Properties; 22 | 23 | import org.apache.log.LogTarget; 24 | import org.apache.log.Logger; 25 | import org.apache.log.Priority; 26 | import org.slf4j.LoggerFactory; 27 | 28 | /** 29 | * Manages JMeter logging 30 | * @deprecated since 3.2, use SLF4J for logger creation 31 | */ 32 | @Deprecated 33 | public final class LoggingManager { 34 | 35 | /** 36 | * Predefined format patterns, selected by the property log_format_type (see 37 | * jmeter.properties) The new-line is added later 38 | * @deprecated since 3.2, use SLF4J for logging 39 | */ 40 | @Deprecated 41 | public static final String DEFAULT_PATTERN = "%{time:yyyy/MM/dd HH:mm:ss} %5.5{priority} - " //$NON_NLS-1$ 42 | + "%{category}: %{message} %{throwable}"; //$NON_NLS-1$ 43 | 44 | /** 45 | * @deprecated since 3.2, use SLF4J for logging 46 | */ 47 | @Deprecated 48 | public static final String LOG_FILE = "log_file"; //$NON_NLS-1$ 49 | 50 | /** 51 | * @deprecated since 3.2, use SLF4J for logging 52 | */ 53 | @Deprecated 54 | public static final String LOG_PRIORITY = "log_level"; //$NON_NLS-1$ 55 | 56 | private LoggingManager() { 57 | // non-instantiable - static methods only 58 | } 59 | 60 | /** 61 | * Initialise the logging system from the Jmeter properties. Logkit loggers 62 | * inherit from their parents. 63 | * 64 | * Normally the jmeter properties file defines a single log file, so set 65 | * this as the default from "log_file", default "jmeter.log" The default 66 | * priority is set from "log_level", with a default of INFO 67 | * 68 | * @param properties 69 | * {@link Properties} to be used for initialization 70 | * @deprecated since 3.2, use SLF4J for logging 71 | */ 72 | @Deprecated 73 | public static void initializeLogging(Properties properties) { 74 | // NOP 75 | } 76 | 77 | /** 78 | * Handle LOG_PRIORITY.category=priority and LOG_FILE.category=file_name 79 | * properties. If the prefix is detected, then remove it to get the 80 | * category. 81 | * 82 | * @param appProperties 83 | * {@link Properties} that contain the 84 | * {@link LoggingManager#LOG_PRIORITY LOG_PRIORITY} and 85 | * {@link LoggingManager#LOG_FILE LOG_FILE} prefixed entries 86 | * @deprecated since 3.2, use SLF4J for logging 87 | */ 88 | @Deprecated 89 | public static void setLoggingLevels(Properties appProperties) { 90 | // NOP 91 | } 92 | 93 | /** 94 | * @deprecated 95 | */ 96 | @Deprecated 97 | private static final String PACKAGE_PREFIX = "org.apache."; //$NON_NLS-1$ 98 | 99 | /** 100 | * Removes the standard prefix, i.e. "org.apache.". 101 | * 102 | * @param name from which to remove the prefix 103 | * @return the name with the prefix removed 104 | * @deprecated since 3.2, use SLF4J for logging 105 | */ 106 | @Deprecated 107 | public static String removePrefix(String name){ 108 | if (name.startsWith(PACKAGE_PREFIX)) { // remove the package prefix 109 | name = name.substring(PACKAGE_PREFIX.length()); 110 | } 111 | return name; 112 | } 113 | 114 | /** 115 | * Get the Logger for a class - no argument needed because the calling class 116 | * name is derived automatically from the call stack. 117 | * 118 | * @return Logger 119 | */ 120 | public static Logger getLoggerForClass() { 121 | String className = new Exception().getStackTrace()[1].getClassName(); 122 | return new Slf4jLogkitLogger(LoggerFactory.getLogger(className)); 123 | } 124 | 125 | /** 126 | * Get the Logger for a class. 127 | * 128 | * @param category - the full name of the logger category 129 | * 130 | * @return Logger 131 | */ 132 | public static Logger getLoggerFor(String category) { 133 | return new Slf4jLogkitLogger(LoggerFactory.getLogger(category)); 134 | } 135 | 136 | /** 137 | * Get the Logger for a class. 138 | * 139 | * @param category - the full name of the logger category, this will have the prefix removed. 140 | * 141 | * @return Logger 142 | * @deprecated since 3.2, use SLF4J for logging 143 | */ 144 | @Deprecated 145 | public static Logger getLoggerForShortName(String category) { 146 | return getLoggerFor(category); 147 | } 148 | 149 | /** 150 | * Set the logging priority for a category. 151 | * 152 | * @param priority - string containing the priority name, e.g. "INFO", "WARN", "DEBUG", "FATAL_ERROR" 153 | * @param category - string containing the category 154 | * @deprecated since 3.2, use SLF4J for logging 155 | */ 156 | @Deprecated 157 | public static void setPriority(String priority, String category) { 158 | // NOP 159 | } 160 | 161 | /** 162 | * Set the logging priority for a category. 163 | * 164 | * @param priority - priority, e.g. DEBUG, INFO 165 | * @param fullName - e.g. org.apache.jmeter.etc, will have the prefix removed. 166 | * @deprecated since 3.2, use SLF4J for logging 167 | */ 168 | @Deprecated 169 | public static void setPriorityFullName(String priority, String fullName) { 170 | // NOP 171 | } 172 | 173 | /** 174 | * Set the logging priority for a category. 175 | * 176 | * @param priority - e.g. Priority.DEBUG 177 | * @param category - string containing the category 178 | * @deprecated since 3.2, use SLF4J for logging 179 | */ 180 | @Deprecated 181 | public static void setPriority(Priority priority, String category) { 182 | // NOP 183 | } 184 | 185 | /** 186 | * Set the logging priority. 187 | * 188 | * @param priority - e.g. Priority.DEBUG 189 | * @deprecated since 3.2, use SLF4J for logging 190 | */ 191 | @Deprecated 192 | public static void setPriority(String priority) { 193 | // NOP 194 | } 195 | 196 | /** 197 | * Set the default logging priority. 198 | * 199 | * @param priority e.g. Priority.DEBUG 200 | * @deprecated since 3.2, use SLF4J for logging 201 | */ 202 | @Deprecated 203 | public static void setPriority(Priority priority) { 204 | // NOP 205 | } 206 | 207 | /** 208 | * Set the logging target for a category. 209 | * 210 | * @param target the LogTarget 211 | * @param category the category name 212 | * @deprecated since 3.2, use SLF4J for logging 213 | */ 214 | @Deprecated 215 | public static void setTarget(LogTarget target, String category) { 216 | // NOP 217 | } 218 | 219 | /** 220 | * Add logTargets to root logger 221 | * FIXME What's the clean way to add a LogTarget afterwards ? 222 | * @param logTargets LogTarget array 223 | * @deprecated since 3.2, use SLF4J for logging 224 | */ 225 | @Deprecated 226 | public static void addLogTargetToRootLogger(LogTarget[] logTargets) { 227 | // NOP 228 | } 229 | } 230 | -------------------------------------------------------------------------------- /src/main/java/org/jmeterplugins/repository/PluginManagerCMD.java: -------------------------------------------------------------------------------- 1 | package org.jmeterplugins.repository; 2 | 3 | import kg.apc.cmdtools.AbstractCMDTool; 4 | import org.apache.jmeter.util.JMeterUtils; 5 | import org.jmeterplugins.repository.plugins.PluginSuggester; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | import java.io.File; 10 | import java.io.PrintStream; 11 | import java.io.UnsupportedEncodingException; 12 | import java.lang.reflect.Constructor; 13 | import java.net.URLDecoder; 14 | import java.util.Collections; 15 | import java.util.HashMap; 16 | import java.util.HashSet; 17 | import java.util.ListIterator; 18 | import java.util.Map; 19 | import java.util.Set; 20 | 21 | import static org.jmeterplugins.repository.logging.LoggingHooker.isJMeter32orLater; 22 | 23 | public class PluginManagerCMD extends AbstractCMDTool implements GenericCallback { 24 | private static final Logger log = LoggerFactory.getLogger(PluginManagerCMD.class); 25 | 26 | public PluginManagerCMD() { 27 | setJMeterHome(); 28 | if (isJMeter32orLater()) { 29 | configureCMDLogging(); 30 | } 31 | } 32 | 33 | private void configureCMDLogging() { 34 | try { 35 | Class cls = Class.forName("org.jmeterplugins.repository.logging.LoggingConfigurator"); 36 | Constructor constructor = cls.getConstructor(); 37 | constructor.newInstance(); 38 | } catch (Throwable ex) { 39 | System.out.println("Fail to configure logging " + ex.getMessage()); 40 | ex.printStackTrace(System.out); 41 | } 42 | } 43 | 44 | private void setJMeterHome() { 45 | if (JMeterUtils.getJMeterHome() == null || JMeterUtils.getJMeterHome().isEmpty()) { 46 | File self = new File(PluginManagerCMD.class.getProtectionDomain().getCodeSource().getLocation().getFile()); 47 | String home = self.getParentFile().getParentFile().getParent(); 48 | try { 49 | home = URLDecoder.decode(home, "UTF-8"); 50 | } catch (UnsupportedEncodingException e) { 51 | System.out.println("Failed decode JMeter home path: " + home); 52 | e.printStackTrace(System.out); 53 | } 54 | log.debug("Set JMeter home: " + home); 55 | JMeterUtils.setJMeterHome(home); 56 | JMeterUtils.loadJMeterProperties(JMeterUtils.getJMeterBinDir() + File.separator + "jmeter.properties"); 57 | } 58 | } 59 | 60 | @Override 61 | protected int processParams(ListIterator listIterator) throws UnsupportedOperationException, IllegalArgumentException { 62 | if (!listIterator.hasNext()) { 63 | showHelp(System.out); 64 | throw new IllegalArgumentException("Command parameter is missing"); 65 | } 66 | 67 | String command = listIterator.next().toString(); 68 | log.info("Command is: " + command); 69 | try { 70 | switch (command) { 71 | case "status": 72 | System.out.println(PluginManager.getAllPluginsStatus()); 73 | break; 74 | case "install": 75 | process(listIterator, true); 76 | break; 77 | case "install-all-except": 78 | installAll(listIterator, true); 79 | break; 80 | case "install-for-jmx": 81 | installPluginsForJmx(listIterator); 82 | break; 83 | case "uninstall": 84 | process(listIterator, false); 85 | break; 86 | case "help": 87 | showHelp(System.out); 88 | break; 89 | case "available": 90 | System.out.println(PluginManager.getAvailablePluginsAsString()); 91 | break; 92 | case "upgrades": 93 | System.out.println(PluginManager.getUpgradablePluginsAsString()); 94 | break; 95 | default: 96 | showHelp(System.out); 97 | throw new UnsupportedOperationException("Wrong command: " + command); 98 | } 99 | } catch (IllegalArgumentException e) { 100 | throw e; 101 | } catch (Throwable e) { 102 | throw new RuntimeException("Failed to perform cmdline operation: " + e.getMessage(), e); 103 | } 104 | 105 | return 0; 106 | } 107 | 108 | private PluginManager getPluginsManager(boolean isSendRepoStats) throws Throwable { 109 | PluginManager mgr = new PluginManager(); 110 | mgr.setSendRepoStats(isSendRepoStats); 111 | mgr.setTimeout(30000); // TODO: add property? 112 | mgr.load(); 113 | return mgr; 114 | } 115 | 116 | protected void installPluginsForJmx(ListIterator jmxFilesIterator) throws Throwable { 117 | if (!jmxFilesIterator.hasNext()) { 118 | throw new IllegalArgumentException("No jmx files specified"); 119 | } 120 | String files = jmxFilesIterator.next().toString(); 121 | 122 | PluginManager mgr = getPluginsManager(false); 123 | PluginSuggester suggester = new PluginSuggester(mgr); 124 | final Set pluginsToInstall = new HashSet<>(); 125 | Set jmxFiles = parseParams(files).keySet(); 126 | for (String jmxPath : jmxFiles) { 127 | pluginsToInstall.addAll(suggester.analyzeTestPlan(jmxPath)); 128 | } 129 | 130 | mgr.togglePlugins(pluginsToInstall, true); 131 | mgr.applyChanges(this, false, null); 132 | } 133 | 134 | protected void installAll(ListIterator exclusions, boolean install) throws Throwable { 135 | Set exceptedPlugins = Collections.emptySet(); 136 | if (exclusions.hasNext()) { 137 | exceptedPlugins = parseParams(exclusions.next().toString()).keySet(); 138 | } 139 | 140 | PluginManager mgr = getPluginsManager(true); 141 | for (Plugin plugin : mgr.getAvailablePlugins()) { 142 | if (!exceptedPlugins.contains(plugin.getID())) { 143 | mgr.toggleInstalled(plugin, install); 144 | } 145 | } 146 | mgr.applyChanges(this, false, null); 147 | } 148 | 149 | protected void process(ListIterator listIterator, boolean install) throws Throwable { 150 | if (!listIterator.hasNext()) { 151 | throw new IllegalArgumentException("Plugins list parameter is missing"); 152 | } 153 | 154 | Map params = parseParams(listIterator.next().toString()); 155 | PluginManager mgr = getPluginsManager(true); 156 | 157 | for (Map.Entry pluginSpec : params.entrySet()) { 158 | Plugin plugin = mgr.getPluginByID(pluginSpec.getKey()); 159 | if (pluginSpec.getValue() != null) { 160 | plugin.setCandidateVersion(pluginSpec.getValue()); 161 | } 162 | mgr.toggleInstalled(plugin, install); 163 | } 164 | mgr.applyChanges(this, false, null); 165 | } 166 | 167 | private Map parseParams(String paramStr) { 168 | log.info("Params line is: " + paramStr); 169 | HashMap res = new HashMap<>(); 170 | for (String part : paramStr.split(",")) { 171 | if (part.contains("=")) { 172 | String[] pieces = part.split("="); 173 | res.put(pieces[0].trim(), pieces[1].trim()); 174 | } else { 175 | res.put(part.trim(), null); 176 | } 177 | } 178 | return res; 179 | } 180 | 181 | @Override 182 | protected void showHelp(PrintStream printStream) { 183 | printStream.println("Options for tool 'PluginManagerCMD': " 184 | + " where is one of: help, status, available, upgrades, install, install-all-except, install-for-jmx, uninstall."); 185 | } 186 | 187 | @Override 188 | public void notify(String s) { 189 | if (s.endsWith("%")) { 190 | log.debug(s); 191 | } else { 192 | log.info(s); 193 | } 194 | } 195 | } 196 | -------------------------------------------------------------------------------- /src/main/java/org/jmeterplugins/repository/ChangesMaker.java: -------------------------------------------------------------------------------- 1 | package org.jmeterplugins.repository; 2 | 3 | import org.apache.jmeter.util.JMeterUtils; 4 | import org.apache.jorphan.util.JOrphanUtils; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | import java.io.File; 9 | import java.io.IOException; 10 | import java.io.PrintWriter; 11 | import java.io.UnsupportedEncodingException; 12 | import java.lang.management.ManagementFactory; 13 | import java.lang.management.RuntimeMXBean; 14 | import java.net.URLDecoder; 15 | import java.nio.file.Files; 16 | import java.util.ArrayList; 17 | import java.util.LinkedList; 18 | import java.util.List; 19 | import java.util.Map; 20 | import java.util.Set; 21 | 22 | public class ChangesMaker { 23 | private static final Logger log = LoggerFactory.getLogger(ChangesMaker.class); 24 | private final Map allPlugins; 25 | 26 | public ChangesMaker(Map allPlugins) { 27 | this.allPlugins = allPlugins; 28 | } 29 | 30 | 31 | public ProcessBuilder getProcessBuilder(File moveFile, File installFile, File restartFile) throws IOException { 32 | final ArrayList command = new ArrayList<>(); 33 | command.add(SafeDeleter.getJVM()); 34 | command.add("-classpath"); 35 | command.add(URLDecoder.decode(getTempPmgrJAR().getPath(), "UTF-8")); 36 | command.add(SafeDeleter.class.getCanonicalName()); 37 | command.add("--move-list"); 38 | command.add(moveFile.getAbsolutePath()); 39 | command.add("--install-list"); 40 | command.add(installFile.getAbsolutePath()); 41 | 42 | if (restartFile != null) { 43 | command.add("--restart-command"); 44 | command.add(restartFile.getAbsolutePath()); 45 | } 46 | 47 | log.debug("Command to execute: " + command); 48 | final ProcessBuilder builder = new ProcessBuilder(command); 49 | File cleanerLog = File.createTempFile("jpgc-cleaner-", ".log"); 50 | builder.redirectError(cleanerLog); 51 | builder.redirectOutput(cleanerLog); 52 | return builder; 53 | } 54 | 55 | private File getTempPmgrJAR() throws IOException { 56 | String jarPath = URLDecoder.decode(PluginManager.class.getProtectionDomain().getCodeSource().getLocation().getFile(), "UTF-8"); 57 | if (!jarPath.endsWith(".jar")) { 58 | log.warn("Suspicious JAR path detected: " + jarPath); 59 | } 60 | 61 | File origJAR = new File(jarPath); 62 | File tempJAR = File.createTempFile(origJAR.getName(), ".jar"); 63 | tempJAR.delete(); 64 | Files.copy(origJAR.toPath(), tempJAR.toPath()); 65 | return tempJAR; 66 | } 67 | 68 | 69 | public File getRestartFile(LinkedList additionalJMeterOptions) throws IOException { 70 | File file = File.createTempFile("jpgc-restart-", ".list"); 71 | try (PrintWriter out = new PrintWriter(file)) { 72 | 73 | out.print(SafeDeleter.getJVM() + "\n"); 74 | 75 | RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean(); 76 | List jvmArgs = runtimeMXBean.getInputArguments(); 77 | for (String arg : jvmArgs) { 78 | out.print(arg + "\n"); 79 | } 80 | 81 | out.print("-jar\n"); 82 | 83 | out.print(getJMeterStartCommand(additionalJMeterOptions)); 84 | 85 | return file; 86 | } 87 | } 88 | 89 | private String getJMeterStartCommand(LinkedList additionalJMeterOptions) { 90 | StringBuilder cmd = new StringBuilder(JMeterUtils.getJMeterBinDir() + File.separator + "ApacheJMeter.jar\n"); 91 | if (additionalJMeterOptions != null) { 92 | for (String option : additionalJMeterOptions) { 93 | cmd.append(option).append("\n"); 94 | } 95 | } 96 | return cmd.toString(); 97 | } 98 | 99 | public File getInstallFile(Set plugins, Set installLibs) throws IOException { 100 | File file = File.createTempFile("jpgc-installers-", ".list"); 101 | try (PrintWriter out = new PrintWriter(file)) { 102 | for (Plugin plugin : plugins) { 103 | String cls = plugin.getInstallerClass(); 104 | if (cls != null) { 105 | log.debug("Plugin " + plugin + " has installer: " + cls); 106 | StringBuilder cp = new StringBuilder(); 107 | Map libs = plugin.getLibs(plugin.getCandidateVersion()); 108 | for (String lib : libs.keySet()) { 109 | Library.InstallationInfo libInfo = getLibForInstallLibs(lib, installLibs); 110 | if (libInfo != null) { 111 | cp.append(generateLibPath(libInfo.getDestinationFileName())); 112 | cp.append(File.pathSeparator); 113 | continue; 114 | } 115 | 116 | String installedPath = Plugin.getLibInstallPath(lib); 117 | if (installedPath != null) { 118 | cp.append(generateLibPath(installedPath)); 119 | cp.append(File.pathSeparator); 120 | continue; 121 | } 122 | 123 | log.error("Library '" + lib + "' will not be installed!"); 124 | } 125 | cp.append(plugin.getDestName()); 126 | // add class for run 127 | cp.append('\t'); 128 | cp.append(cls); 129 | cp.append('\n'); 130 | out.print(cp.toString()); 131 | } 132 | } 133 | return file; 134 | } 135 | } 136 | 137 | protected Library.InstallationInfo getLibForInstallLibs(String lib, Set installLibs) { 138 | for (Library.InstallationInfo info : installLibs) { 139 | if (info.getName().equals(lib)) { 140 | return info; 141 | } 142 | } 143 | return null; 144 | } 145 | 146 | protected String generateLibPath(String libName) throws UnsupportedEncodingException { 147 | String libPath = new File(JOrphanUtils.class.getProtectionDomain().getCodeSource().getLocation().getFile()).getParent(); 148 | return URLDecoder.decode(libPath, "UTF-8") + File.separator + libName; 149 | } 150 | 151 | public File getMovementsFile(Set deletes, Set installs, Set installLibs, Set libDeletions) throws IOException { 152 | final File file = File.createTempFile("jpgc-jar-changes", ".list"); 153 | try (PrintWriter out = new PrintWriter(file)) { 154 | 155 | if (!deletes.isEmpty() || !libDeletions.isEmpty()) { 156 | File delDir = File.createTempFile("jpgc-deleted-jars-", ""); 157 | delDir.delete(); 158 | delDir.mkdir(); 159 | log.info("Will move deleted JARs to directory " + delDir); 160 | for (Plugin plugin : deletes) { 161 | File installed = new File(plugin.getInstalledPath()); 162 | String delTo = delDir + File.separator + installed.getName(); 163 | out.print(plugin.getInstalledPath() + "\t" + delTo + "\n"); 164 | } 165 | 166 | for (String lib : libDeletions) { 167 | for (Plugin plugin : allPlugins.keySet()) { 168 | if (plugin.isInstalled() && plugin.getInstalledPath().equals(lib)) { 169 | log.warn("Cannot delete " + lib + " since it is part of plugin " + plugin); 170 | libDeletions.remove(lib); 171 | } 172 | } 173 | } 174 | 175 | for (String lib : libDeletions) { 176 | File installed = new File(lib); 177 | String delTo = delDir + File.separator + installed.getName(); 178 | out.print(lib + "\t" + delTo + "\n"); 179 | } 180 | } 181 | 182 | for (Library.InstallationInfo libInfo : installLibs) { 183 | out.print(libInfo.getTmpPath() + "\t" + generateLibPath(libInfo.getDestinationFileName()) + "\n"); 184 | } 185 | 186 | for (Plugin plugin : installs) { 187 | out.print(plugin.getTempName() + "\t" + plugin.getDestName() + "\n"); 188 | } 189 | return file; 190 | } 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /src/test/resources/testplan.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | false 7 | false 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | continue 16 | 17 | false 18 | 10 19 | 20 | 1 21 | 1 22 | 1500968737000 23 | 1500968737000 24 | false 25 | 26 | 27 | 28 | 29 | 30 | false 31 | true 32 | false 33 | 34 | 35 | 36 | true 37 | true 38 | 200 39 | OK 40 | Dummy Sampler used to simulate requests and responses 41 | without actual network activity. This helps debugging tests. 42 | Dummy Sampler used to simulate requests and responses 43 | without actual network activity. This helps debugging tests. 44 | ${__Random(50,500)} 45 | ${__Random(1,50)} 46 | ${__Random(1,5)} 47 | 48 | 49 | 50 | false 51 | 52 | saveConfig 53 | 54 | 55 | true 56 | true 57 | true 58 | 59 | true 60 | true 61 | true 62 | true 63 | false 64 | true 65 | true 66 | false 67 | false 68 | false 69 | true 70 | false 71 | false 72 | false 73 | true 74 | 0 75 | true 76 | true 77 | true 78 | true 79 | true 80 | 81 | 82 | 83 | 84 | 85 | 86 | false 87 | 88 | saveConfig 89 | 90 | 91 | true 92 | true 93 | true 94 | 95 | true 96 | true 97 | true 98 | true 99 | false 100 | true 101 | true 102 | false 103 | false 104 | false 105 | true 106 | false 107 | false 108 | false 109 | true 110 | 0 111 | true 112 | true 113 | true 114 | true 115 | true 116 | 117 | 118 | 119 | 500 120 | false 121 | 122 | 123 | 124 | 125 | false 126 | false 127 | 128 | 129 | 130 | 131 | 132 | true 133 | 134 | 135 | 136 | 137 | -------------------------------------------------------------------------------- /src/main/java/org/apache/log/Logger.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package org.apache.log; 19 | 20 | /** 21 | * The object interacted with by client objects to perform logging. 22 | * 23 | * @author Avalon Development Team 24 | * @author Peter Donald 25 | * @deprecated Will be dropped in 3.3 26 | */ 27 | @Deprecated 28 | public abstract class Logger 29 | { 30 | private static final Logger[] EMPTY_SET = new Logger[ 0 ]; 31 | 32 | /** 33 | * Separator character use to separate different categories 34 | * @deprecated Will be dropped in 3.3 35 | */ 36 | @Deprecated 37 | public static final char CATEGORY_SEPARATOR = '.'; 38 | 39 | /** 40 | * Determine if messages of priority DEBUG will be logged. 41 | * 42 | * @return true if DEBUG messages will be logged 43 | */ 44 | public abstract boolean isDebugEnabled(); 45 | 46 | /** 47 | * Log a debug priority event. 48 | * 49 | * @param message the message 50 | * @param throwable the throwable 51 | */ 52 | public abstract void debug( final String message, final Throwable throwable ); 53 | 54 | /** 55 | * Log a debug priority event. 56 | * 57 | * @param message the message 58 | */ 59 | public abstract void debug( final String message ); 60 | 61 | /** 62 | * Determine if messages of priority INFO will be logged. 63 | * 64 | * @return true if INFO messages will be logged 65 | */ 66 | public abstract boolean isInfoEnabled(); 67 | 68 | /** 69 | * Log a info priority event. 70 | * 71 | * @param message the message 72 | * @param throwable the throwable 73 | */ 74 | public abstract void info( final String message, final Throwable throwable ); 75 | 76 | /** 77 | * Log a info priority event. 78 | * 79 | * @param message the message 80 | */ 81 | public abstract void info( final String message ); 82 | 83 | /** 84 | * Determine if messages of priority WARN will be logged. 85 | * 86 | * @return true if WARN messages will be logged 87 | */ 88 | public abstract boolean isWarnEnabled(); 89 | 90 | /** 91 | * Log a warn priority event. 92 | * 93 | * @param message the message 94 | * @param throwable the throwable 95 | */ 96 | public abstract void warn( final String message, final Throwable throwable ); 97 | 98 | /** 99 | * Log a warn priority event. 100 | * 101 | * @param message the message 102 | */ 103 | public abstract void warn( final String message ); 104 | 105 | /** 106 | * Determine if messages of priority ERROR will be logged. 107 | * 108 | * @return true if ERROR messages will be logged 109 | */ 110 | public abstract boolean isErrorEnabled(); 111 | 112 | /** 113 | * Log a error priority event. 114 | * 115 | * @param message the message 116 | * @param throwable the throwable 117 | */ 118 | public abstract void error( final String message, final Throwable throwable ); 119 | 120 | /** 121 | * Log a error priority event. 122 | * 123 | * @param message the message 124 | */ 125 | public abstract void error( final String message ); 126 | 127 | /** 128 | * Determine if messages of priority FATAL_ERROR will be logged. 129 | * 130 | * @return true if FATAL_ERROR messages will be logged 131 | */ 132 | public abstract boolean isFatalErrorEnabled(); 133 | 134 | /** 135 | * Log a fatalError priority event. 136 | * 137 | * @param message the message 138 | * @param throwable the throwable 139 | */ 140 | public abstract void fatalError( final String message, final Throwable throwable ); 141 | 142 | /** 143 | * Log a fatalError priority event. 144 | * 145 | * @param message the message 146 | */ 147 | public abstract void fatalError( final String message ); 148 | 149 | /** 150 | * Make this logger additive. I.e. Send all log events to parent 151 | * loggers LogTargets regardless of whether or not the 152 | * LogTargets have been overridden. 153 | * 154 | * This is derived from Log4js notion of Additivity. 155 | * 156 | * @param additivity true to make logger additive, false otherwise 157 | * @deprecated Will be dropped in 3.3 158 | */ 159 | @Deprecated 160 | public void setAdditivity( final boolean additivity ) 161 | { 162 | // NOP 163 | } 164 | 165 | /** 166 | * Determine if messages of priority will be logged. 167 | * @param priority the priority 168 | * @return true if messages will be logged 169 | */ 170 | public abstract boolean isPriorityEnabled( final Priority priority ); 171 | 172 | /** 173 | * Log a event at specific priority with a certain message and throwable. 174 | * 175 | * @param priority the priority 176 | * @param message the message 177 | * @param throwable the throwable 178 | */ 179 | public abstract void log( final Priority priority, 180 | final String message, 181 | final Throwable throwable ); 182 | 183 | /** 184 | * Log a event at specific priority with a certain message. 185 | * 186 | * @param priority the priority 187 | * @param message the message 188 | */ 189 | public abstract void log( final Priority priority, final String message ); 190 | 191 | /** 192 | * Set the priority for this logger. 193 | * 194 | * @param priority the priority 195 | * @deprecated Will be dropped in 3.3 196 | */ 197 | @Deprecated 198 | public void setPriority( final Priority priority ) 199 | { 200 | // NOP 201 | } 202 | 203 | /** 204 | * Unset the priority of Logger. 205 | * (Thus it will use it's parent's priority or DEBUG if no parent. 206 | * @deprecated Will be dropped in 3.3 207 | */ 208 | @Deprecated 209 | public void unsetPriority() 210 | { 211 | // NOP 212 | } 213 | 214 | /** 215 | * Unset the priority of Logger. 216 | * (Thus it will use it's parent's priority or DEBUG if no parent. 217 | * If recursive is true unset priorities of all child loggers. 218 | * 219 | * @param recursive true to unset priority of all child loggers 220 | * @deprecated Will be dropped in 3.3 221 | */ 222 | @Deprecated 223 | public void unsetPriority( final boolean recursive ) 224 | { 225 | // NOP 226 | } 227 | 228 | /** 229 | * Set the log targets for this logger. 230 | * 231 | * @param logTargets the Log Targets 232 | * @deprecated Will be dropped in 3.3 233 | */ 234 | @Deprecated 235 | public void setLogTargets( final LogTarget[] logTargets ) 236 | { 237 | // NOP 238 | } 239 | 240 | /** 241 | * Unset the logtargets for this logger. 242 | * This logger (and thus all child loggers who don't specify logtargets) will 243 | * inherit from the parents LogTargets. 244 | * @deprecated Will be dropped in 3.3 245 | */ 246 | @Deprecated 247 | public void unsetLogTargets() 248 | { 249 | // NOP 250 | } 251 | 252 | /** 253 | * Unset the logtargets for this logger and all child loggers if recursive is set. 254 | * The loggers unset (and all child loggers who don't specify logtargets) will 255 | * inherit from the parents LogTargets. 256 | * @param recursive the recursion policy 257 | * @deprecated Will be dropped in 3.3 258 | */ 259 | @Deprecated 260 | public void unsetLogTargets( final boolean recursive ) 261 | { 262 | // NOP 263 | } 264 | 265 | /** 266 | * Get all the child Loggers of current logger. 267 | * 268 | * @return the child loggers 269 | * @deprecated Will be dropped in 3.3 270 | */ 271 | @Deprecated 272 | public Logger[] getChildren() 273 | { 274 | // NOP 275 | return EMPTY_SET; 276 | } 277 | 278 | /** 279 | * Create a new child logger. 280 | * The category of child logger is [current-category].subcategory 281 | * 282 | * @param subCategory the subcategory of this logger 283 | * @return the new logger 284 | * @exception IllegalArgumentException if subCategory has an empty element name 285 | */ 286 | public abstract Logger getChildLogger( final String subCategory ); 287 | } 288 | --------------------------------------------------------------------------------