|
@@ -1,5 +1,14 @@
|
|
|
package hello;
|
|
|
|
|
|
+import java.text.DateFormat;
|
|
|
+import java.text.SimpleDateFormat;
|
|
|
+import java.util.Date;
|
|
|
+import java.util.concurrent.ScheduledExecutorService;
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
+
|
|
|
+import com.fasterxml.jackson.databind.ObjectMapper;
|
|
|
+import com.fasterxml.jackson.module.afterburner.AfterburnerModule;
|
|
|
+
|
|
|
import io.netty.buffer.ByteBuf;
|
|
|
import io.netty.buffer.Unpooled;
|
|
|
import io.netty.channel.ChannelFutureListener;
|
|
@@ -14,100 +23,90 @@ import io.netty.handler.codec.http.HttpVersion;
|
|
|
import io.netty.util.CharsetUtil;
|
|
|
import io.netty.util.concurrent.FastThreadLocal;
|
|
|
|
|
|
-import java.text.DateFormat;
|
|
|
-import java.text.SimpleDateFormat;
|
|
|
-import java.util.Date;
|
|
|
-import java.util.concurrent.ScheduledExecutorService;
|
|
|
-import java.util.concurrent.TimeUnit;
|
|
|
+public class HelloServerHandler extends SimpleChannelInboundHandler<Object> {
|
|
|
+ private static final FastThreadLocal<DateFormat> FORMAT = new FastThreadLocal<DateFormat>() {
|
|
|
+ @Override
|
|
|
+ protected DateFormat initialValue() {
|
|
|
+ return new SimpleDateFormat("E, dd MMM yyyy HH:mm:ss z");
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ private static final ByteBuf CONTENT_BUFFER = Unpooled.unreleasableBuffer(Unpooled.directBuffer().writeBytes("Hello, World!".getBytes(CharsetUtil.UTF_8)));
|
|
|
+ private static final CharSequence contentLength = HttpHeaders.newEntity(String.valueOf(CONTENT_BUFFER.readableBytes()));
|
|
|
+
|
|
|
+ private static final CharSequence TYPE_PLAIN = HttpHeaders.newEntity("text/plain; charset=UTF-8");
|
|
|
+ private static final CharSequence TYPE_JSON = HttpHeaders.newEntity("application/json; charset=UTF-8");
|
|
|
+ private static final CharSequence SERVER_NAME = HttpHeaders.newEntity("Netty");
|
|
|
+ private static final CharSequence CONTENT_TYPE_ENTITY = HttpHeaders.newEntity(HttpHeaders.Names.CONTENT_TYPE);
|
|
|
+ private static final CharSequence DATE_ENTITY = HttpHeaders.newEntity(HttpHeaders.Names.DATE);
|
|
|
+ private static final CharSequence CONTENT_LENGTH_ENTITY = HttpHeaders.newEntity(HttpHeaders.Names.CONTENT_LENGTH);
|
|
|
+ private static final CharSequence SERVER_ENTITY = HttpHeaders.newEntity(HttpHeaders.Names.SERVER);
|
|
|
+ private static final ObjectMapper MAPPER;
|
|
|
+
|
|
|
+ static {
|
|
|
+ MAPPER = new ObjectMapper();
|
|
|
+ MAPPER.registerModule(new AfterburnerModule());
|
|
|
+ }
|
|
|
|
|
|
-import com.fasterxml.jackson.databind.ObjectMapper;
|
|
|
-import com.fasterxml.jackson.module.afterburner.AfterburnerModule;
|
|
|
+ private volatile CharSequence date = HttpHeaders.newEntity(FORMAT.get().format(new Date()));
|
|
|
+
|
|
|
+ HelloServerHandler(ScheduledExecutorService service) {
|
|
|
+ service.scheduleWithFixedDelay(new Runnable() {
|
|
|
+ private final DateFormat format = FORMAT.get();
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void run() {
|
|
|
+ date = HttpHeaders.newEntity(format.format(new Date()));
|
|
|
+ }
|
|
|
+ }, 1000, 1000, TimeUnit.MILLISECONDS);
|
|
|
|
|
|
-public class HelloServerHandler extends SimpleChannelInboundHandler<Object> {
|
|
|
- private static final FastThreadLocal<DateFormat> FORMAT = new FastThreadLocal<DateFormat>() {
|
|
|
- @Override
|
|
|
- protected DateFormat initialValue() {
|
|
|
- return new SimpleDateFormat("E, dd MMM yyyy HH:mm:ss z");
|
|
|
}
|
|
|
- };
|
|
|
-
|
|
|
- private static final ByteBuf CONTENT_BUFFER = Unpooled.unreleasableBuffer(Unpooled.directBuffer().writeBytes("Hello, World!".getBytes(CharsetUtil.UTF_8)));
|
|
|
- private static final CharSequence contentLength = HttpHeaders.newEntity(String.valueOf(CONTENT_BUFFER.readableBytes()));
|
|
|
-
|
|
|
- private static final CharSequence TYPE_PLAIN = HttpHeaders.newEntity("text/plain; charset=UTF-8");
|
|
|
- private static final CharSequence TYPE_JSON = HttpHeaders.newEntity("application/json; charset=UTF-8");
|
|
|
- private static final CharSequence SERVER_NAME = HttpHeaders.newEntity("Netty");
|
|
|
- private static final CharSequence CONTENT_TYPE_ENTITY = HttpHeaders.newEntity(HttpHeaders.Names.CONTENT_TYPE);
|
|
|
- private static final CharSequence DATE_ENTITY = HttpHeaders.newEntity(HttpHeaders.Names.DATE);
|
|
|
- private static final CharSequence CONTENT_LENGTH_ENTITY = HttpHeaders.newEntity(HttpHeaders.Names.CONTENT_LENGTH);
|
|
|
- private static final CharSequence SERVER_ENTITY = HttpHeaders.newEntity(HttpHeaders.Names.SERVER);
|
|
|
- private static final ObjectMapper MAPPER;
|
|
|
-
|
|
|
- static {
|
|
|
- MAPPER = new ObjectMapper();
|
|
|
- MAPPER.registerModule(new AfterburnerModule());
|
|
|
- }
|
|
|
-
|
|
|
- private volatile CharSequence date = HttpHeaders.newEntity(FORMAT.get().format(new Date()));
|
|
|
-
|
|
|
- HelloServerHandler(ScheduledExecutorService service) {
|
|
|
- service.scheduleWithFixedDelay(new Runnable() {
|
|
|
- private final DateFormat format = FORMAT.get();
|
|
|
-
|
|
|
- @Override
|
|
|
- public void run() {
|
|
|
- date = HttpHeaders.newEntity(format.format(new Date()));
|
|
|
- }
|
|
|
- }, 1000, 1000, TimeUnit.MILLISECONDS);
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
|
|
|
- if (msg instanceof HttpRequest) {
|
|
|
- HttpRequest request = (HttpRequest) msg;
|
|
|
- String uri = request.getUri();
|
|
|
- switch (uri) {
|
|
|
- case "/plaintext":
|
|
|
- writeResponse(ctx, request, CONTENT_BUFFER.duplicate(), TYPE_PLAIN, contentLength);
|
|
|
- return;
|
|
|
- case "/json":
|
|
|
- byte[] json = MAPPER.writeValueAsBytes(new Message("Hello, World!"));
|
|
|
- writeResponse(ctx, request, Unpooled.wrappedBuffer(json), TYPE_JSON, String.valueOf(json.length));
|
|
|
- return;
|
|
|
- }
|
|
|
- FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.NOT_FOUND, Unpooled.EMPTY_BUFFER, false);
|
|
|
- ctx.write(response).addListener(ChannelFutureListener.CLOSE);
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
|
|
|
+ if (msg instanceof HttpRequest) {
|
|
|
+ HttpRequest request = (HttpRequest) msg;
|
|
|
+ String uri = request.getUri();
|
|
|
+ switch (uri) {
|
|
|
+ case "/plaintext":
|
|
|
+ writeResponse(ctx, request, CONTENT_BUFFER.duplicate(), TYPE_PLAIN, contentLength);
|
|
|
+ return;
|
|
|
+ case "/json":
|
|
|
+ byte[] json = MAPPER.writeValueAsBytes(new Message("Hello, World!"));
|
|
|
+ writeResponse(ctx, request, Unpooled.wrappedBuffer(json), TYPE_JSON, String.valueOf(json.length));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.NOT_FOUND, Unpooled.EMPTY_BUFFER, false);
|
|
|
+ ctx.write(response).addListener(ChannelFutureListener.CLOSE);
|
|
|
+ }
|
|
|
}
|
|
|
- }
|
|
|
-
|
|
|
- private void writeResponse(ChannelHandlerContext ctx, HttpRequest request, ByteBuf buf, CharSequence contentType, CharSequence contentLength) {
|
|
|
- // Decide whether to close the connection or not.
|
|
|
- boolean keepAlive = HttpHeaders.isKeepAlive(request);
|
|
|
- // Build the response object.
|
|
|
- FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, buf, false);
|
|
|
- HttpHeaders headers = response.headers();
|
|
|
- headers.set(CONTENT_TYPE_ENTITY, contentType);
|
|
|
- headers.set(SERVER_ENTITY, SERVER_NAME);
|
|
|
- headers.set(DATE_ENTITY, date);
|
|
|
- headers.set(CONTENT_LENGTH_ENTITY, contentLength);
|
|
|
-
|
|
|
- // Close the non-keep-alive connection after the write operation is
|
|
|
- // done.
|
|
|
- if (!keepAlive) {
|
|
|
- ctx.write(response).addListener(ChannelFutureListener.CLOSE);
|
|
|
- } else {
|
|
|
- ctx.write(response, ctx.voidPromise());
|
|
|
+
|
|
|
+ private void writeResponse(ChannelHandlerContext ctx, HttpRequest request, ByteBuf buf, CharSequence contentType, CharSequence contentLength) {
|
|
|
+ // Decide whether to close the connection or not.
|
|
|
+ boolean keepAlive = HttpHeaders.isKeepAlive(request);
|
|
|
+ // Build the response object.
|
|
|
+ FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, buf, false);
|
|
|
+ HttpHeaders headers = response.headers();
|
|
|
+ headers.set(CONTENT_TYPE_ENTITY, contentType);
|
|
|
+ headers.set(SERVER_ENTITY, SERVER_NAME);
|
|
|
+ headers.set(DATE_ENTITY, date);
|
|
|
+ headers.set(CONTENT_LENGTH_ENTITY, contentLength);
|
|
|
+
|
|
|
+ // Close the non-keep-alive connection after the write operation is done.
|
|
|
+ if (!keepAlive) {
|
|
|
+ ctx.write(response).addListener(ChannelFutureListener.CLOSE);
|
|
|
+ } else {
|
|
|
+ ctx.write(response, ctx.voidPromise());
|
|
|
+ }
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- @Override
|
|
|
- public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
|
|
- ctx.close();
|
|
|
- }
|
|
|
+ @Override
|
|
|
+ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
|
|
+ ctx.close();
|
|
|
+ }
|
|
|
|
|
|
- @Override
|
|
|
- public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
|
|
|
- ctx.flush();
|
|
|
- }
|
|
|
+ @Override
|
|
|
+ public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
|
|
|
+ ctx.flush();
|
|
|
+ }
|
|
|
}
|