org.jmeterplugins.repository.PluginManager Maven / Gradle / Ivy
package org.jmeterplugins.repository;
import net.sf.json.*;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.conn.params.ConnRoutePNames;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.params.HttpParams;
import org.apache.jmeter.util.JMeterUtils;
import org.apache.jorphan.logging.LoggingManager;
import org.apache.log.Logger;
import java.io.File;
import java.io.IOException;
import java.net.*;
import java.util.*;
public class PluginManager {
private static final Logger log = LoggingManager.getLoggerForClass();
private int timeout = 1000; // don't delay JMeter startup for more than 1 second
protected HttpClient httpClient = new DefaultHttpClient();
private final static String address = JMeterUtils.getPropDefault("jpgc.repo.address", System.getProperty("jpgc.repo.address", "http://jmeter-plugins.org"));
protected Map allPlugins = new HashMap<>();
private static PluginManager staticManager = new PluginManager();
private boolean doRestart = true;
public PluginManager() {
String proxyHost = System.getProperty("http.proxyHost", "");
if (!proxyHost.isEmpty()) {
int proxyPort = Integer.parseInt(System.getProperty("http.proxyPort", "-1"));
HttpParams params = httpClient.getParams();
HttpHost proxy = new HttpHost(proxyHost, proxyPort);
params.setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);
}
}
public void load() throws IOException {
if (allPlugins.size() > 0) {
return;
}
JSON json = getJSON("/repo/?installID=" + getInstallID());
if (!(json instanceof JSONArray)) {
throw new RuntimeException("Result is not array");
}
for (Object elm : (JSONArray) json) {
if (elm instanceof JSONObject) {
Plugin plugin = Plugin.fromJSON((JSONObject) elm);
if (plugin.getName().isEmpty()) {
log.debug("Skip empty name: " + plugin);
continue;
}
if (!plugin.isVirtual()) {
plugin.detectInstalled(getInstalledPlugins());
}
allPlugins.put(plugin, plugin.isInstalled());
} else {
log.warn("Invalid array element: " + elm);
}
}
// after all usual plugins detected, detect virtual sets
for (Plugin plugin : allPlugins.keySet()) {
if (plugin.isVirtual()) {
plugin.detectInstalled(getInstalledPlugins());
}
}
log.debug("Plugins: " + allPlugins.keySet());
if (JMeterUtils.getPropDefault("jpgc.repo.sendstats", "true").equals("true")) {
try {
reportStats();
} catch (Exception e) {
log.debug("Failed to report usage stats", e);
}
}
}
protected JSON getJSON(String path) throws IOException {
String uri = address + path;
log.debug("Requesting " + uri);
HttpRequestBase get = new HttpGet(uri);
HttpParams requestParams = get.getParams();
requestParams.setIntParameter(CoreConnectionPNames.SO_TIMEOUT, timeout);
requestParams.setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, timeout);
HttpResponse result = httpClient.execute(get);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
result.getEntity().writeTo(bos);
byte[] bytes = bos.toByteArray();
if (bytes == null) {
bytes = "null".getBytes();
}
String response = new String(bytes);
int statusCode = result.getStatusLine().getStatusCode();
if (statusCode >= 300) {
log.warn("Response with code " + result + ": " + response);
throw new IOException("Repository responded with wrong status code: " + statusCode);
} else {
log.debug("Response with code " + result + ": " + response);
}
return JSONSerializer.toJSON(response, new JsonConfig());
}
public void startModifications(Set delPlugins, Set installPlugins, Map installLibs, Set libDeletions) throws IOException {
ChangesMaker maker = new ChangesMaker(allPlugins);
File moveFile = maker.getMovementsFile(delPlugins, installPlugins, installLibs, libDeletions);
File installFile = maker.getInstallFile(installPlugins);
File restartFile;
if (doRestart) {
restartFile = maker.getRestartFile();
} else {
restartFile = null;
}
final ProcessBuilder builder = maker.getProcessBuilder(moveFile, installFile, restartFile);
log.info("JAR Modifications log will be saved into: " + builder.redirectOutput().file().getPath());
builder.start();
}
public void applyChanges(GenericCallback statusChanged) {
DependencyResolver resolver = new DependencyResolver(allPlugins);
Set additions = resolver.getAdditions();
Map libInstalls = new HashMap<>();
for (Map.Entry entry : resolver.getLibAdditions().entrySet()) {
Downloader dwn = new Downloader(statusChanged);
try {
String tmpFile = dwn.download(entry.getKey(), new URI(entry.getValue()));
libInstalls.put(tmpFile, dwn.getFilename());
} catch (Exception e) {
String msg = "Failed to download " + entry.getKey();
log.error(msg, e);
statusChanged.notify(msg);
throw new RuntimeException("Failed to download library " + entry.getKey(), e);
}
}
for (Plugin plugin : additions) {
try {
plugin.download(statusChanged);
} catch (IOException e) {
String msg = "Failed to download " + plugin;
log.error(msg, e);
statusChanged.notify(msg);
throw new RuntimeException("Failed to download plugin " + plugin, e);
}
}
statusChanged.notify("Restarting JMeter...");
Set libDeletions = new HashSet<>();
for (String lib : resolver.getLibDeletions()) {
libDeletions.add(Plugin.getLibInstallPath(lib));
}
modifierHook(resolver.getDeletions(), additions, libInstalls, libDeletions);
}
private void modifierHook(final Set deletions, final Set additions, final Map libInstalls, final Set libDeletions) {
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
try {
startModifications(deletions, additions, libInstalls, libDeletions);
} catch (Exception e) {
log.warn("Failed to run plugin cleaner job", e);
}
}
});
}
private void reportStats() throws IOException {
String uri = address + "/repo/";
HttpPost post = new HttpPost(uri);
HttpEntity body = new StringEntity("stats=" + URLEncoder.encode(getUsageStats(), "UTF-8"));
post.setEntity(body);
HttpParams requestParams = post.getParams();
requestParams.setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 3000);
requestParams.setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 1000);
log.debug("Requesting " + uri);
httpClient.execute(post);
}
protected String getUsageStats() {
ArrayList data = new ArrayList<>();
data.add(getInstallID());
data.add(JMeterUtils.getJMeterVersion());
for (Plugin p : getInstalledPlugins()) {
data.add(p.getID() + "=" + p.getInstalledVersion());
}
log.debug("Usage stats: " + data);
return Arrays.toString(data.toArray(new String[0]));
}
public String getChangesAsText() {
DependencyResolver resolver = new DependencyResolver(allPlugins);
String text = "";
for (Plugin pl : resolver.getDeletions()) {
text += "Uninstall plugin: " + pl + " " + pl.getInstalledVersion() + "\n";
}
for (String pl : resolver.getLibDeletions()) {
text += "Uninstall library: " + pl + "\n";
}
for (String pl : resolver.getLibAdditions().keySet()) {
text += "Install library: " + pl + "\n";
}
for (Plugin pl : resolver.getAdditions()) {
text += "Install plugin: " + pl + " " + pl.getCandidateVersion() + "\n";
}
return text;
}
public Set getInstalledPlugins() {
Set result = new TreeSet<>(new PluginComparator());
for (Plugin plugin : allPlugins.keySet()) {
if (plugin.isInstalled()) {
result.add(plugin);
}
}
return result;
}
public Set getAvailablePlugins() {
Set result = new TreeSet<>(new PluginComparator());
for (Plugin plugin : allPlugins.keySet()) {
if (!plugin.isInstalled()) {
result.add(plugin);
}
}
return result;
}
public Set getUpgradablePlugins() {
Set result = new TreeSet<>(new PluginComparator());
for (Plugin plugin : allPlugins.keySet()) {
if (plugin.isUpgradable()) {
result.add(plugin);
}
}
return result;
}
public void toggleInstalled(Plugin plugin, boolean cbState) {
if (!cbState && !plugin.canUninstall()) {
log.warn("Cannot uninstall plugin: " + plugin);
cbState = true;
}
allPlugins.put(plugin, cbState);
}
public boolean hasAnyUpdates() {
for (Plugin p : allPlugins.keySet()) {
if (p.isUpgradable()) {
return true;
}
}
return false;
}
public Plugin getPluginByID(String key) {
for (Plugin p : allPlugins.keySet()) {
if (p.getID().equals(key)) {
return p;
}
}
throw new IllegalArgumentException("Plugin not found in repo: " + key);
}
public void setDoRestart(boolean doRestart) {
this.doRestart = doRestart;
}
private class PluginComparator implements java.util.Comparator {
@Override
public int compare(Plugin o1, Plugin o2) {
return o1.getName().compareTo(o2.getName());
}
}
/**
* This function makes sure anonymous identifier sent
*
* @return unique ID for installation
*/
public String getInstallID() {
String str = "";
str += getClass().getProtectionDomain().getCodeSource().getLocation().getFile();
try {
str += "\t" + InetAddress.getLocalHost().getHostName();
} catch (UnknownHostException e) {
log.warn("Cannot get local host name", e);
}
try {
Enumeration ifs = NetworkInterface.getNetworkInterfaces();
for (NetworkInterface netint : Collections.list(ifs)) {
str += "\t" + Arrays.toString(netint.getHardwareAddress());
}
} catch (SocketException e) {
log.warn("Failed to get network addresses", e);
}
return DigestUtils.md5Hex(str);
}
public void setTimeout(int timeout) {
this.timeout = timeout;
}
/**
* @return Static instance of manager, used to spare resources on repo loading
*/
public static PluginManager getStaticManager() {
try {
staticManager.load();
} catch (IOException e) {
throw new RuntimeException("Failed to get plugin repositories");
}
return staticManager;
}
/**
* @param id ID of the plugin to check
* @return Version name for the plugin if it is installed, null otherwise
*/
public static String getPluginStatus(String id) {
PluginManager manager = getStaticManager();
for (Plugin plugin : manager.allPlugins.keySet()) {
if (plugin.id.equals(id)) {
return plugin.getInstalledVersion();
}
}
return null;
}
/**
* @return Version name for the plugin if it is installed, null otherwise
*/
public static String getAllPluginsStatus() {
PluginManager manager = getStaticManager();
ArrayList res = new ArrayList<>();
for (Plugin plugin : manager.getInstalledPlugins()) {
res.add(plugin.getID() + "=" + plugin.getInstalledVersion());
}
return Arrays.toString(res.toArray());
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy