package restx.server.simple.simple;
import com.google.common.base.Optional;
import com.google.common.eventbus.EventBus;
import org.simpleframework.http.Request;
import org.simpleframework.http.Response;
import org.simpleframework.http.core.Container;
import org.simpleframework.http.core.ContainerServer;
import org.simpleframework.transport.Server;
import org.simpleframework.transport.connect.Connection;
import org.simpleframework.transport.connect.SocketConnection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import restx.HttpSettings;
import restx.RestxMainRouter;
import restx.RestxMainRouterFactory;
import restx.common.MoreIO;
import restx.common.Version;
import restx.factory.Factory;
import restx.server.WebServer;
import restx.server.WebServerSupplier;
import restx.server.WebServers;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.concurrent.atomic.AtomicLong;
import static restx.common.MoreIO.checkCanOpenSocket;
/**
* User: xavierhanin
* Date: 2/16/13
* Time: 1:34 PM
*/
public abstract class SimpleWebServer implements WebServer {
private static final AtomicLong SERVER_ID = new AtomicLong();
public static class SimpleWebServerBuilder {
private int port;
private String routerPath = "/api";
private String appBase = null;
private String serverId;
private RestxMainRouter router;
public SimpleWebServerBuilder setPort(int port) {
this.port = port;
return this;
}
public SimpleWebServerBuilder setRouterPath(String routerPath) {
this.routerPath = routerPath;
return this;
}
public SimpleWebServerBuilder setAppBase(String appBase) {
this.appBase = appBase;
return this;
}
public SimpleWebServerBuilder setServerId(String serverId) {
this.serverId = serverId;
return this;
}
public SimpleWebServerBuilder setRouter(RestxMainRouter router) {
this.router = router;
return this;
}
public SimpleWebServer build() {
if (serverId == null) {
serverId = "SimpleWebServer#" + SERVER_ID.incrementAndGet();
}
if (router == null) {
return new SimpleWebServer(serverId, routerPath, appBase, port) {
@Override
protected RestxMainRouter setupRouter() {
return RestxMainRouterFactory.newInstance(
serverId,
Optional.of(WebServers.baseUri("0.0.0.0", port, routerPath)));
}
@Override
public synchronized void stop() throws Exception {
super.stop();
RestxMainRouterFactory.clear(serverId);
}
};
} else {
return new SimpleWebServer(serverId, routerPath, appBase, port) {
@Override
protected RestxMainRouter setupRouter() {
return router;
}
};
}
}
}
public static SimpleWebServerBuilder builder() {
return new SimpleWebServerBuilder();
}
private static final Logger logger = LoggerFactory.getLogger(SimpleWebServer.class);
private final String serverId;
private final String routerPath;
private final HttpSettings httpSettings;
private final String appBase;
private final int port;
private RestxMainRouter router;
private Connection connection;
private SimpleWebServer(String serverId, String routerPath, String appBase, int port) {
this.serverId = serverId;
this.routerPath = routerPath;
this.appBase = appBase;
this.port = port;
this.httpSettings = Factory.getInstance().getComponent(HttpSettings.class);
}
public String getServerId() {
return serverId;
}
@Override
public String getServerType() {
return "SimpleFramework " + Version.getVersion("org.simpleframework", "simple") + ", embedded";
}
public RestxMainRouter getRouter() {
return router;
}
@Override
public synchronized void start() throws Exception {
checkCanOpenSocket(port);
logger.debug("starting web server");
WebServers.register(this);
router = setupRouter();
Container container = new Container() {
@Override
public void handle(Request request, Response response) {
try {
if (request.getTarget().startsWith(routerPath)) {
router.route(
new SimpleRestxRequest(httpSettings, routerPath, request), new SimpleRestxResponse(response));
} else {
response.getPrintStream().print("Not found...");
response.getPrintStream().close();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
};
Server server = new ContainerServer(container);
connection = new SocketConnection(server);
SocketAddress address = new InetSocketAddress(port);
connection.connect(address);
}
protected abstract RestxMainRouter setupRouter();
@Override
public void startAndAwait() throws Exception {
start();
// this doesn't await but since the simple thread is not a daemon thread it will keep the jvm alive
}
@Override
public void await() throws Exception {
// does nothing, simple is started in daemon mode which keeps jvm alive
}
@Override
public synchronized void stop() throws Exception {
if (router instanceof AutoCloseable) {
((AutoCloseable) router).close();
}
connection.close();
connection = null;
WebServers.unregister(serverId);
}
@Override
public synchronized boolean isStarted() {
return connection != null;
}
@Override
public String baseUrl() {
return String.format("http://localhost:%s", port);
}
@Override
public int getPort() {
return port;
}
public static WebServerSupplier simpleWebServerSupplier() {
return new WebServerSupplier() {
@Override
public WebServer newWebServer(int port) {
return SimpleWebServer.builder().setPort(port).build();
}
};
}
}