package io.vertx.core.impl.launcher.commands;
import io.vertx.core.AsyncResult;
import io.vertx.core.DeploymentOptions;
import io.vertx.core.Handler;
import io.vertx.core.Vertx;
import io.vertx.core.VertxOptions;
import io.vertx.core.cli.annotations.Description;
import io.vertx.core.cli.annotations.Option;
import io.vertx.core.logging.Logger;
import io.vertx.core.logging.LoggerFactory;
import io.vertx.core.spi.launcher.DefaultCommand;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public abstract class ClasspathHandler extends DefaultCommand {
protected static final String PATH_SEP = System.getProperty("path.separator");
protected final Logger log = LoggerFactory.getLogger(this.getClass());
protected List<String> classpath;
protected Object manager;
private ClassLoader classloader;
@Option(shortName = "cp", longName = "classpath", argName = "classpath")
@Description("Provides an extra classpath to be used for the verticle deployment.")
public void setClasspath(String classpath) {
if (classpath == null || classpath.isEmpty()) {
this.classloader = ClasspathHandler.class.getClassLoader();
this.classpath = Collections.emptyList();
} else {
this.classpath = Arrays.asList(classpath.split(PATH_SEP));
this.classloader = createClassloader();
}
}
protected synchronized ClassLoader createClassloader() {
URL[] urls = classpath.stream().map(path -> {
File file = new File(path);
try {
return file.toURI().toURL();
} catch (MalformedURLException e) {
throw new IllegalStateException(e);
}
}).toArray(URL[]::new);
return new URLClassLoader(urls, this.getClass().getClassLoader());
}
protected synchronized Object newInstance() {
try {
classloader = (classpath == null || classpath.isEmpty()) ?
ClasspathHandler.class.getClassLoader() : createClassloader();
Class<?> clazz = classloader.loadClass("io.vertx.core.impl.launcher.commands.VertxIsolatedDeployer");
return clazz.getDeclaredConstructor().newInstance();
} catch (Exception e) {
log.error("Failed to load or instantiate the isolated deployer", e);
throw new IllegalStateException(e);
}
}
protected synchronized Vertx create(VertxOptions options) {
final ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(classloader != null ? classloader : getClass().getClassLoader());
return Vertx.vertx(options);
} catch (Exception e) {
log.error("Failed to create the vert.x instance", e);
} finally {
Thread.currentThread().setContextClassLoader(originalClassLoader);
}
return null;
}
protected synchronized void create(VertxOptions options, Handler<AsyncResult<Vertx>> resultHandler) {
final ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(classloader != null ? classloader : getClass().getClassLoader());
Vertx.clusteredVertx(options, resultHandler);
} catch (Exception e) {
log.error("Failed to create the vert.x instance", e);
} finally {
Thread.currentThread().setContextClassLoader(originalClassLoader);
}
}
public synchronized void deploy(String verticle, Vertx vertx, DeploymentOptions options,
Handler<AsyncResult<String>> completionHandler) {
if (manager == null) {
manager = newInstance();
}
final ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(classloader);
Method method = manager.getClass().getMethod("deploy", String.class, Vertx.class, DeploymentOptions.class,
Handler.class);
if (executionContext.get("Default-Verticle-Factory") != null) {
if (verticle.indexOf(':') == -1) {
verticle = executionContext.get("Default-Verticle-Factory") + ":" + verticle;
}
}
method.invoke(manager, verticle, vertx, options, completionHandler);
} catch (InvocationTargetException e) {
log.error("Failed to deploy verticle " + verticle, e.getCause());
} catch (Exception e) {
log.error("Failed to deploy verticle " + verticle, e);
} finally {
Thread.currentThread().setContextClassLoader(originalClassLoader);
}
}
}