package org.jboss.resteasy.plugins.server.vertx;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.DeploymentOptions;
import io.vertx.core.Future;
import io.vertx.core.Handler;
import io.vertx.core.Vertx;
import io.vertx.core.VertxOptions;
import io.vertx.core.http.HttpServer;
import io.vertx.core.http.HttpServerOptions;
import io.vertx.core.http.HttpServerRequest;
import io.vertx.core.json.JsonObject;
import org.jboss.resteasy.plugins.server.embedded.EmbeddedJaxrsServer;
import org.jboss.resteasy.plugins.server.embedded.SecurityDomain;
import org.jboss.resteasy.spi.ResteasyDeployment;
/**
* An HTTP server that sends back the content of the received HTTP request
* in a pretty plaintext form.
*
* @author Andy Taylor (andy.taylor@jboss.org)
* @author <a href="http://gleamynode.net/">Trustin Lee</a>
* @author Norman Maurer
* @author Julien Viet
* @version $Rev: 2080 $, $Date: 2010-01-26 18:04:19 +0900 (Tue, 26 Jan 2010) $
*/
public class VertxJaxrsServer implements EmbeddedJaxrsServer
{
private static final ConcurrentMap<String, Helper> deploymentMap = new ConcurrentHashMap<>();
protected VertxOptions vertxOptions = new VertxOptions();
protected Vertx vertx;
protected HttpServerOptions serverOptions = new HttpServerOptions();
protected VertxResteasyDeployment deployment = new VertxResteasyDeployment();
protected String root = "";
protected SecurityDomain domain;
private String deploymentID;
// default no idle timeout.
public String getHostname()
{
return serverOptions.getHost();
}
public void setHostname(String hostname)
{
serverOptions.setHost(hostname);
}
public int getPort()
{
return serverOptions.getPort();
}
public void setPort(int port)
{
serverOptions.setPort(port);
}
public VertxOptions getVertxOptions()
{
return vertxOptions;
}
/**
* Set {@link io.vertx.core.VertxOptions}.
*
* @param options the {@link io.vertx.core.VertxOptions}.
* @see Vertx#vertx(VertxOptions)
*/
public void setVertxOptions(VertxOptions options)
{
this.vertxOptions = options;
}
/**
* Set {@link io.vertx.core.http.HttpServerOptions}.
*
* @param options the {@link io.vertx.core.http.HttpServerOptions}.
* @see Vertx#createHttpServer(HttpServerOptions)
*/
public void setServerOptions(HttpServerOptions options)
{
this.serverOptions = options;
}
public HttpServerOptions getServerOptions()
{
return serverOptions;
}
@Override
public void setDeployment(ResteasyDeployment deployment)
{
this.deployment = (VertxResteasyDeployment) deployment;
}
@Override
public void setRootResourcePath(String rootResourcePath)
{
root = rootResourcePath;
if (root != null && root.equals("/")) root = "";
}
@Override
public VertxResteasyDeployment getDeployment()
{
return deployment;
}
@Override
public void setSecurityDomain(SecurityDomain sc)
{
this.domain = sc;
}
@SuppressWarnings("unchecked")
@Override
public void start()
{
vertx = Vertx.vertx(vertxOptions);
deployment.start();
String key = UUID.randomUUID().toString();
deploymentMap.put(key, new Helper(root, serverOptions, deployment, domain));
// Configure the server.
CompletableFuture<String> fut = new CompletableFuture<>();
DeploymentOptions deploymentOptions = new DeploymentOptions()
.setInstances(vertxOptions.getEventLoopPoolSize())
.setConfig(new JsonObject().put("helper", key));
vertx.deployVerticle(Verticle.class.getName(), deploymentOptions, ar -> {
deploymentMap.remove(key);
if (ar.succeeded())
{
fut.complete(ar.result());
} else
{
fut.completeExceptionally(ar.cause());
}
});
try
{
deploymentID = fut.get(60, TimeUnit.SECONDS);
} catch (InterruptedException e)
{
Thread.currentThread().interrupt();
} catch (ExecutionException e)
{
throw new RuntimeException(e.getCause());
} catch (TimeoutException e)
{
throw new RuntimeException(e);
}
}
@Override
public void stop()
{
if (deploymentID != null)
{
CompletableFuture<Void> fut = new CompletableFuture<>();
vertx.close(ar ->
{
fut.complete(null);
});
deploymentID = null;
try
{
fut.get(10, TimeUnit.SECONDS);
} catch (InterruptedException e)
{
Thread.currentThread().interrupt();
} catch (Exception ignore)
{
}
}
}
private static class Helper
{
final String root;
final HttpServerOptions serverOptions;
final ResteasyDeployment deployment;
final SecurityDomain domain;
Helper(String root, HttpServerOptions serverOptions, ResteasyDeployment deployment, SecurityDomain domain)
{
this.root = root;
this.serverOptions = serverOptions;
this.deployment = deployment;
this.domain = domain;
}
public Handler<HttpServerRequest> createHandler(Vertx vertx)
{
return new VertxRequestHandler(vertx, deployment, root, domain);
}
}
public static class Verticle extends AbstractVerticle
{
protected HttpServer server;
@Override
public void start(Future<Void> startFuture) throws Exception
{
Helper helper = deploymentMap.get(config().getString("helper"));
server = vertx.createHttpServer(helper.serverOptions);
server.requestHandler(new VertxRequestHandler(vertx, helper.deployment, helper.root, helper.domain));
server.listen(ar -> {
if (ar.succeeded())
{
startFuture.complete();
} else
{
startFuture.fail(ar.cause());
}
});
}
}
}