[infinispan-commits] Infinispan SVN: r1328 - in trunk/server/memcached/src: test/java/org/infinispan/server/memcached and 1 other directories.

infinispan-commits at lists.jboss.org infinispan-commits at lists.jboss.org
Mon Dec 28 06:34:16 EST 2009


Author: galder.zamarreno at jboss.com
Date: 2009-12-28 06:34:15 -0500 (Mon, 28 Dec 2009)
New Revision: 1328

Added:
   trunk/server/memcached/src/main/java/org/infinispan/server/memcached/AbstractVisitor.java
   trunk/server/memcached/src/main/java/org/infinispan/server/memcached/CallInterceptor.java
   trunk/server/memcached/src/main/java/org/infinispan/server/memcached/CommandInterceptor.java
   trunk/server/memcached/src/main/java/org/infinispan/server/memcached/InterceptorChain.java
   trunk/server/memcached/src/main/java/org/infinispan/server/memcached/InterceptorChainFactory.java
   trunk/server/memcached/src/main/java/org/infinispan/server/memcached/MemcachedStats.java
   trunk/server/memcached/src/main/java/org/infinispan/server/memcached/MemcachedStatsImpl.java
   trunk/server/memcached/src/main/java/org/infinispan/server/memcached/StatsCommand.java
   trunk/server/memcached/src/main/java/org/infinispan/server/memcached/StatsInterceptor.java
   trunk/server/memcached/src/main/java/org/infinispan/server/memcached/Visitor.java
   trunk/server/memcached/src/test/java/org/infinispan/server/memcached/StatsTest.java
   trunk/server/memcached/src/test/java/org/infinispan/server/memcached/test/
   trunk/server/memcached/src/test/java/org/infinispan/server/memcached/test/MemcachedTestingUtil.java
Modified:
   trunk/server/memcached/src/main/java/org/infinispan/server/memcached/AddCommand.java
   trunk/server/memcached/src/main/java/org/infinispan/server/memcached/AppendCommand.java
   trunk/server/memcached/src/main/java/org/infinispan/server/memcached/CasCommand.java
   trunk/server/memcached/src/main/java/org/infinispan/server/memcached/Command.java
   trunk/server/memcached/src/main/java/org/infinispan/server/memcached/CommandFactory.java
   trunk/server/memcached/src/main/java/org/infinispan/server/memcached/DecrementCommand.java
   trunk/server/memcached/src/main/java/org/infinispan/server/memcached/DeleteCommand.java
   trunk/server/memcached/src/main/java/org/infinispan/server/memcached/GetCommand.java
   trunk/server/memcached/src/main/java/org/infinispan/server/memcached/IncrementCommand.java
   trunk/server/memcached/src/main/java/org/infinispan/server/memcached/MemcachedTextServer.java
   trunk/server/memcached/src/main/java/org/infinispan/server/memcached/NumericCommand.java
   trunk/server/memcached/src/main/java/org/infinispan/server/memcached/PrependCommand.java
   trunk/server/memcached/src/main/java/org/infinispan/server/memcached/ReplaceCommand.java
   trunk/server/memcached/src/main/java/org/infinispan/server/memcached/Reply.java
   trunk/server/memcached/src/main/java/org/infinispan/server/memcached/RetrievalReply.java
   trunk/server/memcached/src/main/java/org/infinispan/server/memcached/SetCommand.java
   trunk/server/memcached/src/main/java/org/infinispan/server/memcached/TextCommandDecoder.java
   trunk/server/memcached/src/main/java/org/infinispan/server/memcached/TextCommandHandler.java
   trunk/server/memcached/src/main/java/org/infinispan/server/memcached/TextProtocolPipelineFactory.java
   trunk/server/memcached/src/test/java/org/infinispan/server/memcached/FunctionalTest.java
Log:
[ISPN-173] (Build memcached server module) Stats command completed.

Added: trunk/server/memcached/src/main/java/org/infinispan/server/memcached/AbstractVisitor.java
===================================================================
--- trunk/server/memcached/src/main/java/org/infinispan/server/memcached/AbstractVisitor.java	                        (rev 0)
+++ trunk/server/memcached/src/main/java/org/infinispan/server/memcached/AbstractVisitor.java	2009-12-28 11:34:15 UTC (rev 1328)
@@ -0,0 +1,98 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat, Inc. and/or its affiliates, and
+ * individual contributors as indicated by the @author tags. See the
+ * copyright.txt file in the distribution for a full listing of
+ * individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.infinispan.server.memcached;
+
+import org.jboss.netty.channel.Channel;
+
+/**
+ * CommandInterceptor.
+ * 
+ * @author Galder Zamarreño
+ * @since 4.0
+ */
+public abstract class AbstractVisitor implements Visitor {
+
+   @Override
+   public Object visitAdd(Channel ch, AddCommand command) throws Exception {
+      return handleDefault(ch, command);
+   }
+
+   @Override
+   public Object visitAppend(Channel ch, AppendCommand command) throws Exception {
+      return handleDefault(ch, command);
+   }
+
+   @Override
+   public Object visitCas(Channel ch, CasCommand command) throws Exception {
+      return handleDefault(ch, command);
+   }
+
+   @Override
+   public Object visitDecrement(Channel ch, DecrementCommand command) throws Exception {
+      return handleDefault(ch, command);
+   }
+
+   @Override
+   public Object visitDelete(Channel ch, DeleteCommand command) throws Exception {
+      return handleDefault(ch, command);
+   }
+
+   @Override
+   public Object visitGet(Channel ch, GetCommand command) throws Exception {
+      return handleDefault(ch, command);
+   }
+
+   @Override
+   public Object visitGets(Channel ch, GetsCommand command) throws Exception {
+      return handleDefault(ch, command);
+   }
+
+   @Override
+   public Object visitIncrement(Channel ch, IncrementCommand command) throws Exception {
+      return handleDefault(ch, command);
+   }
+
+   @Override
+   public Object visitPrepend(Channel ch, PrependCommand command) throws Exception {
+      return handleDefault(ch, command);
+   }
+
+   @Override
+   public Object visitReplace(Channel ch, ReplaceCommand command) throws Exception {
+      return handleDefault(ch, command);
+   }
+
+   @Override
+   public Object visitSet(Channel ch, SetCommand command) throws Exception {
+      return handleDefault(ch, command);
+   }
+
+   @Override
+   public Object visitStats(Channel ch, StatsCommand command) throws Exception {
+      return handleDefault(ch, command);
+   }
+
+   protected Object handleDefault(Channel ch, Command command) throws Exception {
+      return null;
+   }
+}

Modified: trunk/server/memcached/src/main/java/org/infinispan/server/memcached/AddCommand.java
===================================================================
--- trunk/server/memcached/src/main/java/org/infinispan/server/memcached/AddCommand.java	2009-12-24 14:05:03 UTC (rev 1327)
+++ trunk/server/memcached/src/main/java/org/infinispan/server/memcached/AddCommand.java	2009-12-28 11:34:15 UTC (rev 1328)
@@ -25,6 +25,7 @@
 import java.util.concurrent.TimeUnit;
 
 import org.infinispan.Cache;
+import org.jboss.netty.channel.Channel;
 
 /**
  * AddCommand.
@@ -39,6 +40,11 @@
    }
 
    @Override
+   public Object acceptVisitor(Channel ch, CommandInterceptor next) throws Exception {
+      return next.visitAdd(ch, this);
+   }
+
+   @Override
    protected Reply put(String key, int flags, byte[] data, long expiry) {
       Value value = new Value(flags, data);
       Object prev = cache.putIfAbsent(key, value, expiry, TimeUnit.MILLISECONDS);

Modified: trunk/server/memcached/src/main/java/org/infinispan/server/memcached/AppendCommand.java
===================================================================
--- trunk/server/memcached/src/main/java/org/infinispan/server/memcached/AppendCommand.java	2009-12-24 14:05:03 UTC (rev 1327)
+++ trunk/server/memcached/src/main/java/org/infinispan/server/memcached/AppendCommand.java	2009-12-28 11:34:15 UTC (rev 1328)
@@ -23,6 +23,7 @@
 package org.infinispan.server.memcached;
 
 import org.infinispan.Cache;
+import org.jboss.netty.channel.Channel;
 
 /**
  * AppendCommand.
@@ -41,6 +42,11 @@
    }
 
    @Override
+   public Object acceptVisitor(Channel ch, CommandInterceptor next) throws Exception {
+      return next.visitAppend(ch, this);
+   }
+
+   @Override
    protected Reply put(String key, int flags, byte[] data) {
       Value append = new Value(flags, data);
       Value current = (Value) cache.get(key);

Added: trunk/server/memcached/src/main/java/org/infinispan/server/memcached/CallInterceptor.java
===================================================================
--- trunk/server/memcached/src/main/java/org/infinispan/server/memcached/CallInterceptor.java	                        (rev 0)
+++ trunk/server/memcached/src/main/java/org/infinispan/server/memcached/CallInterceptor.java	2009-12-28 11:34:15 UTC (rev 1328)
@@ -0,0 +1,43 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat, Inc. and/or its affiliates, and
+ * individual contributors as indicated by the @author tags. See the
+ * copyright.txt file in the distribution for a full listing of
+ * individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.infinispan.server.memcached;
+
+import org.jboss.netty.channel.Channel;
+
+/**
+ * CallInterceptor.
+ * 
+ * @author Galder Zamarreño
+ * @since 4.0
+ */
+public class CallInterceptor extends CommandInterceptor {
+
+   public CallInterceptor(CommandInterceptor next) {
+      super(next);
+   }
+
+   @Override
+   protected Object handleDefault(Channel ch, Command command) throws Exception {
+      return command.perform(ch);
+   }
+}

Modified: trunk/server/memcached/src/main/java/org/infinispan/server/memcached/CasCommand.java
===================================================================
--- trunk/server/memcached/src/main/java/org/infinispan/server/memcached/CasCommand.java	2009-12-24 14:05:03 UTC (rev 1327)
+++ trunk/server/memcached/src/main/java/org/infinispan/server/memcached/CasCommand.java	2009-12-28 11:34:15 UTC (rev 1328)
@@ -25,6 +25,7 @@
 import java.io.IOException;
 
 import org.infinispan.Cache;
+import org.jboss.netty.channel.Channel;
 
 /**
  * CasCommand.
@@ -41,6 +42,11 @@
    }
 
    @Override
+   public Object acceptVisitor(Channel ch, CommandInterceptor next) throws Exception {
+      return next.visitCas(ch, this);
+   }
+
+   @Override
    public Command setData(byte[] data) throws IOException {
       return newCasCommand(cache, params, cas, data);
    }

Modified: trunk/server/memcached/src/main/java/org/infinispan/server/memcached/Command.java
===================================================================
--- trunk/server/memcached/src/main/java/org/infinispan/server/memcached/Command.java	2009-12-24 14:05:03 UTC (rev 1327)
+++ trunk/server/memcached/src/main/java/org/infinispan/server/memcached/Command.java	2009-12-28 11:34:15 UTC (rev 1328)
@@ -33,6 +33,8 @@
 public interface Command {
 
    Object perform(Channel ch) throws Exception;
+   
+   Object acceptVisitor(Channel ch, CommandInterceptor next) throws Exception;
 
    CommandType getType();
 }

Modified: trunk/server/memcached/src/main/java/org/infinispan/server/memcached/CommandFactory.java
===================================================================
--- trunk/server/memcached/src/main/java/org/infinispan/server/memcached/CommandFactory.java	2009-12-24 14:05:03 UTC (rev 1327)
+++ trunk/server/memcached/src/main/java/org/infinispan/server/memcached/CommandFactory.java	2009-12-28 11:34:15 UTC (rev 1328)
@@ -46,12 +46,11 @@
    private static final Log log = LogFactory.getLog(CommandFactory.class);
 
    private final Cache cache;
-   @Deprecated
-   private final BlockingQueue<DeleteDelayedEntry> queue;
+   private final InterceptorChain chain;
    
-   public CommandFactory(Cache cache, BlockingQueue<DeleteDelayedEntry> queue) {
+   public CommandFactory(Cache cache, InterceptorChain chain) {
       this.cache = cache;
-      this.queue = queue;
+      this.chain = chain;
    }
 
    public Command createCommand(String line) throws IOException {
@@ -83,13 +82,16 @@
             return RetrievalCommand.newRetrievalCommand(cache, type, new RetrievalParameters(keys));
          case DELETE:
             String delKey = getKey(args[1]);
-            return DeleteCommand.newDeleteCommand(cache, delKey, queue);
+            return DeleteCommand.newDeleteCommand(cache, delKey);
          case INCR:
          case DECR:
             String key = getKey(args[1]);
             // Value is defined as unsigned 64-integer (or simply unsigned long in java language)
+            // TODO: To simplify, could use long as long as the value was less than Long.MAX_VALUE
             BigInteger value = new BigInteger(args[2]);
             return NumericCommand.newNumericCommand(cache, type, key, value);
+         case STATS:
+            return StatsCommand.newStatsCommand(cache, type, chain);
          default:
             throw new NotImplementedException("Parsed type not implemented yet");
       }

Added: trunk/server/memcached/src/main/java/org/infinispan/server/memcached/CommandInterceptor.java
===================================================================
--- trunk/server/memcached/src/main/java/org/infinispan/server/memcached/CommandInterceptor.java	                        (rev 0)
+++ trunk/server/memcached/src/main/java/org/infinispan/server/memcached/CommandInterceptor.java	2009-12-28 11:34:15 UTC (rev 1328)
@@ -0,0 +1,53 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat, Inc. and/or its affiliates, and
+ * individual contributors as indicated by the @author tags. See the
+ * copyright.txt file in the distribution for a full listing of
+ * individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.infinispan.server.memcached;
+
+import org.jboss.netty.channel.Channel;
+
+
+/**
+ * CommandInterceptor.
+ * 
+ * @author Galder Zamarreño
+ * @since 4.0
+ */
+public class CommandInterceptor extends AbstractVisitor {
+   private final CommandInterceptor next;
+   
+   public CommandInterceptor(CommandInterceptor next) {
+      this.next = next;
+   }
+
+   public CommandInterceptor getNext() {
+      return next;
+   }
+
+   public final Object invokeNextInterceptor(Channel ch, Command command) throws Exception {
+      return command.acceptVisitor(ch, next);
+   }
+
+   protected Object handleDefault(Channel ch, Command command) throws Exception {
+      return invokeNextInterceptor(ch, command);
+   }
+
+}

Modified: trunk/server/memcached/src/main/java/org/infinispan/server/memcached/DecrementCommand.java
===================================================================
--- trunk/server/memcached/src/main/java/org/infinispan/server/memcached/DecrementCommand.java	2009-12-24 14:05:03 UTC (rev 1327)
+++ trunk/server/memcached/src/main/java/org/infinispan/server/memcached/DecrementCommand.java	2009-12-28 11:34:15 UTC (rev 1328)
@@ -27,6 +27,7 @@
 import org.infinispan.Cache;
 import org.infinispan.util.logging.Log;
 import org.infinispan.util.logging.LogFactory;
+import org.jboss.netty.channel.Channel;
 
 /**
  * DecrementCommand.
@@ -42,6 +43,11 @@
    }
 
    @Override
+   public Object acceptVisitor(Channel ch, CommandInterceptor next) throws Exception {
+      return next.visitDecrement(ch, this);
+   }
+
+   @Override
    protected BigInteger operate(BigInteger oldValue, BigInteger newValue) {
       if (log.isTraceEnabled()) log.trace("Substract {0} to {1}", newValue, oldValue);
       BigInteger b = oldValue.subtract(newValue);

Modified: trunk/server/memcached/src/main/java/org/infinispan/server/memcached/DeleteCommand.java
===================================================================
--- trunk/server/memcached/src/main/java/org/infinispan/server/memcached/DeleteCommand.java	2009-12-24 14:05:03 UTC (rev 1327)
+++ trunk/server/memcached/src/main/java/org/infinispan/server/memcached/DeleteCommand.java	2009-12-28 11:34:15 UTC (rev 1328)
@@ -41,18 +41,10 @@
 
    final Cache cache;
    final String key;
-   @Deprecated
-   /** @deprecated No longer in memcached spec: http://github.com/memcached/memcached/blob/master/doc/protocol.txt */
-   final long time;
-   @Deprecated
-   /** @deprecated No longer in memcached spec: http://github.com/memcached/memcached/blob/master/doc/protocol.txt */
-   final BlockingQueue<DeleteDelayedEntry> queue;
 
-   DeleteCommand(Cache cache, String key, long time, BlockingQueue<DeleteDelayedEntry> queue) {
+   DeleteCommand(Cache cache, String key, long time) {
       this.cache = cache;
       this.key = key;
-      this.time = time;
-      this.queue = queue;
    }
 
    @Override
@@ -61,16 +53,15 @@
    }
 
    @Override
+   public Object acceptVisitor(Channel ch, CommandInterceptor next) throws Exception {
+      return next.visitDelete(ch, this);
+   }
+
+   @Override
    public Object perform(Channel ch) throws Exception {
       Reply reply;
-      if (time > 0) {
-         DeleteDelayedEntry d = new DeleteDelayedEntry(key, time);
-         queue.offer(d);
-         reply = Reply.DELETED;
-      } else {
-         Object prev = cache.remove(key);
-         reply = reply(prev);
-      }
+      Object prev = cache.remove(key);
+      reply = reply(prev);
       ch.write(wrappedBuffer(wrappedBuffer(reply.bytes()), wrappedBuffer(CRLF)));
       return null;
    }
@@ -82,7 +73,7 @@
          return Reply.DELETED;
    }
 
-   public static DeleteCommand newDeleteCommand(Cache cache, String key, BlockingQueue<DeleteDelayedEntry> queue) {
-      return new DeleteCommand(cache, key, 0, queue);
+   public static DeleteCommand newDeleteCommand(Cache cache, String key) {
+      return new DeleteCommand(cache, key, 0);
    }
 }

Modified: trunk/server/memcached/src/main/java/org/infinispan/server/memcached/GetCommand.java
===================================================================
--- trunk/server/memcached/src/main/java/org/infinispan/server/memcached/GetCommand.java	2009-12-24 14:05:03 UTC (rev 1327)
+++ trunk/server/memcached/src/main/java/org/infinispan/server/memcached/GetCommand.java	2009-12-28 11:34:15 UTC (rev 1328)
@@ -28,8 +28,8 @@
 
 import static org.infinispan.server.memcached.TextProtocolUtil.CRLF;
 import static org.jboss.netty.buffer.ChannelBuffers.*;
-import static org.infinispan.server.memcached.RetrievalReply.VALUE;
-import static org.infinispan.server.memcached.RetrievalReply.END;
+import static org.infinispan.server.memcached.Reply.VALUE;
+import static org.infinispan.server.memcached.Reply.END;
 
 /**
  * GetCommand.
@@ -43,6 +43,10 @@
       super(cache, type, params);
    }
 
+   @Override
+   public Object acceptVisitor(Channel ch, CommandInterceptor next) throws Exception {
+      return next.visitGet(ch, this);
+   }
    
    @Override
    public Object perform(Channel ch) throws Exception {

Modified: trunk/server/memcached/src/main/java/org/infinispan/server/memcached/IncrementCommand.java
===================================================================
--- trunk/server/memcached/src/main/java/org/infinispan/server/memcached/IncrementCommand.java	2009-12-24 14:05:03 UTC (rev 1327)
+++ trunk/server/memcached/src/main/java/org/infinispan/server/memcached/IncrementCommand.java	2009-12-28 11:34:15 UTC (rev 1328)
@@ -27,6 +27,7 @@
 import org.infinispan.Cache;
 import org.infinispan.util.logging.Log;
 import org.infinispan.util.logging.LogFactory;
+import org.jboss.netty.channel.Channel;
 
 /**
  * IncrementCommand.
@@ -42,9 +43,15 @@
    }
 
    @Override
+   public Object acceptVisitor(Channel ch, CommandInterceptor next) throws Exception {
+      return next.visitIncrement(ch, this);
+   }
+
+   @Override
    protected BigInteger operate(BigInteger oldValue, BigInteger newValue) {
       if (log.isTraceEnabled()) log.trace("Increment {0} with {1}", oldValue, newValue);
       return oldValue.add(newValue);
    }
 
+
 }

Added: trunk/server/memcached/src/main/java/org/infinispan/server/memcached/InterceptorChain.java
===================================================================
--- trunk/server/memcached/src/main/java/org/infinispan/server/memcached/InterceptorChain.java	                        (rev 0)
+++ trunk/server/memcached/src/main/java/org/infinispan/server/memcached/InterceptorChain.java	2009-12-28 11:34:15 UTC (rev 1328)
@@ -0,0 +1,77 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat, Inc. and/or its affiliates, and
+ * individual contributors as indicated by the @author tags. See the
+ * copyright.txt file in the distribution for a full listing of
+ * individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.infinispan.server.memcached;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.jboss.netty.channel.Channel;
+
+/**
+ * InterceptorChain.
+ * 
+ * @author Galder Zamarreño
+ * @since 4.0
+ */
+public class InterceptorChain {
+
+   private final CommandInterceptor firstInChain;
+
+   public InterceptorChain(CommandInterceptor firstInChain) {
+      this.firstInChain = firstInChain;
+   }
+
+   public Object invoke(Channel ch, Command command) throws Exception {
+      return command.acceptVisitor(ch, firstInChain);
+   }
+
+   public List<CommandInterceptor> getInterceptorsWhichExtend(Class<? extends CommandInterceptor> interceptorClass) {
+      List<CommandInterceptor> result = new ArrayList<CommandInterceptor>();
+      for (CommandInterceptor interceptor : asList()) {
+         boolean isSubclass = interceptorClass.isAssignableFrom(interceptor.getClass());
+         if (isSubclass) {
+            result.add(interceptor);
+         }
+      }
+      return result;
+   }
+
+   /**
+    * Returns an unmofiable list with all the interceptors in sequence. If first in chain is null an empty list is
+    * returned.
+    */
+   public List<CommandInterceptor> asList() {
+      if (firstInChain == null) return Collections.emptyList();
+
+      List<CommandInterceptor> retval = new LinkedList<CommandInterceptor>();
+      CommandInterceptor tmp = firstInChain;
+      do {
+         retval.add(tmp);
+         tmp = tmp.getNext();
+      }
+      while (tmp != null);
+      return Collections.unmodifiableList(retval);
+   }
+}

Added: trunk/server/memcached/src/main/java/org/infinispan/server/memcached/InterceptorChainFactory.java
===================================================================
--- trunk/server/memcached/src/main/java/org/infinispan/server/memcached/InterceptorChainFactory.java	                        (rev 0)
+++ trunk/server/memcached/src/main/java/org/infinispan/server/memcached/InterceptorChainFactory.java	2009-12-28 11:34:15 UTC (rev 1328)
@@ -0,0 +1,57 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat, Inc. and/or its affiliates, and
+ * individual contributors as indicated by the @author tags. See the
+ * copyright.txt file in the distribution for a full listing of
+ * individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.infinispan.server.memcached;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.infinispan.Cache;
+
+/**
+ * InterceptorChainFactory.
+ * 
+ * @author Galder Zamarreño
+ * @since 4.0
+ */
+public class InterceptorChainFactory {
+   final boolean statsEnabled;
+   
+   private InterceptorChainFactory(Cache cache) {
+      statsEnabled = cache.getConfiguration().isExposeJmxStatistics();
+   }
+
+   public InterceptorChain buildInterceptorChain() {
+      CommandInterceptor first;
+      if (statsEnabled) {
+         first = new StatsInterceptor(new CallInterceptor(null));
+      } else {
+         first = new CallInterceptor(null);
+      }
+      
+      return new InterceptorChain(first);
+   }
+
+   public static InterceptorChainFactory getInstance(Cache cache) {
+      return new InterceptorChainFactory(cache);
+   }
+}

Added: trunk/server/memcached/src/main/java/org/infinispan/server/memcached/MemcachedStats.java
===================================================================
--- trunk/server/memcached/src/main/java/org/infinispan/server/memcached/MemcachedStats.java	                        (rev 0)
+++ trunk/server/memcached/src/main/java/org/infinispan/server/memcached/MemcachedStats.java	2009-12-28 11:34:15 UTC (rev 1328)
@@ -0,0 +1,49 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat, Inc. and/or its affiliates, and
+ * individual contributors as indicated by the @author tags. See the
+ * copyright.txt file in the distribution for a full listing of
+ * individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.infinispan.server.memcached;
+
+import org.infinispan.stats.Stats;
+
+/**
+ * MemcachedStats.
+ * 
+ * @author Galder Zamarreño
+ * @since 4.0
+ */
+public interface MemcachedStats {
+   
+   long getIncrMisses();
+
+   long getIncrHits();
+
+   long getDecrMisses();
+
+   long getDecrHits();
+
+   long getCasMisses();
+
+   long getCasHits();
+
+   long getCasBadval();
+
+}

Added: trunk/server/memcached/src/main/java/org/infinispan/server/memcached/MemcachedStatsImpl.java
===================================================================
--- trunk/server/memcached/src/main/java/org/infinispan/server/memcached/MemcachedStatsImpl.java	                        (rev 0)
+++ trunk/server/memcached/src/main/java/org/infinispan/server/memcached/MemcachedStatsImpl.java	2009-12-28 11:34:15 UTC (rev 1328)
@@ -0,0 +1,137 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat, Inc. and/or its affiliates, and
+ * individual contributors as indicated by the @author tags. See the
+ * copyright.txt file in the distribution for a full listing of
+ * individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.infinispan.server.memcached;
+
+import java.util.List;
+
+import org.infinispan.stats.Stats;
+import org.infinispan.server.memcached.InterceptorChain;
+
+/**
+ * MemcachedStats.
+ * 
+ * @author Galder Zamarreño
+ * @since 4.0
+ */
+public class MemcachedStatsImpl implements MemcachedStats, Stats {
+   final Stats cacheStats;
+   final long incrMisses;
+   final long incrHits;
+   final long decrMisses;
+   final long decrHits;
+   final long casMisses;
+   final long casHits;
+   final long casBadval;
+
+   MemcachedStatsImpl(Stats cacheStats, InterceptorChain chain) {
+      this.cacheStats = cacheStats;
+      List<CommandInterceptor> interceptors = chain.getInterceptorsWhichExtend(StatsInterceptor.class);
+      if (!interceptors.isEmpty()) {
+         StatsInterceptor statsInt = (StatsInterceptor) interceptors.get(0);
+         incrMisses = statsInt.getIncrMisses();
+         incrHits = statsInt.getIncrHits();
+         decrMisses = statsInt.getDecrMisses();
+         decrHits = statsInt.getDecrHits();
+         casMisses = statsInt.getCasMisses();
+         casHits = statsInt.getCasHits();
+         casBadval = statsInt.getCasBadval();
+      } else {
+         incrMisses = -1;
+         incrHits = -1;
+         decrMisses = -1;
+         decrHits = -1;
+         casMisses = -1;
+         casHits = -1;
+         casBadval = -1;
+      }
+   }
+
+   public long getCasBadval() {
+      return casBadval;
+   }
+
+   public long getCasHits() {
+      return casHits;
+   }
+
+   public long getCasMisses() {
+      return casMisses;
+   }
+
+   public long getDecrHits() {
+      return decrHits;
+   }
+
+   public long getDecrMisses() {
+      return decrMisses;
+   }
+
+   public long getIncrHits() {
+      return incrHits;
+   }
+
+   public long getIncrMisses() {
+      return incrMisses;
+   }
+
+   public int getCurrentNumberOfEntries() {
+      return cacheStats.getCurrentNumberOfEntries();
+   }
+
+   public long getEvictions() {
+      return cacheStats.getEvictions();
+   }
+
+   public long getHits() {
+      return cacheStats.getHits();
+   }
+
+   public long getMisses() {
+      return cacheStats.getMisses();
+   }
+
+   public long getRemoveHits() {
+      return cacheStats.getRemoveHits();
+   }
+
+   public long getRemoveMisses() {
+      return cacheStats.getRemoveMisses();
+   }
+
+   public long getRetrievals() {
+      return cacheStats.getRetrievals();
+   }
+
+   public long getStores() {
+      return cacheStats.getStores();
+   }
+
+   public long getTimeSinceStart() {
+      return cacheStats.getTimeSinceStart();
+   }
+
+   public long getTotalNumberOfEntries() {
+      return cacheStats.getTotalNumberOfEntries();
+   }
+   
+}

Modified: trunk/server/memcached/src/main/java/org/infinispan/server/memcached/MemcachedTextServer.java
===================================================================
--- trunk/server/memcached/src/main/java/org/infinispan/server/memcached/MemcachedTextServer.java	2009-12-24 14:05:03 UTC (rev 1327)
+++ trunk/server/memcached/src/main/java/org/infinispan/server/memcached/MemcachedTextServer.java	2009-12-28 11:34:15 UTC (rev 1328)
@@ -23,14 +23,10 @@
 package org.infinispan.server.memcached;
 
 import java.net.InetSocketAddress;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.DelayQueue;
-import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 
 import org.infinispan.Cache;
 import org.infinispan.manager.CacheManager;
-import org.infinispan.manager.DefaultCacheManager;
 import org.jboss.netty.bootstrap.ServerBootstrap;
 import org.jboss.netty.channel.ChannelFactory;
 import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
@@ -41,34 +37,32 @@
  * @author Galder Zamarreño
  * @since 4.0
  */
-class MemcachedTextServer {
-   final CacheManager manager;
-   @Deprecated
-   final ExecutorService delayedExecutor;
+public class MemcachedTextServer {
+   private final CacheManager manager;
+   private final int port;
    
-   MemcachedTextServer(CacheManager manager) {
+   public MemcachedTextServer(CacheManager manager, int port) {
       this.manager = manager;
-      this.delayedExecutor = Executors.newSingleThreadExecutor();
+      this.port = port;
    }
 
+   public int getPort() {
+      return port;
+   }
+
    public void start() {
       // Configure Infinispan Cache instance
       Cache cache = manager.getCache();
 
-      // Create delaye queue for delayed deletes and start thread
-      BlockingQueue<DeleteDelayedEntry> queue = new DelayQueue<DeleteDelayedEntry>();
-      DeleteDelayed runnable = new DeleteDelayed(cache, queue);
-      delayedExecutor.submit(runnable);
-
       // Configure the server.
       ChannelFactory factory = new NioServerSocketChannelFactory(Executors.newCachedThreadPool(), Executors.newCachedThreadPool());
       ServerBootstrap bootstrap = new ServerBootstrap(factory);
-      bootstrap.setPipelineFactory(new TextProtocolPipelineFactory(cache, queue));
-      bootstrap.bind(new InetSocketAddress(11211));
+      InterceptorChain chain = InterceptorChainFactory.getInstance(cache).buildInterceptorChain();
+      bootstrap.setPipelineFactory(new TextProtocolPipelineFactory(cache, chain));
+      bootstrap.bind(new InetSocketAddress(port));
    }
 
    public void stop() {
       manager.stop();
-      delayedExecutor.shutdown();
    }
 }

Modified: trunk/server/memcached/src/main/java/org/infinispan/server/memcached/NumericCommand.java
===================================================================
--- trunk/server/memcached/src/main/java/org/infinispan/server/memcached/NumericCommand.java	2009-12-24 14:05:03 UTC (rev 1327)
+++ trunk/server/memcached/src/main/java/org/infinispan/server/memcached/NumericCommand.java	2009-12-28 11:34:15 UTC (rev 1328)
@@ -73,10 +73,11 @@
          } else {
             throw new CacheException("Value modified since we retrieved from the cache, old value was " + oldBigInt);
          }
+         return curr;
       } else {
          ch.write(wrappedBuffer(wrappedBuffer(Reply.NOT_FOUND.bytes()), wrappedBuffer(CRLF)));
+         return null;
       }
-      return null;
    }
 
    protected abstract BigInteger operate(BigInteger oldValue, BigInteger newValue);

Modified: trunk/server/memcached/src/main/java/org/infinispan/server/memcached/PrependCommand.java
===================================================================
--- trunk/server/memcached/src/main/java/org/infinispan/server/memcached/PrependCommand.java	2009-12-24 14:05:03 UTC (rev 1327)
+++ trunk/server/memcached/src/main/java/org/infinispan/server/memcached/PrependCommand.java	2009-12-28 11:34:15 UTC (rev 1328)
@@ -23,6 +23,7 @@
 package org.infinispan.server.memcached;
 
 import org.infinispan.Cache;
+import org.jboss.netty.channel.Channel;
 
 /**
  * PrependCommand.
@@ -37,6 +38,11 @@
    }
 
    @Override
+   public Object acceptVisitor(Channel ch, CommandInterceptor next) throws Exception {
+      return next.visitPrepend(ch, this);
+   }
+
+   @Override
    protected byte[] concat(byte[] current, byte[] prepend) {
       return TextProtocolUtil.concat(prepend, current); 
    }

Modified: trunk/server/memcached/src/main/java/org/infinispan/server/memcached/ReplaceCommand.java
===================================================================
--- trunk/server/memcached/src/main/java/org/infinispan/server/memcached/ReplaceCommand.java	2009-12-24 14:05:03 UTC (rev 1327)
+++ trunk/server/memcached/src/main/java/org/infinispan/server/memcached/ReplaceCommand.java	2009-12-28 11:34:15 UTC (rev 1328)
@@ -25,6 +25,7 @@
 import java.util.concurrent.TimeUnit;
 
 import org.infinispan.Cache;
+import org.jboss.netty.channel.Channel;
 
 /**
  * ReplaceCommand.
@@ -39,6 +40,11 @@
    }
 
    @Override
+   public Object acceptVisitor(Channel ch, CommandInterceptor next) throws Exception {
+      return next.visitReplace(ch, this);
+   }
+
+   @Override
    protected Reply put(String key, int flags, byte[] data, long expiry) {
       Value value = new Value(flags, data);
       Object prev = cache.replace(params.key, value, expiry, TimeUnit.MILLISECONDS);

Modified: trunk/server/memcached/src/main/java/org/infinispan/server/memcached/Reply.java
===================================================================
--- trunk/server/memcached/src/main/java/org/infinispan/server/memcached/Reply.java	2009-12-24 14:05:03 UTC (rev 1327)
+++ trunk/server/memcached/src/main/java/org/infinispan/server/memcached/Reply.java	2009-12-28 11:34:15 UTC (rev 1328)
@@ -29,7 +29,7 @@
  * @since 4.0
  */
 public enum Reply {
-   STORED, NOT_STORED, EXISTS, NOT_FOUND, DELETED,
+   STORED, NOT_STORED, EXISTS, NOT_FOUND, DELETED, STAT, VALUE, END,
    ERROR, CLIENT_ERROR, SERVER_ERROR;
    
    public byte[] bytes() {

Modified: trunk/server/memcached/src/main/java/org/infinispan/server/memcached/RetrievalReply.java
===================================================================
--- trunk/server/memcached/src/main/java/org/infinispan/server/memcached/RetrievalReply.java	2009-12-24 14:05:03 UTC (rev 1327)
+++ trunk/server/memcached/src/main/java/org/infinispan/server/memcached/RetrievalReply.java	2009-12-28 11:34:15 UTC (rev 1328)
@@ -29,5 +29,5 @@
  * @since 4.0
  */
 public enum RetrievalReply {
-   VALUE, END;
+   , ;
 }

Modified: trunk/server/memcached/src/main/java/org/infinispan/server/memcached/SetCommand.java
===================================================================
--- trunk/server/memcached/src/main/java/org/infinispan/server/memcached/SetCommand.java	2009-12-24 14:05:03 UTC (rev 1327)
+++ trunk/server/memcached/src/main/java/org/infinispan/server/memcached/SetCommand.java	2009-12-28 11:34:15 UTC (rev 1328)
@@ -48,6 +48,11 @@
    }
 
    @Override
+   public Object acceptVisitor(Channel ch, CommandInterceptor next) throws Exception {
+      return next.visitSet(ch, this);
+   }
+
+   @Override
    public Object perform(Channel ch) throws Exception {
       Reply reply;
       try {
@@ -79,7 +84,7 @@
          reply = Reply.NOT_STORED;
       }
       ch.write(wrappedBuffer(wrappedBuffer(reply.bytes()), wrappedBuffer(CRLF)));
-      return null;
+      return reply;
    }
 
    protected Reply put(String key, int flags, byte[] data) {
@@ -95,4 +100,7 @@
    private Reply reply() {
       return Reply.STORED;
    }
+
+
+
 }

Added: trunk/server/memcached/src/main/java/org/infinispan/server/memcached/StatsCommand.java
===================================================================
--- trunk/server/memcached/src/main/java/org/infinispan/server/memcached/StatsCommand.java	                        (rev 0)
+++ trunk/server/memcached/src/main/java/org/infinispan/server/memcached/StatsCommand.java	2009-12-28 11:34:15 UTC (rev 1328)
@@ -0,0 +1,119 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat, Inc. and/or its affiliates, and
+ * individual contributors as indicated by the @author tags. See the
+ * copyright.txt file in the distribution for a full listing of
+ * individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.infinispan.server.memcached;
+
+import static org.infinispan.server.memcached.Reply.END;
+import static org.infinispan.server.memcached.Reply.STAT;
+import static org.infinispan.server.memcached.TextProtocolUtil.CRLF;
+import static org.jboss.netty.buffer.ChannelBuffers.wrappedBuffer;
+
+import java.util.concurrent.TimeUnit;
+
+import org.infinispan.Cache;
+import org.jboss.netty.channel.Channel;
+
+/**
+ * StatsCommand.
+ * 
+ * @author Galder Zamarreño
+ * @since 4.0
+ */
+public class StatsCommand implements Command {
+   final Cache cache;
+   private final CommandType type;
+   final InterceptorChain chain;
+
+   StatsCommand(Cache cache, CommandType type, InterceptorChain chain) {
+      this.cache = cache;
+      this.type = type;
+      this.chain = chain;
+   }
+
+   @Override
+   public CommandType getType() {
+      return CommandType.STATS;
+   }
+
+   @Override
+   public Object acceptVisitor(Channel ch, CommandInterceptor next) throws Exception {
+      return next.visitStats(ch, this);
+   }
+
+   @Override
+   public Object perform(Channel ch) throws Exception {
+      MemcachedStatsImpl stats = new MemcachedStatsImpl(cache.getAdvancedCache().getStats(), chain);
+      
+      StringBuilder sb = new StringBuilder();
+      writeStat("pid", 0, sb, ch); // Unsupported
+      writeStat("uptime", stats.getTimeSinceStart(), sb, ch);
+      writeStat("time", TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()), sb, ch);
+      writeStat("version", cache.getVersion(), sb, ch);
+      writeStat("pointer_size", 0, sb, ch); // Unsupported
+      writeStat("rusage_user", 0, sb, ch); // Unsupported
+      writeStat("rusage_system", 0, sb, ch); // Unsupported
+      writeStat("curr_items", stats.getCurrentNumberOfEntries(), sb, ch);
+      writeStat("total_items", stats.getTotalNumberOfEntries(), sb, ch);
+      writeStat("bytes", 0, sb, ch); // Unsupported
+      writeStat("curr_connections", 0, sb, ch); // TODO: Through netty?
+      writeStat("total_connections", 0, sb, ch); // TODO: Through netty?
+      writeStat("connection_structures", 0, sb, ch); // Unsupported
+      writeStat("cmd_get", stats.getRetrievals(), sb, ch);
+      writeStat("cmd_set", stats.getStores(), sb, ch);
+      writeStat("get_hits", stats.getHits(), sb, ch);
+      writeStat("get_misses", stats.getMisses(), sb, ch);
+      writeStat("delete_misses", stats.getRemoveMisses(), sb, ch);
+      writeStat("delete_hits", stats.getRemoveHits(), sb, ch);
+      writeStat("incr_misses", stats.getIncrMisses(), sb, ch);
+      writeStat("incr_hits", stats.getIncrHits(), sb, ch);
+      writeStat("decr_misses", stats.getDecrMisses(), sb, ch);
+      writeStat("decr_hits", stats.getDecrHits(), sb, ch);
+      writeStat("cas_misses", stats.getCasMisses(), sb, ch);
+      writeStat("cas_hits", stats.getCasHits(), sb, ch);
+      writeStat("cas_badval", stats.getCasBadval(), sb, ch);
+      writeStat("auth_cmds", 0, sb, ch);  // Unsupported
+      writeStat("auth_errors", 0, sb, ch); // Unsupported
+      //TODO: Evictions are measure by evict calls, but not by nodes are that 
+      //      are expired after the entry's lifespan has expired.
+      writeStat("evictions", stats.getEvictions(), sb, ch);
+      writeStat("bytes_read", 0, sb, ch); // TODO: Through netty?
+      writeStat("bytes_written", 0, sb, ch); // TODO: Through netty?
+      writeStat("limit_maxbytes", 0, sb, ch); // Unsupported
+      writeStat("threads", 0, sb, ch); // TODO: Through netty?
+      writeStat("conn_yields", 0, sb, ch); // Unsupported
+      
+      ch.write(wrappedBuffer(wrappedBuffer(END.toString().getBytes()), wrappedBuffer(CRLF)));
+      
+      return null;
+   }
+
+   private void writeStat(String stat, Object value, StringBuilder sb, Channel ch) {
+      sb.append(STAT).append(' ').append(stat).append(' ').append(value);
+      ch.write(wrappedBuffer(wrappedBuffer(sb.toString().getBytes()), wrappedBuffer(CRLF)));
+      sb.setLength(0);
+   }
+
+   public static Command newStatsCommand(Cache cache, CommandType type, InterceptorChain chain) {
+      return new StatsCommand(cache, type, chain);
+   }
+
+}

Added: trunk/server/memcached/src/main/java/org/infinispan/server/memcached/StatsInterceptor.java
===================================================================
--- trunk/server/memcached/src/main/java/org/infinispan/server/memcached/StatsInterceptor.java	                        (rev 0)
+++ trunk/server/memcached/src/main/java/org/infinispan/server/memcached/StatsInterceptor.java	2009-12-28 11:34:15 UTC (rev 1328)
@@ -0,0 +1,120 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat, Inc. and/or its affiliates, and
+ * individual contributors as indicated by the @author tags. See the
+ * copyright.txt file in the distribution for a full listing of
+ * individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.infinispan.server.memcached;
+
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.jboss.netty.channel.Channel;
+
+/**
+ * StatsInterceptor.
+ * 
+ * @author Galder Zamarreño
+ * @since 4.0
+ */
+public class StatsInterceptor extends CommandInterceptor implements MemcachedStats {
+   private final AtomicLong incrMisses = new AtomicLong(0);
+   private final AtomicLong incrHits = new AtomicLong(0);
+   private final AtomicLong decrMisses = new AtomicLong(0);
+   private final AtomicLong decrHits = new AtomicLong(0);
+   private final AtomicLong casMisses = new AtomicLong(0);
+   private final AtomicLong casHits = new AtomicLong(0);
+   private final AtomicLong casBadval = new AtomicLong(0);
+
+   public StatsInterceptor(CommandInterceptor next) {
+      super(next);
+   }
+
+   @Override
+   public Object visitIncrement(Channel ch, IncrementCommand command) throws Exception {
+      Object ret = invokeNextInterceptor(ch, command);
+      if (ret != null)
+         incrHits.incrementAndGet();
+      else
+         incrMisses.incrementAndGet();
+      return ret;
+   }
+
+   @Override
+   public Object visitDecrement(Channel ch, DecrementCommand command) throws Exception {
+      Object ret = invokeNextInterceptor(ch, command);
+      if (ret != null)
+         decrHits.incrementAndGet();
+      else
+         decrMisses.incrementAndGet();
+      return ret;
+   }
+
+   @Override
+   public Object visitCas(Channel ch, CasCommand command) throws Exception {
+      Reply ret = (Reply) invokeNextInterceptor(ch, command);
+      switch(ret) {
+         case STORED:
+            casHits.incrementAndGet();
+            break;
+         case NOT_FOUND:
+            casMisses.incrementAndGet();
+            break;
+         case EXISTS:
+            casBadval.incrementAndGet();
+            break;
+      }
+      return ret;
+   }
+
+   @Override
+   public long getIncrHits() {
+      return incrHits.get();
+   }
+
+   @Override
+   public long getIncrMisses() {
+      return incrMisses.get();
+   }
+
+   @Override
+   public long getDecrHits() {
+      return decrHits.get();
+   }
+
+   @Override
+   public long getDecrMisses() {
+      return decrMisses.get();
+   }
+
+   @Override
+   public long getCasBadval() {
+      return casBadval.get();
+   }
+
+   @Override
+   public long getCasHits() {
+      return casHits.get();
+   }
+
+   @Override
+   public long getCasMisses() {
+      return casMisses.get();
+   }
+
+}

Modified: trunk/server/memcached/src/main/java/org/infinispan/server/memcached/TextCommandDecoder.java
===================================================================
--- trunk/server/memcached/src/main/java/org/infinispan/server/memcached/TextCommandDecoder.java	2009-12-24 14:05:03 UTC (rev 1327)
+++ trunk/server/memcached/src/main/java/org/infinispan/server/memcached/TextCommandDecoder.java	2009-12-28 11:34:15 UTC (rev 1328)
@@ -55,9 +55,9 @@
       READ_COMMAND, READ_UNSTRUCTURED_DATA;
    }
 
-   TextCommandDecoder(Cache cache, BlockingQueue<DeleteDelayedEntry> queue) {
+   TextCommandDecoder(Cache cache, InterceptorChain chain) {
       super(State.READ_COMMAND, true);
-      factory = new CommandFactory(cache, queue);
+      factory = new CommandFactory(cache, chain);
    }
 
    @Override

Modified: trunk/server/memcached/src/main/java/org/infinispan/server/memcached/TextCommandHandler.java
===================================================================
--- trunk/server/memcached/src/main/java/org/infinispan/server/memcached/TextCommandHandler.java	2009-12-24 14:05:03 UTC (rev 1327)
+++ trunk/server/memcached/src/main/java/org/infinispan/server/memcached/TextCommandHandler.java	2009-12-28 11:34:15 UTC (rev 1328)
@@ -22,9 +22,7 @@
  */
 package org.infinispan.server.memcached;
 
-import org.jboss.netty.buffer.ChannelBuffer;
-import org.jboss.netty.buffer.ChannelBuffers;
-import org.jboss.netty.channel.Channel;
+import org.infinispan.Cache;
 import org.jboss.netty.channel.ChannelHandlerContext;
 import org.jboss.netty.channel.ChannelPipelineCoverage;
 import org.jboss.netty.channel.MessageEvent;
@@ -38,18 +36,19 @@
  */
 @ChannelPipelineCoverage("one")
 class TextCommandHandler extends SimpleChannelUpstreamHandler {
+   final Cache cache;
+   final InterceptorChain chain;
 
+   TextCommandHandler(Cache cache, InterceptorChain chain) {
+      this.cache = cache;
+      this.chain = chain;
+   }
+
    @Override
    public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
-      Command c = (Command) e.getMessage();
-      c.perform(ctx.getChannel());
-//      Channel ch = ctx.getChannel();
-//      
-//      byte[] bytes = ret.toString().getBytes();
-//      ChannelBuffer buffer = ChannelBuffers.buffer(bytes.length);
-//      buffer.writeBytes(bytes);
-//      
-//      ch.write(buffer);
+      chain.invoke(ctx.getChannel(), (Command) e.getMessage());
+//      Command c = (Command) e.getMessage();
+//      c.perform(ctx.getChannel());
    }
 
    

Modified: trunk/server/memcached/src/main/java/org/infinispan/server/memcached/TextProtocolPipelineFactory.java
===================================================================
--- trunk/server/memcached/src/main/java/org/infinispan/server/memcached/TextProtocolPipelineFactory.java	2009-12-24 14:05:03 UTC (rev 1327)
+++ trunk/server/memcached/src/main/java/org/infinispan/server/memcached/TextProtocolPipelineFactory.java	2009-12-28 11:34:15 UTC (rev 1328)
@@ -47,14 +47,13 @@
 //   }
 
 //   private final Cache cache;
-//   private final BlockingQueue<DelayedDeleteEntry> queue;
    
    private final ReplayingDecoder<TextCommandDecoder.State> decoder;
    private final ChannelHandler handler;
 
-   public TextProtocolPipelineFactory(Cache cache, BlockingQueue<DeleteDelayedEntry> queue) {
-      this.decoder = new TextCommandDecoder(cache, queue);
-      this.handler = new TextCommandHandler();
+   public TextProtocolPipelineFactory(Cache cache, InterceptorChain chain) {
+      this.decoder = new TextCommandDecoder(cache, chain);
+      this.handler = new TextCommandHandler(cache, chain);
    }
 
    @Override

Added: trunk/server/memcached/src/main/java/org/infinispan/server/memcached/Visitor.java
===================================================================
--- trunk/server/memcached/src/main/java/org/infinispan/server/memcached/Visitor.java	                        (rev 0)
+++ trunk/server/memcached/src/main/java/org/infinispan/server/memcached/Visitor.java	2009-12-28 11:34:15 UTC (rev 1328)
@@ -0,0 +1,49 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat, Inc. and/or its affiliates, and
+ * individual contributors as indicated by the @author tags. See the
+ * copyright.txt file in the distribution for a full listing of
+ * individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.infinispan.server.memcached;
+
+import org.jboss.netty.channel.Channel;
+
+/**
+ * CommandInterceptor.
+ * 
+ * @author Galder Zamarreño
+ * @since 4.0
+ */
+public interface Visitor {
+   Object visitSet(Channel ch, SetCommand command) throws Exception;
+   Object visitAdd(Channel ch, AddCommand command) throws Exception;
+   Object visitReplace(Channel ch, ReplaceCommand command) throws Exception;
+   Object visitAppend(Channel ch, AppendCommand command) throws Exception;
+   Object visitPrepend(Channel ch, PrependCommand command) throws Exception;
+   Object visitCas(Channel ch, CasCommand command) throws Exception;
+   Object visitGet(Channel ch, GetCommand command) throws Exception;
+   Object visitGets(Channel ch, GetsCommand command) throws Exception;
+   Object visitDelete(Channel ch, DeleteCommand command) throws Exception;
+   Object visitIncrement(Channel ch, IncrementCommand command) throws Exception;
+   Object visitDecrement(Channel ch, DecrementCommand command) throws Exception;
+   Object visitStats(Channel ch, StatsCommand command) throws Exception;
+///   Object visitFlushAll(Channel ch, FlushAllCommand command);
+//   Object visitVersion(Channel ch, VersionCommand command);
+//   Object visitQuit(Channel ch, QuitCommand command);
+}

Modified: trunk/server/memcached/src/test/java/org/infinispan/server/memcached/FunctionalTest.java
===================================================================
--- trunk/server/memcached/src/test/java/org/infinispan/server/memcached/FunctionalTest.java	2009-12-24 14:05:03 UTC (rev 1327)
+++ trunk/server/memcached/src/test/java/org/infinispan/server/memcached/FunctionalTest.java	2009-12-28 11:34:15 UTC (rev 1328)
@@ -23,7 +23,6 @@
 package org.infinispan.server.memcached;
 
 import java.lang.reflect.Method;
-import java.net.InetSocketAddress;
 import java.util.Arrays;
 import java.util.Map;
 import java.util.concurrent.Future;
@@ -31,17 +30,17 @@
 
 import net.spy.memcached.CASResponse;
 import net.spy.memcached.CASValue;
-import net.spy.memcached.DefaultConnectionFactory;
 import net.spy.memcached.MemcachedClient;
 
 import org.infinispan.manager.CacheManager;
+import org.infinispan.server.memcached.test.MemcachedTestingUtil;
 import org.infinispan.test.SingleCacheManagerTest;
-import org.infinispan.test.TestingUtil;
-import org.infinispan.test.AbstractCacheTest.CleanupPhase;
 import org.infinispan.test.fwk.TestCacheManagerFactory;
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.Test;
 
+import static org.infinispan.server.memcached.test.MemcachedTestingUtil.*;
+
 /**
  * FunctionalTest.
  * 
@@ -50,23 +49,15 @@
  */
 @Test(groups = "functional", testName = "server.memcached.FunctionalTest")
 public class FunctionalTest extends SingleCacheManagerTest {
-   private MemcachedClient client;
-   private MemcachedTextServer server;
+   MemcachedClient client;
+   MemcachedTextServer server;
 
    @Override
    protected CacheManager createCacheManager() throws Exception {
       cacheManager = TestCacheManagerFactory.createLocalCacheManager();
-      server = new MemcachedTextServer(cacheManager);
+      server = MemcachedTestingUtil.createMemcachedTextServer(cacheManager);
       server.start();
-      DefaultConnectionFactory d = new DefaultConnectionFactory() {
-         @Override
-         public long getOperationTimeout() {
-            return 360000;
-            // return 5000;
-         }
-      };
-      
-      client = new MemcachedClient(d, Arrays.asList(new InetSocketAddress[]{new InetSocketAddress(11211)}));
+      client = createMemcachedClient(5000, server.getPort());
       return cacheManager;
    }
 
@@ -331,20 +322,4 @@
       assert 0 ==  newValue : "Unexpected result: " + newValue;
    }
 
-   private String k(Method method, String prefix) {
-      return prefix + method.getName();
-   }
-
-   private Object v(Method method, String prefix) {
-      return prefix  + method.getName();
-   }
-
-   private String k(Method method) {
-      return k(method, "k-");
-   }
-
-   private Object v(Method method) {
-      return v(method, "v-");
-   }
-
 }

Added: trunk/server/memcached/src/test/java/org/infinispan/server/memcached/StatsTest.java
===================================================================
--- trunk/server/memcached/src/test/java/org/infinispan/server/memcached/StatsTest.java	                        (rev 0)
+++ trunk/server/memcached/src/test/java/org/infinispan/server/memcached/StatsTest.java	2009-12-28 11:34:15 UTC (rev 1328)
@@ -0,0 +1,227 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat, Inc. and/or its affiliates, and
+ * individual contributors as indicated by the @author tags. See the
+ * copyright.txt file in the distribution for a full listing of
+ * individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.infinispan.server.memcached;
+
+import java.lang.reflect.Method;
+import java.net.SocketAddress;
+import java.util.Map;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+
+import net.spy.memcached.CASValue;
+import net.spy.memcached.MemcachedClient;
+
+import org.infinispan.Version;
+import org.infinispan.manager.CacheManager;
+import org.infinispan.server.memcached.test.MemcachedTestingUtil;
+import org.infinispan.test.SingleCacheManagerTest;
+import org.infinispan.test.TestingUtil;
+import org.infinispan.test.fwk.TestCacheManagerFactory;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.Test;
+
+import static org.infinispan.server.memcached.test.MemcachedTestingUtil.*;
+
+/**
+ * StatsTest.
+ * 
+ * @author Galder Zamarreño
+ * @since 4.0
+ */
+ at Test(groups = "functional", testName = "server.memcached.StatsTest")
+public class StatsTest extends SingleCacheManagerTest {
+   static final String JMX_DOMAIN = StatsTest.class.getSimpleName();
+   MemcachedClient client;
+   MemcachedTextServer server;
+
+   @Override
+   protected CacheManager createCacheManager() throws Exception {
+      cacheManager = TestCacheManagerFactory.createJmxEnabledCacheManager(JMX_DOMAIN);
+      server = MemcachedTestingUtil.createMemcachedTextServer(cacheManager);
+      server.start();
+      client = createMemcachedClient(5000, server.getPort());
+      return cacheManager;
+   }
+
+   @AfterClass(alwaysRun=true)
+   protected void destroyAfterClass() {
+      server.stop();
+   }
+
+   public void testUnsupportedStats(Method m) throws Exception {
+      Map<String, String> stats = getStats();
+      assert "0".equals(stats.get("pid"));
+      assert "0".equals(stats.get("pointer_size"));
+      assert "0".equals(stats.get("rusage_user"));
+      assert "0".equals(stats.get("rusage_system"));
+      assert "0".equals(stats.get("bytes"));
+      assert "0".equals(stats.get("connection_structures"));
+      assert "0".equals(stats.get("auth_cmds"));
+      assert "0".equals(stats.get("auth_errors"));
+      assert "0".equals(stats.get("limit_maxbytes"));
+      assert "0".equals(stats.get("conn_yields"));
+   }
+
+   public void testUncomparableStats(Method m) throws Exception {
+      TestingUtil.sleepThread(TimeUnit.SECONDS.toMillis(1));
+      Map<String, String> stats = getStats();
+      assert !"0".equals(stats.get("uptime"));
+      assert !"0".equals(stats.get("time"));
+      assert !stats.get("uptime").equals(stats.get("time"));
+   }
+
+   public void testStaticStats(Method m) throws Exception {
+      Map<String, String> stats = getStats();
+      assert Version.version.equals(stats.get("version"));
+   }
+
+   public void testTodoStats() throws Exception {
+      Map<String, String> stats = getStats();
+      assert "0".equals(stats.get("curr_connections"));
+      assert "0".equals(stats.get("total_connections"));
+      assert "0".equals(stats.get("bytes_read"));
+      assert "0".equals(stats.get("bytes_written"));
+      assert "0".equals(stats.get("threads"));
+   }
+
+   public void testStats(Method m) throws Exception {
+      Map<String, String> stats = getStats();
+      assert "0".equals(stats.get("cmd_set"));
+      assert "0".equals(stats.get("cmd_get"));
+      assert "0".equals(stats.get("get_hits"));
+      assert "0".equals(stats.get("get_misses"));
+      assert "0".equals(stats.get("delete_hits"));
+      assert "0".equals(stats.get("delete_misses"));
+      assert "0".equals(stats.get("curr_items"));
+      assert "0".equals(stats.get("total_items"));
+      assert "0".equals(stats.get("incr_misses"));
+      assert "0".equals(stats.get("incr_hits"));
+      assert "0".equals(stats.get("decr_misses"));
+      assert "0".equals(stats.get("decr_hits"));
+      assert "0".equals(stats.get("cas_misses"));
+      assert "0".equals(stats.get("cas_hits"));
+      assert "0".equals(stats.get("cas_badval"));
+
+      Future<Boolean> f = client.set(k(m), 0, v(m));
+      assert f.get(5, TimeUnit.SECONDS);
+      assert v(m).equals(client.get(k(m)));
+
+      f = client.set(k(m, "k1-"), 0, v(m, "v1-"));
+      assert f.get(5, TimeUnit.SECONDS);
+      assert v(m, "v1-").equals(client.get(k(m, "k1-")));
+
+      stats = getStats();
+      assert "2".equals(stats.get("cmd_set"));
+      assert "2".equals(stats.get("cmd_get"));
+      assert "2".equals(stats.get("get_hits"));
+      assert "0".equals(stats.get("get_misses"));
+      assert "0".equals(stats.get("delete_hits"));
+      assert "0".equals(stats.get("delete_misses"));
+      assert "2".equals(stats.get("curr_items"));
+      assert "2".equals(stats.get("total_items"));
+
+      f = client.delete(k(m, "k1-"));
+      assert f.get(5, TimeUnit.SECONDS);
+      stats = getStats();
+      assert "1".equals(stats.get("curr_items"));
+      assert "2".equals(stats.get("total_items"));
+      assert "1".equals(stats.get("delete_hits"));
+      assert "0".equals(stats.get("delete_misses"));
+
+      assert null == client.get(k(m, "k99-"));
+      stats = getStats();
+      assert "2".equals(stats.get("get_hits"));
+      assert "1".equals(stats.get("get_misses"));
+
+      f = client.delete(k(m, "k99-"));
+      assert !f.get(5, TimeUnit.SECONDS);
+      stats = getStats();
+      assert "1".equals(stats.get("delete_hits"));
+      assert "1".equals(stats.get("delete_misses"));
+
+      int future = (int) TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis() + 1000);
+      f = client.set(k(m, "k3-"), future, v(m, "v3-"));
+      assert f.get(5, TimeUnit.SECONDS);
+      Thread.sleep(1100);
+      assert null == client.get(k(m, "k3-"));
+      stats = getStats();
+      assert "1".equals(stats.get("curr_items"));
+      assert "3".equals(stats.get("total_items"));
+
+      client.incr(k(m, "k4-"), 1);
+      stats = getStats();
+      assert "1".equals(stats.get("incr_misses"));
+      assert "0".equals(stats.get("incr_hits"));
+
+      f = client.set(k(m, "k4-"), 0, 1);
+      assert f.get(5, TimeUnit.SECONDS);
+      client.incr(k(m, "k4-"), 1);
+      client.incr(k(m, "k4-"), 2);
+      client.incr(k(m, "k4-"), 4);
+      stats = getStats();
+      assert "1".equals(stats.get("incr_misses"));
+      assert "3".equals(stats.get("incr_hits"));
+
+      client.decr(k(m, "k5-"), 1);
+      stats = getStats();
+      assert "1".equals(stats.get("decr_misses"));
+      assert "0".equals(stats.get("decr_hits"));
+      
+      f = client.set(k(m, "k5-"), 0, 8);
+      assert f.get(5, TimeUnit.SECONDS);
+      client.decr(k(m, "k5-"), 1);
+      client.decr(k(m, "k5-"), 2);
+      client.decr(k(m, "k5-"), 4);
+      stats = getStats();
+      assert "1".equals(stats.get("decr_misses"));
+      assert "3".equals(stats.get("decr_hits"));
+
+      client.cas(k(m, "k6-"), 1234, v(m, "v6-"));
+      stats = getStats();
+      assert "1".equals(stats.get("cas_misses"));
+      assert "0".equals(stats.get("cas_hits"));
+      assert "0".equals(stats.get("cas_badval"));
+
+      f = client.set(k(m, "k6-"), 0, v(m, "v6-"));
+      assert f.get(5, TimeUnit.SECONDS);
+      CASValue<Object> value = client.gets(k(m, "k6-"));
+      long old = value.getCas();
+      client.cas(k(m, "k6-"), value.getCas(), v(m, "v66-"));
+      stats = getStats();
+      assert "1".equals(stats.get("cas_misses"));
+      assert "1".equals(stats.get("cas_hits"));
+      assert "0".equals(stats.get("cas_badval"));
+
+      client.cas(k(m, "k6-"), old, v(m, "v66-"));
+      stats = getStats();
+      assert "1".equals(stats.get("cas_misses"));
+      assert "1".equals(stats.get("cas_hits"));
+      assert "1".equals(stats.get("cas_badval"));
+   }
+
+   private Map<String, String> getStats() {
+      Map<SocketAddress, Map<String, String>> stats = client.getStats();
+      assert 1 == stats.size();
+      return stats.values().iterator().next();
+   }
+}

Added: trunk/server/memcached/src/test/java/org/infinispan/server/memcached/test/MemcachedTestingUtil.java
===================================================================
--- trunk/server/memcached/src/test/java/org/infinispan/server/memcached/test/MemcachedTestingUtil.java	                        (rev 0)
+++ trunk/server/memcached/src/test/java/org/infinispan/server/memcached/test/MemcachedTestingUtil.java	2009-12-28 11:34:15 UTC (rev 1328)
@@ -0,0 +1,83 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat, Inc. and/or its affiliates, and
+ * individual contributors as indicated by the @author tags. See the
+ * copyright.txt file in the distribution for a full listing of
+ * individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.infinispan.server.memcached.test;
+
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.net.InetSocketAddress;
+import java.util.Arrays;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.infinispan.manager.CacheManager;
+import org.infinispan.server.memcached.MemcachedTextServer;
+
+import net.spy.memcached.DefaultConnectionFactory;
+import net.spy.memcached.MemcachedClient;
+
+/**
+ * TestingUtil.
+ * 
+ * @author Galder Zamarreño
+ * @since 4.0
+ */
+public class MemcachedTestingUtil {
+
+   private static final ThreadLocal<Integer> threadMemcachedPort = new ThreadLocal<Integer>() {
+      private final AtomicInteger uniqueAddr = new AtomicInteger(11211);
+
+      @Override
+      protected Integer initialValue() {
+         return uniqueAddr.getAndAdd(100);
+      }
+   };
+
+   public static String k(Method method, String prefix) {
+      return prefix + method.getName();
+   }
+
+   public static Object v(Method method, String prefix) {
+      return prefix  + method.getName();
+   }
+
+   public static String k(Method method) {
+      return k(method, "k-");
+   }
+
+   public static Object v(Method method) {
+      return v(method, "v-");
+   }
+
+   public static MemcachedClient createMemcachedClient(final long timeout, final int port) throws IOException {
+      DefaultConnectionFactory d = new DefaultConnectionFactory() {
+         @Override
+         public long getOperationTimeout() {
+            return timeout;
+         }
+      };
+      return new MemcachedClient(d, Arrays.asList(new InetSocketAddress[]{new InetSocketAddress(port)}));
+   }
+
+   public static MemcachedTextServer createMemcachedTextServer(CacheManager cacheManager) {
+      return new MemcachedTextServer(cacheManager, threadMemcachedPort.get());
+   }
+}



More information about the infinispan-commits mailing list