diff --git a/example/pom.xml b/example/pom.xml
index c5c9fdce87..dde14f8226 100644
--- a/example/pom.xml
+++ b/example/pom.xml
@@ -52,6 +52,11 @@
netty-codec-http
${project.version}
+
+ ${project.groupId}
+ netty-codec-memcache
+ ${project.version}
+
${project.groupId}
netty-codec-http2
diff --git a/example/src/main/java/io/netty/example/memcache/binary/MemcacheClient.java b/example/src/main/java/io/netty/example/memcache/binary/MemcacheClient.java
new file mode 100644
index 0000000000..2a15e0e736
--- /dev/null
+++ b/example/src/main/java/io/netty/example/memcache/binary/MemcacheClient.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2014 The Netty Project
+ *
+ * The Netty Project licenses this file to you under the Apache License,
+ * version 2.0 (the "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+package io.netty.example.memcache.binary;
+
+import io.netty.bootstrap.Bootstrap;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.ChannelPipeline;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.channel.socket.nio.NioSocketChannel;
+import io.netty.handler.codec.memcache.binary.BinaryMemcacheClientCodec;
+import io.netty.handler.codec.memcache.binary.BinaryMemcacheObjectAggregator;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+
+/**
+ * Simple memcache client that demonstrates get and set commands against a memcache server.
+ */
+public class MemcacheClient {
+
+ private final String host;
+ private final int port;
+
+ public MemcacheClient(String host, int port) {
+ this.host = host;
+ this.port = port;
+ }
+
+ public void run() throws Exception {
+ EventLoopGroup group = new NioEventLoopGroup();
+ try {
+ Bootstrap b = new Bootstrap();
+ b.group(group)
+ .channel(NioSocketChannel.class)
+ .handler(new ChannelInitializer() {
+ @Override
+ protected void initChannel(SocketChannel ch) throws Exception {
+ ChannelPipeline p = ch.pipeline();
+ p.addLast(new BinaryMemcacheClientCodec());
+ p.addLast(new BinaryMemcacheObjectAggregator(Integer.MAX_VALUE));
+ p.addLast(new MemcacheClientHandler());
+ }
+ });
+
+ // Start the connection attempt.
+ Channel ch = b.connect(host, port).sync().channel();
+
+ // Read commands from the stdin.
+ System.out.println("Enter commands (quit to end)");
+ System.out.println("get ");
+ System.out.println("set ");
+ ChannelFuture lastWriteFuture = null;
+ BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
+ for (;;) {
+ String line = in.readLine();
+ if (line == null) {
+ break;
+ }
+ if ("quit".equals(line.toLowerCase())) {
+ ch.close().sync();
+ break;
+ }
+ // Sends the received line to the server.
+ lastWriteFuture = ch.writeAndFlush(line);
+ }
+
+ // Wait until all messages are flushed before closing the channel.
+ if (lastWriteFuture != null) {
+ lastWriteFuture.sync();
+ }
+ } finally {
+ group.shutdownGracefully();
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ // Print usage if no argument is specified.
+ if (args.length != 2) {
+ System.err.println(
+ "Usage: " + MemcacheClient.class.getSimpleName() +
+ " ");
+ return;
+ }
+
+ // Parse options.
+ String host = args[0];
+ int port = Integer.parseInt(args[1]);
+
+ new MemcacheClient(host, port).run();
+ }
+}
diff --git a/example/src/main/java/io/netty/example/memcache/binary/MemcacheClientHandler.java b/example/src/main/java/io/netty/example/memcache/binary/MemcacheClientHandler.java
new file mode 100644
index 0000000000..95d617f441
--- /dev/null
+++ b/example/src/main/java/io/netty/example/memcache/binary/MemcacheClientHandler.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2014 The Netty Project
+ *
+ * The Netty Project licenses this file to you under the Apache License,
+ * version 2.0 (the "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+package io.netty.example.memcache.binary;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import io.netty.channel.ChannelHandlerAdapter;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelPromise;
+import io.netty.handler.codec.memcache.binary.BinaryMemcacheOpcodes;
+import io.netty.handler.codec.memcache.binary.BinaryMemcacheRequest;
+import io.netty.handler.codec.memcache.binary.DefaultBinaryMemcacheRequest;
+import io.netty.handler.codec.memcache.binary.DefaultFullBinaryMemcacheRequest;
+import io.netty.handler.codec.memcache.binary.FullBinaryMemcacheResponse;
+import io.netty.util.CharsetUtil;
+
+public class MemcacheClientHandler extends ChannelHandlerAdapter {
+
+ /**
+ * Transforms basic string requests to binary memcache requests
+ */
+ @Override
+ public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
+ String command = (String) msg;
+ if (command.startsWith("get ")) {
+ String key = command.substring("get ".length());
+
+ BinaryMemcacheRequest req = new DefaultBinaryMemcacheRequest(key);
+ req.setOpcode(BinaryMemcacheOpcodes.GET);
+ req.setKeyLength((short) key.length());
+ req.setTotalBodyLength(key.length());
+
+ ctx.write(req, promise);
+ } else if (command.startsWith("set ")) {
+ String[] parts = command.split(" ", 3);
+ if (parts.length < 3) {
+ throw new IllegalArgumentException("Malformed Command: " + command);
+ }
+ String key = parts[1];
+ String value = parts[2];
+
+ ByteBuf content = Unpooled.wrappedBuffer(value.getBytes(CharsetUtil.UTF_8));
+ ByteBuf extras = ctx.alloc().buffer(8);
+
+ BinaryMemcacheRequest req = new DefaultFullBinaryMemcacheRequest(key, extras, content);
+ req.setOpcode(BinaryMemcacheOpcodes.SET);
+ req.setKeyLength((short) key.length());
+ req.setExtrasLength((byte) 8);
+ req.setTotalBodyLength(key.length() + 8 + value.length());
+
+ ctx.write(req, promise);
+ } else {
+ throw new IllegalStateException("Unknown Message: " + msg);
+ }
+ }
+
+ @Override
+ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
+ FullBinaryMemcacheResponse res = (FullBinaryMemcacheResponse) msg;
+ System.out.println(res.content().toString(CharsetUtil.UTF_8));
+ }
+
+ @Override
+ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
+ cause.printStackTrace();
+ ctx.close();
+ }
+}