package org.caudexorigo.http.netty4;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.ServerChannel;
import java.net.InetSocketAddress;
import javax.net.ssl.SSLContext;
import org.caudexorigo.http.netty4.reporting.ResponseFormatter;
import org.caudexorigo.http.netty4.reporting.StandardResponseFormatter;
import org.caudexorigo.netty.DefaultNettyContext;
import org.caudexorigo.netty.NettyContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class NettyHttpServer
{
private static final String DEFAULT_HOST = "0.0.0.0";
private static final int DEFAULT_PORT = 8080;
private static final int DEFAULT_MAX_CONTENT_LENGHT = 1024 * 1024 * 4;
private static Logger log = LoggerFactory.getLogger(NettyHttpServer.class);
private String _host;
private RequestRouter _mapper;
private RequestObserver _requestObserver;
private ResponseFormatter _rspFmt;
private int _port;
private int _maxContentLenght = -1;
private boolean _validate_headers;
private NettyContext _nettyCtx;
public NettyHttpServer()
{
this(DEFAULT_HOST, DEFAULT_PORT);
}
public NettyHttpServer(int port)
{
this(DEFAULT_HOST, port);
}
public NettyHttpServer(String host, int port)
{
_host = host;
_port = port;
_validate_headers = false;
}
public String getHost()
{
return _host;
}
public int getPort()
{
return _port;
}
public RequestRouter getRouter()
{
return _mapper;
}
private boolean getValidateHeaders()
{
return _validate_headers;
}
public void setHost(String host)
{
_host = host;
}
public void setPort(int port)
{
_port = port;
}
public void setRouter(RequestRouter mapper)
{
_mapper = mapper;
}
public ResponseFormatter getResponseFormtter()
{
if (_rspFmt != null)
{
return _rspFmt;
}
else
{
return new StandardResponseFormatter(false);
}
}
public RequestObserver getRequestObserver()
{
if (_requestObserver != null)
{
return _requestObserver;
}
else
{
return new DefaultObserver();
}
}
public void setRequestObserver(RequestObserver requestObserver)
{
_requestObserver = requestObserver;
}
public void setResponseFormatter(ResponseFormatter rspFmt)
{
_rspFmt = rspFmt;
}
public void setValidateHeaders(boolean validate_headers)
{
_validate_headers = validate_headers;
}
public void setMaxContentLenght(int maxContentLenght)
{
_maxContentLenght = maxContentLenght;
}
public synchronized void start()
{
log.info("Starting Httpd");
NettyContext nctx = getNettyContext();
EventLoopGroup bossGroup = nctx.getBossEventLoopGroup();
EventLoopGroup workerGroup = nctx.getWorkerEventLoopGroup();
try
{
Class<? extends ServerChannel> serverChannelClass = nctx.getServerChannelClass();
NettyHttpServerInitializer server_init = new NettyHttpServerInitializer(_mapper, getRequestObserver(), getResponseFormtter(), getMaxContentLength(), getValidateHeaders());
ServerBootstrap b = new ServerBootstrap();
setupBootStrap(b);
b.group(bossGroup, workerGroup).channel(serverChannelClass).childHandler(server_init);
InetSocketAddress inet = new InetSocketAddress(_host, _port);
log.info("Httpd started. Listening on {}:{}", _host, _port);
b.bind(inet).sync().channel().closeFuture().sync();
}
catch (Throwable t)
{
throw new RuntimeException(t);
}
finally
{
stop(bossGroup, workerGroup);
}
}
public int getMaxContentLength()
{
if (_maxContentLenght > 0)
{
return _maxContentLenght;
}
else
{
return DEFAULT_MAX_CONTENT_LENGHT;
}
}
public synchronized void startSsl(final HttpSslContext http_ssl_ctx)
{
log.info("Starting Httpd - SSL");
NettyContext nctx = getNettyContext();
EventLoopGroup bossGroup = nctx.getBossEventLoopGroup();
EventLoopGroup workerGroup = nctx.getWorkerEventLoopGroup();
final SSLContext sslContext;
try
{
sslContext = http_ssl_ctx.getSSLContext();
}
catch (Exception e)
{
throw new RuntimeException(e);
}
try
{
HttpProtocolHandler http_handler = new HttpProtocolHandler(_mapper, getRequestObserver(), getResponseFormtter());
NettySslHttpServerInitializer server_init = new NettySslHttpServerInitializer(sslContext, http_handler);
ServerBootstrap b = new ServerBootstrap();
setupBootStrap(b);
Class<? extends ServerChannel> serverChannelClass = nctx.getServerChannelClass();
b.group(bossGroup, workerGroup).channel(serverChannelClass).childHandler(server_init);
b.bind(http_ssl_ctx.getSslPort()).sync().channel().closeFuture().sync();
log.info("Httpd SSL started. Listening on port: {}", http_ssl_ctx.getSslPort());
}
catch (Throwable t)
{
throw new RuntimeException(t);
}
finally
{
stop(bossGroup, workerGroup);
}
}
private void setupBootStrap(ServerBootstrap bootstrap)
{
bootstrap.childOption(ChannelOption.ALLOCATOR, getNettyContext().getAllocator());
bootstrap.childOption(ChannelOption.MAX_MESSAGES_PER_READ, Integer.MAX_VALUE);
bootstrap.childOption(ChannelOption.SO_REUSEADDR, true);
bootstrap.option(ChannelOption.MAX_MESSAGES_PER_READ, Integer.MAX_VALUE);
bootstrap.option(ChannelOption.SO_BACKLOG, 1024);
bootstrap.option(ChannelOption.SO_REUSEADDR, true);
}
private NettyContext getNettyContext()
{
if (_nettyCtx == null)
{
_nettyCtx = DefaultNettyContext.get();
}
return _nettyCtx;
}
public void setNettyContext(NettyContext nettyCtx)
{
_nettyCtx = nettyCtx;
}
private void stop(EventLoopGroup bossGroup, EventLoopGroup workerGroup)
{
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
// Wait until all threads are terminated.
try
{
bossGroup.terminationFuture().sync();
}
catch (InterruptedException e)
{
Thread.currentThread().interrupt();
}
try
{
workerGroup.terminationFuture().sync();
}
catch (InterruptedException e)
{
Thread.currentThread().interrupt();
}
}
}