From 08b7833b080965df632f49952fdc381166a0d455 Mon Sep 17 00:00:00 2001 From: rollno748 Date: Tue, 5 Sep 2023 20:57:42 +0100 Subject: [PATCH 1/5] Added dashboard page for iewing plugins --- pom.xml | 2 +- .../controller/RestController.java | 6 +++++ src/main/resources/public/dashboard.html | 26 +++++++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 src/main/resources/public/dashboard.html diff --git a/pom.xml b/pom.xml index c787365..7c5a86c 100644 --- a/pom.xml +++ b/pom.xml @@ -13,7 +13,7 @@ 4.5.14 20230618 2.8.9 - 2.12.5 + 2.12.7.1 1.16.1 1.2.6 1.5 diff --git a/src/main/java/io/perfwise/local/pluginsmanager/controller/RestController.java b/src/main/java/io/perfwise/local/pluginsmanager/controller/RestController.java index 15ef33b..c415ca0 100644 --- a/src/main/java/io/perfwise/local/pluginsmanager/controller/RestController.java +++ b/src/main/java/io/perfwise/local/pluginsmanager/controller/RestController.java @@ -107,6 +107,12 @@ public void loadRestApiServices() { ""; }); + get("/dashboard", (req, res) -> { + res.type("text/html"); + res.redirect("/dashboard.html"); + return null; + }); + get("/upload", (req, res) -> { res.type("text/html"); res.redirect("/"); diff --git a/src/main/resources/public/dashboard.html b/src/main/resources/public/dashboard.html new file mode 100644 index 0000000..aae83fb --- /dev/null +++ b/src/main/resources/public/dashboard.html @@ -0,0 +1,26 @@ + + + + Custom Plugin Form + + + + + Fork me on GitHub + +
+ +
+
+

Plugin Dashboard

+
+ + + From 3d3cf9bbc8a4252d1f76ed3fcb52f05122263aaa Mon Sep 17 00:00:00 2001 From: rollno748 Date: Wed, 6 Sep 2023 07:50:15 +0100 Subject: [PATCH 2/5] Organised imports --- .../pluginsmanager/model/MetadataModel.java | 2 - .../local/pluginsmanager/model/Plugin.java | 97 ------------------- 2 files changed, 99 deletions(-) delete mode 100644 src/main/java/io/perfwise/local/pluginsmanager/model/Plugin.java diff --git a/src/main/java/io/perfwise/local/pluginsmanager/model/MetadataModel.java b/src/main/java/io/perfwise/local/pluginsmanager/model/MetadataModel.java index 54037fe..85f7cbd 100644 --- a/src/main/java/io/perfwise/local/pluginsmanager/model/MetadataModel.java +++ b/src/main/java/io/perfwise/local/pluginsmanager/model/MetadataModel.java @@ -1,8 +1,6 @@ package io.perfwise.local.pluginsmanager.model; - import com.fasterxml.jackson.annotation.JsonProperty; -import org.json.JSONObject; public class MetadataModel { @JsonProperty("id") diff --git a/src/main/java/io/perfwise/local/pluginsmanager/model/Plugin.java b/src/main/java/io/perfwise/local/pluginsmanager/model/Plugin.java deleted file mode 100644 index 987ed67..0000000 --- a/src/main/java/io/perfwise/local/pluginsmanager/model/Plugin.java +++ /dev/null @@ -1,97 +0,0 @@ -package io.perfwise.local.pluginsmanager.model; - -public class Plugin { - private String id; - private String name; - private String description; - private String helpUrl; - private String screenshotUlr; - private String vendor ; - private String version; - private String pluginPath; - private String libPath; - - public Plugin(String id, String name, String description, String helpUrl, String screenshotUlr, String vendor, String version, String pluginPath, String libPath) { - this.id = id; - this.name = name; - this.description = description; - this.helpUrl = helpUrl; - this.screenshotUlr = screenshotUlr; - this.vendor = vendor; - this.version = version; - this.pluginPath = pluginPath; - this.libPath = libPath; - } - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public String getHelpUrl() { - return helpUrl; - } - - public void setHelpUrl(String helpUrl) { - this.helpUrl = helpUrl; - } - - public String getScreenshotUlr() { - return screenshotUlr; - } - - public void setScreenshotUlr(String screenshotUlr) { - this.screenshotUlr = screenshotUlr; - } - - public String getVendor() { - return vendor; - } - - public void setVendor(String vendor) { - this.vendor = vendor; - } - - public String getVersion() { - return version; - } - - public void setVersion(String version) { - this.version = version; - } - - public String getPluginPath() { - return pluginPath; - } - - public void setPluginPath(String pluginPath) { - this.pluginPath = pluginPath; - } - - public String getLibPath() { - return libPath; - } - - public void setLibPath(String libPath) { - this.libPath = libPath; - } -} From e6b8de6aa69b9931563cad0eada5845d3c55a687 Mon Sep 17 00:00:00 2001 From: rollno748 Date: Wed, 6 Sep 2023 08:15:58 +0100 Subject: [PATCH 3/5] Updated Readme --- README.md | 75 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 48 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index 3b5e963..cc7899c 100644 --- a/README.md +++ b/README.md @@ -1,52 +1,73 @@ -# Jmeter-local-plugins-manager -Intranet Plugin Manager for JMeter - which downloads the plugins from internet periodically. - -## Motive -Some organization will not have/provide access to internet on certain hosts - This will enable the team to create an own server to manage the plugins - -## Features -1. Downloads the plugins, and it's associated dependent libraries to local storage. -2. Stores all the information to SQLITE DB. -3. Enables a UI to upload custom plugin which are restricted to share outside of organization. -4. Creates and exposes modified API with to get the Plugins info for Jmeter Plugin manager -5. Easily configurable scheduler to check for the newly available plugins/versions in the market. +# JMeter local plugins manager +Intranet Plugin Manager for JMeter - Periodically downloads plugins from the internet. +## Motive +In situations where specific hosts lack internet access, this tool enables the team to establish a dedicated server for managing plugins within the organization. ## Required Components 1. Java 8 or above -## Architecture +## Creating Properties file +create a properties file with the below contents. +```sh +server.port=2222 +server.uri.path=/v1 -## How to Set up +# Scheduler interval (in ms) +scheduler.interval=86400000 -* Download the source code and compile or Download the releases -* Create config to override configuration for application -* Run the jar (java -jar jmeter-local-plugins-manager-2.0.jar) +# DB Connection Pool configuration +db.min.threads=2 +db.max.threads=10 +db.timeout.secs=300 +# External APIs +jmeter.plugins.url=https://jmeter-plugins.org/repo/ +mvn.repo.url=https://mvnrepository.com/search?q= + +# Directory Configs +local.repo.path=/app/plugins-manager/ + +# Uncomment the below if you are running this on Windows +local.repo.path=C:\\Temp\\plugins-manager\\ +``` ## Available APIs | Service | HTTP Method | URI | |:-------------------|:-----------:|:----------------------------------------| | App Running Status | GET | http://:\/v1/ | -| Upload Plugin | GET | http://:\/v1/upload | | Get Plugins | GET | http://:\/v1/plugins | +| Upload Custom Plugin | GET | http://:\/v1/upload | +## How to Set up + +* Download the Latest release from [here](https://github.com/rollno748/Jmeter-local-plugins-manager/tags) +* Create `configuration.properties` file +* Run the JAR (java -jar jmeter-local-plugins-manager-2.0.jar -c configuration.properties) +* Go to the JMeter installed directory and set `jpgc.repo.address` (this should be the local plugins manager API) in the jmeter.properties + +## Features +1. Downloads plugins and their associated dependent libraries to local storage. +2. Stores all information in an SQLITE DB. +3. Provides a UI to upload custom plugins restricted to sharing within the organization. +4. Creates and exposes a modified API to retrieve plugin info for JMeter Plugin Manager. +5. Easily configurable scheduler to check for newly available plugins/versions in the market. + ## Uploading Custom plugin ![Custom Upload Form](/img/upload-form.jpg) - ## How it works ? -* Its acts as an independent server which polls plugins manager for update (which is configurable) -* It creates the required directories to store the plugins and its dependencies to the local -* It checks the permission on the local directories before storing the files -* Exposes 3 APIs in intranet - - Public plugins api - - Custom Plugins api - - Merged (Public and Custom) Plugins api +* Acts as an independent server that polls the plugins manager for updates (configurable). +* Creates the required directories to store plugins and their dependencies locally. +* Checks permissions on local directories before storing files. +* Exposes 3 APIs in the intranet: + - Public plugins API + - Custom Plugins API + - Merged (Public and Custom) Plugins API ## Tools used - Spark java framework @@ -62,4 +83,4 @@ If this project help you reduce time to develop, you can give me a cup of coffee Please rate a star(:star2:) - If you like it. Please open up a bug(:beetle:) - If you experience abnormalities. - + From 9fd367bafdae05f65814331b56e7b2872664a665 Mon Sep 17 00:00:00 2001 From: rollno748 Date: Fri, 8 Sep 2023 07:13:23 +0100 Subject: [PATCH 4/5] Added Dashboard page for viewing plugins --- .../controller/RestController.java | 7 ++ .../scheduler/http/HttpRequest.java | 39 +++++++++- .../scheduler/parser/Parse.java | 4 ++ .../pluginsmanager/service/PluginService.java | 1 + .../service/PluginServiceImpl.java | 7 ++ .../resources/public/assets/css/dashboard.css | 30 ++++++++ .../public/{ => assets/css}/styles.css | 0 .../resources/public/assets/ico/search.png | Bin 0 -> 12657 bytes .../resources/public/assets/js/dashboard.js | 67 ++++++++++++++++++ .../public/{ => assets/js}/script.js | 0 src/main/resources/public/dashboard.html | 21 ++++-- src/main/resources/public/index.html | 4 +- 12 files changed, 173 insertions(+), 7 deletions(-) create mode 100644 src/main/resources/public/assets/css/dashboard.css rename src/main/resources/public/{ => assets/css}/styles.css (100%) create mode 100644 src/main/resources/public/assets/ico/search.png create mode 100644 src/main/resources/public/assets/js/dashboard.js rename src/main/resources/public/{ => assets/js}/script.js (100%) diff --git a/src/main/java/io/perfwise/local/pluginsmanager/controller/RestController.java b/src/main/java/io/perfwise/local/pluginsmanager/controller/RestController.java index c415ca0..de1f053 100644 --- a/src/main/java/io/perfwise/local/pluginsmanager/controller/RestController.java +++ b/src/main/java/io/perfwise/local/pluginsmanager/controller/RestController.java @@ -135,6 +135,13 @@ public void loadRestApiServices() { } }); + get("/plugins-table", (req, res) -> { + res.type("application/json"); + String type = req.queryParams("type"); + PluginService pluginService = new PluginServiceImpl(); + return pluginService.getPluginTable(); + }); + post("/upload", (req, res) -> { req.attribute("org.eclipse.jetty.multipartConfig", new MultipartConfigElement("/temp")); UploadService uploadService = new UploadServiceImpl(this.customPluginsPath, this.libPath); diff --git a/src/main/java/io/perfwise/local/pluginsmanager/scheduler/http/HttpRequest.java b/src/main/java/io/perfwise/local/pluginsmanager/scheduler/http/HttpRequest.java index 1a6616c..5f3d27d 100644 --- a/src/main/java/io/perfwise/local/pluginsmanager/scheduler/http/HttpRequest.java +++ b/src/main/java/io/perfwise/local/pluginsmanager/scheduler/http/HttpRequest.java @@ -52,6 +52,7 @@ public class HttpRequest { private static final String INSERT_PLUGIN_INFO = "INSERT INTO plugins (id, name, type, description, helpUrl, markerClass, screenshotUrl, vendor, versions_count) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"; private static final String SELECT_PLUGIN_VERSION_METADATA = "SELECT COUNT(*) AS COUNT FROM METADATA WHERE ID = ? AND VERSION = ?"; private static final String SELECT_PLUGINS = "SELECT ID, NAME, DESCRIPTION, HELPURL, MARKERCLASS, SCREENSHOTURL, VENDOR FROM plugins"; + private static final String SELECT_PLUGINS_TABLE_DATA = "SELECT ID, NAME, TYPE, DESCRIPTION, HELPURL, MARKERCLASS, SCREENSHOTURL, VENDOR, VERSIONS_COUNT FROM plugins"; private static final String SELECT_PLUGINS_WITH_FILTER = "SELECT ID, NAME, DESCRIPTION, HELPURL, MARKERCLASS, SCREENSHOTURL, VENDOR FROM plugins WHERE type = ?"; private static final String SELECT_METADATA_BY_ID = "SELECT ID, VERSION, DOWNLOADURL, LIBS FROM metadata WHERE ID = ?"; @@ -226,6 +227,43 @@ public JSONArray getCustomPlugins() { return fetchPluginsFromLocalDB(SELECT_PLUGINS_WITH_FILTER, "custom"); } + public JSONArray getAllPluginsTableData() { + return fetchAllPluginsTableData(); + } + + private JSONArray fetchAllPluginsTableData() { + JSONArray jsonArray = new JSONArray(); + try{ + if(conn == null || conn.isClosed()){ + conn = SQLiteConnectionPool.getConnection(); + } + PreparedStatement preparedStatement = conn.prepareStatement(HttpRequest.SELECT_PLUGINS_TABLE_DATA); + ResultSet rs = preparedStatement.executeQuery(); + + while (rs.next()) { + JSONObject pluginObject = new JSONObject(); + JSONObject libraryObj; + + pluginObject.put("id", rs.getString("id")); + pluginObject.put("name", rs.getString("name")); + pluginObject.put("type", rs.getString("type")); + pluginObject.put("description", rs.getString("description")); + pluginObject.put("helpUrl", rs.getString("helpUrl")); + pluginObject.put("markerClass", rs.getString("markerClass")); + pluginObject.put("screenshotUrl", rs.getString("screenshotUrl")); + pluginObject.put("vendor", rs.getString("vendor")); + pluginObject.put("versions_count", rs.getString("versions_count")); + jsonArray.put(pluginObject); + } + preparedStatement.close(); + }catch(SQLException | InterruptedException e){ + LOGGER.error("Exception occurred while fetching plugins information"); + } finally { + SQLiteConnectionPool.releaseConnection(conn); + } + return jsonArray; + } + private JSONObject getDependentLibraryObj(String id, String type) throws UnknownHostException { String host = InetAddress.getLocalHost().getHostAddress(); @@ -404,5 +442,4 @@ public Properties getProps() { public void setProps(Properties props) { this.props = props; } - } diff --git a/src/main/java/io/perfwise/local/pluginsmanager/scheduler/parser/Parse.java b/src/main/java/io/perfwise/local/pluginsmanager/scheduler/parser/Parse.java index 155b460..3bd27c6 100644 --- a/src/main/java/io/perfwise/local/pluginsmanager/scheduler/parser/Parse.java +++ b/src/main/java/io/perfwise/local/pluginsmanager/scheduler/parser/Parse.java @@ -120,6 +120,10 @@ public static JSONArray getCustomPlugins() { return httpRequest.getCustomPlugins(); } + public static JSONArray getPluginsTableData() { + return httpRequest.getAllPluginsTableData(); + } + public void downloadMissingPlugins(JSONArray missingPluginsList) throws URISyntaxException, IOException { for (int i = 0; i < missingPluginsList.length(); i++) { httpRequest.downloadMissingPlugins(missingPluginsList.getJSONObject(i)); diff --git a/src/main/java/io/perfwise/local/pluginsmanager/service/PluginService.java b/src/main/java/io/perfwise/local/pluginsmanager/service/PluginService.java index 69f6b5c..acebc29 100644 --- a/src/main/java/io/perfwise/local/pluginsmanager/service/PluginService.java +++ b/src/main/java/io/perfwise/local/pluginsmanager/service/PluginService.java @@ -6,4 +6,5 @@ public interface PluginService { JSONArray getAllPlugins(); JSONArray getPublicPlugins(); JSONArray getCustomPlugins(); + JSONArray getPluginTable(); } diff --git a/src/main/java/io/perfwise/local/pluginsmanager/service/PluginServiceImpl.java b/src/main/java/io/perfwise/local/pluginsmanager/service/PluginServiceImpl.java index 645f5a7..3c7bac6 100644 --- a/src/main/java/io/perfwise/local/pluginsmanager/service/PluginServiceImpl.java +++ b/src/main/java/io/perfwise/local/pluginsmanager/service/PluginServiceImpl.java @@ -19,4 +19,11 @@ public JSONArray getPublicPlugins() { public JSONArray getCustomPlugins() { return Parse.getCustomPlugins(); } + + @Override + public JSONArray getPluginTable() { + return Parse.getPluginsTableData(); + } + + } diff --git a/src/main/resources/public/assets/css/dashboard.css b/src/main/resources/public/assets/css/dashboard.css new file mode 100644 index 0000000..7c69f8e --- /dev/null +++ b/src/main/resources/public/assets/css/dashboard.css @@ -0,0 +1,30 @@ +#tableInput { + background-image: url('./../ico/search.png'); + background-position: 10px 12px; + background-repeat: no-repeat; + width: 97%; + font-size: 16px; + padding: 12px 20px 12px 40px; + border: 1px solid #ddd; + margin-bottom: 12px; +} + +#pluginTable { + border-collapse: collapse; + width: 100%; + border: 1px solid #ddd; + font-size: 18px; +} + +#pluginTable th, #pluginTable td { + text-align: left; + padding: 12px; +} + +#pluginTable tr { + border-bottom: 1px solid #ddd; +} + +#pluginTable tr.header, #pluginTable tr:hover { + background-color: #f1f1f1; +} \ No newline at end of file diff --git a/src/main/resources/public/styles.css b/src/main/resources/public/assets/css/styles.css similarity index 100% rename from src/main/resources/public/styles.css rename to src/main/resources/public/assets/css/styles.css diff --git a/src/main/resources/public/assets/ico/search.png b/src/main/resources/public/assets/ico/search.png new file mode 100644 index 0000000000000000000000000000000000000000..9d28b05dca57b7685b7619b31b30db8d7c60b255 GIT binary patch literal 12657 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/public/assets/js/dashboard.js b/src/main/resources/public/assets/js/dashboard.js new file mode 100644 index 0000000..5c734ab --- /dev/null +++ b/src/main/resources/public/assets/js/dashboard.js @@ -0,0 +1,67 @@ +function myFunction() { + // Declare variables + var input, filter, table, tr, td, i, txtValue; + input = document.getElementById("tableInput"); + filter = input.value.toUpperCase(); + table = document.getElementById("pluginTable"); + tr = table.getElementsByTagName("tr"); + + for (i = 0; i < tr.length; i++) { + var displayRow = false; // Flag to determine if the row should be displayed + + // Loop through all columns in the current row + for (j = 0; j < tr[i].cells.length; j++) { + td = tr[i].cells[j]; + if (td) { + txtValue = td.textContent || td.innerText; + if (txtValue.toUpperCase().indexOf(filter) > -1) { + displayRow = true; // Set the flag to true if the filter text is found in any column + break; // No need to check other columns, so exit the loop + } + } + } + + // Set the row's display property based on the flag + tr[i].style.display = displayRow ? "" : "none"; + } +} + + +function populateTable(data) { + var table = document.getElementById("pluginTable"); + + for (var i = 0; i < data.length; i++) { + var row = table.insertRow(-1); // Insert a new row at the end of the table + + // Insert cells into the row and populate them with data + var idCell = row.insertCell(0); + var nameCell = row.insertCell(1); + var typeCell = row.insertCell(2); + var vendorCell = row.insertCell(3); + var versionsCountCell = row.insertCell(4); + + + idCell.innerHTML = data[i].id; + nameCell.innerHTML = data[i].name; + typeCell.innerHTML = data[i].type; + vendorCell.innerHTML = data[i].vendor; + versionsCountCell.innerHTML = data[i].versions_count; + } +} + +// Function to fetch data from the API +function fetchDataAndPopulateTable() { + fetch('/v1/plugins-table') + .then(response => response.json()) + .then(data => { + populateTable(data); + }) + .catch(error => { + console.error('Error fetching data:', error); + }); +} + +// Call the function to fetch and populate data when the page loads +window.onload = function () { + fetchDataAndPopulateTable(); +}; \ No newline at end of file diff --git a/src/main/resources/public/script.js b/src/main/resources/public/assets/js/script.js similarity index 100% rename from src/main/resources/public/script.js rename to src/main/resources/public/assets/js/script.js diff --git a/src/main/resources/public/dashboard.html b/src/main/resources/public/dashboard.html index aae83fb..8146d93 100644 --- a/src/main/resources/public/dashboard.html +++ b/src/main/resources/public/dashboard.html @@ -1,8 +1,10 @@ - Custom Plugin Form - + Plugins Table + + + @@ -19,8 +21,19 @@
-

Plugin Dashboard

+ + + + + + + + + + +
IDNameTypeVendorVersions Count
- + + diff --git a/src/main/resources/public/index.html b/src/main/resources/public/index.html index 3ce40ed..1111a0b 100644 --- a/src/main/resources/public/index.html +++ b/src/main/resources/public/index.html @@ -2,7 +2,7 @@ Custom Plugin Form - +
@@ -45,6 +45,6 @@

Custom Plugin Upload Form

- + From 408f628b0445d0f71a0fbef261469550ad5343cb Mon Sep 17 00:00:00 2001 From: rollno748 Date: Fri, 8 Sep 2023 07:18:40 +0100 Subject: [PATCH 5/5] Updated Readme and bumped version --- README.md | 39 +++++++++++++++++++++++---------------- pom.xml | 2 +- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index cc7899c..50a2a1f 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,22 @@ In situations where specific hosts lack internet access, this tool enables the t ## Required Components 1. Java 8 or above +## Features +1. Downloads plugins and their associated dependent libraries to local storage. +2. Stores all information in an SQLITE DB. +3. Provides a UI to upload custom plugins restricted to sharing within the organization. +4. Creates and exposes a modified API to retrieve plugin info for JMeter Plugin Manager. +5. Easily configurable scheduler to check for newly available plugins/versions in the market. + +## Available APIs + +| Service | HTTP Method | URI | +|:----------------------|:-----------:|:------------------------------------------| +| App Running Status | GET | http://:\/v1/status | +| Get Plugins | GET | http://:\/v1/plugins | +| Upload Custom Plugin | GET | http://:\/v1/upload | +| View Plugins in table | GET | http://:\/v1/dashboard | + ## Creating Properties file create a properties file with the below contents. @@ -33,28 +49,13 @@ local.repo.path=/app/plugins-manager/ local.repo.path=C:\\Temp\\plugins-manager\\ ``` -## Available APIs - -| Service | HTTP Method | URI | -|:-------------------|:-----------:|:----------------------------------------| -| App Running Status | GET | http://:\/v1/ | -| Get Plugins | GET | http://:\/v1/plugins | -| Upload Custom Plugin | GET | http://:\/v1/upload | - - ## How to Set up * Download the Latest release from [here](https://github.com/rollno748/Jmeter-local-plugins-manager/tags) * Create `configuration.properties` file -* Run the JAR (java -jar jmeter-local-plugins-manager-2.0.jar -c configuration.properties) +* Run the JAR (java -jar jmeter-local-plugins-manager-.jar -c configuration.properties) * Go to the JMeter installed directory and set `jpgc.repo.address` (this should be the local plugins manager API) in the jmeter.properties -## Features -1. Downloads plugins and their associated dependent libraries to local storage. -2. Stores all information in an SQLITE DB. -3. Provides a UI to upload custom plugins restricted to sharing within the organization. -4. Creates and exposes a modified API to retrieve plugin info for JMeter Plugin Manager. -5. Easily configurable scheduler to check for newly available plugins/versions in the market. ## Uploading Custom plugin ![Custom Upload Form](/img/upload-form.jpg) @@ -69,6 +70,12 @@ local.repo.path=C:\\Temp\\plugins-manager\\ - Custom Plugins API - Merged (Public and Custom) Plugins API + +## Detailed Instructions + +* Detailed instructions is available at [Medium](https://rollno748.medium.com/creating-your-own-jmeter-plugin-manager-a-comprehensive-guide-aaa57021dda9) + + ## Tools used - Spark java framework - Sqlite DB diff --git a/pom.xml b/pom.xml index 7c5a86c..9d03204 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 io.perfwise.local.pluginsmanager jmeter-local-plugins-manager - 2.0 + 2.1 2.9.4