com.arangodb.shaded.vertx.core.impl.launcher.commands.ClasspathHandler Maven / Gradle / Ivy
/*
* Copyright (c) 2011-2019 Contributors to the Eclipse Foundation
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
* which is available at https://www.apache.org/licenses/LICENSE-2.0.
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
*/
package com.arangodb.shaded.vertx.core.impl.launcher.commands;
import com.arangodb.shaded.vertx.core.AsyncResult;
import com.arangodb.shaded.vertx.core.DeploymentOptions;
import com.arangodb.shaded.vertx.core.Handler;
import com.arangodb.shaded.vertx.core.Vertx;
import com.arangodb.shaded.vertx.core.VertxOptions;
import com.arangodb.shaded.vertx.core.cli.annotations.Description;
import com.arangodb.shaded.vertx.core.cli.annotations.Option;
import com.arangodb.shaded.vertx.core.impl.VertxBuilder;
import com.arangodb.shaded.vertx.core.impl.logging.Logger;
import com.arangodb.shaded.vertx.core.impl.logging.LoggerFactory;
import com.arangodb.shaded.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;
/**
* Command using the classpath option should extends this class as it manages the interaction with the
* custom classloader.
*
* @author Clement Escoffier
*/
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 classpath;
protected Object manager;
private ClassLoader classloader;
/**
* Sets the classpath.
*
* @param classpath the classpath
*/
@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();
}
}
/**
* Creates a classloader respecting the classpath option.
*
* @return the classloader.
*/
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());
}
/**
* Creates a new instance of {@link VertxIsolatedDeployer}.
*
* @return the new instance.
*/
protected synchronized Object newInstance() {
try {
classloader = (classpath == null || classpath.isEmpty()) ?
ClasspathHandler.class.getClassLoader() : createClassloader();
Class clazz = classloader.loadClass("com.arangodb.shaded.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);
}
}
/**
* Creates a new non-clustered vert.x instance.
*
* @param builder the builder
* @return the created instance
*/
protected synchronized Vertx create(VertxBuilder builder) {
final ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(classloader != null ? classloader : getClass().getClassLoader());
return builder.vertx();
} catch (Exception e) {
log.error("Failed to create the vert.x instance", e);
} finally {
Thread.currentThread().setContextClassLoader(originalClassLoader);
}
return null;
}
/**
* Creates a new clustered vert.x instance.
*
* @param builder the builder
* @param resultHandler the result handler
*/
protected synchronized void create(VertxBuilder builder, Handler> resultHandler) {
final ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(classloader != null ? classloader : getClass().getClassLoader());
builder.clusteredVertx(resultHandler);
} catch (Exception e) {
log.error("Failed to create the vert.x instance", e);
} finally {
Thread.currentThread().setContextClassLoader(originalClassLoader);
}
}
/**
* Deploys the given verticle using the given deployment options.
*
* @param verticle the verticle
* @param vertx the vert.x instance
* @param options the deployment options
* @param completionHandler the completion handler
*/
public synchronized void deploy(String verticle, Vertx vertx, DeploymentOptions options,
Handler> 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) {
// there is a configured default
if (verticle.indexOf(':') == -1) {
// and the verticle is not using a explicit factory
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);
}
}
}