[infinispan-commits] Infinispan SVN: r1248 - in trunk/server/memcached: src and 12 other directories.

infinispan-commits at lists.jboss.org infinispan-commits at lists.jboss.org
Wed Dec 2 15:18:04 EST 2009


Author: galder.zamarreno at jboss.com
Date: 2009-12-02 15:18:03 -0500 (Wed, 02 Dec 2009)
New Revision: 1248

Added:
   trunk/server/memcached/pom.xml
   trunk/server/memcached/src/
   trunk/server/memcached/src/main/
   trunk/server/memcached/src/main/java/
   trunk/server/memcached/src/main/java/org/
   trunk/server/memcached/src/main/java/org/infinispan/
   trunk/server/memcached/src/main/java/org/infinispan/server/
   trunk/server/memcached/src/main/java/org/infinispan/server/memcached/
   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/CasValue.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/CommandType.java
   trunk/server/memcached/src/main/java/org/infinispan/server/memcached/GetCommand.java
   trunk/server/memcached/src/main/java/org/infinispan/server/memcached/MemcachedTextServer.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/RetrievalCommand.java
   trunk/server/memcached/src/main/java/org/infinispan/server/memcached/RetrievalParameters.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/StorageCommand.java
   trunk/server/memcached/src/main/java/org/infinispan/server/memcached/StorageParameters.java
   trunk/server/memcached/src/main/java/org/infinispan/server/memcached/StorageReply.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/main/java/org/infinispan/server/memcached/TextProtocolUtil.java
   trunk/server/memcached/src/main/java/org/infinispan/server/memcached/Value.java
   trunk/server/memcached/src/test/
   trunk/server/memcached/src/test/java/
   trunk/server/memcached/src/test/java/org/
   trunk/server/memcached/src/test/java/org/infinispan/
   trunk/server/memcached/src/test/java/org/infinispan/server/
   trunk/server/memcached/src/test/java/org/infinispan/server/memcached/
   trunk/server/memcached/src/test/java/org/infinispan/server/memcached/FunctionalTest.java
Modified:
   trunk/server/memcached/
Log:
[ISPN-173] (Build memcached server module) Initial commit with set, get, append, prepend, replace commands implemented. Test client used is provided Spy Memcached.


Property changes on: trunk/server/memcached
___________________________________________________________________
Name: svn:ignore
   + .classpath
.settings
.project
target
eclipse-output
test-output
output
temp-testng-customsuite.xml


Added: trunk/server/memcached/pom.xml
===================================================================
--- trunk/server/memcached/pom.xml	                        (rev 0)
+++ trunk/server/memcached/pom.xml	2009-12-02 20:18:03 UTC (rev 1248)
@@ -0,0 +1,63 @@
+<?xml version="1.0"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+   <modelVersion>4.0.0</modelVersion>
+   <parent>
+      <groupId>org.infinispan</groupId>
+      <artifactId>infinispan-parent</artifactId>
+      <version>4.0.0-SNAPSHOT</version>
+      <relativePath>../parent/pom.xml</relativePath>
+   </parent>
+
+   <artifactId>infinispan-server-memcached</artifactId>
+   <name>Infinispan Server Memcached Module</name>
+   <description>Infinispan server memcached module</description>
+
+   <properties>
+      <version.netty>3.1.5.GA</version.netty>
+      <version.spymemcached>2.4.2</version.spymemcached>
+   </properties>
+
+   <dependencies>
+      <dependency>
+         <groupId>${project.groupId}</groupId>
+         <artifactId>infinispan-core</artifactId>
+         <version>${project.version}</version>
+      </dependency>
+
+      <dependency>
+         <groupId>${project.groupId}</groupId>
+         <artifactId>infinispan-core</artifactId>
+         <version>${project.version}</version>
+         <type>test-jar</type>
+         <scope>test</scope>
+      </dependency>
+
+      <dependency>
+         <groupId>org.jboss.netty</groupId>
+         <artifactId>netty</artifactId>
+         <version>${version.netty}</version>
+      </dependency>
+
+      <dependency>
+         <groupId>spy</groupId>
+         <artifactId>memcached</artifactId>
+         <version>${version.spymemcached}</version>
+         <scope>test</scope>
+      </dependency>
+   </dependencies>
+
+  <repositories>
+    <repository>
+      <id>spy</id>
+      <name>Spy Repository</name>
+      <layout>default</layout>
+      <url>http://bleu.west.spy.net/~dustin/m2repo/</url>
+      <snapshots>
+        <enabled>false</enabled>
+      </snapshots>
+    </repository>
+  </repositories>
+  
+</project>

Added: trunk/server/memcached/src/main/java/org/infinispan/server/memcached/AddCommand.java
===================================================================
--- trunk/server/memcached/src/main/java/org/infinispan/server/memcached/AddCommand.java	                        (rev 0)
+++ trunk/server/memcached/src/main/java/org/infinispan/server/memcached/AddCommand.java	2009-12-02 20:18:03 UTC (rev 1248)
@@ -0,0 +1,66 @@
+/*
+ * 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.TimeUnit;
+
+import org.infinispan.Cache;
+
+/**
+ * AddCommand.
+ * 
+ * @author Galder Zamarreño
+ * @since 4.0
+ */
+public class AddCommand extends SetCommand {
+
+   AddCommand(Cache cache, StorageParameters params, byte[] data) {
+      super(cache, CommandType.ADD, params, data);
+   }
+
+   @Override
+   protected StorageReply put(String key, Value value) {
+      Object prev = cache.putIfAbsent(params.key, value);
+      return reply(prev);
+   }
+
+   @Override
+   protected StorageReply putExpiry(String key, Value value, long expiry) {
+      Object prev = cache.putIfAbsent(params.key, value, expiry, TimeUnit.SECONDS);
+      return reply(prev);
+   }
+
+   @Override
+   protected StorageReply putExpiryUnixTime(String key, Value value, long expiry) {
+      Object prev = cache.putIfAbsent(params.key, value, expiry, TimeUnit.MILLISECONDS);
+      return reply(prev);
+   }
+
+   private StorageReply reply(Object prev) {
+      if (prev == null)
+         return StorageReply.STORED;
+      else 
+         return StorageReply.NOT_STORED;
+   }
+
+}

Added: trunk/server/memcached/src/main/java/org/infinispan/server/memcached/AppendCommand.java
===================================================================
--- trunk/server/memcached/src/main/java/org/infinispan/server/memcached/AppendCommand.java	                        (rev 0)
+++ trunk/server/memcached/src/main/java/org/infinispan/server/memcached/AppendCommand.java	2009-12-02 20:18:03 UTC (rev 1248)
@@ -0,0 +1,73 @@
+/*
+ * 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.Cache;
+
+/**
+ * AppendCommand.
+ * 
+ * @author Galder Zamarreño
+ * @since 4.0
+ */
+public class AppendCommand extends SetCommand {
+
+   AppendCommand(Cache cache, StorageParameters params, byte[] data) {
+      super(cache, CommandType.APPEND, params, data);
+   }
+
+   AppendCommand(Cache cache, CommandType type, StorageParameters params, byte[] data) {
+      super(cache, type, params, data);
+   }
+
+   @Override
+   protected StorageReply put(String key, Value append) {
+      Value current = (Value) cache.get(key);
+      if (current != null) {
+         byte[] data = concat(current.getData(), append.getData());
+         Value next = new Value(current.getFlags(), data);
+         boolean replaced = cache.replace(key, current, next);
+         if (replaced)
+            return StorageReply.STORED;
+         else
+            return StorageReply.NOT_STORED;
+      } else {
+         return StorageReply.NOT_STORED;
+      }
+   }
+
+   protected byte[] concat(byte[] current, byte[] append) {
+      return TextProtocolUtil.concat(current, append);
+   }
+
+   @Override
+   protected StorageReply putExpiry(String key, Value value, long expiry) {
+      return put(key, value); // ignore expiry
+   }
+
+   @Override
+   protected StorageReply putExpiryUnixTime(String key, Value value, long expiry) {
+      return put(key, value); // ignore expiry
+   }
+
+}

Added: trunk/server/memcached/src/main/java/org/infinispan/server/memcached/CasCommand.java
===================================================================
--- trunk/server/memcached/src/main/java/org/infinispan/server/memcached/CasCommand.java	                        (rev 0)
+++ trunk/server/memcached/src/main/java/org/infinispan/server/memcached/CasCommand.java	2009-12-02 20:18:03 UTC (rev 1248)
@@ -0,0 +1,45 @@
+/*
+ * 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;
+
+/**
+ * CasCommand.
+ * 
+ * @author Galder Zamarreño
+ * @since 4.0
+ */
+public class CasCommand /* extends StorageCommand */ {
+//   final long unique;
+//   
+//   CasCommand(String key, int flags, long expiry, int bytes, long unique) {
+//      super(CommandType.CAS, key, flags, expiry, bytes);
+//      this.unique = unique;
+//   }
+//
+//   @Override
+//   public Object perform() throws Throwable {
+//      throw new org.jboss.util.NotImplementedException("FIXME NYI perform");
+//      return null;
+//   }
+
+}

Added: trunk/server/memcached/src/main/java/org/infinispan/server/memcached/CasValue.java
===================================================================
--- trunk/server/memcached/src/main/java/org/infinispan/server/memcached/CasValue.java	                        (rev 0)
+++ trunk/server/memcached/src/main/java/org/infinispan/server/memcached/CasValue.java	2009-12-02 20:18:03 UTC (rev 1248)
@@ -0,0 +1,39 @@
+/*
+ * 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;
+
+/**
+ * CasValue.
+ * 
+ * @author Galder Zamarreño
+ * @since 4.0
+ */
+public class CasValue {
+   final Value value;
+   final long unique;
+   
+   CasValue(Value value, long unique) {
+      this.value = value;
+      this.unique = unique;
+   }
+}

Added: trunk/server/memcached/src/main/java/org/infinispan/server/memcached/Command.java
===================================================================
--- trunk/server/memcached/src/main/java/org/infinispan/server/memcached/Command.java	                        (rev 0)
+++ trunk/server/memcached/src/main/java/org/infinispan/server/memcached/Command.java	2009-12-02 20:18:03 UTC (rev 1248)
@@ -0,0 +1,38 @@
+/*
+ * 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;
+
+/**
+ * Command.
+ * 
+ * @author Galder Zamarreño
+ * @since 4.0
+ */
+public interface Command {
+
+   Object perform(Channel ch) throws Exception;
+
+   CommandType getType();
+}

Added: trunk/server/memcached/src/main/java/org/infinispan/server/memcached/CommandFactory.java
===================================================================
--- trunk/server/memcached/src/main/java/org/infinispan/server/memcached/CommandFactory.java	                        (rev 0)
+++ trunk/server/memcached/src/main/java/org/infinispan/server/memcached/CommandFactory.java	2009-12-02 20:18:03 UTC (rev 1248)
@@ -0,0 +1,101 @@
+/*
+ * 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.io.EOFException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import org.infinispan.Cache;
+import org.infinispan.util.logging.Log;
+import org.infinispan.util.logging.LogFactory;
+
+/**
+ * CommandFactory.
+ * 
+ * @author Galder Zamarreño
+ * @since 4.0
+ */
+public class CommandFactory {
+   private static final Log log = LogFactory.getLog(CommandFactory.class);
+
+   private final Cache cache;
+   
+   public CommandFactory(Cache cache) {
+      this.cache = cache;
+   }
+
+   public Command createCommand(String line) throws IOException {
+      if (log.isTraceEnabled()) log.trace("Command line: " + line);
+      String[] args = line.trim().split(" +");
+
+      CommandType type = null;
+      String tmp = args[0];
+      if(tmp == null) 
+         throw new EOFException();
+      else
+         type = CommandType.parseType(tmp);
+
+      switch(type) {
+         case SET:
+         case ADD:
+         case REPLACE:
+         case APPEND:
+         case PREPEND:
+         case CAS:
+            String key = args[1]; // key
+            if(key == null) throw new EOFException();
+
+            tmp = args[2]; // flags
+            if(tmp == null) throw new EOFException();
+            int flags = Integer.parseInt(tmp);
+
+            tmp = args[3]; // expiry time
+            if(tmp == null) throw new EOFException();
+            long expiry = Long.parseLong(tmp); // seconds
+
+            tmp = args[4]; // number of bytes
+            if(tmp == null) throw new EOFException();
+            int bytes = Integer.parseInt(tmp);
+
+//            if (type == CommandType.CAS) {
+//               tmp = args[5]; // cas unique, 64-bit integer
+//               long unique = Long.parseLong(tmp);
+//               return type.buildCasCommand(key, flags, expiry, bytes, unique); 
+//            }
+
+            return StorageCommand.newStorageCommand(cache, type, new StorageParameters(key, flags, expiry, bytes), null);
+         case GET:
+         case GETS:
+            List<String> keys = new ArrayList<String>(5);
+            keys.addAll(Arrays.asList(args).subList(1, args.length));
+            return RetrievalCommand.newRetrievalCommand(cache, type, new RetrievalParameters(keys));
+         default:
+            return null;
+      }
+   }
+
+}

Added: trunk/server/memcached/src/main/java/org/infinispan/server/memcached/CommandType.java
===================================================================
--- trunk/server/memcached/src/main/java/org/infinispan/server/memcached/CommandType.java	                        (rev 0)
+++ trunk/server/memcached/src/main/java/org/infinispan/server/memcached/CommandType.java	2009-12-02 20:18:03 UTC (rev 1248)
@@ -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;
+
+import java.io.IOException;
+import java.io.StreamCorruptedException;
+
+/**
+ * Command.
+ * 
+ * @author Galder Zamarreño
+ * @since 4.0
+ */
+enum CommandType {
+   SET, ADD, REPLACE, APPEND, PREPEND, CAS,
+   GET, GETS,
+   DELETE,
+   INCR, DECR,
+   STATS,
+   FLUSH_ALL,
+   VERSION,
+   QUIT
+   ;
+   
+   boolean isStorage() {
+      switch(this) {
+         case SET:
+         case ADD:
+         case REPLACE:
+         case APPEND:
+         case PREPEND:
+            return true;
+         default:
+            return false;
+      }
+   }
+
+   @Override
+   public String toString() {
+      return super.toString().toLowerCase();
+   }
+
+   static CommandType parseType(String type) throws IOException {
+     if(type.equals(CommandType.SET.toString())) return SET;
+     else if(type.equals(CommandType.ADD.toString())) return ADD;
+     else if(type.equals(CommandType.REPLACE.toString())) return REPLACE;
+     else if(type.equals(CommandType.APPEND.toString())) return APPEND;
+     else if(type.equals(CommandType.PREPEND.toString())) return PREPEND;
+     else if(type.equals(CommandType.CAS.toString())) return CAS;
+     else if(type.equals(CommandType.GET.toString())) return GET;
+     else if(type.equals(CommandType.GETS.toString())) return GETS;
+     else if(type.equals(CommandType.DELETE.toString())) return DELETE;
+     else if(type.equals(CommandType.INCR.toString())) return INCR;
+     else if(type.equals(CommandType.DECR.toString())) return DECR;
+     else if(type.equals(CommandType.STATS.toString())) return STATS;
+     else if(type.equals(CommandType.FLUSH_ALL.toString())) return FLUSH_ALL;
+     else if(type.equals(CommandType.VERSION.toString())) return VERSION;
+     else if(type.equals(CommandType.QUIT.toString())) return QUIT;
+     else throw new StreamCorruptedException("request \"" + type + "\" not known");
+   }
+
+
+}

Added: trunk/server/memcached/src/main/java/org/infinispan/server/memcached/GetCommand.java
===================================================================
--- trunk/server/memcached/src/main/java/org/infinispan/server/memcached/GetCommand.java	                        (rev 0)
+++ trunk/server/memcached/src/main/java/org/infinispan/server/memcached/GetCommand.java	2009-12-02 20:18:03 UTC (rev 1248)
@@ -0,0 +1,67 @@
+/*
+ * 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.Cache;
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.channel.Channel;
+
+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;
+
+/**
+ * GetCommand.
+ * 
+ * @author Galder Zamarreño
+ * @since 4.0
+ */
+public class GetCommand extends RetrievalCommand {
+
+   GetCommand(Cache cache, CommandType type, RetrievalParameters params) {
+      super(cache, type, params);
+   }
+
+   @Override
+   public Object perform(Channel ch) throws Exception {
+      ChannelBuffer buffer;
+      for (String key : params.keys) {
+         Value value = (Value) cache.get(key);
+         if (value != null) {
+            StringBuilder sb = new StringBuilder();
+            sb.append(VALUE).append(" ")
+               .append(key).append(" ")
+               .append(value.getFlags()).append(" ")
+               .append(value.getData().length).append(" ");
+            buffer = wrappedBuffer(wrappedBuffer(sb.toString().getBytes()), wrappedBuffer(CRLF),
+                     wrappedBuffer(value.getData()), wrappedBuffer(CRLF));
+            ch.write(buffer);
+         }
+      }
+      
+      ch.write(wrappedBuffer(wrappedBuffer(END.toString().getBytes()), wrappedBuffer(CRLF)));
+      return null;
+   }
+
+}

Added: trunk/server/memcached/src/main/java/org/infinispan/server/memcached/MemcachedTextServer.java
===================================================================
--- trunk/server/memcached/src/main/java/org/infinispan/server/memcached/MemcachedTextServer.java	                        (rev 0)
+++ trunk/server/memcached/src/main/java/org/infinispan/server/memcached/MemcachedTextServer.java	2009-12-02 20:18:03 UTC (rev 1248)
@@ -0,0 +1,58 @@
+/*
+ * 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.net.InetSocketAddress;
+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;
+
+/**
+ * TextServer.
+ * 
+ * @author Galder Zamarreño
+ * @since 4.0
+ */
+class MemcachedTextServer {
+   final CacheManager manager;
+   
+   MemcachedTextServer(CacheManager manager) {
+      this.manager = manager;
+   }
+
+   public void start() {
+      // Configure Infinispan Cache instance
+      Cache cache = manager.getCache();
+
+      // Configure the server.
+      ChannelFactory factory = new NioServerSocketChannelFactory(Executors.newCachedThreadPool(), Executors.newCachedThreadPool());
+      ServerBootstrap bootstrap = new ServerBootstrap(factory);
+      bootstrap.setPipelineFactory(new TextProtocolPipelineFactory(cache));
+      bootstrap.bind(new InetSocketAddress(11211));
+   }
+}

Added: trunk/server/memcached/src/main/java/org/infinispan/server/memcached/PrependCommand.java
===================================================================
--- trunk/server/memcached/src/main/java/org/infinispan/server/memcached/PrependCommand.java	                        (rev 0)
+++ trunk/server/memcached/src/main/java/org/infinispan/server/memcached/PrependCommand.java	2009-12-02 20:18:03 UTC (rev 1248)
@@ -0,0 +1,44 @@
+/*
+ * 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.Cache;
+
+/**
+ * PrependCommand.
+ * 
+ * @author Galder Zamarreño
+ * @since 4.0
+ */
+public class PrependCommand extends AppendCommand {
+
+   PrependCommand(Cache cache, StorageParameters params, byte[] data) {
+      super(cache, CommandType.PREPEND, params, data);
+   }
+
+   @Override
+   protected byte[] concat(byte[] current, byte[] prepend) {
+      return TextProtocolUtil.concat(prepend, current); 
+   }
+
+}

Added: trunk/server/memcached/src/main/java/org/infinispan/server/memcached/ReplaceCommand.java
===================================================================
--- trunk/server/memcached/src/main/java/org/infinispan/server/memcached/ReplaceCommand.java	                        (rev 0)
+++ trunk/server/memcached/src/main/java/org/infinispan/server/memcached/ReplaceCommand.java	2009-12-02 20:18:03 UTC (rev 1248)
@@ -0,0 +1,66 @@
+/*
+ * 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.TimeUnit;
+
+import org.infinispan.Cache;
+
+/**
+ * ReplaceCommand.
+ * 
+ * @author Galder Zamarreño
+ * @since 4.0
+ */
+public class ReplaceCommand extends SetCommand {
+
+   ReplaceCommand(Cache cache, StorageParameters params, byte[] data) {
+      super(cache, CommandType.REPLACE, params, data);
+   }
+
+   @Override
+   protected StorageReply put(String key, Value value) {
+      Object prev = cache.replace(params.key, value);
+      return reply(prev);
+   }
+
+   @Override
+   protected StorageReply putExpiry(String key, Value value, long expiry) {
+      Object prev = cache.replace(params.key, value, expiry, TimeUnit.SECONDS);
+      return reply(prev);
+   }
+
+   @Override
+   protected StorageReply putExpiryUnixTime(String key, Value value, long expiry) {
+      Object prev = cache.replace(params.key, value, expiry, TimeUnit.MILLISECONDS);
+      return reply(prev);
+   }
+
+   private StorageReply reply(Object prev) {
+      if (prev == null)
+         return StorageReply.NOT_STORED;
+      else
+         return StorageReply.STORED;
+   }
+
+}

Added: trunk/server/memcached/src/main/java/org/infinispan/server/memcached/RetrievalCommand.java
===================================================================
--- trunk/server/memcached/src/main/java/org/infinispan/server/memcached/RetrievalCommand.java	                        (rev 0)
+++ trunk/server/memcached/src/main/java/org/infinispan/server/memcached/RetrievalCommand.java	2009-12-02 20:18:03 UTC (rev 1248)
@@ -0,0 +1,58 @@
+/*
+ * 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.Cache;
+
+/**
+ * RetrievalCommand.
+ * 
+ * @author Galder Zamarreño
+ * @since 4.0
+ */
+public abstract class RetrievalCommand implements Command {
+   final Cache cache;
+   private final CommandType type;
+   final RetrievalParameters params;
+   
+   RetrievalCommand(Cache cache, CommandType type, RetrievalParameters params) {
+      this.cache = cache;
+      this.type = type;
+      this.params = params;
+   }
+
+   @Override
+   public CommandType getType() {
+      return type;
+   }
+
+   public static Command newRetrievalCommand(Cache cache, CommandType type, RetrievalParameters params) {
+      switch(type) {
+         case GET: return new GetCommand(cache, type, params);
+//       case GETS: ...
+         default: throw new IllegalStateException("Unable to build storage command for type: " + type);
+      }
+      
+      
+   }
+}

Added: trunk/server/memcached/src/main/java/org/infinispan/server/memcached/RetrievalParameters.java
===================================================================
--- trunk/server/memcached/src/main/java/org/infinispan/server/memcached/RetrievalParameters.java	                        (rev 0)
+++ trunk/server/memcached/src/main/java/org/infinispan/server/memcached/RetrievalParameters.java	2009-12-02 20:18:03 UTC (rev 1248)
@@ -0,0 +1,39 @@
+/*
+ * 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;
+
+/**
+ * RetrievalParameters.
+ * 
+ * @author Galder Zamarreño
+ * @since 4.0
+ */
+public class RetrievalParameters {
+   final List<String> keys;
+   
+   RetrievalParameters(List<String> keys) {
+      this.keys = keys;
+   }
+}

Added: trunk/server/memcached/src/main/java/org/infinispan/server/memcached/RetrievalReply.java
===================================================================
--- trunk/server/memcached/src/main/java/org/infinispan/server/memcached/RetrievalReply.java	                        (rev 0)
+++ trunk/server/memcached/src/main/java/org/infinispan/server/memcached/RetrievalReply.java	2009-12-02 20:18:03 UTC (rev 1248)
@@ -0,0 +1,33 @@
+/*
+ * 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;
+
+/**
+ * RetrievalReply.
+ * 
+ * @author Galder Zamarreño
+ * @since 4.0
+ */
+public enum RetrievalReply {
+   VALUE, END;
+}

Added: trunk/server/memcached/src/main/java/org/infinispan/server/memcached/SetCommand.java
===================================================================
--- trunk/server/memcached/src/main/java/org/infinispan/server/memcached/SetCommand.java	                        (rev 0)
+++ trunk/server/memcached/src/main/java/org/infinispan/server/memcached/SetCommand.java	2009-12-02 20:18:03 UTC (rev 1248)
@@ -0,0 +1,107 @@
+/*
+ * 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.Date;
+import java.util.concurrent.TimeUnit;
+
+import org.infinispan.Cache;
+import org.infinispan.CacheException;
+import org.infinispan.util.logging.Log;
+import org.infinispan.util.logging.LogFactory;
+
+import static org.infinispan.server.memcached.TextProtocolUtil.CRLF;
+import static org.jboss.netty.buffer.ChannelBuffers.*;
+import org.jboss.netty.channel.Channel;
+
+/**
+ * SetCommand.
+ * 
+ * @author Galder Zamarreño
+ * @since 4.0
+ */
+public class SetCommand extends StorageCommand {
+
+   private static final Log log = LogFactory.getLog(SetCommand.class);
+
+   SetCommand(Cache cache, StorageParameters params, byte[] data) {
+      super(cache, CommandType.SET, params, data);
+   }
+   
+   SetCommand(Cache cache, CommandType type, StorageParameters params, byte[] data) {
+      super(cache, type, params, data);
+   }
+
+   @Override
+   public Object perform(Channel ch) throws Exception {
+      StorageReply reply;
+      try {
+         Value value = new Value(params.flags, data);
+         if (params.expiry == 0) {
+            reply = put(params.key, value);
+         } else {
+            if (params.expiry > 60*60*24*30) {
+               // If expiry bigger number of seconds in 30 days, then it's considered unix time
+               long future = TimeUnit.SECONDS.toMillis(params.expiry);
+               long expiry = future - System.currentTimeMillis();
+               if (expiry > 0) {
+                  reply = putExpiryUnixTime(params.key, value, expiry);
+               } else {
+                  StringBuilder sb = new StringBuilder();
+                  sb.append("Given expiry is bigger than 30 days, hence is treated as Unix time, ")
+                    .append("but this time is in the past: ").append(future)
+                    .append(", date: ").append(new Date(future));
+                  throw new CacheException(sb.toString());
+               }
+            } else {
+               reply = putExpiry(params.key, value, params.expiry);
+            }
+         }
+         
+      } catch (Exception e) {
+         log.error("Unexpected exception performing command", e);
+         reply = StorageReply.NOT_STORED;
+      }
+      ch.write(wrappedBuffer(wrappedBuffer(reply.toString().getBytes()), wrappedBuffer(CRLF)));
+      return null;
+   }
+
+   protected StorageReply put(String key, Value value) {
+      cache.put(params.key, value);
+      return reply();
+   }
+
+   protected StorageReply putExpiry(String key, Value value, long expiry) {
+      cache.put(params.key, value, params.expiry, TimeUnit.SECONDS);
+      return reply();
+   }
+
+   protected StorageReply putExpiryUnixTime(String key, Value value, long expiry) {
+      cache.put(params.key, value, expiry, TimeUnit.MILLISECONDS);
+      return reply();
+   }
+
+   private StorageReply reply() {
+      return StorageReply.STORED;
+   }
+}

Added: trunk/server/memcached/src/main/java/org/infinispan/server/memcached/StorageCommand.java
===================================================================
--- trunk/server/memcached/src/main/java/org/infinispan/server/memcached/StorageCommand.java	                        (rev 0)
+++ trunk/server/memcached/src/main/java/org/infinispan/server/memcached/StorageCommand.java	2009-12-02 20:18:03 UTC (rev 1248)
@@ -0,0 +1,79 @@
+/*
+ * 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.io.IOException;
+import java.io.StreamCorruptedException;
+
+import org.infinispan.Cache;
+
+/**
+ * StorageCommand.
+ * 
+ * @author Galder Zamarreño
+ * @since 4.0
+ */
+public abstract class StorageCommand implements Command {
+   final Cache cache;
+   private final CommandType type;
+   final StorageParameters params;
+//   final String key;
+//   final int flags;
+//   final long expiry;
+//   final int bytes;
+   final byte[] data;
+
+   StorageCommand(Cache cache, CommandType type, StorageParameters params, byte[] data) {
+      this.type = type;
+      this.params = params;
+      this.cache = cache;
+//      this.key = key;
+//      this.flags = flags;
+//      this.expiry = expiry;
+//      this.bytes = bytes;
+      this.data = data;
+   }
+
+   public CommandType getType() {
+      return type;
+   }
+
+   public Command setData(byte[] data) throws IOException {
+      return newStorageCommand(cache, type, params, data);
+   }
+
+   public static Command newStorageCommand(Cache cache, CommandType type, StorageParameters params, byte[] data) throws IOException {
+      switch(type) {
+         case SET: return new SetCommand(cache, params, data);
+         case ADD: return new AddCommand(cache, params, data);
+         case REPLACE: return new ReplaceCommand(cache, params, data);
+         case APPEND: return new AppendCommand(cache, params, data);
+         case PREPEND: return new PrependCommand(cache, params, data);
+         default: throw new StreamCorruptedException("Unable to build storage command for type: " + type);
+      }
+   }
+   
+//   public static Command buildCasCommand(String key, int flags, long expiry, int bytes, long unique) {
+//      return new CasCommand(key, flags, expiry, bytes, unique);
+//   }
+}

Added: trunk/server/memcached/src/main/java/org/infinispan/server/memcached/StorageParameters.java
===================================================================
--- trunk/server/memcached/src/main/java/org/infinispan/server/memcached/StorageParameters.java	                        (rev 0)
+++ trunk/server/memcached/src/main/java/org/infinispan/server/memcached/StorageParameters.java	2009-12-02 20:18:03 UTC (rev 1248)
@@ -0,0 +1,44 @@
+/*
+ * 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;
+
+/**
+ * StorageParameters.
+ * 
+ * @author Galder Zamarreño
+ * @since 4.0
+ */
+public class StorageParameters {
+   final String key;
+   final int flags;
+   final long expiry;
+   final int bytes;
+   boolean noreply;
+
+   StorageParameters(String key, int flags, long expiry, int bytes) {
+      this.key = key;
+      this.flags = flags;
+      this.expiry = expiry;
+      this.bytes = bytes;
+   }
+}

Added: trunk/server/memcached/src/main/java/org/infinispan/server/memcached/StorageReply.java
===================================================================
--- trunk/server/memcached/src/main/java/org/infinispan/server/memcached/StorageReply.java	                        (rev 0)
+++ trunk/server/memcached/src/main/java/org/infinispan/server/memcached/StorageReply.java	2009-12-02 20:18:03 UTC (rev 1248)
@@ -0,0 +1,38 @@
+/*
+ * 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;
+
+/**
+ * StorageReply.
+ * 
+ * @author Galder Zamarreño
+ * @since 4.0
+ */
+public enum StorageReply {
+   STORED, NOT_STORED, EXISTS, NOT_FOUND;
+
+//   @Override
+//   public String toString() {
+//      return super.toString() + "\r\n";
+//   }
+}

Added: trunk/server/memcached/src/main/java/org/infinispan/server/memcached/TextCommandDecoder.java
===================================================================
--- trunk/server/memcached/src/main/java/org/infinispan/server/memcached/TextCommandDecoder.java	                        (rev 0)
+++ trunk/server/memcached/src/main/java/org/infinispan/server/memcached/TextCommandDecoder.java	2009-12-02 20:18:03 UTC (rev 1248)
@@ -0,0 +1,184 @@
+/*
+ * 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.io.IOException;
+import java.io.StreamCorruptedException;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.infinispan.Cache;
+import org.infinispan.util.logging.Log;
+import org.infinispan.util.logging.LogFactory;
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.channel.Channel;
+import org.jboss.netty.channel.ChannelHandlerContext;
+import org.jboss.netty.channel.ExceptionEvent;
+import org.jboss.netty.handler.codec.replay.ReplayingDecoder;
+import static org.infinispan.server.memcached.TextProtocolUtil.*;
+
+/**
+ * TextCommandDecoder.
+ * 
+ * @author Galder Zamarreño
+ * @since 4.0
+ */
+public class TextCommandDecoder extends ReplayingDecoder<TextCommandDecoder.State> {
+   private static final Log log = LogFactory.getLog(TextCommandDecoder.class);
+   
+   private final CommandFactory factory;
+   private volatile Command command;
+   private final AtomicBoolean corrupted = new AtomicBoolean();
+
+   protected enum State {
+      READ_COMMAND, READ_UNSTRUCTURED_DATA;
+   }
+
+   TextCommandDecoder(Cache cache) {
+      super(State.READ_COMMAND, true);
+      factory = new CommandFactory(cache);
+   }
+
+   @Override
+   protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer, State state) throws Exception {
+      switch (state) {
+         case READ_COMMAND:
+            String line = readLine(buffer);
+            try {
+               command = factory.createCommand(line);
+               corrupted.set(false);
+            } catch (IOException ioe) {
+               if (corrupted.get())
+                  log.debug("Channel is corrupted and we're reading garbage, ignore read until we find a good command again");
+               else
+                  throw ioe;
+            }
+            
+            if (command.getType().isStorage())
+               checkpoint(State.READ_UNSTRUCTURED_DATA);
+            else
+               return command;
+            break;
+         case READ_UNSTRUCTURED_DATA:
+            StorageCommand storageCmd = (StorageCommand) command;
+            byte[] data= new byte[storageCmd.params.bytes];
+            buffer.readBytes(data, 0, data.length);
+            byte next = buffer.readByte();
+            if (next == CR) {
+               next = buffer.readByte();
+               if (next == LF) {
+                  try {
+                     return reset(storageCmd.setData(data));
+                  } catch (IOException ioe) {
+                     checkpoint(State.READ_COMMAND);
+                     throw ioe;
+                  }
+               } else {
+                  throw new StreamCorruptedException("Expecting \r\n after data block");
+               }
+            } else {
+               throw new StreamCorruptedException("Expecting \r\n after data block");
+            }
+      }
+      return null;
+   }
+
+   @Override
+   public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
+      corrupted.compareAndSet(false, true);
+      log.error("Unexpected exception", e.getCause());
+   }
+
+   private Object reset(Command c) {
+      this.command = null;
+      checkpoint(State.READ_COMMAND);
+      return c;
+  }
+
+   private String readLine(ChannelBuffer buffer) {
+      StringBuilder sb = new StringBuilder(64);
+      int lineLength = 0;
+      while (true) {
+         byte next = buffer.readByte();
+         if (next == CR) {
+            next = buffer.readByte();
+            if (next == LF) {
+               return sb.toString();
+            }
+         } else if (next == LF) {
+            return sb.toString();
+         } else {
+            lineLength++;
+            sb.append((char) next);
+         }
+      }
+   }
+
+   // private String readLine(ChannelBuffer buffer) {
+   // int minFrameLength = Integer.MAX_VALUE;
+   //
+   // ChannelBuffer minDelim = null;
+   // int frameLength = indexOf(buffer, CR);
+   // if (frameLength >= 0 && frameLength < minFrameLength) {
+   // minFrameLength = frameLength;
+   // minDelim = CR;
+   // }
+   //
+   // if (minDelim != null) {
+   // int minDelimLength = minDelim.capacity();
+   // ChannelBuffer frame = buffer.readBytes(minFrameLength);
+   // buffer.skipBytes(minDelimLength);
+   // return frame.toString(Charset.defaultCharset().name());
+   // } else {
+   // return null;
+   // }
+   // }
+   //
+   // /**
+   // * Returns the number of bytes between the readerIndex of the haystack and
+   // * the first needle found in the haystack. -1 is returned if no needle is
+   // * found in the haystack.
+   // */
+   // private static int indexOf(ChannelBuffer haystack, ChannelBuffer needle) {
+   // for (int i = haystack.readerIndex(); i < haystack.writerIndex(); i ++) {
+   // int haystackIndex = i;
+   // int needleIndex;
+   // for (needleIndex = 0; needleIndex < needle.capacity(); needleIndex ++) {
+   // if (haystack.getByte(haystackIndex) != needle.getByte(needleIndex)) {
+   // break;
+   // } else {
+   // haystackIndex ++;
+   // if (haystackIndex == haystack.writerIndex() &&
+   // needleIndex != needle.capacity() - 1) {
+   // return -1;
+   // }
+   // }
+   // }
+   //
+   // if (needleIndex == needle.capacity()) {
+   // // Found the needle from the haystack!
+   // return i - haystack.readerIndex();
+   // }
+   // }
+   // return -1;
+   // }
+}

Added: trunk/server/memcached/src/main/java/org/infinispan/server/memcached/TextCommandHandler.java
===================================================================
--- trunk/server/memcached/src/main/java/org/infinispan/server/memcached/TextCommandHandler.java	                        (rev 0)
+++ trunk/server/memcached/src/main/java/org/infinispan/server/memcached/TextCommandHandler.java	2009-12-02 20:18:03 UTC (rev 1248)
@@ -0,0 +1,56 @@
+/*
+ * 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.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBuffers;
+import org.jboss.netty.channel.Channel;
+import org.jboss.netty.channel.ChannelHandlerContext;
+import org.jboss.netty.channel.ChannelPipelineCoverage;
+import org.jboss.netty.channel.MessageEvent;
+import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
+
+/**
+ * TextProtocolServerHandler.
+ * 
+ * @author Galder Zamarreño
+ * @since 4.0
+ */
+ at ChannelPipelineCoverage("one")
+class TextCommandHandler extends SimpleChannelUpstreamHandler {
+
+   @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);
+   }
+
+   
+}

Added: trunk/server/memcached/src/main/java/org/infinispan/server/memcached/TextProtocolPipelineFactory.java
===================================================================
--- trunk/server/memcached/src/main/java/org/infinispan/server/memcached/TextProtocolPipelineFactory.java	                        (rev 0)
+++ trunk/server/memcached/src/main/java/org/infinispan/server/memcached/TextProtocolPipelineFactory.java	2009-12-02 20:18:03 UTC (rev 1248)
@@ -0,0 +1,63 @@
+/*
+ * 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.jboss.netty.channel.Channels.*;
+
+import org.infinispan.Cache;
+import org.jboss.netty.channel.ChannelHandler;
+import org.jboss.netty.channel.ChannelPipeline;
+import org.jboss.netty.channel.ChannelPipelineFactory;
+
+/**
+ * TextProtocolPipelineFactory.
+ * 
+ * @author Galder Zamarreño
+ * @since 4.0
+ */
+class TextProtocolPipelineFactory implements ChannelPipelineFactory {
+
+//   private final ChannelHandler handler;
+//
+//   public TextProtocolPipelineFactory(TextCommandHandler handler) {
+//      this.handler = handler;
+//   }
+
+   private final Cache cache;
+
+   public TextProtocolPipelineFactory(Cache cache) {
+      this.cache = cache;
+   }
+
+   @Override
+   public ChannelPipeline getPipeline() throws Exception {
+      // Create a default pipeline implementation.
+      ChannelPipeline pipeline = pipeline();
+      pipeline.addLast("decoder", new TextCommandDecoder(cache));
+      pipeline.addLast("handler", new TextCommandHandler());
+//      pipeline.addLast("encoder", new TextResponseEncoder());
+
+      return pipeline;
+   }
+
+}

Added: trunk/server/memcached/src/main/java/org/infinispan/server/memcached/TextProtocolUtil.java
===================================================================
--- trunk/server/memcached/src/main/java/org/infinispan/server/memcached/TextProtocolUtil.java	                        (rev 0)
+++ trunk/server/memcached/src/main/java/org/infinispan/server/memcached/TextProtocolUtil.java	2009-12-02 20:18:03 UTC (rev 1248)
@@ -0,0 +1,42 @@
+/*
+ * 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;
+
+/**
+ * TextProtocolUtil.
+ * 
+ * @author Galder Zamarreño
+ * @since 4.0
+ */
+public class TextProtocolUtil {
+   static final byte CR = 13;
+   static final byte LF = 10;
+   static final byte[] CRLF = new byte[] { CR, LF };
+
+   public static byte[] concat(byte[] a, byte[] b) {
+      byte[] data = new byte[a.length + b.length];
+      System.arraycopy(a, 0, data, 0, a.length);
+      System.arraycopy(b, 0, data, a.length , b.length);
+      return data;
+   }
+}

Added: trunk/server/memcached/src/main/java/org/infinispan/server/memcached/Value.java
===================================================================
--- trunk/server/memcached/src/main/java/org/infinispan/server/memcached/Value.java	                        (rev 0)
+++ trunk/server/memcached/src/main/java/org/infinispan/server/memcached/Value.java	2009-12-02 20:18:03 UTC (rev 1248)
@@ -0,0 +1,85 @@
+/*
+ * 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.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.util.Arrays;
+
+/**
+ * Value.
+ * 
+ * @author Galder Zamarreño
+ * @since 4.0
+ */
+class Value implements Externalizable {
+   private int flags;
+   private byte[] data;
+   
+   Value(int flags, byte[] data) {
+      this.flags = flags;
+      this.data = data;
+   }
+
+   public int getFlags() {
+      return flags;
+   }
+
+   public byte[] getData() {
+      return data;
+   }
+
+   @Override
+   public boolean equals(Object obj) {
+      if (obj == this)
+         return true;
+      if (!(obj instanceof Value))
+         return false;
+      Value other = (Value) obj;
+      return Arrays.equals(data, other.data) && flags == other.flags;
+   }
+
+   @Override
+   public int hashCode() {
+      int result = 17;
+      result = 31 * result + flags;
+      result = 31 * result + data.hashCode();
+      return result;
+   }
+
+   @Override
+   public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
+      flags = in.read();
+      data = new byte[in.read()];
+      in.read(data);
+   }
+
+   @Override
+   public void writeExternal(ObjectOutput out) throws IOException {
+      out.write(flags);
+      out.write(data.length);
+      out.write(data);
+   }
+}

Added: trunk/server/memcached/src/test/java/org/infinispan/server/memcached/FunctionalTest.java
===================================================================
--- trunk/server/memcached/src/test/java/org/infinispan/server/memcached/FunctionalTest.java	                        (rev 0)
+++ trunk/server/memcached/src/test/java/org/infinispan/server/memcached/FunctionalTest.java	2009-12-02 20:18:03 UTC (rev 1248)
@@ -0,0 +1,220 @@
+/*
+ * 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.InetSocketAddress;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+
+import net.spy.memcached.DefaultConnectionFactory;
+import net.spy.memcached.MemcachedClient;
+
+import org.infinispan.manager.CacheManager;
+import org.infinispan.test.SingleCacheManagerTest;
+import org.infinispan.test.fwk.TestCacheManagerFactory;
+import org.testng.annotations.Test;
+
+/**
+ * FunctionalTest.
+ * 
+ * @author Galder Zamarreño
+ * @since 4.0
+ */
+ at Test(groups = "functional", testName = "server.memcached.FunctionalTest")
+public class FunctionalTest extends SingleCacheManagerTest {
+   private MemcachedClient client;
+   private MemcachedTextServer server;
+
+   @Override
+   protected CacheManager createCacheManager() throws Exception {
+      cacheManager = TestCacheManagerFactory.createLocalCacheManager();
+      server = new MemcachedTextServer(cacheManager);
+      server.start();
+      DefaultConnectionFactory d = new DefaultConnectionFactory() {
+         @Override
+         public long getOperationTimeout() {
+            return 5000;
+         }
+      };
+      
+      client = new MemcachedClient(d, Arrays.asList(new InetSocketAddress[]{new InetSocketAddress(11211)}));
+      return cacheManager;
+   }
+
+   public void testBasicSet(Method m) throws Exception {
+      Future<Boolean> f = client.set(k(m), 0, v(m));
+      assert f.get(5, TimeUnit.SECONDS);
+      assert client.get(k(m)).equals(v(m));
+   }
+
+   public void testSetWithExpirySeconds(Method m) throws Exception {
+      Future<Boolean> f = client.set(k(m), 1, v(m));
+      assert f.get(5, TimeUnit.SECONDS);
+      Thread.sleep(1100);
+      assert null == client.get(k(m));
+   }
+
+   public void testSetWithExpiryUnixTime(Method m) throws Exception {
+      int future = (int) TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis() + 1000);
+      Future<Boolean> f = client.set(k(m), future, v(m));
+      assert f.get(5, TimeUnit.SECONDS);
+      Thread.sleep(1100);
+      assert null == client.get(k(m));
+   }
+
+   public void testGetMultipleKeys(Method m) throws Exception {
+      Future<Boolean> f1 = client.set(k(m, "k1-"), 0, v(m, "v1-"));
+      Future<Boolean> f2 = client.set(k(m, "k2-"), 0, v(m, "v2-"));
+      Future<Boolean> f3 = client.set(k(m, "k3-"), 0, v(m, "v3-"));
+      assert f1.get(5, TimeUnit.SECONDS);
+      assert f2.get(5, TimeUnit.SECONDS);
+      assert f3.get(5, TimeUnit.SECONDS);
+      
+      Map<String, Object> ret = client.getBulk(Arrays.asList(new String[]{k(m, "k1-"), k(m, "k2-"), k(m, "k3-")}));
+      assert ret.get(k(m, "k1-")).equals(v(m, "v1-"));
+      assert ret.get(k(m, "k2-")).equals(v(m, "v2-"));
+      assert ret.get(k(m, "k3-")).equals(v(m, "v3-"));
+   }
+
+   public void testBasicAdd(Method m) throws Exception {
+      Future<Boolean> f = client.add(k(m), 0, v(m));
+      assert f.get(5, TimeUnit.SECONDS);
+      assert v(m).equals(client.get(k(m)));
+   }
+
+   public void testAddWithExpirySeconds(Method m) throws Exception {
+      Future<Boolean> f = client.add(k(m), 1, v(m));
+      assert f.get(5, TimeUnit.SECONDS);
+      Thread.sleep(1100);
+      assert null == client.get(k(m));
+
+      f = client.add(k(m), 0, v(m, "k1-"));
+      assert f.get(5, TimeUnit.SECONDS);
+      assert v(m, "k1-").equals(client.get(k(m)));
+   }
+
+   public void testAddWithExpiryUnixTime(Method m) throws Exception {
+      int future = (int) TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis() + 1000);
+      Future<Boolean> f = client.add(k(m), future, v(m));
+      assert f.get(5, TimeUnit.SECONDS);
+      Thread.sleep(1100);
+      assert null == client.get(k(m));
+
+      f = client.add(k(m), 0, v(m, "k1-"));
+      assert f.get(5, TimeUnit.SECONDS);
+      assert v(m, "k1-").equals(client.get(k(m)));
+   }
+
+   public void testNotAddIsPresent(Method m) throws Exception {
+      Future<Boolean> f = client.add(k(m), 0, v(m));
+      assert(f.get(5, TimeUnit.SECONDS));
+      assert v(m).equals(client.get(k(m)));
+
+      f = client.add(k(m), 0, v(m, "k1-"));
+      assert false == f.get(5, TimeUnit.SECONDS);
+      assert client.get(k(m)).equals(v(m));
+   }
+
+   public void testBasicReplace(Method m) throws Exception {
+      Future<Boolean> f = client.add(k(m), 0, v(m));
+      assert(f.get(5, TimeUnit.SECONDS));
+      assert v(m).equals(client.get(k(m)));
+      
+      f = client.replace(k(m), 0, v(m, "k1-"));
+      assert f.get(5, TimeUnit.SECONDS);
+      assert v(m, "k1-").equals(client.get(k(m)));
+   }
+
+   public void testNotReplaceIsNotPresent(Method m) throws Exception {
+      Future<Boolean> f = client.replace(k(m), 0, v(m));
+      assert false == f.get(5, TimeUnit.SECONDS);
+      assert null == client.get(k(m));
+   }
+
+   public void testReplaceWithExpirySeconds(Method m) throws Exception {
+      Future<Boolean> f = client.add(k(m), 0, v(m));
+      assert(f.get(5, TimeUnit.SECONDS));
+      assert v(m).equals(client.get(k(m)));
+      
+      f = client.replace(k(m), 1, v(m, "k1-"));
+      assert f.get(5, TimeUnit.SECONDS);
+      assert client.get(k(m)).equals(v(m, "k1-"));
+      Thread.sleep(1100);
+      assert null == client.get(k(m));
+   }
+
+   public void testReplaceWithExpiryUnixTime(Method m) throws Exception {
+      Future<Boolean> f = client.add(k(m), 0, v(m));
+      assert f.get(5, TimeUnit.SECONDS);
+      assert v(m).equals(client.get(k(m)));
+
+      int future = (int) TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis() + 1000);
+      f = client.replace(k(m), future, v(m, "k1-"));
+      assert f.get(5, TimeUnit.SECONDS);
+      assert client.get(k(m)).equals(v(m, "k1-"));
+      Thread.sleep(1100);
+      assert null == client.get(k(m));
+   }
+
+   public void testBasicAppend(Method m) throws Exception {
+      Future<Boolean> f = client.add(k(m), 0, v(m));
+      assert f.get(5, TimeUnit.SECONDS);
+      assert v(m).equals(client.get(k(m)));
+
+      f = client.append(0, k(m), v(m, "v1-"));
+      assert f.get(5, TimeUnit.SECONDS);
+      String expected = v(m).toString() + v(m, "v1-").toString();
+      assert expected.equals(client.get(k(m)));
+   }
+
+   public void testBasicPrepend(Method m) throws Exception {
+      Future<Boolean> f = client.add(k(m), 0, v(m));
+      assert f.get(5, TimeUnit.SECONDS);
+      assert v(m).equals(client.get(k(m)));
+
+      f = client.prepend(0, k(m), v(m, "v1-"));
+      assert f.get(5, TimeUnit.SECONDS);
+      String expected = v(m, "v1-").toString() + v(m).toString();
+      assert expected.equals(client.get(k(m)));
+   }
+
+   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-");
+   }
+
+}



More information about the infinispan-commits mailing list