diff --git a/src/main/java/edu/jhuapl/trinity/messages/TrinityHttpHandler.java b/src/main/java/edu/jhuapl/trinity/messages/TrinityHttpHandler.java new file mode 100644 index 0000000..fb07402 --- /dev/null +++ b/src/main/java/edu/jhuapl/trinity/messages/TrinityHttpHandler.java @@ -0,0 +1,90 @@ +package edu.jhuapl.trinity.messages; + +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.handler.codec.http.DefaultFullHttpResponse; +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.FullHttpResponse; +import io.netty.handler.codec.http.HttpHeaderNames; +import io.netty.handler.codec.http.HttpMethod; +import io.netty.handler.codec.http.HttpResponseStatus; +import io.netty.handler.codec.http.HttpVersion; +import io.netty.util.CharsetUtil; +import javafx.scene.Scene; + +import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * @author Sean Phillips + */ +public class TrinityHttpHandler extends SimpleChannelInboundHandler { + + private static final Logger LOGGER = Logger.getLogger(TrinityHttpHandler.class.getName()); + + private final MessageProcessor processor; + + public TrinityHttpHandler(Scene scene) { + this.processor = new MessageProcessor(scene); + } + + @Override + public void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) { + // Check HTTP Method + if (request.method() != HttpMethod.POST) { + handleInvalidMethodResponse(ctx, request); + return; + } + // Process Request + String rawContent = request.content().toString(CharsetUtil.UTF_8); + boolean success = processMessage(rawContent); + + // Generate the response + if (success) { + handleOkResponse(ctx, request); + } else { + handleErrorResponse(ctx, request, "Malformed JSON"); + } + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { + LOGGER.log(Level.SEVERE, null, cause); + ctx.close(); + } + + private void setCommonHeaders(FullHttpRequest request, FullHttpResponse response) { + response.headers().set(HttpHeaderNames.CONTENT_TYPE, "application/json; charset=UTF-8"); + response.headers().setInt(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes()); + } + + private void handleInvalidMethodResponse(ChannelHandlerContext ctx, FullHttpRequest request) { + FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.NOT_FOUND, Unpooled.copiedBuffer(String.format("{\"error\":\"%s\"}", HttpResponseStatus.NOT_FOUND.reasonPhrase()), CharsetUtil.UTF_8)); + this.setCommonHeaders(request, response); + ctx.writeAndFlush(response); + } + + private void handleErrorResponse(ChannelHandlerContext ctx, FullHttpRequest request, String errorMsg) { + FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST, Unpooled.copiedBuffer(String.format("{\"error\":\"%s\"}", errorMsg), CharsetUtil.UTF_8)); + this.setCommonHeaders(request, response); + ctx.writeAndFlush(response); + } + + private void handleOkResponse(ChannelHandlerContext ctx, FullHttpRequest request) { + FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.copiedBuffer(String.format("{\"message\":\"%s\"}", HttpResponseStatus.OK.reasonPhrase()), CharsetUtil.UTF_8)); + this.setCommonHeaders(request, response); + ctx.writeAndFlush(response); + } + + public boolean processMessage(String messageBody) { + try { + processor.process(messageBody); + return true; + } catch (IOException ex) { + LOGGER.log(Level.INFO, "Malformed JSON from injectMessage", ex); + return false; + } + } +} diff --git a/src/main/java/edu/jhuapl/trinity/messages/TrinityHttpServer.java b/src/main/java/edu/jhuapl/trinity/messages/TrinityHttpServer.java index 436a9c0..a0438f8 100644 --- a/src/main/java/edu/jhuapl/trinity/messages/TrinityHttpServer.java +++ b/src/main/java/edu/jhuapl/trinity/messages/TrinityHttpServer.java @@ -1,39 +1,28 @@ package edu.jhuapl.trinity.messages; import io.netty.bootstrap.ServerBootstrap; -import io.netty.buffer.Unpooled; import io.netty.channel.ChannelFuture; -import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInitializer; import io.netty.channel.EventLoopGroup; -import io.netty.channel.SimpleChannelInboundHandler; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; -import io.netty.handler.codec.http.DefaultFullHttpResponse; -import io.netty.handler.codec.http.FullHttpRequest; -import io.netty.handler.codec.http.FullHttpResponse; -import io.netty.handler.codec.http.HttpHeaderNames; -import io.netty.handler.codec.http.HttpMethod; import io.netty.handler.codec.http.HttpObjectAggregator; -import io.netty.handler.codec.http.HttpResponseStatus; import io.netty.handler.codec.http.HttpServerCodec; -import io.netty.handler.codec.http.HttpVersion; -import io.netty.util.CharsetUtil; import javafx.scene.Scene; -import java.io.IOException; import java.util.logging.Level; import java.util.logging.Logger; /** - * @author phillsm1 + * @author Sean Phillips */ public class TrinityHttpServer implements Runnable { + public static final String DEFAULT_HTTP_HOST = "0.0.0.0"; + public static final int DEFAULT_HTTP_PORT = 8080; + private static final Logger LOGGER = Logger.getLogger(TrinityHttpServer.class.getName()); - private static final String DEFAULT_HTTP_HOST = "0.0.0.0"; - private static final int DEFAULT_HTTP_PORT = 8080; private final Scene scene; public TrinityHttpServer(Scene scene) { @@ -45,17 +34,14 @@ public void run() { EventLoopGroup parentGroup = new NioEventLoopGroup(); EventLoopGroup childGroup = new NioEventLoopGroup(); try { - ServerBootstrap bootstrap = new ServerBootstrap() - .group(parentGroup, childGroup) - .channel(NioServerSocketChannel.class) - .childHandler(new ChannelInitializer() { - @Override - protected void initChannel(SocketChannel ch) { - ch.pipeline().addLast(new HttpServerCodec()); - ch.pipeline().addLast(new HttpObjectAggregator(Integer.MAX_VALUE)); - ch.pipeline().addLast(new TrinityServerHandler(scene)); - } - }); + ServerBootstrap bootstrap = new ServerBootstrap().group(parentGroup, childGroup).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer() { + @Override + protected void initChannel(SocketChannel ch) { + ch.pipeline().addLast(new HttpServerCodec()); + ch.pipeline().addLast(new HttpObjectAggregator(Integer.MAX_VALUE)); + ch.pipeline().addLast(new TrinityHttpHandler(scene)); + } + }); ChannelFuture future = bootstrap.bind(DEFAULT_HTTP_HOST, DEFAULT_HTTP_PORT).sync(); future.channel().closeFuture().sync(); } catch (InterruptedException ex) { @@ -66,72 +52,4 @@ protected void initChannel(SocketChannel ch) { } } - public static class TrinityServerHandler extends SimpleChannelInboundHandler { - - private static final Logger LOGGER = Logger.getLogger(TrinityServerHandler.class.getName()); - - private final MessageProcessor processor; - - public TrinityServerHandler(Scene scene) { - this.processor = new MessageProcessor(scene); - } - - @Override - public void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) { - // Check HTTP Method - if (request.method() != HttpMethod.POST) { - handleInvalidMethodResponse(ctx, request); - return; - } - // Process Request - String rawContent = request.content().toString(CharsetUtil.UTF_8); - boolean success = processMessage(rawContent); - - // Generate the response - if (success) { - handleOkResponse(ctx, request); - } else { - handleErrorResponse(ctx, request, "Malformed JSON"); - } - } - - @Override - public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { - LOGGER.log(Level.SEVERE, null, cause); - ctx.close(); - } - - private void setCommonHeaders(FullHttpRequest request, FullHttpResponse response) { - response.headers().set(HttpHeaderNames.CONTENT_TYPE, "application/json; charset=UTF-8"); - response.headers().setInt(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes()); - } - - private void handleInvalidMethodResponse(ChannelHandlerContext ctx, FullHttpRequest request) { - FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.NOT_FOUND, Unpooled.copiedBuffer(String.format("{\"error\":\"%s\"}", HttpResponseStatus.NOT_FOUND.reasonPhrase()), CharsetUtil.UTF_8)); - this.setCommonHeaders(request, response); - ctx.writeAndFlush(response); - } - - private void handleErrorResponse(ChannelHandlerContext ctx, FullHttpRequest request, String errorMsg) { - FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST, Unpooled.copiedBuffer(String.format("{\"error\":\"%s\"}", errorMsg), CharsetUtil.UTF_8)); - this.setCommonHeaders(request, response); - ctx.writeAndFlush(response); - } - - private void handleOkResponse(ChannelHandlerContext ctx, FullHttpRequest request) { - FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.copiedBuffer(String.format("{\"message\":\"%s\"}", HttpResponseStatus.OK.reasonPhrase()), CharsetUtil.UTF_8)); - this.setCommonHeaders(request, response); - ctx.writeAndFlush(response); - } - - public boolean processMessage(String messageBody) { - try { - processor.process(messageBody); - return true; - } catch (IOException ex) { - LOGGER.log(Level.INFO, "Malformed JSON from injectMessage", ex); - return false; - } - } - } }