Browse Source

Use Netty 4.0.14.Beta1

Norman Maurer 11 years ago
parent
commit
b26cdaaac3

+ 2 - 2
netty/README.md

@@ -8,7 +8,7 @@ This is the netty portion of a [benchmarking test suite](../) comparing a variet
 ## Versions
 
 * [Java OpenJDK 1.7.0_09](http://openjdk.java.net/)
-* [Netty 4.0.0.Beta2](http://netty.io/)
+* [Netty 4.0.14.Beta1](http://netty.io/)
 
 ## References
 * https://github.com/netty/netty/tree/master/example/src/main/java/io/netty/example/http/snoop
@@ -17,4 +17,4 @@ This is the netty portion of a [benchmarking test suite](../) comparing a variet
 
 ### JSON Encoding Test
 
-    http://localhost:8080/json
+    http://localhost:8080/json

+ 25 - 25
netty/pom.xml

@@ -10,36 +10,36 @@
 
   <dependencies>
     <dependency>
-    	<groupId>io.netty</groupId>
-    	<artifactId>netty-codec-http</artifactId>
-    	<version>4.0.0.CR7</version>
+      <groupId>io.netty</groupId>
+      <artifactId>netty-codec-http</artifactId>
+      <version>4.0.14.Beta1</version>
     </dependency>
-	 <dependency>
-		<groupId>com.fasterxml.jackson.core</groupId>
-		<artifactId>jackson-databind</artifactId>
-		<version>2.1.1</version>
-	</dependency>
     <dependency>
-        <groupId>org.javassist</groupId>
-        <artifactId>javassist</artifactId>
-        <version>3.18.0-GA</version>
+      <groupId>com.fasterxml.jackson.core</groupId>
+      <artifactId>jackson-databind</artifactId>
+      <version>2.1.1</version>
+    </dependency>
+    <dependency>
+      <groupId>org.javassist</groupId>
+      <artifactId>javassist</artifactId>
+      <version>3.18.0-GA</version>
     </dependency>
   </dependencies>
   
   <build>
     <plugins>
-			<plugin>
-				<inherited>true</inherited>
-				<groupId>org.apache.maven.plugins</groupId>
-				<artifactId>maven-compiler-plugin</artifactId>
-				<version>2.3.2</version>
-				<configuration>
-					<source>1.7</source>
-					<target>1.7</target>
-					<optimize>true</optimize>
-					<debug>false</debug>
-				</configuration>
-			</plugin>
+      <plugin>
+        <inherited>true</inherited>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <version>2.3.2</version>
+        <configuration>
+          <source>1.7</source>
+          <target>1.7</target>
+          <optimize>true</optimize>
+          <debug>false</debug>
+        </configuration>
+      </plugin>
       <plugin>
         <artifactId>maven-assembly-plugin</artifactId>
         <configuration>
@@ -62,6 +62,6 @@
           </execution>
         </executions>
       </plugin>
-       </plugins>
+    </plugins>
   </build>
-</project>
+</project>

+ 2 - 2
netty/setup.py

@@ -6,7 +6,7 @@ import os
 def start(args, logfile, errfile):
   try:
     subprocess.check_call("mvn clean compile assembly:single", shell=True, cwd="netty", stderr=errfile, stdout=logfile)
-    subprocess.Popen("java -Dio.netty.noResourceLeakDetection=true -jar netty-example-0.1-jar-with-dependencies.jar".rsplit(" "), cwd="netty/target", stderr=errfile, stdout=logfile)
+    subprocess.Popen("java -jar netty-example-0.1-jar-with-dependencies.jar".rsplit(" "), cwd="netty/target", stderr=errfile, stdout=logfile)
     return 0
   except subprocess.CalledProcessError:
     return 1
@@ -20,4 +20,4 @@ def stop(logfile, errfile):
       if 'netty-example' in line:
         pid = int(line.split(None, 2)[1])
         os.kill(pid, 9)
-  return 0
+  return 0

+ 78 - 91
netty/src/main/java/hello/HelloServerHandler.java

@@ -2,135 +2,122 @@ package hello;
 
 import io.netty.buffer.ByteBuf;
 import io.netty.buffer.Unpooled;
+
+import java.text.SimpleDateFormat;
+import java.util.*;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
+import com.fasterxml.jackson.databind.*;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelFuture;
 import io.netty.channel.ChannelFutureListener;
 import io.netty.channel.ChannelHandlerContext;
-import io.netty.channel.MessageList;
 import io.netty.channel.SimpleChannelInboundHandler;
-import io.netty.handler.codec.http.Cookie;
-import io.netty.handler.codec.http.CookieDecoder;
 import io.netty.handler.codec.http.DefaultFullHttpResponse;
 import io.netty.handler.codec.http.FullHttpResponse;
 import io.netty.handler.codec.http.HttpHeaders;
 import io.netty.handler.codec.http.HttpRequest;
-import io.netty.handler.codec.http.HttpResponse;
-import io.netty.handler.codec.http.ServerCookieEncoder;
-
-import java.util.Map;
-import java.util.HashMap;
-import java.util.Set;
-
-import java.io.*;
-
-import com.fasterxml.jackson.databind.*;
+import io.netty.handler.codec.http.HttpResponseStatus;
+import io.netty.handler.codec.http.HttpVersion;
 import io.netty.util.CharsetUtil;
 
-import static io.netty.handler.codec.http.HttpHeaders.Names.*;
-import static io.netty.handler.codec.http.HttpHeaders.*;
-import static io.netty.handler.codec.http.HttpResponseStatus.*;
-import static io.netty.handler.codec.http.HttpVersion.*;
 
-public class HelloServerHandler extends SimpleChannelInboundHandler<Object>{
+public class HelloServerHandler extends SimpleChannelInboundHandler<Object> {
+    private final SimpleDateFormat format = new SimpleDateFormat("E, dd MMM yyyy HH:mm:ss z");
+    private CharSequence date;
 
-    /** Buffer that stores the response content */
-    private static final ObjectMapper mapper = new ObjectMapper();
+    private static final ObjectMapper MAPPER = new ObjectMapper();
+    private final ByteBuf buffer = Unpooled.directBuffer().writeBytes("Hello, World!".getBytes(CharsetUtil.UTF_8));
+    private final CharSequence contentLength = HttpHeaders.newEntity(String.valueOf(buffer.readableBytes()));
 
-    private MessageList<Object> out;
+    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");
 
-    @Override
-    public void beginMessageReceived(ChannelHandlerContext ctx) throws Exception {
-        out = MessageList.newInstance();
-        super.beginMessageReceived(ctx);
-    }
+    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);
 
     @Override
-    public void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception {
+    public void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
         if (msg instanceof HttpRequest) {
             HttpRequest request = (HttpRequest) msg;
-
-            if (is100ContinueExpected(request)) {
-                send100Continue(out);
+            String uri = request.getUri();
+            switch (uri) {
+                case "/plaintext":
+                    writeResponse(ctx, request, buffer.duplicate().retain(), TYPE_PLAIN, contentLength);
+                    return;
+                case "/json":
+                    byte[] json = MAPPER.writeValueAsBytes(Collections.singletonMap("message", "Hello, World!"));
+                    writeResponse(ctx, request, ctx.alloc().buffer(json.length).writeBytes(json), TYPE_JSON,
+                            String.valueOf(json.length));
+                    return;
             }
-            ByteBuf buf = ctx.alloc().buffer();
-            if("/plaintext".equals(request.getUri())) {
-                buf.writeBytes("Hello, World!".getBytes(CharsetUtil.UTF_8));
-            } else {
-                Map<String, String> data = new HashMap<String, String>();
-                data.put("message", "Hello, world");
-
-                try
-                {
-                  buf.writeBytes(HelloServerHandler.mapper.writeValueAsBytes(data));
-                }
-                catch (IOException ex)
-                {
-                  // do nothing
-                }
-            }
-            writeResponse(ctx, request, buf, out);
+            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, MessageList<Object> out) {
+    private void writeResponse(ChannelHandlerContext ctx, HttpRequest request, ByteBuf buf,
+                               CharSequence contentType, CharSequence contentLength) {
         // Decide whether to close the connection or not.
-        boolean keepAlive = isKeepAlive(request);
+        boolean keepAlive = HttpHeaders.isKeepAlive(request);
         // Build the response object.
         FullHttpResponse response = new DefaultFullHttpResponse(
-                HTTP_1_1, OK, buf);
-
-        response.headers().set(CONTENT_TYPE, "text/plain; charset=UTF-8");
+                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);
 
         if (keepAlive) {
-            // Add 'Content-Length' header only for a keep-alive connection.
-            response.headers().set(CONTENT_LENGTH, response.content().readableBytes());
-            // Add keep alive header as per:
-            // - http://www.w3.org/Protocols/HTTP/1.1/draft-ietf-http-v11-spec-01.html#Connection
-            response.headers().set(CONNECTION, HttpHeaders.Values.KEEP_ALIVE);
-        }
-
-        // Encode the cookie.
-        String cookieString = request.headers().get(COOKIE);
-        if (cookieString != null) {
-            Set<Cookie> cookies = CookieDecoder.decode(cookieString);
-            if (!cookies.isEmpty()) {
-                // Reset the cookies if necessary.
-                for (Cookie cookie: cookies) {
-                    response.headers().add(SET_COOKIE, ServerCookieEncoder.encode(cookie));
-                }
-            }
-        } else {
-            // Browser sent no cookie. Add some.
-            response.headers().add(SET_COOKIE, ServerCookieEncoder.encode("key1", "value1"));
-            response.headers().add(SET_COOKIE, ServerCookieEncoder.encode("key2", "value2"));
+            headers.set(CONTENT_LENGTH_ENTITY, contentLength);
         }
 
-        // Write the response.
-        out.add(response);
-
         // Close the non-keep-alive connection after the write operation is done.
         if (!keepAlive) {
-            this.out = MessageList.newInstance();
-            ctx.write(out).addListener(ChannelFutureListener.CLOSE);
+            ctx.write(response).addListener(ChannelFutureListener.CLOSE);
+        } else {
+            ctx.write(response, ctx.voidPromise());
         }
     }
 
-    private void send100Continue(MessageList<Object> out) {
-        HttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, CONTINUE, Unpooled.EMPTY_BUFFER);
-        out.add(response);
+    @Override
+    public void exceptionCaught(
+            ChannelHandlerContext ctx, Throwable cause) throws Exception {
+        ctx.close();
     }
 
     @Override
-    public void endMessageReceived(ChannelHandlerContext ctx) throws Exception {
-        if (out != null) {
-            MessageList<Object> msgs = out;
-            this.out = null;
-            ctx.write(msgs);
-        }
+    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
+        ctx.flush();
     }
 
     @Override
-    public void exceptionCaught(
-            ChannelHandlerContext ctx, Throwable cause) throws Exception {
-        cause.printStackTrace();
-        ctx.close();
+    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
+        super.handlerRemoved(ctx);
+        buffer.release();
+    }
+
+    @Override
+    public void channelActive(ChannelHandlerContext ctx) throws Exception {
+        date = HttpHeaders.newEntity(format.format(new Date()));
+
+        Channel channel = ctx.channel();
+        final ScheduledFuture<?> future = channel.eventLoop().scheduleWithFixedDelay(new Runnable() {
+            @Override
+            public void run() {
+                date = HttpHeaders.newEntity(format.format(new Date()));
+            }
+        }, 1000, 1000, TimeUnit.MILLISECONDS);
+
+        channel.closeFuture().addListener(new ChannelFutureListener() {
+            @Override
+            public void operationComplete(ChannelFuture channelFuture) throws Exception {
+                future.cancel(false);
+            }
+        });
     }
 }

+ 2 - 13
netty/src/main/java/hello/HelloServerInitializer.java

@@ -9,20 +9,9 @@ import io.netty.handler.codec.http.HttpResponseEncoder;
 public class HelloServerInitializer extends ChannelInitializer<SocketChannel> {
     @Override
     public void initChannel(SocketChannel ch) throws Exception {
-        // Create a default pipeline implementation.
         ChannelPipeline p = ch.pipeline();
-
-        // Uncomment the following line if you want HTTPS
-        //SSLEngine engine = SecureChatSslContextFactory.getServerContext().createSSLEngine();
-        //engine.setUseClientMode(false);
-        //p.addLast("ssl", new SslHandler(engine));
-
-        p.addLast("decoder", new HttpRequestDecoder());
-        // Uncomment the following line if you don't want to handle HttpChunks.
-        //p.addLast("aggregator", new HttpObjectAggregator(1048576));
         p.addLast("encoder", new HttpResponseEncoder());
-        // Remove the following line if you don't want automatic content compression.
-        //p.addLast("deflater", new HttpContentCompressor());
+        p.addLast("decoder", new HttpRequestDecoder(4096, 8192, 8192, false));
         p.addLast("handler", new HelloServerHandler());
     }
-}
+}

+ 16 - 7
netty/src/main/java/hello/HelloWebServer.java

@@ -1,11 +1,19 @@
 package hello;
 
 import io.netty.bootstrap.ServerBootstrap;
+import io.netty.buffer.PooledByteBufAllocator;
 import io.netty.channel.Channel;
+import io.netty.channel.ChannelOption;
+import io.netty.channel.EventLoopGroup;
 import io.netty.channel.nio.NioEventLoopGroup;
 import io.netty.channel.socket.nio.NioServerSocketChannel;
+import io.netty.util.ResourceLeakDetector;
+
 
 public class HelloWebServer {
+    static {
+        ResourceLeakDetector.setEnabled(false);
+    }
 
     private final int port;
 
@@ -15,17 +23,18 @@ public class HelloWebServer {
 
     public void run() throws Exception {
         // Configure the server.
-        ServerBootstrap b = new ServerBootstrap();
-
+        EventLoopGroup group = new NioEventLoopGroup();
         try {
-            b.group(new NioEventLoopGroup(), new NioEventLoopGroup())
+            ServerBootstrap b = new ServerBootstrap();
+            b.group(group)
+             .childHandler(new HelloServerInitializer())
              .channel(NioServerSocketChannel.class)
-             .childHandler(new HelloServerInitializer());
-
+             .childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
+             
             Channel ch = b.bind(port).sync().channel();
             ch.closeFuture().sync();
         } finally {
-            b.shutdown();
+            group.shutdownGracefully().sync();
         }
     }
 
@@ -38,4 +47,4 @@ public class HelloWebServer {
         }
         new HelloWebServer(port).run();
     }
-}
+}