org.jmeterplugins.repository.Plugin Maven / Gradle / Ivy
package org.jmeterplugins.repository;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.sf.json.JSONArray;
import net.sf.json.JSONNull;
import net.sf.json.JSONObject;
import org.apache.jmeter.engine.JMeterEngine;
import org.apache.jmeter.util.JMeterUtils;
import org.apache.jorphan.logging.LoggingManager;
import org.apache.log.Logger;
public class Plugin {
private static final Logger log = LoggingManager.getLoggerForClass();
private static final Pattern dependsParser = Pattern.compile("([^=<>]+)([=<>]+[0-9.]+)?");
public static final String VER_STOCK = "0.0.0-STOCK";
protected JSONObject versions = new JSONObject();
protected String id;
protected String markerClass;
protected String installedPath;
protected String installedVersion;
protected String tempName;
protected String destName;
protected String name;
protected String description;
protected String screenshot;
protected String helpLink;
protected String vendor;
protected String candidateVersion;
protected String installerClass = null;
protected List componentClasses;
protected boolean canUninstall = true;
private String searchIndexString;
public Plugin(String aId) {
id = aId;
}
public static Plugin fromJSON(JSONObject elm) {
Plugin inst = new Plugin(elm.getString("id"));
if (!(elm.get("markerClass") instanceof JSONNull)) {
inst.markerClass = elm.getString("markerClass");
}
inst.componentClasses = new ArrayList<>();
if (inst.markerClass != null) {
inst.componentClasses.add(inst.markerClass);
}
if (elm.containsKey("componentClasses")) {
JSONArray componentsJSON = elm.getJSONArray("componentClasses");
if (componentsJSON.size() > 0) {
for (int i = 0; i < componentsJSON.size(); i++) {
inst.componentClasses.add(componentsJSON.getString(i));
}
}
}
if (elm.get("versions") instanceof JSONObject) {
inst.versions = elm.getJSONObject("versions");
}
inst.name = elm.getString("name");
inst.description = elm.getString("description");
if (elm.containsKey("screenshotUrl")) {
inst.screenshot = elm.getString("screenshotUrl");
}
inst.helpLink = elm.getString("helpUrl");
inst.vendor = elm.getString("vendor");
if (elm.containsKey("canUninstall")) {
inst.canUninstall = elm.getBoolean("canUninstall");
}
if (elm.containsKey("installerClass")) {
inst.installerClass = elm.getString("installerClass");
}
return inst;
}
@Override
public String toString() {
return id;
}
public void detectInstalled(Set others) {
if (isVirtual()) {
detectInstalledVirtual(others);
} else {
detectInstalledPlugin();
}
if (isInstalled()) {
candidateVersion = installedVersion;
} else {
candidateVersion = getMaxVersion();
}
}
private void detectInstalledPlugin() {
String path = getJARPath(markerClass);
if (path != null) {
try {
installedPath = URLDecoder.decode(path, "UTF-8");
} catch (UnsupportedEncodingException e) {
log.warn("Failed decode plugin installed Path ", e);
installedPath = path;
}
}
if (installedPath != null) {
installedVersion = getVersionFromPath(installedPath);
if (installedVersion.equals(VER_STOCK) && isVersionFrozenToJMeter()) {
installedVersion = getJMeterVersion();
}
log.debug("Found plugin " + this + " version " + installedVersion + " at path " + installedPath);
}
}
private void detectInstalledVirtual(Set others) {
candidateVersion = getMaxVersion();
log.debug("Detecting virtual " + this + " by depends: " + getDepends());
for (String depID : getDepends()) {
installedPath = null;
for (Plugin plugin : others) {
if (plugin.getID().equals(depID) && plugin.isInstalled()) {
installedPath = "";
}
}
if (installedPath == null) {
break;
}
}
if (isInstalled()) {
installedVersion = candidateVersion;
}
}
public boolean isVersionFrozenToJMeter() {
return versions.containsKey("");
}
public String getMaxVersion() {
Set versions = getVersions();
if (versions.size() > 0) {
String[] vers = versions.toArray(new String[0]);
return vers[vers.length - 1];
}
return null;
}
public Set getVersions() {
Set versions = new TreeSet<>(new VersionComparator());
for (Object o : this.versions.keySet()) {
if (o instanceof String) {
String ver = (String) o;
if (ver.isEmpty()) {
versions.add(getJMeterVersion());
} else {
versions.add(ver);
}
}
}
if (isInstalled()) {
versions.add(installedVersion);
}
return versions;
}
public static String getJMeterVersion() {
String ver = JMeterUtils.getJMeterVersion();
String[] parts = ver.split(" ");
if (parts.length > 1) {
return parts[0];
}
return ver;
}
public static String getVersionFromPath(String installedPath) {
Pattern p = Pattern.compile("-([\\.0-9]+(-[\\w]+)?).jar");
Matcher m = p.matcher(installedPath);
if (m.find()) {
return m.group(1);
}
return VER_STOCK;
}
public static String getJARPath(String className) {
Class cls;
try {
log.debug("Trying: " + className);
cls = Thread.currentThread().getContextClassLoader().loadClass(className);
} catch (Throwable e) {
if (e instanceof ClassNotFoundException) {
log.debug("Plugin not found by class: " + className);
} else {
log.warn("Unable to load class: " + className, e);
}
return null;
}
String file = cls.getProtectionDomain().getCodeSource().getLocation().getFile();
if (!file.toLowerCase().endsWith(".jar")) {
log.warn("Path is not JAR: " + file);
}
return file;
}
public static String getLibInstallPath(String lib) {
String[] cp = System.getProperty(DependencyResolver.JAVA_CLASS_PATH).split(File.pathSeparator);
String path = getLibPath(lib, cp);
if (path != null) return path;
return null;
}
public static String getLibPath(String lib, String[] paths) {
for (String path : paths) {
Pattern p = Pattern.compile("\\W" + lib + "-([0-9]+\\..+).jar");
Matcher m = p.matcher(path);
if (m.find()) {
log.debug("Found library " + lib + " at " + path);
return path;
}
}
return null;
}
public String getID() {
return id;
}
public String getInstalledPath() {
return installedPath;
}
public String getDestName() {
return destName;
}
public String getTempName() {
return tempName;
}
public boolean isInstalled() {
return installedPath != null;
}
public void download(JARSource jarSource, GenericCallback notify) throws IOException {
if (isVirtual()) {
log.debug("Virtual set, won't download: " + this);
return;
}
String version = getCandidateVersion();
String location = getDownloadUrl(version);
JARSource.DownloadResult dwn = jarSource.getJAR(id, location, notify);
tempName = dwn.getTmpFile();
File f = new File(JMeterEngine.class.getProtectionDomain().getCodeSource().getLocation().getFile());
destName = URLDecoder.decode(f.getParent(), "UTF-8") + File.separator + dwn.getFilename();
}
/**
* @param version
* @return
*/
public String getDownloadUrl(String version) {
String location;
if (isVersionFrozenToJMeter()) {
String downloadUrl = versions.getJSONObject("").getString("downloadUrl");
location = String.format(downloadUrl, getJMeterVersion());
} else {
if (!versions.containsKey(version)) {
throw new IllegalArgumentException("Version " + version + " not found for plugin " + this);
}
location = versions.getJSONObject(version).getString("downloadUrl");
}
return location;
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
public String getScreenshot() {
return screenshot;
}
public String getHelpLink() {
return helpLink;
}
public String getVendor() {
return vendor;
}
public String getCandidateVersion() {
return candidateVersion;
}
public boolean canUninstall() {
return canUninstall;
}
public String getInstalledVersion() {
return installedVersion;
}
public void setCandidateVersion(String candidateVersion) {
this.candidateVersion = candidateVersion;
}
public boolean isUpgradable() {
if (!isInstalled()) {
return false;
}
VersionComparator comparator = new VersionComparator();
return comparator.compare(getInstalledVersion(), getMaxVersion()) < 0;
}
public Set getDepends() {
Set depends = new HashSet<>();
JSONObject version = versions.getJSONObject(getCandidateVersion());
if (version.containsKey("depends")) {
JSONArray list = version.getJSONArray("depends");
for (Object o : list) {
if (o instanceof String) {
String dep = (String) o;
Matcher m = dependsParser.matcher(dep);
if (!m.find()) {
throw new IllegalArgumentException("Cannot parse depend str: " + dep);
}
depends.add(m.group(1));
}
}
}
return depends;
}
public Map getLibs(String verStr) {
Map depends = new HashMap<>();
JSONObject version = versions.getJSONObject(isVersionFrozenToJMeter() ? "" : verStr);
if (version.containsKey("libs")) {
JSONObject list = version.getJSONObject("libs");
for (Object o : list.keySet()) {
if (o instanceof String) {
String dep = (String) o;
depends.put(dep, list.getString(dep));
}
}
}
return depends;
}
public Map getRequiredLibs(String verStr) {
Map libs = getLibs(verStr);
Map requiredLibs = new HashMap<>();
for (String libName : libs.keySet()) {
if (libName.contains(">=")) {
requiredLibs.put(libName, libs.get(libName));
}
}
return requiredLibs;
}
public String getVersionChanges(String versionStr) {
JSONObject version = versions.getJSONObject(versionStr);
return version.containsKey("changes") ?
version.getString("changes") :
null;
}
public String getInstallerClass() {
return installerClass;
}
public boolean containsComponentClasses(Set classes) {
for (String cls : componentClasses) {
if (classes.contains(cls)) {
return true;
}
}
return false;
}
private class VersionComparator implements java.util.Comparator {
@Override
public int compare(String a, String b) {
String[] aParts = a.split("\\W+");
String[] bParts = b.split("\\W+");
for (int aN = 0; aN < aParts.length; aN++) {
if (aN < bParts.length) {
int res = compare2(aParts[aN], bParts[aN]);
if (res != 0) return res;
}
}
return a.compareTo(b);
}
private int compare2(String a, String b) {
if (a.equals(b)) {
return 0;
}
Object ai, bi;
try {
ai = Integer.parseInt(a);
} catch (NumberFormatException e) {
ai = a;
}
try {
bi = Integer.parseInt(b);
} catch (NumberFormatException e) {
bi = b;
}
if (ai instanceof Integer && bi instanceof Integer) {
return Integer.compare((Integer) ai, (Integer) bi);
} else if (ai instanceof String && bi instanceof String) {
return ((String) ai).compareTo((String) bi);
} else if (ai instanceof String) {
return 1;
} else {
return -1;
}
}
}
public boolean isVirtual() {
return markerClass == null;
}
public String getSearchIndexString() {
if (searchIndexString == null || searchIndexString.isEmpty()) {
StringBuilder builder = new StringBuilder();
builder.append(id);
builder.append(name);
builder.append(description);
for (String component : componentClasses) {
builder.append(component);
}
searchIndexString = builder.toString().toLowerCase();
}
return searchIndexString;
}
}