[infinispan-commits] Infinispan SVN: r1620 - in trunk/server: core/src/main/scala/org/infinispan/server/core/transport and 9 other directories.

infinispan-commits at lists.jboss.org infinispan-commits at lists.jboss.org
Thu Mar 25 07:46:51 EDT 2010


Author: galder.zamarreno at jboss.com
Date: 2010-03-25 07:46:48 -0400 (Thu, 25 Mar 2010)
New Revision: 1620

Added:
   trunk/server/core/src/main/scala/org/infinispan/server/core/CacheValue.scala
   trunk/server/core/src/main/scala/org/infinispan/server/core/transport/VInt.scala
   trunk/server/core/src/main/scala/org/infinispan/server/core/transport/VLong.scala
   trunk/server/core/src/test/scala/org/infinispan/server/core/VariableLengthTest.scala
   trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/AbstractVersionedDecoder.scala
   trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/CacheKey.scala
   trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/Decoder10.scala
   trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/HotRodDecoder.scala
   trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/HotRodEncoder.scala
   trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/HotRodHeader.scala
   trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/HotRodOperation.scala
   trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/OperationResponse.scala
   trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/OperationStatus.scala
   trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/ProtocolFlag.scala
   trunk/server/hotrod/src/test/scala/org/infinispan/server/hotrod/HotRodFunctionalTest.scala
Removed:
   trunk/server/core/src/main/scala/org/infinispan/server/core/Value.scala
   trunk/server/hotrod/src/main/java/
   trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/Cache.scala
   trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/CallerCache.scala
   trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/Command.scala
   trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/Decoder410.scala
   trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/Encoder410.scala
   trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/ErrorResponse.scala
   trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/Flags.scala
   trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/GlobalDecoder.scala
   trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/Handler.scala
   trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/Key.scala
   trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/Logging.scala
   trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/OpCodes.scala
   trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/RetrievalCommand.scala
   trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/RetrievalResponse.scala
   trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/StatsCache.scala
   trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/Status.scala
   trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/StorageCommand.scala
   trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/VInt.scala
   trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/VLong.scala
   trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/Value.scala
   trunk/server/hotrod/src/test/java/
   trunk/server/hotrod/src/test/scala/org/infinispan/server/hotrod/FlagsTest.scala
   trunk/server/hotrod/src/test/scala/org/infinispan/server/hotrod/FunctionalTest.scala
   trunk/server/hotrod/src/test/scala/org/infinispan/server/hotrod/VariableLengthTest.scala
Modified:
   trunk/server/core/src/main/scala/org/infinispan/server/core/AbstractProtocolDecoder.scala
   trunk/server/core/src/main/scala/org/infinispan/server/core/Operation.scala
   trunk/server/core/src/main/scala/org/infinispan/server/core/transport/ChannelBuffer.scala
   trunk/server/core/src/main/scala/org/infinispan/server/core/transport/netty/ChannelBufferAdapter.scala
   trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/HotRodServer.scala
   trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/Response.scala
   trunk/server/hotrod/src/test/scala/org/infinispan/server/hotrod/ClusterTest.scala
   trunk/server/hotrod/src/test/scala/org/infinispan/server/hotrod/test/Client.scala
   trunk/server/hotrod/src/test/scala/org/infinispan/server/hotrod/test/Utils.scala
   trunk/server/memcached/src/main/scala/org/infinispan/server/memcached/MemcachedDecoder.scala
   trunk/server/memcached/src/main/scala/org/infinispan/server/memcached/MemcachedValue.scala
   trunk/server/memcached/src/main/scala/org/infinispan/server/memcached/OperationResolver.scala
   trunk/server/memcached/src/test/scala/org/infinispan/server/memcached/test/MemcachedTestingUtil.scala
Log:
[ISPN-171] (Build a server module based on the HotRod protocol) Consolidating Hot Rod module in correspondance with the work done to move more logic to the core module. Implemented the remaining operations except stats.

Modified: trunk/server/core/src/main/scala/org/infinispan/server/core/AbstractProtocolDecoder.scala
===================================================================
--- trunk/server/core/src/main/scala/org/infinispan/server/core/AbstractProtocolDecoder.scala	2010-03-25 10:49:02 UTC (rev 1619)
+++ trunk/server/core/src/main/scala/org/infinispan/server/core/AbstractProtocolDecoder.scala	2010-03-25 11:46:48 UTC (rev 1620)
@@ -2,7 +2,6 @@
 
 import org.infinispan.Cache
 import Operation._
-import transport.{ExceptionEvent, Decoder, ChannelHandlerContext, ChannelBuffer}
 import scala.collection.mutable.HashMap
 import scala.collection.immutable
 import org.infinispan.remoting.transport.Address
@@ -12,6 +11,7 @@
 import org.infinispan.stats.Stats
 import org.infinispan.server.core.VersionGenerator._
 import java.io.StreamCorruptedException
+import transport._
 
 /**
  * // TODO: Document this
@@ -19,92 +19,103 @@
  * @since
  */
 
-abstract class AbstractProtocolDecoder[K, V <: Value] extends Decoder {
+abstract class AbstractProtocolDecoder[K, V <: CacheValue] extends Decoder {
    import AbstractProtocolDecoder._
 
    type SuitableParameters <: RequestParameters
+   type SuitableHeader <: RequestHeader
 
    private val versionCounter = new AtomicInteger
 
    override def decode(ctx: ChannelHandlerContext, buffer: ChannelBuffer): AnyRef = {
       if (buffer.readableBytes < 1) return null
       val header = readHeader(buffer)
-      val cache = getCache(header)
-      header.op match {
-         case PutRequest | PutIfAbsentRequest | ReplaceRequest | ReplaceIfUnmodifiedRequest | DeleteRequest => {
-            val k = readKey(buffer)
-            val params = readParameters(header.op, buffer)
-            header.op match {
-               case PutRequest => {
-                  putInCache(k, params, cache)
-                  sendResponse(header, ctx, None, None, Some(params), None)
-               }
-               case PutIfAbsentRequest => {
-                  val prev = cache.get(k)
-                  if (prev == null) putIfAbsentInCache(k, params, cache) // Generate new version only if key not present
-                  sendResponse(header, ctx, None, None, Some(params), Some(prev))
-               }
-               case ReplaceRequest => {
-                  val prev = cache.get(k)
-                  if (prev != null) replaceInCache(k, params, cache) // Generate new version only if key present
-                  sendResponse(header, ctx, None, None, Some(params), Some(prev))
-               }
-               case ReplaceIfUnmodifiedRequest => {
-                  val prev = cache.get(k)
-                  if (prev != null) {
-                     if (prev.version == params.version) {
-                        // Generate new version only if key present and version has not changed, otherwise it's wasteful
-                        val v = createValue(params, generateVersion(cache))
-                        val replaced = cache.replace(k, prev, v);
-                        if (replaced)
-                           sendResponse(header, ctx, None, Some(v), Some(params), Some(prev))
-                        else
-                           sendResponse(header, ctx, None, None, Some(params), Some(prev))
+      if (header == null) return null // Something went wrong reading the header, so get more bytes 
+      try {
+         val cache = getCache(header)
+         val ret = header.op match {
+            case PutRequest | PutIfAbsentRequest | ReplaceRequest | ReplaceIfUnmodifiedRequest | RemoveRequest => {
+               val k = readKey(header, buffer)
+               val params = readParameters(header, buffer)
+               header.op match {
+                  case PutRequest => {
+                     putInCache(header, k, params.get, cache)
+                     sendResponse(header, ctx, None, None, params, None)
+                  }
+                  case PutIfAbsentRequest => {
+                     val prev = cache.get(k)
+                     if (prev == null) putIfAbsentInCache(header, k, params.get, cache) // Generate new version only if key not present
+                     sendResponse(header, ctx, None, None, params, Some(prev))
+                  }
+                  case ReplaceRequest => {
+                     val prev = cache.get(k)
+                     if (prev != null) replaceInCache(header, k, params.get, cache) // Generate new version only if key present
+                     sendResponse(header, ctx, None, None, params, Some(prev))
+                  }
+                  case ReplaceIfUnmodifiedRequest => {
+                     val prev = cache.get(k)
+                     if (prev != null) {
+                        if (prev.version == params.get.streamVersion) {
+                           // Generate new version only if key present and version has not changed, otherwise it's wasteful
+                           val v = createValue(header, params.get, generateVersion(cache))
+                           val replaced = cache.replace(k, prev, v);
+                           if (replaced)
+                              sendResponse(header, ctx, None, Some(v), params, Some(prev))
+                           else
+                              sendResponse(header, ctx, None, None, params, Some(prev))
+                        } else {
+                           sendResponse(header, ctx, None, None, params, Some(prev))
+                        }
                      } else {
-                        sendResponse(header, ctx, None, None, Some(params), Some(prev))
+                        sendResponse(header, ctx, None, None, params, None)
                      }
-                  } else {
-                     sendResponse(header, ctx, None, None, Some(params), None)
                   }
+                  case RemoveRequest => {
+                     val prev = cache.remove(k)
+                     sendResponse(header, ctx, None, None, params, Some(prev))
+                  }
                }
-               case DeleteRequest => {
-                  val prev = cache.remove(k)
-                  sendResponse(header, ctx, None, None, Some(params), Some(prev))
-               }
             }
-         }
-         case GetRequest | GetWithVersionRequest => {
-            val keys = readKeys(buffer)
-            if (keys.length > 1) {
-               val map = new HashMap[K,V]()
-               for (k <- keys) {
-                  val v = cache.get(k)
-                  if (v != null)
-                     map += (k -> v)
+            case GetRequest | GetWithVersionRequest => {
+               val keys = readKeys(header, buffer)
+               if (keys.length > 1) {
+                  val map = new HashMap[K,V]()
+                  for (k <- keys) {
+                     val v = cache.get(k)
+                     if (v != null)
+                        map += (k -> v)
+                  }
+                  sendMultiGetResponse(header, ctx, new immutable.HashMap ++ map)
+               } else {
+                  sendResponse(header, ctx, Some(keys.head), Some(cache.get(keys.head)), None, None)
                }
-               sendResponse(header, ctx, new immutable.HashMap ++ map)
-            } else {
-               sendResponse(header, ctx, Some(keys.head), Some(cache.get(keys.head)), None, None)
             }
+            case StatsRequest => sendResponse(header, ctx, cache.getAdvancedCache.getStats)
+            case _ => handleCustomRequest(header, ctx, buffer, cache)
          }
-         case StatsRequest => sendResponse(ctx, cache.getAdvancedCache.getStats)
-         case _ => handleCustomRequest(header, ctx, buffer, cache)
+         // TODO: to avoid checking for null, make all send* methods return something, even the memcached ones,
+         // they could send back a buffer whereas hotrod would send back pojos.
+         if (ret != null) ctx.getChannel.write(ret)
+         null
+      } catch {
+         case se: ServerException => throw se
+         case e: Exception => throw new ServerException(header, e)
+         case t: Throwable => throw t
       }
-      null
    }
 
-   private def putInCache(k: K, params: SuitableParameters, cache: Cache[K, V]): V = {
-      val v = createValue(params, generateVersion(cache))
+   private def putInCache(header: SuitableHeader, k: K, params: SuitableParameters, cache: Cache[K, V]): V = {
+      val v = createValue(header, params, generateVersion(cache))
       cache.put(k, v, toMillis(params.lifespan), DefaultTimeUnit, toMillis(params.maxIdle), DefaultTimeUnit)
    }
 
-   private def putIfAbsentInCache(k: K, params: SuitableParameters, cache: Cache[K, V]): V = {
-      val v = createValue(params, generateVersion(cache))
+   private def putIfAbsentInCache(header: SuitableHeader, k: K, params: SuitableParameters, cache: Cache[K, V]): V = {
+      val v = createValue(header, params, generateVersion(cache))
       cache.putIfAbsent(k, v, toMillis(params.lifespan), DefaultTimeUnit, toMillis(params.maxIdle), DefaultTimeUnit)
    }
 
-   private def replaceInCache(k: K, params: SuitableParameters, cache: Cache[K, V]): V = {
-      val v = createValue(params, generateVersion(cache))
+   private def replaceInCache(header: SuitableHeader, k: K, params: SuitableParameters, cache: Cache[K, V]): V = {
+      val v = createValue(header, params, generateVersion(cache))
       cache.replace(k, v, toMillis(params.lifespan), DefaultTimeUnit, toMillis(params.maxIdle), DefaultTimeUnit)
    }
 
@@ -113,29 +124,63 @@
       sendResponse(ctx, e.getCause)
    }
 
-   def readHeader(buffer: ChannelBuffer): RequestHeader
+   def readHeader(buffer: ChannelBuffer): SuitableHeader
 
-   def getCache(header: RequestHeader): Cache[K, V]
+   def getCache(header: SuitableHeader): Cache[K, V]
 
    // todo: probably remove in favour of readKeys
-   def readKey(buffer: ChannelBuffer): K
+   def readKey(header: SuitableHeader, buffer: ChannelBuffer): K
 
-   def readKeys(buffer: ChannelBuffer): Array[K]
+   def readKeys(header: SuitableHeader, buffer: ChannelBuffer): Array[K]
 
-   def readParameters(op: Enumeration#Value, buffer: ChannelBuffer): SuitableParameters
+   def readParameters(header: SuitableHeader, buffer: ChannelBuffer): Option[SuitableParameters]
 
-   def createValue(params: SuitableParameters, nextVersion: Long): V 
+   def createValue(header: SuitableHeader, params: SuitableParameters, nextVersion: Long): V 
 
-   def sendResponse(header: RequestHeader, ctx: ChannelHandlerContext, k: Option[K], v: Option[V], params: Option[SuitableParameters], prev: Option[V])
+   def sendResponse(header: SuitableHeader, ctx: ChannelHandlerContext, k: Option[K], v: Option[V],
+                    params: Option[SuitableParameters], prev: Option[V]): AnyRef = {
+      val buffers = ctx.getChannelBuffers
+      val ch = ctx.getChannel
+      if (params == None || !params.get.noReply) {
+         // TODO consolidate this event further since both hotrod and memcached end up writing to a channel something,
+         // this methods here could just simply create the responses and let the common framework write them
+         val ret = header.op match {
+            case PutRequest => sendPutResponse(header, ch, buffers)
+            case GetRequest | GetWithVersionRequest => sendGetResponse(header, ch, buffers, k.get, v.get)
+            case PutIfAbsentRequest => sendPutIfAbsentResponse(header, ch, buffers, prev.get)
+            case ReplaceRequest => sendReplaceResponse(header, ch, buffers, prev.get)
+            case ReplaceIfUnmodifiedRequest => sendReplaceIfUnmodifiedResponse(header, ch, buffers, v, prev)
+            case RemoveRequest => sendRemoveResponse(header, ch, buffers, prev.get)
+//            case _ => sendCustomResponse(header, ch, buffers, v, prev)
+         }
+         ret
+      } else null
+   }
 
-   def sendResponse(header: RequestHeader, ctx: ChannelHandlerContext, pairs: Map[K, V])
+   def sendPutResponse(header: SuitableHeader, ch: Channel, buffers: ChannelBuffers): AnyRef
 
-   def sendResponse(ctx: ChannelHandlerContext, t: Throwable)
+   def sendGetResponse(header: SuitableHeader, ch: Channel, buffers: ChannelBuffers, k: K, v: V): AnyRef
 
-   def sendResponse(ctx: ChannelHandlerContext, stats: Stats)
+   def sendPutIfAbsentResponse(header: SuitableHeader, ch: Channel, buffers: ChannelBuffers, prev: V): AnyRef
 
-   def handleCustomRequest(header: RequestHeader, ctx: ChannelHandlerContext, buffer: ChannelBuffer, cache: Cache[K, V])
+   def sendReplaceResponse(header: SuitableHeader, ch: Channel, buffers: ChannelBuffers, prev: V): AnyRef
 
+   def sendReplaceIfUnmodifiedResponse(header: SuitableHeader, ch: Channel, buffers: ChannelBuffers,
+                                       v: Option[V], prev: Option[V]): AnyRef
+
+   def sendRemoveResponse(header: SuitableHeader, ch: Channel, buffers: ChannelBuffers, prev: V): AnyRef
+
+   def sendMultiGetResponse(header: SuitableHeader, ctx: ChannelHandlerContext, pairs: Map[K, V]): AnyRef
+   
+//   def sendCustomResponse(header: SuitableHeader, ch: Channel, buffers: ChannelBuffers, v: Option[V], prev: Option[V]): AnyRef
+
+   def sendResponse(ctx: ChannelHandlerContext, t: Throwable): AnyRef
+
+   def sendResponse(header: SuitableHeader, ctx: ChannelHandlerContext, stats: Stats): AnyRef
+
+   def handleCustomRequest(header: SuitableHeader, ctx: ChannelHandlerContext,
+                           buffer: ChannelBuffer, cache: Cache[K, V]): AnyRef
+
    /**
     * Transforms lifespan pass as seconds into milliseconds
     * following this rule:
@@ -170,10 +215,10 @@
    private val DefaultTimeUnit = TimeUnit.MILLISECONDS 
 }
 
-// todo: once I implement the hotrod see, revisit to see whether this class is still necessary,
-// todo: ...I suspect so cos I'd need a place to hold stuff that appears before the operation
 class RequestHeader(val op: Enumeration#Value)
 
-class RequestParameters(val data: Array[Byte], val lifespan: Int, val maxIdle: Int, val version: Long)
+class RequestParameters(val data: Array[Byte], val lifespan: Int, val maxIdle: Int, val streamVersion: Long, val noReply: Boolean)
 
-class UnknownOperationException(reason: String) extends StreamCorruptedException(reason)
\ No newline at end of file
+class UnknownOperationException(reason: String) extends StreamCorruptedException(reason)
+
+class ServerException(val header: RequestHeader, cause: Throwable) extends Exception(cause)
\ No newline at end of file

Copied: trunk/server/core/src/main/scala/org/infinispan/server/core/CacheValue.scala (from rev 1613, trunk/server/core/src/main/scala/org/infinispan/server/core/Value.scala)
===================================================================
--- trunk/server/core/src/main/scala/org/infinispan/server/core/CacheValue.scala	                        (rev 0)
+++ trunk/server/core/src/main/scala/org/infinispan/server/core/CacheValue.scala	2010-03-25 11:46:48 UTC (rev 1620)
@@ -0,0 +1,32 @@
+package org.infinispan.server.core
+
+import org.infinispan.util.Util
+import java.io.{Serializable, ObjectOutput, ObjectInput, Externalizable}
+
+/**
+ * // TODO: Document this
+ * @author Galder Zamarreño
+ * @since
+ */
+// TODO: Make it a hardcoded Externalizer
+class CacheValue(val data: Array[Byte], val version: Long) extends Serializable {
+
+   override def toString = {
+      new StringBuilder().append("CacheValue").append("{")
+         .append("data=").append(Util.printArray(data, false))
+         .append(", version=").append(version)
+         .append("}").toString
+   }
+
+//   override def readExternal(in: ObjectInput) {
+//      data = new Array[Byte](in.read())
+//      in.read(data)
+//      version = in.readLong
+//   }
+//
+//   override def writeExternal(out: ObjectOutput) {
+//      out.write(data.length)
+//      out.write(data)
+//      out.writeLong(version)
+//   }
+}
\ No newline at end of file

Modified: trunk/server/core/src/main/scala/org/infinispan/server/core/Operation.scala
===================================================================
--- trunk/server/core/src/main/scala/org/infinispan/server/core/Operation.scala	2010-03-25 10:49:02 UTC (rev 1619)
+++ trunk/server/core/src/main/scala/org/infinispan/server/core/Operation.scala	2010-03-25 11:46:48 UTC (rev 1620)
@@ -10,5 +10,5 @@
    type Operation = Value
    val PutRequest, PutIfAbsentRequest, ReplaceRequest, ReplaceIfUnmodifiedRequest = Value
    val GetRequest, GetWithVersionRequest = Value
-   val DeleteRequest, StatsRequest = Value
+   val RemoveRequest, StatsRequest = Value
 }
\ No newline at end of file

Deleted: trunk/server/core/src/main/scala/org/infinispan/server/core/Value.scala
===================================================================
--- trunk/server/core/src/main/scala/org/infinispan/server/core/Value.scala	2010-03-25 10:49:02 UTC (rev 1619)
+++ trunk/server/core/src/main/scala/org/infinispan/server/core/Value.scala	2010-03-25 11:46:48 UTC (rev 1620)
@@ -1,32 +0,0 @@
-package org.infinispan.server.core
-
-import org.infinispan.util.Util
-import java.io.{Serializable, ObjectOutput, ObjectInput, Externalizable}
-
-/**
- * // TODO: Document this
- * @author Galder Zamarreño
- * @since
- */
-// TODO: Make it a hardcoded Externalizer
-class Value(val v: Array[Byte], val version: Long) extends Serializable {
-
-   override def toString = {
-      new StringBuilder().append("Value").append("{")
-         .append("v=").append(Util.printArray(v, false))
-         .append(", version=").append(version)
-         .append("}").toString
-   }
-
-//   override def readExternal(in: ObjectInput) {
-//      v = new Array[Byte](in.read())
-//      in.read(v)
-//      version = in.readLong
-//   }
-//
-//   override def writeExternal(out: ObjectOutput) {
-//      out.write(v.length)
-//      out.write(v)
-//      out.writeLong(version)
-//   }
-}
\ No newline at end of file

Modified: trunk/server/core/src/main/scala/org/infinispan/server/core/transport/ChannelBuffer.scala
===================================================================
--- trunk/server/core/src/main/scala/org/infinispan/server/core/transport/ChannelBuffer.scala	2010-03-25 10:49:02 UTC (rev 1619)
+++ trunk/server/core/src/main/scala/org/infinispan/server/core/transport/ChannelBuffer.scala	2010-03-25 11:46:48 UTC (rev 1620)
@@ -9,7 +9,7 @@
 abstract class ChannelBuffer {
    def readByte: Byte
    def readBytes(dst: Array[Byte], dstIndex: Int, length: Int)
-   def readUnsignedByte: Float
+   def readUnsignedByte: Short
    def readUnsignedInt: Int
    def readUnsignedLong: Long
    def readBytes(length: Int): ChannelBuffer
@@ -22,6 +22,7 @@
     * Reads length of String and then returns an UTF-8 formatted String of such length.
     */
    def readString: String
+   def readLong: Long
    def writeByte(value: Byte)
    def writeBytes(src: Array[Byte])
 
@@ -37,6 +38,7 @@
     * Writes the length of the String followed by the String itself. This methods expects String not to be null.
     */
    def writeString(msg: String)
+   def writeLong(l: Long)
 
    def getUnderlyingChannelBuffer: AnyRef
 }
\ No newline at end of file

Copied: trunk/server/core/src/main/scala/org/infinispan/server/core/transport/VInt.scala (from rev 1610, trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/VInt.scala)
===================================================================
--- trunk/server/core/src/main/scala/org/infinispan/server/core/transport/VInt.scala	                        (rev 0)
+++ trunk/server/core/src/main/scala/org/infinispan/server/core/transport/VInt.scala	2010-03-25 11:46:48 UTC (rev 1620)
@@ -0,0 +1,33 @@
+package org.infinispan.server.core.transport
+
+/**
+ * Reads and writes unsigned variable length integer values. Even though it's deprecated, do not
+ * remove from source code for the moment because it's a good scala example and could be used
+ * as reference. 
+ *
+ * @author Galder Zamarreño
+ * @since 4.1
+ */
+object VInt {
+
+   def write(out: ChannelBuffer, i: Int) {
+      if ((i & ~0x7F) == 0) out.writeByte(i.toByte)
+      else {
+         out.writeByte(((i & 0x7f) | 0x80).toByte)
+         write(out, i >>> 7)
+      }
+   }
+
+   def read(in: ChannelBuffer): Int = {
+      val b = in.readByte
+      read(in, b, 7, b & 0x7F)
+   }
+
+   private def read(in: ChannelBuffer, b: Byte, shift: Int, i: Int): Int = {
+      if ((b & 0x80) == 0) i
+      else {
+         val bb = in.readByte
+         read(in, bb, shift + 7, i | ((bb & 0x7FL) << shift).toInt)
+      }
+   }
+}
\ No newline at end of file

Copied: trunk/server/core/src/main/scala/org/infinispan/server/core/transport/VLong.scala (from rev 1610, trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/VLong.scala)
===================================================================
--- trunk/server/core/src/main/scala/org/infinispan/server/core/transport/VLong.scala	                        (rev 0)
+++ trunk/server/core/src/main/scala/org/infinispan/server/core/transport/VLong.scala	2010-03-25 11:46:48 UTC (rev 1620)
@@ -0,0 +1,33 @@
+package org.infinispan.server.core.transport
+
+/**
+ * Reads and writes unsigned variable length long values. Even though it's deprecated, do not
+ * remove from source code for the moment because it's a good scala example and could be used
+ * as reference.
+ *
+ * @author Galder Zamarreño
+ * @since 4.1
+ */
+object VLong {
+
+   def write(out: ChannelBuffer, i: Long) {
+      if ((i & ~0x7F) == 0) out.writeByte(i.toByte)
+      else {
+         out.writeByte(((i & 0x7f) | 0x80).toByte)
+         write(out, i >>> 7)
+      }
+   }
+
+   def read(in: ChannelBuffer): Long = {
+      val b = in.readByte
+      read(in, b, 7, b & 0x7F)
+   }
+
+   private def read(in: ChannelBuffer, b: Byte, shift: Int, i: Long): Long = {
+      if ((b & 0x80) == 0) i
+      else {
+         val bb = in.readByte
+         read(in, bb, shift + 7, i | (bb & 0x7FL) << shift)
+      }
+   }
+}
\ No newline at end of file

Modified: trunk/server/core/src/main/scala/org/infinispan/server/core/transport/netty/ChannelBufferAdapter.scala
===================================================================
--- trunk/server/core/src/main/scala/org/infinispan/server/core/transport/netty/ChannelBufferAdapter.scala	2010-03-25 10:49:02 UTC (rev 1619)
+++ trunk/server/core/src/main/scala/org/infinispan/server/core/transport/netty/ChannelBufferAdapter.scala	2010-03-25 11:46:48 UTC (rev 1620)
@@ -1,7 +1,7 @@
 package org.infinispan.server.core.transport.netty
 
-import org.infinispan.server.core.transport.ChannelBuffer
 import org.jboss.netty.buffer.{ChannelBuffer => NettyChannelBuffer}
+import org.infinispan.server.core.transport.{VLong, VInt, ChannelBuffer}
 
 /**
  * // TODO: Document this
@@ -13,47 +13,43 @@
    
    override def readByte: Byte = buffer.readByte
    override def readBytes(dst: Array[Byte], dstIndex: Int, length: Int) = buffer.readBytes(dst, dstIndex, length)
-   override def readUnsignedByte: Float = buffer.readUnsignedByte
-   override def readUnsignedInt: Int = { // TODO
-      0
-      }
-   override def readUnsignedLong: Long = { // TODO
-      0
-      }
+   override def readUnsignedByte: Short = buffer.readUnsignedByte
+   override def readUnsignedInt: Int = VInt.read(this)
+   override def readUnsignedLong: Long = VLong.read(this)
    override def readBytes(length: Int): ChannelBuffer = new ChannelBufferAdapter(buffer.readBytes(length))
    override def readerIndex: Int = readerIndex
    override def readBytes(dst: Array[Byte]) = buffer.readBytes(dst) 
-   override def readRangedBytes: Array[Byte] = { // TODO
-      null
-      }
+   override def readRangedBytes: Array[Byte] = {
+      val array = new Array[Byte](readUnsignedInt)
+      readBytes(array)
+      array;
+   }
    override def readableBytes = buffer.writerIndex - buffer.readerIndex
 
    /**
     * Reads length of String and then returns an UTF-8 formatted String of such length.
     */
-   override def readString: String = { // TODO
-      null
-      }
+   override def readString: String = new String(readRangedBytes, "UTF8")
+   override def readLong: Long = buffer.readLong
    override def writeByte(value: Byte) = buffer.writeByte(value)
    override def writeBytes(src: Array[Byte]) = buffer.writeBytes(src)
 
    /**
     * Writes the length of the byte array and transfers the specified source array's data to this buffer
    */
-   override def writeRangedBytes(src: Array[Byte]) { // TODO
-      0
-      }
-   override def writeUnsignedInt(i: Int) { // TODO
-      }
-   override def writeUnsignedLong(l: Long) { // TODO
-      }
+   override def writeRangedBytes(src: Array[Byte]) {
+      writeUnsignedInt(src.length)
+      writeBytes(src)
+   }
+   override def writeUnsignedInt(i: Int) = VInt.write(this, i)
+   override def writeUnsignedLong(l: Long) = VLong.write(this, l)
    override def writerIndex: Int = buffer.writerIndex
 
    /**
     * Writes the length of the String followed by the String itself. This methods expects String not to be null.
     */
-   override def writeString(msg: String) { // TODO
-      }
+   override def writeString(msg: String) = writeRangedBytes(msg.getBytes())
+   override def writeLong(l: Long) = buffer.writeLong(l)
 
    override def getUnderlyingChannelBuffer: AnyRef = buffer
 

Copied: trunk/server/core/src/test/scala/org/infinispan/server/core/VariableLengthTest.scala (from rev 1610, trunk/server/hotrod/src/test/scala/org/infinispan/server/hotrod/VariableLengthTest.scala)
===================================================================
--- trunk/server/core/src/test/scala/org/infinispan/server/core/VariableLengthTest.scala	                        (rev 0)
+++ trunk/server/core/src/test/scala/org/infinispan/server/core/VariableLengthTest.scala	2010-03-25 11:46:48 UTC (rev 1620)
@@ -0,0 +1,123 @@
+package org.infinispan.server.hotrod
+
+import org.testng.annotations.Test
+import org.jboss.netty.buffer.{ChannelBuffers}
+import org.testng.Assert._
+import org.infinispan.server.core.transport.netty.{ChannelBufferAdapter}
+
+/**
+ * Appears that optional parameters in annotations result in compiler errors:
+ * https://lampsvn.epfl.ch/trac/scala/ticket/1810
+ *
+ * Keep an eye on that for @Test and @AfterClass annotations
+ *
+ * @author Galder Zamarreño
+ * @since 4.1
+ */
+
+ at Test(groups = Array("functional"), testName = "server.hotrod.VariableLengthTest")
+class VariableLengthTest {
+
+   def test2pow7minus1 {
+      writeReadInt(127, 1)
+   }
+
+   def test2pow7 {
+      writeReadInt(128, 2)
+   }
+
+   def test2pow14minus1 {
+      writeReadInt(16383, 2)
+   }
+
+   def test2pow14 {
+      writeReadInt(16384, 3)
+   }
+
+   def test2pow21minus1 {
+      writeReadInt(2097151, 3)
+   }
+
+   def test2pow21 {
+      writeReadInt(2097152, 4)
+   }
+
+   def test2pow28minus1 {
+      writeReadInt(268435455, 4)
+   }
+
+   def test2pow28 {
+      writeReadInt(268435456, 5)
+   }
+
+   def test2pow35minus1 {
+      writeReadLong(34359738367L, 5)
+   }
+
+   def test2pow35 {
+      writeReadLong(34359738368L, 6)
+   }
+
+   def test2pow42minus1 {
+      writeReadLong(4398046511103L, 6)
+   }
+
+   def test2pow42 {
+      writeReadLong(4398046511104L, 7)
+   }
+
+   def test2pow49minus1 {
+      writeReadLong(562949953421311L, 7)
+   }
+
+   def test2pow49 {
+      writeReadLong(562949953421312L, 8)
+   }
+
+   def test2pow56minus1 {
+      writeReadLong(72057594037927935L, 8)
+   }
+
+   def test2pow56 {
+      writeReadLong(72057594037927936L, 9)
+   }
+
+   def test2pow63minus1 {
+      writeReadLong(9223372036854775807L, 9)
+   }
+
+//   def test2pow63() {
+//      writeReadLong(9223372036854775808L, 10)
+//   }
+
+   private def writeReadInt(num: Int, expected: Int) {
+      val buffer = new ChannelBufferAdapter(ChannelBuffers.directBuffer(1024))
+      assert(buffer.writerIndex == 0)
+//      VInt.write(buffer, num)
+      buffer.writeUnsignedInt(num)
+      assertEquals(buffer.writerIndex, expected)
+//      assertEquals(VInt.read(buffer), num)
+      assertEquals(buffer.readUnsignedInt, num)
+   }
+
+   private def writeReadLong(num: Long, expected: Int) {
+      val buffer = new ChannelBufferAdapter(ChannelBuffers.directBuffer(1024))
+      assert(buffer.writerIndex == 0)
+//      VLong.write(buffer, num)
+      buffer.writeUnsignedLong(num)
+      assertEquals(buffer.writerIndex, expected)
+//      assertEquals(VLong.read(buffer), num)
+      assertEquals(buffer.readUnsignedLong, num)
+   }
+
+//   def testEquals128Old() {
+//      val baos = new ByteArrayOutputStream(1024);
+//      val oos = new ObjectOutputStream(baos);
+//      UnsignedNumeric.writeUnsignedInt(oos, 128);
+//      oos.flush();
+//      assertEquals(baos.size() - 6, 2);
+//      val bais = new ByteArrayInputStream(baos.toByteArray());
+//      val ois = new ObjectInputStream(bais);
+//      assertEquals(UnsignedNumeric.readUnsignedInt(ois), 128);
+//   }
+}
\ No newline at end of file

Added: trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/AbstractVersionedDecoder.scala
===================================================================
--- trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/AbstractVersionedDecoder.scala	                        (rev 0)
+++ trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/AbstractVersionedDecoder.scala	2010-03-25 11:46:48 UTC (rev 1620)
@@ -0,0 +1,42 @@
+package org.infinispan.server.hotrod
+
+import org.infinispan.server.core.RequestParameters
+import org.infinispan.server.core.CacheValue
+import org.infinispan.server.core.transport.{ChannelBuffers, Channel, ChannelBuffer}
+import org.infinispan.Cache
+import org.infinispan.stats.Stats
+
+/**
+ * // TODO: Document this
+ * @author Galder Zamarreño
+ * @since
+ */   
+abstract class AbstractVersionedDecoder {
+
+   def readHeader(buffer: ChannelBuffer, messageId: Long): HotRodHeader
+
+   def readKey(buffer: ChannelBuffer): CacheKey
+
+   def readKeys(buffer: ChannelBuffer): Array[CacheKey]
+
+   def readParameters(header: HotRodHeader, buffer: ChannelBuffer): Option[RequestParameters]
+
+   def createValue(params: RequestParameters, nextVersion: Long): CacheValue
+
+   def sendPutResponse(messageId: Long): AnyRef
+
+   def sendGetResponse(messageId: Long, v: CacheValue, op: Enumeration#Value): AnyRef
+
+   def sendPutIfAbsentResponse(messageId: Long, prev: CacheValue): AnyRef
+
+   def sendReplaceResponse(messageId: Long, prev: CacheValue): AnyRef
+
+   def sendReplaceIfUnmodifiedResponse(messageId: Long, v: Option[CacheValue], prev: Option[CacheValue]): AnyRef
+
+   def sendRemoveResponse(messageId: Long, prev: CacheValue): AnyRef
+
+   def handleCustomRequest(header: HotRodHeader, buffer: ChannelBuffer, cache: Cache[CacheKey, CacheValue]): AnyRef
+
+   def sendStatsResponse(header: HotRodHeader, stats: Stats): AnyRef
+
+}
\ No newline at end of file

Deleted: trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/Cache.scala
===================================================================
--- trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/Cache.scala	2010-03-25 10:49:02 UTC (rev 1619)
+++ trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/Cache.scala	2010-03-25 11:46:48 UTC (rev 1620)
@@ -1,13 +0,0 @@
-package org.infinispan.server.hotrod
-
-/**
- * // TODO: Document this
- * @author Galder Zamarreño
- * @since 4.1
- */
-
-abstract class Cache {
-   def put(c: StorageCommand): Response
-   def get(c: RetrievalCommand): Response
-   def putIfAbsent(c: StorageCommand): Response
-}
\ No newline at end of file

Added: trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/CacheKey.scala
===================================================================
--- trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/CacheKey.scala	                        (rev 0)
+++ trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/CacheKey.scala	2010-03-25 11:46:48 UTC (rev 1620)
@@ -0,0 +1,31 @@
+package org.infinispan.server.hotrod
+
+import java.io.Serializable
+import org.infinispan.util.Util
+import java.util.Arrays
+
+/**
+ * // TODO: Document this
+ * @author Galder Zamarreño
+ * @since
+ */
+
+final class CacheKey(val k: Array[Byte]) extends Serializable {
+
+   override def equals(obj: Any) = {
+      obj match {
+         // TODO: find out the right way to compare arrays in Scala
+         case k: CacheKey => Arrays.equals(k.k, this.k)
+         case _ => false
+      }
+   }
+
+   override def hashCode: Int = 41 + Arrays.hashCode(k)
+
+   override def toString = {
+      new StringBuilder().append("HotRodKey").append("{")
+         .append("k=").append(Util.printArray(k, true))
+         .append("}").toString
+   }
+
+}
\ No newline at end of file

Deleted: trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/CallerCache.scala
===================================================================
--- trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/CallerCache.scala	2010-03-25 10:49:02 UTC (rev 1619)
+++ trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/CallerCache.scala	2010-03-25 11:46:48 UTC (rev 1620)
@@ -1,89 +0,0 @@
-package org.infinispan.server.hotrod
-
-import org.infinispan.manager.{DefaultCacheManager, CacheManager}
-import java.util.concurrent.TimeUnit
-import org.infinispan.context.Flag
-import org.infinispan.{AdvancedCache, Cache => InfinispanCache}
-
-/**
- * // TODO: Document this
- * @author Galder Zamarreño
- * @since 4.0
- */
-
-class CallerCache(val manager: CacheManager) extends Cache {
-
-   import CallerCache._
-
-   override def put(c: StorageCommand): Response = {
-      val cache = getCache(c.cacheName, c.flags)
-      (c.lifespan, c.maxIdle) match {
-         case (0, 0) => cache.put(c.k, c.v)
-         case (x, 0) => cache.put(c.k, c.v, toMillis(c.lifespan), TimeUnit.MILLISECONDS)
-         case (x, y) => cache.put(c.k, c.v, toMillis(c.lifespan), TimeUnit.MILLISECONDS, c.maxIdle, TimeUnit.SECONDS)
-      }
-      new Response(c.id, OpCodes.PutResponse, Status.Success)
-   }
-
-   override def get(c: RetrievalCommand): Response = {
-      val cache = getCache(c.cacheName, c.flags)
-      val value = cache.get(c.k)
-      if (value != null)
-         new RetrievalResponse(c.id, OpCodes.GetResponse, Status.Success, value.v)
-      else
-         new RetrievalResponse(c.id, OpCodes.GetResponse, Status.KeyDoesNotExist, null)
-   }
-
-   override def putIfAbsent(c: StorageCommand): Response = {
-      val cache = getCache(c.cacheName, c.flags)
-      val prev =
-         (c.lifespan, c.maxIdle) match {
-            case (0, 0) => cache.putIfAbsent(c.k, c.v)
-            case (x, 0) => cache.putIfAbsent(c.k, c.v, toMillis(c.lifespan), TimeUnit.MILLISECONDS)
-            case (x, y) => cache.putIfAbsent(c.k, c.v, toMillis(c.lifespan), TimeUnit.MILLISECONDS, c.maxIdle, TimeUnit.SECONDS)
-         }
-      if (prev == null)
-         new Response(c.id, OpCodes.PutIfAbsentResponse, Status.Success)
-      else
-         new Response(c.id, OpCodes.PutIfAbsentResponse, Status.OperationNotExecuted)
-   }
-
-   private def getCache(cacheName: String, flags: Set[Flag]): InfinispanCache[Key, Value] = {
-      val isDefaultCache = cacheName == DefaultCacheManager.DEFAULT_CACHE_NAME
-      val isWithFlags = ! flags.isEmpty
-      (isDefaultCache, isWithFlags) match {
-         case (true, true) => getAdvancedCache.withFlags(flags.toSeq : _*)
-         case (true, false) => getAdvancedCache
-         case (false, true) => getAdvancedCache(cacheName).withFlags(flags.toSeq : _*)
-         case (false, false) => getAdvancedCache(cacheName)
-      }
-   }
-
-   private def getAdvancedCache(): AdvancedCache[Key, Value] =
-      manager.getCache[Key, Value].getAdvancedCache
-   
-   private def getAdvancedCache(cacheName: String): AdvancedCache[Key, Value] =
-      manager.getCache[Key, Value](cacheName).getAdvancedCache
-
-
-   /**
-    * Transforms lifespan pass as seconds into milliseconds
-    * following this rule:
-    *
-    * If lifespan is bigger than number of seconds in 30 days,
-    * then it is considered unix time. After converting it to
-    * milliseconds, we substract the current time in and the
-    * result is returned.
-    *
-    * Otherwise it's just considered number of seconds from
-    * now and it's returned in milliseconds unit.
-    */
-   private def toMillis(lifespan: Int) = {
-      if (lifespan > SecondsInAMonth) TimeUnit.SECONDS.toMillis(lifespan) - System.currentTimeMillis
-      else TimeUnit.SECONDS.toMillis(lifespan)
-   }
-}
-
-object CallerCache extends Logging {
-   private val SecondsInAMonth = 60 * 60 * 24 * 30
-}
\ No newline at end of file

Deleted: trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/Command.scala
===================================================================
--- trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/Command.scala	2010-03-25 10:49:02 UTC (rev 1619)
+++ trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/Command.scala	2010-03-25 11:46:48 UTC (rev 1620)
@@ -1,17 +0,0 @@
-package org.infinispan.server.hotrod
-
-import org.infinispan.context.Flag
-   
-/**
- * // TODO: Document this
- * 
- * @author Galder Zamarreño
- * @since 4.1
- */
-abstract class Command(val cacheName: String,
-                       val id: Long,
-                       val flags: Set[Flag]) {
-
-   def perform(cache: Cache): Response
-   
-}
\ No newline at end of file

Added: trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/Decoder10.scala
===================================================================
--- trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/Decoder10.scala	                        (rev 0)
+++ trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/Decoder10.scala	2010-03-25 11:46:48 UTC (rev 1620)
@@ -0,0 +1,188 @@
+package org.infinispan.server.hotrod
+
+import org.infinispan.server.core.Operation._
+import HotRodOperation._
+import OperationResponse._
+import OperationStatus._
+import org.infinispan.manager.CacheManager
+import org.infinispan.server.core.transport.{ChannelBuffer}
+import org.infinispan.server.core.{UnknownOperationException, RequestParameters, Logging, CacheValue}
+import org.infinispan.Cache
+import collection.mutable
+import collection.immutable
+import org.infinispan.stats.Stats
+
+/**
+ * // TODO: Document this
+ * @author Galder Zamarreño
+ * @since
+ */
+
+class Decoder10(cacheManager: CacheManager) extends AbstractVersionedDecoder {
+
+   type SuitableHeader = HotRodHeader
+
+   override def readHeader(buffer: ChannelBuffer, messageId: Long): HotRodHeader = {
+      val streamOp = buffer.readUnsignedByte
+      val op = OperationResolver.resolve(streamOp)
+      if (op == None) {
+         throw new UnknownOperationException("Unknown operation: " + streamOp);
+      }
+      val cacheName = buffer.readString
+      val flag = ProtocolFlag.apply(buffer.readUnsignedInt)
+      val clientIntelligence = buffer.readUnsignedByte
+      val topologyId = buffer.readUnsignedInt
+      new HotRodHeader(op.get, messageId, cacheName, flag, clientIntelligence, topologyId, this)
+   }
+
+   override def readKey(buffer: ChannelBuffer): CacheKey = new CacheKey(buffer.readRangedBytes)
+
+   override def readKeys(buffer: ChannelBuffer): Array[CacheKey] = Array(new CacheKey(buffer.readRangedBytes))
+
+   override def readParameters(header: HotRodHeader, buffer: ChannelBuffer): Option[RequestParameters] = {
+      if (header.op != RemoveRequest) {
+         val lifespan = {
+            val streamLifespan = buffer.readUnsignedInt
+            if (streamLifespan <= 0) -1 else streamLifespan
+         }
+         val maxIdle = {
+            val streamMaxIdle = buffer.readUnsignedInt
+            if (streamMaxIdle <= 0) -1 else streamMaxIdle
+         }
+         val version = header.op match {
+            case ReplaceIfUnmodifiedRequest | RemoveIfUnmodifiedRequest => buffer.readLong
+            case _ => -1
+         }
+         val data = buffer.readRangedBytes
+         Some(new RequestParameters(data, lifespan, maxIdle, version, false))
+      } else {
+         None
+      }
+   }
+
+   override def createValue(params: RequestParameters, nextVersion: Long): CacheValue = new CacheValue(params.data, nextVersion)
+
+   override def sendPutResponse(messageId: Long): AnyRef = new Response(messageId, PutResponse, Success)
+
+   override def sendGetResponse(messageId: Long, v: CacheValue, op: Enumeration#Value): AnyRef = {
+      if (v != null && op == GetRequest)
+         new GetResponse(messageId, GetResponse, Success, Some(v.data))
+      else if (v != null && op == GetWithVersionRequest)
+         new GetWithVersionResponse(messageId, GetWithVersionResponse, Success, Some(v.data), v.version)
+      else if (op == GetRequest)
+         new GetResponse(messageId, GetResponse, KeyDoesNotExist, None)
+      else
+         new GetWithVersionResponse(messageId, GetWithVersionResponse, KeyDoesNotExist, None, 0)
+   }
+
+   override def sendPutIfAbsentResponse(messageId: Long, prev: CacheValue): AnyRef = {
+      if (prev == null)
+         new Response(messageId, PutIfAbsentResponse, Success)
+      else
+         new Response(messageId, PutIfAbsentResponse, OperationNotExecuted)
+   }
+
+   def sendReplaceResponse(messageId: Long, prev: CacheValue): AnyRef = {
+      if (prev != null)
+         new Response(messageId, ReplaceResponse, Success)
+      else
+         new Response(messageId, ReplaceResponse, OperationNotExecuted)
+   }
+
+   override def sendReplaceIfUnmodifiedResponse(messageId: Long, v: Option[CacheValue],
+                                                prev: Option[CacheValue]): AnyRef = {
+      if (v != None && prev != None)
+         new Response(messageId, ReplaceIfUnmodifiedResponse, Success)
+      else if (v == None && prev != None)
+         new Response(messageId, ReplaceIfUnmodifiedResponse, OperationNotExecuted)
+      else
+         new Response(messageId, ReplaceIfUnmodifiedResponse, KeyDoesNotExist)
+   }
+
+   override def sendRemoveResponse(messageId: Long, prev: CacheValue): AnyRef = {
+      if (prev != null)
+         new Response(messageId, ReplaceResponse, Success)
+      else
+         new Response(messageId, ReplaceResponse, KeyDoesNotExist)
+   }
+
+   override def handleCustomRequest(header: HotRodHeader, buffer: ChannelBuffer, cache: Cache[CacheKey, CacheValue]): AnyRef = {
+      val messageId = header.messageId
+      header.op match {
+         case RemoveIfUnmodifiedRequest => {
+            val k = readKey(buffer)
+            val params = readParameters(header, buffer)
+            val prev = cache.get(k)
+            if (prev != null) {
+               if (prev.version == params.get.streamVersion) {
+                  val removed = cache.remove(k, prev);
+                  if (removed)
+                     new Response(messageId, RemoveIfUnmodifiedResponse, Success)
+                  else
+                     new Response(messageId, RemoveIfUnmodifiedResponse, OperationNotExecuted)
+               } else {
+                  new Response(messageId, RemoveIfUnmodifiedResponse, OperationNotExecuted)
+               }
+            } else {
+               new Response(messageId, RemoveIfUnmodifiedResponse, KeyDoesNotExist)
+            }
+         }
+         case ContainsKeyRequest => {
+            val k = readKey(buffer)
+            if (cache.containsKey(k))
+               new Response(messageId, ContainsKeyResponse, Success)
+            else
+               new Response(messageId, ContainsKeyResponse, KeyDoesNotExist)
+         }
+         case ClearRequest => {
+            cache.clear
+            new Response(messageId, ClearResponse, Success)
+         }
+         case PingRequest => new Response(messageId, PingResponse, Success) 
+      }
+   }
+
+   override def sendStatsResponse(header: HotRodHeader, stats: Stats): AnyRef = {
+      null
+//      val cacheStats = cache.getAdvancedCache.getStats
+//      val stats = mutable.Map[String, String]
+//      stats += ("timeSinceStart", cacheStats.getTimeSinceStart)
+//      stats += ("currentNumberOfEntries", cacheStats.getCurrentNumberOfEntries)
+//      stats += ("totalNumberOfEntries", cacheStats.getTotalNumberOfEntries)
+//      stats += ("stores", cacheStats.getStores)
+//      stats += ("retrievals", cacheStats.getRetrievals)
+//      stats += ("hits", cacheStats.getHits)
+//      stats += ("misses", cacheStats.getMisses)
+//      stats += ("removeHits", cacheStats.getRemoveHits)
+//      stats += ("removeMisses", cacheStats.getRemoveMisses)
+//      stats += ("evictions", cacheStats.getEvictions)
+//      new StatsResponse(header.messageId, immutable.Map ++ stats)
+   }
+}
+
+object OperationResolver extends Logging {
+   private val operations = Map[Int, Enumeration#Value](
+      0x01 -> PutRequest,
+      0x03 -> GetRequest,
+      0x05 -> PutIfAbsentRequest,
+      0x07 -> ReplaceRequest,
+      0x09 -> ReplaceIfUnmodifiedRequest,
+      0x0B -> RemoveRequest,
+      0x0D -> RemoveIfUnmodifiedRequest,
+      0x0F -> ContainsKeyRequest,
+      0x11 -> GetWithVersionRequest,
+      0x13 -> ClearRequest,
+      0x15 -> StatsRequest,
+      0x17 -> PingRequest 
+   )
+
+   def resolve(streamOp: Short): Option[Enumeration#Value] = {
+      val op = operations.get(streamOp)
+      if (op == None)
+         trace("Operation code: {0} was unmatched", streamOp)
+      else
+         trace("Operation code: {0} has been matched to {1}", streamOp, op)
+      op
+   }
+
+}
\ No newline at end of file

Deleted: trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/Decoder410.scala
===================================================================
--- trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/Decoder410.scala	2010-03-25 10:49:02 UTC (rev 1619)
+++ trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/Decoder410.scala	2010-03-25 11:46:48 UTC (rev 1620)
@@ -1,69 +0,0 @@
-package org.infinispan.server.hotrod
-
-import org.infinispan.server.core.UnknownCommandException
-import org.infinispan.server.hotrod.OpCodes._
-import org.infinispan.server.core.transport._
-
-/**
- * // TODO: Document this
- * @author Galder Zamarreño
- * @since 4.1
- */
-class Decoder410 {
-   import Decoder410._
-
-   def decode(ctx: ChannelHandlerContext, buffer: ChannelBuffer, id: Long): Command = {
-      val op = getOpCode(buffer)
-      val cacheName = buffer.readString
-      val flags = Flags.toContextFlags(buffer.readUnsignedInt)
-      val command: Command =
-         op match {                                   
-            case PutRequest | PutIfAbsentRequest => {
-               val k = new Key(buffer.readRangedBytes)
-               val lifespan = buffer.readUnsignedInt
-               val maxIdle = buffer.readUnsignedInt
-               val v = new Value(buffer.readRangedBytes)
-               val f = op match {
-                  case PutRequest => (cache: Cache, command: StorageCommand) => cache.put(command)
-                  case PutIfAbsentRequest => (cache: Cache, command: StorageCommand) => cache.putIfAbsent(command)
-               }
-               new StorageCommand(cacheName, id, k, lifespan, maxIdle, v, flags)(f)
-            }
-            case GetRequest => {
-               val k =  new Key(buffer.readRangedBytes)
-               new RetrievalCommand(cacheName, id, k, flags)({
-                  (cache: Cache, command: RetrievalCommand) => cache.get(command)
-               })
-            }
-            case _ => throw new UnknownCommandException("Command " + op + " not known")
-         }
-      command
-   }
-
-   private def getOpCode(buffer: ChannelBuffer): OpCodes.OpCode = {
-      val op: Int = buffer.readUnsignedByte
-      try {
-         OpCodes.apply(op)
-      } catch {
-         case n: NoSuchElementException =>
-            throw new UnknownCommandException("Operation code not valid: 0x" + op.toHexString + " (" + op + ")")
-      }
-   }
-
-//   override def exceptionCaught(ctx: ChannelHandlerContext, e: ExceptionEvent) {
-//      // no-op, handled by parent decoder
-////      val t = e.getCause
-////      error("Error", t)
-////      ctx.sendDownstream(e)
-////      val ch = ctx.getChannel
-////      val buffers = ctx.getChannelBuffers
-////      t match {
-////         case u: UnknownCommandException =>
-////      }
-//
-//
-//   }
-
-}
-
-object Decoder410 extends Logging
\ No newline at end of file

Deleted: trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/Encoder410.scala
===================================================================
--- trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/Encoder410.scala	2010-03-25 10:49:02 UTC (rev 1619)
+++ trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/Encoder410.scala	2010-03-25 11:46:48 UTC (rev 1620)
@@ -1,42 +0,0 @@
-package org.infinispan.server.hotrod
-
-import org.infinispan.server.core.transport.{ChannelBuffer, ChannelHandlerContext, Channel, Encoder}
-
-/**
- * // TODO: Document this
- * @author Galder Zamarreño
- * @since 4.1
- */
-
-class Encoder410 extends Encoder {
-   import Encoder410._
-
-   private val Magic = 0xA1
-
-   override def encode(ctx: ChannelHandlerContext, ch: Channel, msg: Object) = {
-      trace("Encode msg {0}", msg)
-      val buffer: ChannelBuffer =
-         msg match {
-            case r: Response => {
-               val buffer = ctx.getChannelBuffers.dynamicBuffer
-               buffer.writeByte(Magic.byteValue)
-               buffer.writeUnsignedLong(r.id)
-               buffer.writeByte(r.opCode.id.byteValue)
-               buffer.writeByte(r.status.id.byteValue)
-               buffer
-            }
-      }
-      msg match {
-         case rr: RetrievalResponse => if (rr.status == Status.Success) buffer.writeRangedBytes(rr.value)
-         case er: ErrorResponse => buffer.writeString(er.msg)
-         case _ => {
-            if (buffer == null)
-               throw new IllegalArgumentException("Response received is unknown: " + msg);
-         }
-      }
-      buffer
-   }
-   
-}
-
-object Encoder410 extends Logging
\ No newline at end of file

Deleted: trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/ErrorResponse.scala
===================================================================
--- trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/ErrorResponse.scala	2010-03-25 10:49:02 UTC (rev 1619)
+++ trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/ErrorResponse.scala	2010-03-25 11:46:48 UTC (rev 1620)
@@ -1,23 +0,0 @@
-package org.infinispan.server.hotrod
-
-/**
- * // TODO: Document this
- * @author Galder Zamarreño
- * @since 4.1
- */
-
-class ErrorResponse(override val id: Long,
-                    override val opCode: OpCodes.OpCode,
-                    override val status: Status.Status,
-                    val msg: String) extends Response(id, opCode, status) {
-
-   override def toString = {
-      new StringBuilder().append("ErrorResponse").append("{")
-         .append("id=").append(id)
-         .append(", opCode=").append(opCode)
-         .append(", status=").append(status)
-         .append(", msg=").append(msg)
-         .append("}").toString
-   }
-   
-}
\ No newline at end of file

Deleted: trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/Flags.scala
===================================================================
--- trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/Flags.scala	2010-03-25 10:49:02 UTC (rev 1619)
+++ trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/Flags.scala	2010-03-25 11:46:48 UTC (rev 1620)
@@ -1,46 +0,0 @@
-package org.infinispan.server.hotrod
-
-import scala.collection.mutable.HashSet
-import scala.collection.immutable
-import org.infinispan.context.Flag
-
-/**
- * // TODO: Document this
- * @author Galder Zamarreño
- * @since 4.0
- */
-
-object Flags extends Enumeration {
-
-   private val ZeroLockAcquisitionTimeout = Value(1, Flag.ZERO_LOCK_ACQUISITION_TIMEOUT.toString)
-   private val CacheModeLocal = Value(1 << 1, Flag.CACHE_MODE_LOCAL.toString)
-   private val SkipLocking = Value(1 << 2, Flag.SKIP_LOCKING.toString)
-   private val ForceWriteLock = Value(1 << 3, Flag.FORCE_WRITE_LOCK.toString) // TODO: Does it make sense? How start txs remotely?
-   private val SkipCacheStatusCheck = Value(1 << 4, Flag.SKIP_CACHE_STATUS_CHECK.toString)
-   private val ForceAsynchronous = Value(1 << 5, Flag.FORCE_ASYNCHRONOUS.toString)
-   private val ForceSynchronous = Value(1 << 6, Flag.FORCE_SYNCHRONOUS.toString)
-   // 1 << 7 skipped since that's the variable length marker
-   private val SkipCacheStore = Value(1 << 8, Flag.SKIP_CACHE_STORE.toString)
-   private val FailSilently = Value(1 << 9, Flag.FAIL_SILENTLY.toString)
-   private val SkipRemoteLookup = Value(1 << 10, Flag.SKIP_REMOTE_LOOKUP.toString)
-   private val PutForExternalRead = Value(1 << 11, Flag.PUT_FOR_EXTERNAL_READ.toString)
-
-   def toContextFlags(bitFlags: Int): Set[Flag] = {
-      val s = new HashSet[Flag]
-      Flags.values.filter(f => (bitFlags & f.id) > 0).foreach(f => s += Flag.valueOf(f.toString))
-      new immutable.HashSet ++ s
-   }
-
-   /**
-    * Takes a Set of Infinispan context Flag instances and converts
-    * it into a int that can be sent with Hot Rod protocol.
-    * 
-    * This method has merely been implemented for testing purposes,
-    * to make it easier to test clients sending different flags. 
-    */
-   def fromContextFlags(flags: Set[Flag]): Int = {
-      var bitFlags = 0
-      Flags.values.filter(f => flags.contains(Flag.valueOf(f.toString))).foreach(f => bitFlags = bitFlags | f.id)
-      bitFlags
-   }
-}
\ No newline at end of file

Deleted: trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/GlobalDecoder.scala
===================================================================
--- trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/GlobalDecoder.scala	2010-03-25 10:49:02 UTC (rev 1619)
+++ trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/GlobalDecoder.scala	2010-03-25 11:46:48 UTC (rev 1620)
@@ -1,70 +0,0 @@
-package org.infinispan.server.hotrod
-
-import java.io.StreamCorruptedException
-import org.infinispan.server.core.transport._
-import org.infinispan.server.core.UnknownCommandException
-import org.infinispan.util.concurrent.TimeoutException
-
-/**
- * // TODO: Document this
- * @author Galder Zamarreño
- * @since 4.1
- */
-class GlobalDecoder extends NoStateDecoder {
-
-   import GlobalDecoder._
-
-   private val Magic = 0xA0
-   private val Version410 = 41
-   @volatile private var isError = false
-
-   override def decode(ctx: ChannelHandlerContext, buffer: ChannelBuffer): Object = {
-      val magic = buffer.readUnsignedByte()
-      if (magic != Magic) {
-         if (!isError) {
-            val t = new StreamCorruptedException("Error reading magic byte or message id: " + magic)
-            return createErrorResponse(0, Status.InvalidMagicOrMsgId, t) 
-         } else {
-            trace("Error happened previously, ignoring {0} byte until we find the magic number again", magic)
-            return null // Keep trying to read until we find magic
-         }
-      }
-
-      val id = buffer.readUnsignedLong
-
-      try {
-         val version = buffer.readUnsignedByte()
-         val decoder =
-            version match {
-               case Version410 => new Decoder410
-               case _ => {
-                  isError = true
-                  return new ErrorResponse(id, OpCodes.ErrorResponse, Status.UnknownVersion, "Unknown version:" + version)
-               }
-            }
-         val command = decoder.decode(ctx, buffer, id)
-         trace("Decoded msg {0}", command)
-         isError = false
-         command
-      } catch {
-         case u: UnknownCommandException => createErrorResponse(id, Status.UnknownCommand, u)
-         case s: StreamCorruptedException => createErrorResponse(id, Status.ParseError, s)
-         case o: TimeoutException => createErrorResponse(id, Status.CommandTimedOut, o)
-         case t: Throwable => createErrorResponse(id, Status.ServerError, t)
-      }
-   }
-
-   private def createErrorResponse(id: Long, status: Status.Status, t: Throwable): ErrorResponse = {
-      isError = true
-      error("Error processing command", t)
-      val m = if (t.getMessage != null) t.getMessage else ""
-      new ErrorResponse(id, OpCodes.ErrorResponse, status, m)
-   }
-
-   override def exceptionCaught(ctx: ChannelHandlerContext, e: ExceptionEvent) {
-      error("Unexpected error", e.getCause)
-   }
-
-}
-
-object GlobalDecoder extends Logging
\ No newline at end of file

Deleted: trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/Handler.scala
===================================================================
--- trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/Handler.scala	2010-03-25 10:49:02 UTC (rev 1619)
+++ trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/Handler.scala	2010-03-25 11:46:48 UTC (rev 1620)
@@ -1,25 +0,0 @@
-package org.infinispan.server.hotrod
-
-import org.infinispan.server.core.transport.{CommandHandler, MessageEvent, ChannelHandlerContext}
-
-/**
- * // TODO: Document this
- * @author Galder Zamarreño
- * @since 4.1
- */
-
-class Handler(val hotCache: CallerCache) extends CommandHandler {
-
-   override def messageReceived(ctx: ChannelHandlerContext, e: MessageEvent) {
-      e.getMessage match {
-//         case c: StorageCommand => e.getChannel.write(c.op(hotCache, c))
-         case c: Command => e.getChannel.write(c.perform(hotCache))
-         case er: ErrorResponse => e.getChannel.write(er) 
-      }
-
-
-//      e.getMessage match {
-//         case s: StorageCommand => s.perform(s)
-//      }
-   }
-}
\ No newline at end of file

Added: trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/HotRodDecoder.scala
===================================================================
--- trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/HotRodDecoder.scala	                        (rev 0)
+++ trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/HotRodDecoder.scala	2010-03-25 11:46:48 UTC (rev 1620)
@@ -0,0 +1,145 @@
+package org.infinispan.server.hotrod
+
+import org.infinispan.Cache
+import org.infinispan.stats.Stats
+import java.io.StreamCorruptedException
+import org.infinispan.server.core._
+import OperationStatus._
+import HotRodOperation._
+import ProtocolFlag._
+import transport._
+import org.infinispan.manager.{DefaultCacheManager, CacheManager}
+
+/**
+ * // TODO: Document this
+ * @author Galder Zamarreño
+ * @since
+ */
+
+class HotRodDecoder(cacheManager: CacheManager) extends AbstractProtocolDecoder[CacheKey, CacheValue] {
+   import HotRodDecoder._
+   
+   type SuitableHeader = HotRodHeader
+   type SuitableParameters = RequestParameters
+
+   @volatile private var isError = false
+
+   override def readHeader(buffer: ChannelBuffer): HotRodHeader = {
+      try {
+         val magic = buffer.readUnsignedByte
+         if (magic != Magic) {
+            if (!isError) {               
+               throw new InvalidMagicIdException("Error reading magic byte or message id: " + magic)
+            } else {
+               trace("Error happened previously, ignoring {0} byte until we find the magic number again", magic)
+               return null // Keep trying to read until we find magic
+            }
+         }
+      } catch {
+         case e: Exception => {
+            isError = true
+            throw new ServerException(new ErrorHeader(0), e)
+         }
+      }
+
+      val messageId = buffer.readUnsignedLong
+      
+      try {
+         val version = buffer.readUnsignedByte
+         val decoder = version match {
+            case Version10 => new Decoder10(cacheManager)
+            case _ => throw new UnknownVersionException("Unknown version:" + version)
+         }
+         val header = decoder.readHeader(buffer, messageId)
+         trace("Decoded header {0}", header)
+         isError = false
+         header
+      } catch {
+         case e: Exception => {
+            isError = true
+            throw new ServerException(new ErrorHeader(messageId), e)
+         }
+      }
+   }
+
+   override def getCache(header: HotRodHeader): Cache[CacheKey, CacheValue] = {
+      if (header.cacheName == DefaultCacheManager.DEFAULT_CACHE_NAME) cacheManager.getCache[CacheKey, CacheValue]
+      else cacheManager.getCache(header.cacheName)
+   }
+
+   override def readKey(header: HotRodHeader, buffer: ChannelBuffer): CacheKey = header.decoder.readKey(buffer)
+
+   override def readKeys(header: HotRodHeader, buffer: ChannelBuffer): Array[CacheKey] =
+      header.decoder.readKeys(buffer)
+
+   override def readParameters(header: HotRodHeader, buffer: ChannelBuffer): Option[RequestParameters] =
+      header.decoder.readParameters(header, buffer)
+
+   override def createValue(header: HotRodHeader, params: RequestParameters, nextVersion: Long): CacheValue =
+      header.decoder.createValue(params, nextVersion)
+
+   override def sendPutResponse(header: HotRodHeader, ch: Channel, buffers: ChannelBuffers): AnyRef =
+      header.decoder.sendPutResponse(header.messageId)
+
+   override def sendGetResponse(header: HotRodHeader, ch: Channel, buffers: ChannelBuffers,
+                                k: CacheKey, v: CacheValue): AnyRef =
+      header.decoder.sendGetResponse(header.messageId, v, header.op)
+
+   override def sendPutIfAbsentResponse(header: HotRodHeader, ch: Channel, buffers: ChannelBuffers,
+                                        prev: CacheValue): AnyRef =
+      header.decoder.sendPutIfAbsentResponse(header.messageId, prev)
+
+   override def sendReplaceResponse(header: HotRodHeader, ch: Channel, buffers: ChannelBuffers,
+                                    prev: CacheValue): AnyRef =
+      header.decoder.sendReplaceResponse(header.messageId, prev)
+
+   override def sendReplaceIfUnmodifiedResponse(header: HotRodHeader, ch: Channel, buffers: ChannelBuffers,
+                                                v: Option[CacheValue], prev: Option[CacheValue]): AnyRef =
+      header.decoder.sendReplaceIfUnmodifiedResponse(header.messageId, v, prev)
+
+   override def sendRemoveResponse(header: HotRodHeader, ch: Channel, buffers: ChannelBuffers,
+                                   prev: CacheValue): AnyRef =
+      header.decoder.sendRemoveResponse(header.messageId, prev)
+
+   override def sendMultiGetResponse(header: HotRodHeader, ctx: ChannelHandlerContext,
+                                     pairs: Map[CacheKey, CacheValue]): AnyRef = null // Unsupported
+
+   override def handleCustomRequest(header: HotRodHeader, ctx: ChannelHandlerContext,
+                                    buffer: ChannelBuffer, cache: Cache[CacheKey, CacheValue]): AnyRef =
+      header.decoder.handleCustomRequest(header, buffer, cache)
+
+   override def sendResponse(header: HotRodHeader, ctx: ChannelHandlerContext, stats: Stats): AnyRef =
+      header.decoder.sendStatsResponse(header, stats)
+
+   override def sendResponse(ctx: ChannelHandlerContext, t: Throwable): AnyRef = {
+      val ch = ctx.getChannel
+      val buffers = ctx.getChannelBuffers
+      val errorResponse = t match {
+         case se: ServerException => {
+            val messageId = se.header.asInstanceOf[HotRodHeader].messageId
+            se.getCause match {
+               case imie: InvalidMagicIdException => new ErrorResponse(0, InvalidMagicOrMsgId, imie.toString)
+               case uoe: UnknownOperationException => new ErrorResponse(messageId, UnknownOperation, uoe.toString)
+               case uve: UnknownVersionException => new ErrorResponse(messageId, UnknownVersion, uve.toString)
+               // TODO add more cases
+               case e: Exception => new ErrorResponse(messageId, ServerError, e.toString)  
+            }
+         }
+      }
+      ch.write(errorResponse)
+      null
+   }
+
+   override def start {}
+
+   override def stop {}
+}
+
+object HotRodDecoder extends Logging {
+   private val Magic = 0xA0
+   private val Version10 = 10
+}
+
+class UnknownVersionException(reason: String) extends StreamCorruptedException(reason)
+
+class InvalidMagicIdException(reason: String) extends StreamCorruptedException(reason)
\ No newline at end of file

Added: trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/HotRodEncoder.scala
===================================================================
--- trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/HotRodEncoder.scala	                        (rev 0)
+++ trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/HotRodEncoder.scala	2010-03-25 11:46:48 UTC (rev 1620)
@@ -0,0 +1,56 @@
+package org.infinispan.server.hotrod
+
+import org.infinispan.server.core.Logging
+import org.infinispan.server.core.transport.{ChannelBuffer, ChannelHandlerContext, Channel, Encoder}
+import OperationStatus._
+
+/**
+ * // TODO: Document this
+ * @author Galder Zamarreño
+ * @since
+ */
+
+class HotRodEncoder extends Encoder {
+   import HotRodEncoder._
+
+   override def encode(ctx: ChannelHandlerContext, channel: Channel, msg: AnyRef): AnyRef = {
+      trace("Encode msg {0}", msg)
+      val buffer: ChannelBuffer = msg match {
+         case r: Response => writeHeader(ctx.getChannelBuffers.dynamicBuffer, r)
+//         case s: StatsResponse => {
+//            val buffer = ctx.getChannelBuffers.dynamicBuffer
+//            for ((key, value) <- s.stats) {
+//               writeHeader(buffer, s)
+//               buffer.writeString(key)
+//               buffer.writeString(value)
+//            }
+//         }
+      }
+      msg match {
+         case g: GetWithVersionResponse => {
+            if (g.status == Success) {
+               buffer.writeLong(g.version)
+               buffer.writeRangedBytes(g.data.get)
+            }
+         }
+         case g: GetResponse => if (g.status == Success) buffer.writeRangedBytes(g.data.get)
+         case e: ErrorResponse => buffer.writeString(e.msg)
+         case _ => if (buffer == null) throw new IllegalArgumentException("Response received is unknown: " + msg);         
+      }
+      buffer
+   }
+
+   private def writeHeader(buffer: ChannelBuffer, r: Response): ChannelBuffer = {
+      buffer.writeByte(Magic.byteValue)
+      buffer.writeUnsignedLong(r.messageId)
+      buffer.writeByte(r.operation.id.byteValue)
+      buffer.writeByte(r.status.id.byteValue)
+      buffer.writeByte(0) // topology change marker
+      buffer
+   }
+   
+}
+
+object HotRodEncoder extends Logging {
+   private val Magic = 0xA1
+}
\ No newline at end of file

Added: trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/HotRodHeader.scala
===================================================================
--- trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/HotRodHeader.scala	                        (rev 0)
+++ trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/HotRodHeader.scala	2010-03-25 11:46:48 UTC (rev 1620)
@@ -0,0 +1,22 @@
+package org.infinispan.server.hotrod
+
+import org.infinispan.server.core.RequestHeader
+import org.infinispan.server.hotrod.ProtocolFlag._
+import org.infinispan.server.hotrod.OperationResponse._
+
+/**
+ * // TODO: Document this
+ * @author Galder Zamarreño
+ * @since
+ */
+
+class HotRodHeader(override val op: Enumeration#Value, val messageId: Long, val cacheName: String,
+                   val flag: ProtocolFlag, val clientIntelligence: Short, val topologyId: Int,
+                   val decoder: AbstractVersionedDecoder) extends RequestHeader(op) {
+
+   // TODO: add meaningfull toString()
+}
+
+class ErrorHeader(override val messageId: Long) extends HotRodHeader(ErrorResponse, messageId, "", NoFlag, 0, 0, null) {
+   // TODO: add meaningfull toString()   
+}
\ No newline at end of file

Added: trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/HotRodOperation.scala
===================================================================
--- trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/HotRodOperation.scala	                        (rev 0)
+++ trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/HotRodOperation.scala	2010-03-25 11:46:48 UTC (rev 1620)
@@ -0,0 +1,18 @@
+package org.infinispan.server.hotrod
+
+/**
+ * // TODO: Document this
+ * @author Galder Zamarreño
+ * @since
+ */
+
+object HotRodOperation extends Enumeration(20) {
+   type HotRodOperation = Value
+
+   val RemoveIfUnmodifiedRequest = Value
+   val ContainsKeyRequest = Value
+   val ClearRequest = Value
+   val QuitRequest = Value
+   val PingRequest = Value
+
+}
\ No newline at end of file

Modified: trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/HotRodServer.scala
===================================================================
--- trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/HotRodServer.scala	2010-03-25 10:49:02 UTC (rev 1619)
+++ trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/HotRodServer.scala	2010-03-25 11:46:48 UTC (rev 1620)
@@ -1,41 +1,47 @@
 package org.infinispan.server.hotrod
 
 import org.infinispan.manager.CacheManager
-import java.net.InetSocketAddress
-import org.infinispan.server.core.transport.netty.{NettyNoStateDecoder, NettyEncoder, NettyServer, NettyDecoder}
-import org.infinispan.server.core.transport.Server
+import org.infinispan.server.core.AbstractProtocolServer
+import org.infinispan.server.core.transport.{Decoder, Encoder}
 
 /**
  * // TODO: Document this
  * @author Galder Zamarreño
- * @since 3.5
+ * @since 4.1
  */
 
-class HotRodServer(val host: String,
-                val port: Int,
-                val manager: CacheManager,
-                val masterThreads: Int,
-                val workerThreads: Int) {
+class HotRodServer extends AbstractProtocolServer {
 
-   import HotRodServer._
+   protected override def getEncoder: Encoder = new HotRodEncoder
 
-   private var server: Server = _
+   protected override def getDecoder(cacheManager: CacheManager): Decoder = new HotRodDecoder(cacheManager)
 
-   def start {
-      val decoder = new GlobalDecoder
-      val nettyDecoder = new NettyNoStateDecoder(decoder)      
-      val encoder = new Encoder410
-      val nettyEncoder = new NettyEncoder(encoder)
-      val commandHandler = new Handler(new CallerCache(manager))
-      server = new NettyServer(commandHandler, nettyDecoder, nettyEncoder, new InetSocketAddress(host, port),
-                               masterThreads, workerThreads, "HotRod")
-      server.start
-      info("Started Hot Rod bound to {0}:{1}", host, port)
-   }
-
-   def stop {
-      if (server != null) server.stop
-   }
 }
 
-object HotRodServer extends Logging
\ No newline at end of file
+//
+////class HotRodServer(val host: String,
+////                val port: Int,
+////                val manager: CacheManager,
+////                val masterThreads: Int,
+////                val workerThreads: Int) {
+////
+////   import HotRodServer._
+////
+////   private var server: Server = _
+////
+////   def start {
+////      val decoder = new GlobalDecoder
+////      val nettyDecoder = new NettyNoStateDecoder(decoder)
+////      val encoder = new Encoder410
+////      val nettyEncoder = new NettyEncoder(encoder)
+////      val commandHandler = new Handler(new CallerCache(manager))
+////      server = new NettyServer(commandHandler, nettyDecoder, nettyEncoder, new InetSocketAddress(host, port),
+////                               masterThreads, workerThreads, "HotRod")
+////      server.start
+////      info("Started Hot Rod bound to {0}:{1}", host, port)
+////   }
+////
+////   def stop {
+////      if (server != null) server.stop
+////   }
+////}
\ No newline at end of file

Deleted: trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/Key.scala
===================================================================
--- trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/Key.scala	2010-03-25 10:49:02 UTC (rev 1619)
+++ trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/Key.scala	2010-03-25 11:46:48 UTC (rev 1620)
@@ -1,38 +0,0 @@
-package org.infinispan.server.hotrod
-
-import java.util.Arrays
-import java.io.{ObjectOutput, ObjectInput, Externalizable}
-
-/**
- * // TODO: Document this
- * @author Galder Zamarreño
- * @since
- */
-// TODO: Make it an Externalizer once submodules can extend the marshalling framework
-final class Key(var k: Array[Byte]) extends Externalizable {
-
-   override def equals(obj: Any) = {
-      obj match {
-         case k: Key => Arrays.equals(k.k, this.k)
-         case _ => false
-      }
-   }
-
-   override def hashCode: Int = 41 + Arrays.hashCode(k)
-
-   override def toString = {
-      new StringBuilder().append("Key").append("{")
-         .append("k=").append(k)
-         .append("}").toString
-   }
-
-   override def readExternal(in: ObjectInput) {
-      k = new Array[Byte](in.read())
-      in.read(k)
-   }
-
-   override def writeExternal(out: ObjectOutput) {
-      out.write(k.length)
-      out.write(k)
-   }
-}
\ No newline at end of file

Deleted: trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/Logging.scala
===================================================================
--- trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/Logging.scala	2010-03-25 10:49:02 UTC (rev 1619)
+++ trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/Logging.scala	2010-03-25 11:46:48 UTC (rev 1620)
@@ -1,41 +0,0 @@
-package org.infinispan.server.hotrod
-
-import org.infinispan.util.logging.{Log, LogFactory}
-import collection.mutable.WrappedArray
-
-/**
- * TODO: This would be simplest way to get logging in but unfortunately it creates
- * a new Log instance per object created 
- *
- * // TODO: Document this
- * @author Galder Zamarreño
- * @since 4.1
- */
-trait Logging {
-   private lazy val log: Log = LogFactory.getLog(getClass)
-
-   def info(msg: => String) = log.info(msg, null)
-
-   def info(msg: => String, params: Any*) =
-      // params.map(_.asInstanceOf[AnyRef]) => returns a Seq[AnyRef]
-      // the ': _*' part tells the compiler to pass it as varargs
-      if (log.isInfoEnabled) log.info(msg, params.map(_.asInstanceOf[AnyRef]) : _*)
-
-   def trace(msg: => String) = log.trace(msg, null)
-
-   def trace(msg: => String, params: Any*) =
-      if (log.isTraceEnabled) log.trace(msg, params.map(_.asInstanceOf[AnyRef]) : _*)
-
-   def error(msg: => String) = log.error(msg, null)
-
-   def error(msg: => String, t: Throwable) = log.error(msg, t, null)
-
-   // TODO: Sort out the other error methods that take both Throwable and varargs
-
-//   def error(msg: => String, params: Any*) =
-//      if (log.isErrorEnabled) log.error(msg, params.map(_.asInstanceOf[AnyRef]) : _*)
-//
-//   def error(msg: => String, t: Throwable, params: Any*) =
-//      if (log.isErrorEnabled) log.error(msg, t, params.map(_.asInstanceOf[AnyRef]) : _*)
-
-}
\ No newline at end of file

Deleted: trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/OpCodes.scala
===================================================================
--- trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/OpCodes.scala	2010-03-25 10:49:02 UTC (rev 1619)
+++ trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/OpCodes.scala	2010-03-25 11:46:48 UTC (rev 1620)
@@ -1,20 +0,0 @@
-package org.infinispan.server.hotrod
-
-/**
- * // TODO: Document this
- * @author Galder Zamarreño
- * @since 4.1
- */
-
-object OpCodes extends Enumeration {
-   type OpCode = Value
-
-   val PutRequest = Value(0x01)
-   val PutResponse = Value(0x02)
-   val GetRequest = Value(0x03)
-   val GetResponse = Value(0x04)
-   val PutIfAbsentRequest = Value(0x05)
-   val PutIfAbsentResponse = Value(0x06)
-
-   val ErrorResponse = Value(0x50)
-}
\ No newline at end of file

Added: trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/OperationResponse.scala
===================================================================
--- trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/OperationResponse.scala	                        (rev 0)
+++ trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/OperationResponse.scala	2010-03-25 11:46:48 UTC (rev 1620)
@@ -0,0 +1,25 @@
+package org.infinispan.server.hotrod
+
+/**
+ * // TODO: Document this
+ * @author Galder Zamarreño
+ * @since
+ */
+
+object OperationResponse extends Enumeration {
+   type OperationResponse = Value
+
+   val PutResponse = Value(0x02)
+   val GetResponse = Value(0x04)
+   val PutIfAbsentResponse = Value(0x06)
+   val ReplaceResponse = Value(0x08)
+   val ReplaceIfUnmodifiedResponse = Value(0x0A)
+   val RemoveResponse = Value(0x0C)
+   val RemoveIfUnmodifiedResponse = Value(0x0E)
+   val ContainsKeyResponse = Value(0x10)
+   val GetWithVersionResponse = Value(0x12)
+   val ClearResponse = Value(0x14)
+   val StatsResponse = Value(0x16)
+   val PingResponse = Value(0x18)
+   val ErrorResponse = Value(0x50)
+}
\ No newline at end of file

Copied: trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/OperationStatus.scala (from rev 1610, trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/Status.scala)
===================================================================
--- trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/OperationStatus.scala	                        (rev 0)
+++ trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/OperationStatus.scala	2010-03-25 11:46:48 UTC (rev 1620)
@@ -0,0 +1,23 @@
+package org.infinispan.server.hotrod
+
+/**
+ * // TODO: Document this
+ * @author Galder Zamarreño
+ * @since 4.1
+ */
+
+object OperationStatus extends Enumeration {
+   type OperationStatus = Value
+
+   val Success = Value(0x00)
+   val OperationNotExecuted = Value(0x01)
+   val KeyDoesNotExist = Value(0x02)
+
+   val InvalidMagicOrMsgId = Value(0x81)
+   val UnknownOperation = Value(0x82)
+   val UnknownVersion = Value(0x83) // todo: test
+   val ParseError = Value(0x84) // todo: test
+   val ServerError = Value(0x85) // todo: test
+   val OperationTimedOut = Value(0x86) // todo: test
+
+}
\ No newline at end of file

Added: trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/ProtocolFlag.scala
===================================================================
--- trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/ProtocolFlag.scala	                        (rev 0)
+++ trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/ProtocolFlag.scala	2010-03-25 11:46:48 UTC (rev 1620)
@@ -0,0 +1,13 @@
+package org.infinispan.server.hotrod
+
+/**
+ * // TODO: Document this
+ * @author Galder Zamarreño
+ * @since
+ */
+
+object ProtocolFlag extends Enumeration {
+   type ProtocolFlag = Value
+   val NoFlag = Value(0)
+   val ForceReturnValue = Value(1)
+}
\ No newline at end of file

Modified: trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/Response.scala
===================================================================
--- trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/Response.scala	2010-03-25 10:49:02 UTC (rev 1619)
+++ trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/Response.scala	2010-03-25 11:46:48 UTC (rev 1620)
@@ -1,21 +1,53 @@
 package org.infinispan.server.hotrod
 
+import OperationStatus._
+import OperationResponse._
+
 /**
  * // TODO: Document this
  * @author Galder Zamarreño
  * @since 4.1
  */
 
-class Response(val id: Long,
-               val opCode: OpCodes.OpCode,
-               val status: Status.Status) {
+class Response(val messageId: Long, val operation: OperationResponse, val status: OperationStatus) {
 
    override def toString = {
       new StringBuilder().append("Response").append("{")
-         .append("id=").append(id)
-         .append(", opCode=").append(opCode)
+         .append("messageId=").append(messageId)
+         .append(", operation=").append(operation)
          .append(", status=").append(status)
          .append("}").toString
    }
 
-}
\ No newline at end of file
+}
+
+class GetResponse(override val messageId: Long, override val operation: OperationResponse,
+                  override val status: OperationStatus, val data: Option[Array[Byte]])
+      extends Response(messageId, operation, status) {
+
+   // TODO add meaningful toString()
+}
+
+class GetWithVersionResponse(override val messageId: Long, override val operation: OperationResponse,
+                             override val status: OperationStatus, override val data: Option[Array[Byte]],
+                             val version: Long)
+      extends GetResponse(messageId, operation, status, data) {
+
+   // TODO add meaningful toString()
+}
+
+class ErrorResponse(override val messageId: Long, override val status: OperationStatus,
+                    val msg: String) extends Response(messageId, ErrorResponse, status) {
+
+   override def toString = {
+      new StringBuilder().append("ErrorResponse").append("{")
+         .append("messageId=").append(messageId)
+         .append(", operation=").append(operation)
+         .append(", status=").append(status)
+         .append(", msg=").append(msg)
+         .append("}").toString
+   }
+
+}
+
+class StatsResponse(override val messageId: Long, val stats: Map[String, String]) extends Response(messageId, StatsResponse, Success)
\ No newline at end of file

Deleted: trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/RetrievalCommand.scala
===================================================================
--- trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/RetrievalCommand.scala	2010-03-25 10:49:02 UTC (rev 1619)
+++ trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/RetrievalCommand.scala	2010-03-25 11:46:48 UTC (rev 1620)
@@ -1,21 +0,0 @@
-package org.infinispan.server.hotrod
-
-import org.infinispan.context.Flag
-
-/**
- * // TODO: Document this
- * @author Galder Zamarreño
- * @since 4.1
- */
-
-class RetrievalCommand(override val cacheName: String,
-                       override val id: Long,
-                       val k: Key,
-                       override val flags: Set[Flag])
-                      (val op: (Cache, RetrievalCommand) => Response) extends Command(cacheName, id, flags) {
-
-   override def perform(cache: Cache): Response = {
-      op(cache, this)
-   }
-
-}
\ No newline at end of file

Deleted: trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/RetrievalResponse.scala
===================================================================
--- trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/RetrievalResponse.scala	2010-03-25 10:49:02 UTC (rev 1619)
+++ trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/RetrievalResponse.scala	2010-03-25 11:46:48 UTC (rev 1620)
@@ -1,23 +0,0 @@
-package org.infinispan.server.hotrod
-
-/**
- * // TODO: Document this
- * @author Galder Zamarreño
- * @since
- */
-
-class RetrievalResponse(override val id: Long,
-                        override val opCode: OpCodes.OpCode,
-                        override val status: Status.Status,
-                        val value: Array[Byte]) extends Response(id, opCode, status) {
-
-   override def toString = {
-      new StringBuilder().append("RetrievalResponse").append("{")
-         .append("opCode=").append(opCode)
-         .append(", id=").append(id)
-         .append(", status=").append(status)
-         .append(", value=").append(value)
-         .append("}").toString
-   }
-   
-}
\ No newline at end of file

Deleted: trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/StatsCache.scala
===================================================================
--- trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/StatsCache.scala	2010-03-25 10:49:02 UTC (rev 1619)
+++ trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/StatsCache.scala	2010-03-25 11:46:48 UTC (rev 1620)
@@ -1,36 +0,0 @@
-package org.infinispan.server.hotrod
-
-/**
- * // TODO: Document
- *
- * The idea with this trait is to be able to do stuff like this:
- *
- * If stats enabled:
- * val cache = (new CallerCache with StatsCache)
- * If stats disabled:
- * val cache = new CallerCache
- *
- * A very easy way to define interceptors!!!!
- *
- * @author Galder Zamarreño
- * @since 4.1
- */
-
-trait StatsCache extends Cache {
-
-   abstract override def put(c: StorageCommand): Response = {
-      // TODO: calculate stats if necessary
-      super.put(c)
-   }
-
-   abstract override def get(c: RetrievalCommand): Response = {
-      // TODO: calculate stats if necessary
-      super.get(c)
-   }
-
-   abstract override def putIfAbsent(c: StorageCommand): Response = {
-      // TODO: calculate stats if necessary
-      super.putIfAbsent(c)
-   }
-
-}
\ No newline at end of file

Deleted: trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/Status.scala
===================================================================
--- trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/Status.scala	2010-03-25 10:49:02 UTC (rev 1619)
+++ trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/Status.scala	2010-03-25 11:46:48 UTC (rev 1620)
@@ -1,23 +0,0 @@
-package org.infinispan.server.hotrod
-
-/**
- * // TODO: Document this
- * @author Galder Zamarreño
- * @since 4.1
- */
-
-object Status extends Enumeration {
-   type Status = Value
-
-   val Success = Value(0x00)
-   val OperationNotExecuted = Value(0x01)
-   val KeyDoesNotExist = Value(0x02)
-
-   val InvalidMagicOrMsgId = Value(0x81)
-   val UnknownCommand = Value(0x82)
-   val UnknownVersion = Value(0x83) // todo: test
-   val ParseError = Value(0x84) // todo: test
-   val ServerError = Value(0x85) // todo: test
-   val CommandTimedOut = Value(0x86) // todo: test
-   
-}
\ No newline at end of file

Deleted: trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/StorageCommand.scala
===================================================================
--- trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/StorageCommand.scala	2010-03-25 10:49:02 UTC (rev 1619)
+++ trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/StorageCommand.scala	2010-03-25 11:46:48 UTC (rev 1620)
@@ -1,34 +0,0 @@
-package org.infinispan.server.hotrod
-
-import org.infinispan.context.Flag
-
-/**
- * // TODO: Document this
- * @author Galder Zamarreño
- * @since 4.1
- */
-class StorageCommand(override val cacheName: String,
-                     override val id: Long,
-                     val k: Key,
-                     val lifespan: Int,
-                     val maxIdle: Int,
-                     val v: Value,
-                     override val flags: Set[Flag])
-                    (val op: (Cache, StorageCommand) => Response) extends Command(cacheName, id, flags) {
-
-   override def perform(cache: Cache): Response = {
-      op(cache, this)
-   }
-
-   override def toString = {
-      new StringBuilder().append("StorageCommand").append("{")
-         .append("cacheName=").append(cacheName)
-         .append(", id=").append(id)
-         .append(", k=").append(k)
-         .append(", lifespan=").append(lifespan)
-         .append(", maxIdle=").append(maxIdle)
-         .append(", v=").append(v)
-         .append(", flags=").append(flags)
-         .append("}").toString
-   }
-}
\ No newline at end of file

Deleted: trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/VInt.scala
===================================================================
--- trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/VInt.scala	2010-03-25 10:49:02 UTC (rev 1619)
+++ trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/VInt.scala	2010-03-25 11:46:48 UTC (rev 1620)
@@ -1,37 +0,0 @@
-package org.infinispan.server.hotrod
-
-import org.infinispan.server.core.transport.ChannelBuffer
-
-/**
- * Reads and writes unsigned variable length integer values. Even though it's deprecated, do not
- * remove from source code for the moment because it's a good scala example and could be used
- * as reference. 
- *
- * @author Galder Zamarreño
- * @since 4.1
- * @deprecated Instead use ChannelBuffer.writeUnsignedInt and ChannelBuffer.readUnsignedInt
- */
- at deprecated("Instead use ChannelBuffer.writeUnsignedInt and ChannelBuffer.readUnsignedInt")
-object VInt {
-
-   def write(out: ChannelBuffer, i: Int) {
-      if ((i & ~0x7F) == 0) out.writeByte(i.toByte)
-      else {
-         out.writeByte(((i & 0x7f) | 0x80).toByte)
-         write(out, i >>> 7)
-      }
-   }
-
-   def read(in: ChannelBuffer): Int = {
-      val b = in.readByte
-      read(in, b, 7, b & 0x7F)
-   }
-
-   private def read(in: ChannelBuffer, b: Byte, shift: Int, i: Int): Int = {
-      if ((b & 0x80) == 0) i
-      else {
-         val bb = in.readByte
-         read(in, bb, shift + 7, i | ((bb & 0x7FL) << shift).toInt)
-      }
-   }
-}
\ No newline at end of file

Deleted: trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/VLong.scala
===================================================================
--- trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/VLong.scala	2010-03-25 10:49:02 UTC (rev 1619)
+++ trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/VLong.scala	2010-03-25 11:46:48 UTC (rev 1620)
@@ -1,37 +0,0 @@
-package org.infinispan.server.hotrod
-
-import org.infinispan.server.core.transport.ChannelBuffer
-
-/**
- * Reads and writes unsigned variable length long values. Even though it's deprecated, do not
- * remove from source code for the moment because it's a good scala example and could be used
- * as reference.
- *
- * @author Galder Zamarreño
- * @since 4.1
- * @deprecated Instead use ChannelBuffer.writeUnsignedLong and ChannelBuffer.readUnsignedLong
- */
- at deprecated("Instead use ChannelBuffer.writeUnsignedLong and ChannelBuffer.readUnsignedLong")
-object VLong {
-
-   def write(out: ChannelBuffer, i: Long) {
-      if ((i & ~0x7F) == 0) out.writeByte(i.toByte)
-      else {
-         out.writeByte(((i & 0x7f) | 0x80).toByte)
-         write(out, i >>> 7)
-      }
-   }
-
-   def read(in: ChannelBuffer): Long = {
-      val b = in.readByte
-      read(in, b, 7, b & 0x7F)
-   }
-
-   private def read(in: ChannelBuffer, b: Byte, shift: Int, i: Long): Long = {
-      if ((b & 0x80) == 0) i
-      else {
-         val bb = in.readByte
-         read(in, bb, shift + 7, i | (bb & 0x7FL) << shift)
-      }
-   }
-}
\ No newline at end of file

Deleted: trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/Value.scala
===================================================================
--- trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/Value.scala	2010-03-25 10:49:02 UTC (rev 1619)
+++ trunk/server/hotrod/src/main/scala/org/infinispan/server/hotrod/Value.scala	2010-03-25 11:46:48 UTC (rev 1620)
@@ -1,29 +0,0 @@
-package org.infinispan.server.hotrod
-
-import java.io.{ObjectOutput, ObjectInput, Externalizable}
-
-/**
- * // TODO: Document this
- * @author Galder Zamarreño
- * @since
- */
-
-// TODO: Make it an Externalizer once submodules can extend the marshalling framework
-final class Value(var v: Array[Byte]) extends Externalizable {
-
-   override def toString = {
-      new StringBuilder().append("Value").append("{")
-         .append("v=").append(v)
-         .append("}").toString
-   }
-
-   override def readExternal(in: ObjectInput) {
-      v = new Array[Byte](in.read())
-      in.read(v)
-   }
-
-   override def writeExternal(out: ObjectOutput) {
-      out.write(v.length)
-      out.write(v)
-   }
-}
\ No newline at end of file

Modified: trunk/server/hotrod/src/test/scala/org/infinispan/server/hotrod/ClusterTest.scala
===================================================================
--- trunk/server/hotrod/src/test/scala/org/infinispan/server/hotrod/ClusterTest.scala	2010-03-25 10:49:02 UTC (rev 1619)
+++ trunk/server/hotrod/src/test/scala/org/infinispan/server/hotrod/ClusterTest.scala	2010-03-25 11:46:48 UTC (rev 1620)
@@ -1,60 +1,60 @@
-package org.infinispan.server.hotrod
-
-import org.infinispan.test.MultipleCacheManagersTest
-import org.infinispan.config.Configuration
-import org.jboss.netty.channel.Channel
-import test.{Utils, Client}
-import java.lang.reflect.Method
-import org.infinispan.manager.CacheManager
-import org.testng.annotations.{BeforeClass, AfterClass, Test}
-import org.infinispan.config.Configuration.CacheMode
-import org.infinispan.context.Flag
-import org.infinispan.server.hotrod.Status._
-
-/**
- * // TODO: Document this
- * @author Galder Zamarreño
- * @since
- */
-
- at Test(groups = Array("functional"), testName = "server.hotrod.ClusterTest")
-class ClusterTest extends MultipleCacheManagersTest with Utils with Client {
-   private val cacheName = "hotRodReplSync"
-   private[this] var servers: List[HotRodServer] = List()
-   private[this] var channels: List[Channel] = List()
-
-   @Test(enabled=false) // Disable explicitly to avoid TestNG thinking this is a test!!
-   override def createCacheManagers {
-      var replSync = getDefaultClusteredConfig(Configuration.CacheMode.REPL_SYNC)
-      createClusteredCaches(2, cacheName, replSync)
-      servers = createHotRodServer(cacheManagers.get(0)) :: servers
-      servers = createHotRodServer(cacheManagers.get(1), servers.head.port + 50) :: servers
-      servers.foreach {
-         s => s.start
-         channels = connect("127.0.0.1", s.port) :: channels
-      }
-   }
-
-   @AfterClass(alwaysRun = true)
-   override def destroy {
-      super.destroy
-      log.debug("Test finished, close Hot Rod server", null)
-      servers.foreach(_.stop)
-   }
-
-   def tesReplicatedPut(m: Method) {
-      val putSt = put(channels.head, cacheName, k(m) , 0, 0, v(m))
-      assertStatus(putSt, Success)
-      val (getSt, actual) = get(channels.tail.head, cacheName, k(m), null)
-      assertSuccess(getSt, v(m), actual)
-   }
-
-   def tesLocalOnlyPut(m: Method) {
-      val putSt = put(channels.head, cacheName, k(m) , 0, 0, v(m), Set(Flag.CACHE_MODE_LOCAL))
-       assertStatus(putSt, Success)
-      val (getSt, actual) = get(channels.tail.head, cacheName, k(m), null)
-      assertKeyDoesNotExist(getSt, actual)
-   }
-
-   // todo: test multiple flags
-}
\ No newline at end of file
+//package org.infinispan.server.hotrod
+//
+//import org.infinispan.test.MultipleCacheManagersTest
+//import org.infinispan.config.Configuration
+//import org.jboss.netty.channel.Channel
+//import test.{Utils, Client}
+//import java.lang.reflect.Method
+//import org.infinispan.manager.CacheManager
+//import org.testng.annotations.{BeforeClass, AfterClass, Test}
+//import org.infinispan.config.Configuration.CacheMode
+//import org.infinispan.context.Flag
+//import org.infinispan.server.hotrod.Status._
+//
+///**
+// * // TODO: Document this
+// * @author Galder Zamarreño
+// * @since
+// */
+//
+//@Test(groups = Array("functional"), testName = "server.hotrod.ClusterTest")
+//class ClusterTest extends MultipleCacheManagersTest with Utils with Client {
+//   private val cacheName = "hotRodReplSync"
+//   private[this] var servers: List[HotRodServer] = List()
+//   private[this] var channels: List[Channel] = List()
+//
+//   @Test(enabled=false) // Disable explicitly to avoid TestNG thinking this is a test!!
+//   override def createCacheManagers {
+//      var replSync = getDefaultClusteredConfig(Configuration.CacheMode.REPL_SYNC)
+//      createClusteredCaches(2, cacheName, replSync)
+//      servers = startHotRodServer(cacheManagers.get(0)) :: servers
+//      servers = startHotRodServer(cacheManagers.get(1), servers.head.port + 50) :: servers
+//      servers.foreach {
+//         s => s.start
+//         channels = connect("127.0.0.1", s.port) :: channels
+//      }
+//   }
+//
+//   @AfterClass(alwaysRun = true)
+//   override def destroy {
+//      super.destroy
+//      log.debug("Test finished, close Hot Rod server", null)
+//      servers.foreach(_.stop)
+//   }
+//
+//   def tesReplicatedPut(m: Method) {
+//      val putSt = put(channels.head, cacheName, k(m) , 0, 0, v(m))
+//      assertStatus(putSt, Success)
+//      val (getSt, actual) = get(channels.tail.head, cacheName, k(m), null)
+//      assertSuccess(getSt, v(m), actual)
+//   }
+//
+//   def tesLocalOnlyPut(m: Method) {
+//      val putSt = put(channels.head, cacheName, k(m) , 0, 0, v(m), Set(Flag.CACHE_MODE_LOCAL))
+//       assertStatus(putSt, Success)
+//      val (getSt, actual) = get(channels.tail.head, cacheName, k(m), null)
+//      assertKeyDoesNotExist(getSt, actual)
+//   }
+//
+//   // todo: test multiple flags
+//}
\ No newline at end of file

Deleted: trunk/server/hotrod/src/test/scala/org/infinispan/server/hotrod/FlagsTest.scala
===================================================================
--- trunk/server/hotrod/src/test/scala/org/infinispan/server/hotrod/FlagsTest.scala	2010-03-25 10:49:02 UTC (rev 1619)
+++ trunk/server/hotrod/src/test/scala/org/infinispan/server/hotrod/FlagsTest.scala	2010-03-25 11:46:48 UTC (rev 1620)
@@ -1,68 +0,0 @@
-package org.infinispan.server.hotrod
-
-import org.testng.annotations.Test
-import org.infinispan.context.Flag
-import org.testng.Assert._
-
-/**
- * Appears that optional parameters in annotations result in compiler errors:
- * https://lampsvn.epfl.ch/trac/scala/ticket/1810
- *
- * Keep an eye on that for @Test and @AfterClass annotations
- * 
- * @author Galder Zamarreño
- * @since 4.1
- */
- at Test(groups = Array("functional"), testName = "server.hotrod.FlagsTest")
-class FlagsTest {
-
-   def testSingleFlag {
-      flag(1)(1) { flags => flags contains Flag.ZERO_LOCK_ACQUISITION_TIMEOUT }
-      flag(1 << 1)(1) { flags => flags contains Flag.CACHE_MODE_LOCAL }
-      flag(1 << 2)(1) { flags => flags contains Flag.SKIP_LOCKING }
-      flag(1 << 3)(1) { flags => flags contains Flag.FORCE_WRITE_LOCK }
-      flag(1 << 4)(1) { flags => flags contains Flag.SKIP_CACHE_STATUS_CHECK }
-      flag(1 << 5)(1) { flags => flags contains Flag.FORCE_ASYNCHRONOUS }
-      flag(1 << 6)(1) { flags => flags contains Flag.FORCE_SYNCHRONOUS }
-      flag(1 << 8)(1) { flags => flags contains Flag.SKIP_CACHE_STORE }
-      flag(1 << 9)(1) { flags => flags contains Flag.FAIL_SILENTLY }
-      flag(1 << 10)(1) { flags => flags contains Flag.SKIP_REMOTE_LOOKUP }
-      flag(1 << 11)(1) { flags => flags contains Flag.PUT_FOR_EXTERNAL_READ }
-   }
-
-   def testMultipleFlags {
-      flag(3)(2) {
-         flags => (flags contains Flag.ZERO_LOCK_ACQUISITION_TIMEOUT) &&
-                  (flags contains Flag.CACHE_MODE_LOCAL)
-      }
-      flag(15)(4) {
-         flags => (flags contains Flag.ZERO_LOCK_ACQUISITION_TIMEOUT) &&
-                  (flags contains Flag.CACHE_MODE_LOCAL) &&
-                  (flags contains Flag.SKIP_LOCKING) &&
-                  (flags contains Flag.FORCE_WRITE_LOCK)
-      }
-      flag(0xF7F)(11) {
-         flags => (flags contains Flag.ZERO_LOCK_ACQUISITION_TIMEOUT) &&
-                  (flags contains Flag.CACHE_MODE_LOCAL) &&
-                  (flags contains Flag.SKIP_LOCKING) &&
-                  (flags contains Flag.FORCE_WRITE_LOCK) &&
-                  (flags contains Flag.SKIP_CACHE_STATUS_CHECK) &&
-                  (flags contains Flag.FORCE_ASYNCHRONOUS) &&
-                  (flags contains Flag.FORCE_SYNCHRONOUS) &&
-                  (flags contains Flag.SKIP_CACHE_STORE) &&
-                  (flags contains Flag.FAIL_SILENTLY) &&
-                  (flags contains Flag.SKIP_REMOTE_LOOKUP) &&
-                  (flags contains Flag.PUT_FOR_EXTERNAL_READ)
-      }
-   }
-
-   private def flag(bitFlags: Int)(size: Int)(p: Set[Flag] => Boolean) {
-      val contextFlags = Flags.toContextFlags(bitFlags)
-      assertEquals(contextFlags.size, size)
-      assertTrue(p(contextFlags))
-
-      val fromFlags = Flags.fromContextFlags(contextFlags)
-      assertEquals(fromFlags, bitFlags)
-   }
-
-}
\ No newline at end of file

Deleted: trunk/server/hotrod/src/test/scala/org/infinispan/server/hotrod/FunctionalTest.scala
===================================================================
--- trunk/server/hotrod/src/test/scala/org/infinispan/server/hotrod/FunctionalTest.scala	2010-03-25 10:49:02 UTC (rev 1619)
+++ trunk/server/hotrod/src/test/scala/org/infinispan/server/hotrod/FunctionalTest.scala	2010-03-25 11:46:48 UTC (rev 1620)
@@ -1,173 +0,0 @@
-package org.infinispan.server.hotrod
-
-import org.infinispan.test.fwk.TestCacheManagerFactory
-import org.testng.annotations.{AfterClass, Test}
-import java.lang.reflect.Method
-import test.{Client, Utils}
-import org.testng.Assert._
-import org.infinispan.server.hotrod.Status._
-import java.util.Arrays
-import org.jboss.netty.channel.Channel
-import org.infinispan.manager.{DefaultCacheManager, CacheManager}
-import org.infinispan.context.Flag
-import org.infinispan.{AdvancedCache, Cache => InfinispanCache}
-import org.infinispan.test.{SingleCacheManagerTest}
-
-/**
- * TODO: Document
- *
- * Note: It appears that optional parameters in annotations result in compiler errors.
- * This has been solved in Scala 2.8.0.Beta1, so use that compiler,
- * otherwise this class won't compile.
- * https://lampsvn.epfl.ch/trac/scala/ticket/1810
- *
- * Keep an eye on that for @Test and @AfterClass annotations
- *
- * @author Galder Zamarreño
- * @since 4.1
- */
- at Test(groups = Array("functional"), testName = "server.hotrod.FunctionalTest")
-class FunctionalTest extends SingleCacheManagerTest with Utils with Client {
-   private val cacheName = "hotrod-cache"
-   private var server: HotRodServer = _
-   private var ch: Channel = _
-   private var advancedCache: AdvancedCache[Key, Value] = _
-//   private var tm: TransactionManager = _
-
-   override def createCacheManager: CacheManager = {
-      val cacheManager = TestCacheManagerFactory.createLocalCacheManager(true)
-      advancedCache = cacheManager.getCache[Key, Value](cacheName).getAdvancedCache
-//      tm = TestingUtil.getTransactionManager(advancedCache)
-      server = createHotRodServer(cacheManager)
-      server.start
-      ch = connect("127.0.0.1", server.port)
-      cacheManager
-   }
-
-   @AfterClass(alwaysRun = true)
-   override def destroyAfterClass {
-      super.destroyAfterClass
-      log.debug("Test finished, close Hot Rod server", null)
-      server.stop
-   }
-
-   def testUnknownCommand(m: Method) {
-      val status = put(ch, 0xA0, 0x77, cacheName, k(m) , 0, 0, v(m), null)
-      assertTrue(status == UnknownCommand,
-         "Status should have been 'UnknownCommand' but instead was: " + status)
-   }
-
-   def testUnknownMagic(m: Method) {
-      doPut(m) // Do a put to make sure decoder gets back to reading properly
-      val status = put(ch, 0x66, 0x01, cacheName, k(m) , 0, 0, v(m), null)
-      assertTrue(status == InvalidMagicOrMsgId,
-         "Status should have been 'InvalidMagicOrMsgId' but instead was: " + status)
-   }
-
-   // todo: test other error conditions such as invalid version...etc
-
-   def testPutBasic(m: Method) {
-      doPut(m)
-   }
-
-   def testPutOnDefaultCache(m: Method) {
-      val status = put(ch, DefaultCacheManager.DEFAULT_CACHE_NAME, k(m) , 0, 0, v(m))
-      assertStatus(status, Success)
-      val cache: InfinispanCache[Key, Value] = cacheManager.getCache[Key, Value]
-      assertTrue(Arrays.equals(cache.get(new Key(k(m))).v, v(m)));
-   }
-
-   def testPutWithLifespan(m: Method) {
-      doPutWithLifespanMaxIdle(m, 1, 0)
-      Thread.sleep(1100)
-      val (getSt, actual) = doGet(m)
-      assertKeyDoesNotExist(getSt, actual)
-   }
-
-   def testPutWithMaxIdle(m: Method) {
-      doPutWithLifespanMaxIdle(m, 0, 1)
-      Thread.sleep(1100)
-      val (getSt, actual) = doGet(m)
-      assertKeyDoesNotExist(getSt, actual)
-   }
-
-   def testGetBasic(m: Method) {
-      doPut(m)
-      val (getSt, actual) = doGet(m)
-      assertSuccess(getSt, v(m), actual)
-   }
-
-   def testGetDoesNotExist(m: Method) {
-      val (getSt, actual) = doGet(m)
-      assertKeyDoesNotExist(getSt, actual)
-   }
-
-   def testPutIfAbsentNotExist(m: Method) {
-      val status = putIfAbsent(ch, cacheName, k(m) , 0, 0, v(m))
-      assertStatus(status, Success)
-   }
-
-   def testPutIfAbsentExist(m: Method) {
-      doPut(m)
-      val status = putIfAbsent(ch, cacheName, k(m) , 0, 0, v(m, "v2-"))
-      assertStatus(status, OperationNotExecuted)
-   }
-
-   
-
-// Invalid test since starting transactions does not make sense
-// TODO: discuss flags with list
-// def testGetWithWriteLock(m: Method) {
-//      doPut(m)
-//      assertNotLocked(advancedCache, new Key(k(m)))
-//      tm.begin
-//      doGet(m, Set(Flag.FORCE_WRITE_LOCK))
-//      assertLocked(advancedCache, new Key(k(m)))
-//      tm.commit
-//      assertNotLocked(advancedCache, new Key(k(m)))
-//   }
-
-//   private def transactional(op: Unit => Unit) {
-//      tm.begin
-//      try {
-//         op()
-//      } catch {
-//         case _ => tm.setRollbackOnly
-//      } finally {
-//         if (tm.getStatus == TransactionStatus.STATUS_ACTIVE) tm.commit
-//         else tm.rollback
-//      }
-//   }
-
-//   private def assertSuccess(status: Status.Status) {
-//      assertTrue(status == Success, "Status should have been 'Success' but instead was: " + status)
-//   }
-//
-//   private def assertSuccess(status: Status.Status, expected: Array[Byte], actual: Array[Byte]) {
-//      assertSuccess(status)
-//      assertTrue(Arrays.equals(expected, actual))
-//   }
-//
-//   private def assertKeyDoesNotExist(status: Status.Status, actual: Array[Byte]) {
-//      assertTrue(status == KeyDoesNotExist, "Status should have been 'KeyDoesNotExist' but instead was: " + status)
-//      assertNull(actual)
-//   }
-
-   private def doPut(m: Method) {
-      doPutWithLifespanMaxIdle(m, 0, 0)
-   }
-
-   private def doPutWithLifespanMaxIdle(m: Method, lifespan: Int, maxIdle: Int) {
-      val status = put(ch, cacheName, k(m) , lifespan, maxIdle, v(m))
-      assertStatus(status, Success)
-   }
-
-   private def doGet(m: Method): (Status.Status, Array[Byte]) = {
-      doGet(m, null)
-   }
-
-   private def doGet(m: Method, flags: Set[Flag]): (Status.Status, Array[Byte]) = {
-      get(ch, cacheName, k(m), flags)
-   }
-
-}
\ No newline at end of file

Copied: trunk/server/hotrod/src/test/scala/org/infinispan/server/hotrod/HotRodFunctionalTest.scala (from rev 1610, trunk/server/hotrod/src/test/scala/org/infinispan/server/hotrod/FunctionalTest.scala)
===================================================================
--- trunk/server/hotrod/src/test/scala/org/infinispan/server/hotrod/HotRodFunctionalTest.scala	                        (rev 0)
+++ trunk/server/hotrod/src/test/scala/org/infinispan/server/hotrod/HotRodFunctionalTest.scala	2010-03-25 11:46:48 UTC (rev 1620)
@@ -0,0 +1,317 @@
+package org.infinispan.server.hotrod
+
+import org.infinispan.test.fwk.TestCacheManagerFactory
+import org.testng.annotations.{AfterClass, Test}
+import java.lang.reflect.Method
+import test.{Client, Utils}
+import org.testng.Assert._
+import java.util.Arrays
+import org.jboss.netty.channel.Channel
+import org.infinispan.manager.{DefaultCacheManager, CacheManager}
+import org.infinispan.context.Flag
+import org.infinispan.{AdvancedCache, Cache => InfinispanCache}
+import org.infinispan.test.{SingleCacheManagerTest}
+import org.infinispan.server.core.CacheValue
+import org.infinispan.server.hotrod.OperationStatus._
+
+/**
+ * TODO: Document
+ *
+ * Note: It appears that optional parameters in annotations result in compiler errors.
+ * This has been solved in Scala 2.8.0.Beta1, so use that compiler,
+ * otherwise this class won't compile.
+ * https://lampsvn.epfl.ch/trac/scala/ticket/1810
+ *
+ * Keep an eye on that for @Test and @AfterClass annotations
+ *
+ * @author Galder Zamarreño
+ * @since 4.1
+ */
+ at Test(groups = Array("functional"), testName = "server.hotrod.FunctionalTest")
+class HotRodFunctionalTest extends SingleCacheManagerTest with Utils with Client {
+   private val cacheName = "hotrod-cache"
+   private var server: HotRodServer = _
+   private var ch: Channel = _
+   private var advancedCache: AdvancedCache[CacheKey, CacheValue] = _
+
+   override def createCacheManager: CacheManager = {
+      val cacheManager = TestCacheManagerFactory.createLocalCacheManager(true)
+      advancedCache = cacheManager.getCache[CacheKey, CacheValue](cacheName).getAdvancedCache
+      server = startHotRodServer(cacheManager)
+      ch = connect("127.0.0.1", server.getPort)
+      cacheManager
+   }
+
+   @AfterClass(alwaysRun = true)
+   override def destroyAfterClass {
+      super.destroyAfterClass
+      log.debug("Test finished, close client and Hot Rod server", null)
+      ch.disconnect
+      server.stop
+   }
+
+   def testUnknownCommand(m: Method) {
+      val status = put(ch, 0xA0, 0x77, cacheName, k(m) , 0, 0, v(m), 0, 0)
+      assertTrue(status == UnknownOperation,
+         "Status should have been 'UnknownOperation' but instead was: " + status)
+   }
+
+   def testUnknownMagic(m: Method) {
+      doPut(m) // Do a put to make sure decoder gets back to reading properly
+      val status = put(ch, 0x66, 0x01, cacheName, k(m) , 0, 0, v(m), 0, 0)
+      assertTrue(status == InvalidMagicOrMsgId,
+         "Status should have been 'InvalidMagicOrMsgId' but instead was: " + status)
+   }
+
+   // todo: test other error conditions such as invalid version...etc
+   // todo: add test for force return value operation
+
+   def testPutBasic(m: Method) {
+      doPut(m)
+   }
+
+   private def doPut(m: Method) {
+      doPutWithLifespanMaxIdle(m, 0, 0)
+   }
+
+   def testPutOnDefaultCache(m: Method) {
+      val status = put(ch, DefaultCacheManager.DEFAULT_CACHE_NAME, k(m) , 0, 0, v(m))
+      assertStatus(status, Success)
+      val cache = cacheManager.getCache[CacheKey, CacheValue]
+      val value = cache.get(new CacheKey(k(m)))
+      assertTrue(Arrays.equals(value.data, v(m)));
+   }
+
+   def testPutWithLifespan(m: Method) {
+      doPutWithLifespanMaxIdle(m, 1, 0)
+      Thread.sleep(1100)
+      val (getSt, actual) = doGet(m)
+      assertKeyDoesNotExist(getSt, actual)
+   }
+
+   def testPutWithMaxIdle(m: Method) {
+      doPutWithLifespanMaxIdle(m, 0, 1)
+      Thread.sleep(1100)
+      val (getSt, actual) = doGet(m)
+      assertKeyDoesNotExist(getSt, actual)
+   }
+
+   private def doPutWithLifespanMaxIdle(m: Method, lifespan: Int, maxIdle: Int) {
+      val status = put(ch, cacheName, k(m) , lifespan, maxIdle, v(m))
+      assertStatus(status, Success)
+   }
+
+   def testGetBasic(m: Method) {
+      doPut(m)
+      val (getSt, actual) = doGet(m)
+      assertSuccess(getSt, v(m), actual)
+   }
+
+   def testGetDoesNotExist(m: Method) {
+      val (getSt, actual) = doGet(m)
+      assertKeyDoesNotExist(getSt, actual)
+   }
+
+   def testPutIfAbsentNotExist(m: Method) {
+      val status = putIfAbsent(ch, cacheName, k(m) , 0, 0, v(m))
+      assertStatus(status, Success)
+   }
+
+   def testPutIfAbsentExist(m: Method) {
+      doPut(m)
+      val status = putIfAbsent(ch, cacheName, k(m) , 0, 0, v(m, "v2-"))
+      assertStatus(status, OperationNotExecuted)
+   }
+
+   def testPutIfAbsentWithLifespan(m: Method) {
+      val status = putIfAbsent(ch, cacheName, k(m) , 1, 0, v(m))
+      assertStatus(status, Success)
+      Thread.sleep(1100)
+      val (getSt, actual) = doGet(m)
+      assertKeyDoesNotExist(getSt, actual)
+   }
+
+   def testPutIfAbsentWithMaxIdle(m: Method) {
+      val status = putIfAbsent(ch, cacheName, k(m) , 0, 1, v(m))
+      assertStatus(status, Success)
+      Thread.sleep(1100)
+      val (getSt, actual) = doGet(m)
+      assertKeyDoesNotExist(getSt, actual)
+   }
+
+   def testReplaceBasic(m: Method) {
+      doPut(m)
+      val status = replace(ch, cacheName, k(m), 0, 0, v(m, "v1-"))
+      assertStatus(status, Success)
+      val (getSt, actual) = doGet(m)
+      assertSuccess(getSt, v(m, "v1-"), actual)
+   }
+
+   def testNotReplaceIfNotPresent(m: Method) {
+      val status = replace(ch, cacheName, k(m), 0, 0, v(m))
+      assertStatus(status, OperationNotExecuted)
+   }
+
+   def testReplaceWithLifespan(m: Method) {
+      doPut(m)
+      val status = replace(ch, cacheName, k(m), 1, 0, v(m, "v1-"))
+      assertStatus(status, Success)
+      Thread.sleep(1100)
+      val (getSt, actual) = doGet(m)
+      assertKeyDoesNotExist(getSt, actual)
+   }
+
+   def testReplaceWithMaxIdle(m: Method) {
+      doPut(m)
+      val status = replace(ch, cacheName, k(m), 0, 1, v(m, "v1-"))
+      assertStatus(status, Success)
+      Thread.sleep(1100)
+      val (getSt, actual) = doGet(m)
+      assertKeyDoesNotExist(getSt, actual)
+   }
+
+   def testGetWithVersionBasic(m: Method) {
+      doPut(m)
+      val (getSt, actual, version) = getWithVersion(ch, cacheName, k(m), 0)
+      assertSuccess(getSt, v(m), actual)
+      assertTrue(version != 0)
+   }
+
+   def testGetWithVersionDoesNotExist(m: Method) {
+      val (getSt, actual, version) = getWithVersion(ch, cacheName, k(m), 0)
+      assertKeyDoesNotExist(getSt, actual)
+      assertTrue(version == 0)
+   }
+
+   def testReplaceIfUnmodifiedBasic(m: Method) {
+      doPut(m)
+      val (getSt, actual, version) = getWithVersion(ch, cacheName, k(m), 0)
+      assertSuccess(getSt, v(m), actual)
+      assertTrue(version != 0)
+      val status = replaceIfUnmodified(ch, cacheName, k(m), 0, 0, v(m, "v1-"), version)
+      assertStatus(status, Success)
+   }
+
+   def testReplaceIfUnmodifiedNotFound(m: Method) {
+      doPut(m)
+      val (getSt, actual, version) = getWithVersion(ch, cacheName, k(m), 0)
+      assertSuccess(getSt, v(m), actual)
+      assertTrue(version != 0)
+      val status = replaceIfUnmodified(ch, cacheName, k(m, "k1-"), 0, 0, v(m, "v1-"), version)
+      assertStatus(status, KeyDoesNotExist)
+   }
+
+   def testReplaceIfUnmodifiedNotExecuted(m: Method) {
+      doPut(m)
+      val (getSt, actual, version) = getWithVersion(ch, cacheName, k(m), 0)
+      assertSuccess(getSt, v(m), actual)
+      assertTrue(version != 0)
+      var status = replaceIfUnmodified(ch, cacheName, k(m), 0, 0, v(m, "v1-"), version)
+      assertStatus(status, Success)
+      val (getSt2, actual2, version2) = getWithVersion(ch, cacheName, k(m), 0)
+      assertSuccess(getSt2, v(m, "v1-"), actual2)
+      assertTrue(version2 != 0)
+      assertTrue(version != version2)
+      status = replaceIfUnmodified(ch, cacheName, k(m), 0, 0, v(m, "v2-"), version)
+      assertStatus(status, OperationNotExecuted)
+      status = replaceIfUnmodified(ch, cacheName, k(m), 0, 0, v(m, "v2-"), version2)
+      assertStatus(status, Success)
+   }
+
+   def testRemoveBasic(m: Method) {
+      doPut(m)
+      val status = remove(ch, cacheName, k(m), 0)
+      assertStatus(status, Success)
+      val (getSt, actual) = doGet(m)
+      assertKeyDoesNotExist(getSt, actual)
+   }
+
+   def testRemoveDoesNotExist(m: Method) {
+      val status = remove(ch, cacheName, k(m), 0)
+      assertStatus(status, KeyDoesNotExist)
+   }
+
+   def testRemoveIfUnmodifiedBasic(m: Method) {
+      doPut(m)
+      val (getSt, actual, version) = getWithVersion(ch, cacheName, k(m), 0)
+      assertSuccess(getSt, v(m), actual)
+      assertTrue(version != 0)
+      val status = removeIfUnmodified(ch, cacheName, k(m), 0, 0, v(m, "v1-"), version)
+      assertStatus(status, Success)
+      val (getSt2, actual2) = doGet(m)
+      assertKeyDoesNotExist(getSt2, actual2)
+   }
+
+   def testRemoveIfUnmodifiedNotFound(m: Method) {
+      doPut(m)
+      val (getSt, actual, version) = getWithVersion(ch, cacheName, k(m), 0)
+      assertSuccess(getSt, v(m), actual)
+      assertTrue(version != 0)
+      val status = removeIfUnmodified(ch, cacheName, k(m, "k1-"), 0, 0, v(m, "v1-"), version)
+      assertStatus(status, KeyDoesNotExist)
+      val (getSt2, actual2) = doGet(m)
+      assertSuccess(getSt2, v(m), actual2)
+   }
+
+   def testRemoveIfUnmodifiedNotExecuted(m: Method) {
+      doPut(m)
+      val (getSt, actual, version) = getWithVersion(ch, cacheName, k(m), 0)
+      assertSuccess(getSt, v(m), actual)
+      assertTrue(version != 0)
+      var status = replaceIfUnmodified(ch, cacheName, k(m), 0, 0, v(m, "v1-"), version)
+      assertStatus(status, Success)
+      val (getSt2, actual2, version2) = getWithVersion(ch, cacheName, k(m), 0)
+      assertSuccess(getSt2, v(m, "v1-"), actual2)
+      assertTrue(version2 != 0)
+      assertTrue(version != version2)
+      status = removeIfUnmodified(ch, cacheName, k(m), 0, 0, v(m, "v2-"), version)
+      assertStatus(status, OperationNotExecuted)
+      status = removeIfUnmodified(ch, cacheName, k(m), 0, 0, v(m, "v2-"), version2)
+      assertStatus(status, Success)
+   }
+
+   def testContainsKeyBasic(m: Method) {
+      doPut(m)
+      val status = containsKey(ch, cacheName, k(m), 0)
+      assertStatus(status, Success)
+   }
+
+   def testContainsKeyDoesNotExist(m: Method) {
+      val status = containsKey(ch, cacheName, k(m), 0)
+      assertStatus(status, KeyDoesNotExist)
+   }
+
+   def testClear(m: Method) {
+      for (i <- 1 to 5) {
+         val key = k(m, "k" + i + "-");
+         val value = v(m, "v" + i + "-");
+         var status = put(ch, cacheName, key , 0, 0, value)
+         assertStatus(status, Success)
+         status = containsKey(ch, cacheName, key, 0)
+         assertStatus(status, Success)
+      }
+
+      val status = clear(ch, cacheName)
+      assertStatus(status, Success)
+
+      for (i <- 1 to 5) {
+         val key = k(m, "k" + i + "-")
+         val status = containsKey(ch, cacheName, key, 0)
+         assertStatus(status, KeyDoesNotExist)
+      }
+   }
+
+   def testPing(m: Method) {
+      val status = ping(ch, cacheName)
+      assertStatus(status, Success)
+   }
+
+   private def doGet(m: Method): (OperationStatus, Array[Byte]) = {
+      doGet(m, 0)
+   }
+
+   private def doGet(m: Method, flags: Int): (OperationStatus, Array[Byte]) = {
+      get(ch, cacheName, k(m), flags)
+   }
+
+}
\ No newline at end of file

Deleted: trunk/server/hotrod/src/test/scala/org/infinispan/server/hotrod/VariableLengthTest.scala
===================================================================
--- trunk/server/hotrod/src/test/scala/org/infinispan/server/hotrod/VariableLengthTest.scala	2010-03-25 10:49:02 UTC (rev 1619)
+++ trunk/server/hotrod/src/test/scala/org/infinispan/server/hotrod/VariableLengthTest.scala	2010-03-25 11:46:48 UTC (rev 1620)
@@ -1,123 +0,0 @@
-package org.infinispan.server.hotrod
-
-import org.testng.annotations.Test
-import org.infinispan.server.core.transport.netty.NettyChannelBuffer
-import org.jboss.netty.buffer.{ChannelBuffers}
-import org.testng.Assert._
-
-/**
- * Appears that optional parameters in annotations result in compiler errors:
- * https://lampsvn.epfl.ch/trac/scala/ticket/1810
- *
- * Keep an eye on that for @Test and @AfterClass annotations
- *  
- * @author Galder Zamarreño
- * @since 4.1
- */
-
- at Test(groups = Array("functional"), testName = "server.hotrod.VariableLengthTest")
-class VariableLengthTest {
-
-   def test2pow7minus1 {
-      writeReadInt(127, 1)
-   }
-
-   def test2pow7 {
-      writeReadInt(128, 2)
-   }
-
-   def test2pow14minus1 {
-      writeReadInt(16383, 2)
-   }
-
-   def test2pow14 {
-      writeReadInt(16384, 3)
-   }
-
-   def test2pow21minus1 {
-      writeReadInt(2097151, 3)
-   }
-
-   def test2pow21 {
-      writeReadInt(2097152, 4)
-   }
-
-   def test2pow28minus1 {
-      writeReadInt(268435455, 4)
-   }
-
-   def test2pow28 {
-      writeReadInt(268435456, 5)
-   }
-
-   def test2pow35minus1 {
-      writeReadLong(34359738367L, 5)
-   }
-
-   def test2pow35 {
-      writeReadLong(34359738368L, 6)
-   }
-
-   def test2pow42minus1 {
-      writeReadLong(4398046511103L, 6)
-   }
-
-   def test2pow42 {
-      writeReadLong(4398046511104L, 7)
-   }
-
-   def test2pow49minus1 {
-      writeReadLong(562949953421311L, 7)
-   }
-
-   def test2pow49 {
-      writeReadLong(562949953421312L, 8)
-   }
-
-   def test2pow56minus1 {
-      writeReadLong(72057594037927935L, 8)
-   }
-
-   def test2pow56 {
-      writeReadLong(72057594037927936L, 9)
-   }
-
-   def test2pow63minus1 {
-      writeReadLong(9223372036854775807L, 9)
-   }
-
-//   def test2pow63() {
-//      writeReadLong(9223372036854775808L, 10)
-//   }
-
-   private def writeReadInt(num: Int, expected: Int) {
-      val buffer = new NettyChannelBuffer(ChannelBuffers.directBuffer(1024))
-      assert(buffer.writerIndex == 0)
-//      VInt.write(buffer, num)
-      buffer.writeUnsignedInt(num)
-      assertEquals(buffer.writerIndex, expected)
-//      assertEquals(VInt.read(buffer), num)
-      assertEquals(buffer.readUnsignedInt, num)
-   }
-
-   private def writeReadLong(num: Long, expected: Int) {
-      val buffer = new NettyChannelBuffer(ChannelBuffers.directBuffer(1024))
-      assert(buffer.writerIndex == 0)
-//      VLong.write(buffer, num)
-      buffer.writeUnsignedLong(num)
-      assertEquals(buffer.writerIndex, expected)
-//      assertEquals(VLong.read(buffer), num)
-      assertEquals(buffer.readUnsignedLong, num)
-   }
-
-//   def testEquals128Old() {
-//      val baos = new ByteArrayOutputStream(1024);
-//      val oos = new ObjectOutputStream(baos);
-//      UnsignedNumeric.writeUnsignedInt(oos, 128);
-//      oos.flush();
-//      assertEquals(baos.size() - 6, 2);
-//      val bais = new ByteArrayInputStream(baos.toByteArray());
-//      val ois = new ObjectInputStream(bais);
-//      assertEquals(UnsignedNumeric.readUnsignedInt(ois), 128);
-//   }
-}
\ No newline at end of file

Modified: trunk/server/hotrod/src/test/scala/org/infinispan/server/hotrod/test/Client.scala
===================================================================
--- trunk/server/hotrod/src/test/scala/org/infinispan/server/hotrod/test/Client.scala	2010-03-25 10:49:02 UTC (rev 1619)
+++ trunk/server/hotrod/src/test/scala/org/infinispan/server/hotrod/test/Client.scala	2010-03-25 11:46:48 UTC (rev 1620)
@@ -6,23 +6,25 @@
 import org.jboss.netty.handler.codec.oneone.OneToOneEncoder
 import org.jboss.netty.channel._
 import org.jboss.netty.buffer.{ChannelBuffer, ChannelBuffers}
-import org.infinispan.server.core.transport.netty.NettyChannelBuffer
 import org.jboss.netty.handler.codec.replay.ReplayingDecoder
 import org.testng.Assert._
 import org.infinispan.server.hotrod._
-import org.infinispan.server.hotrod.OpCodes._
-import org.infinispan.server.hotrod.Status._
+import org.infinispan.server.hotrod.Response
+import org.infinispan.server.hotrod.OperationStatus._
+import org.infinispan.server.hotrod.OperationResponse._
 import java.util.concurrent.atomic.AtomicInteger
 import org.infinispan.server.core.transport.NoState
 import org.jboss.netty.channel.ChannelHandler.Sharable
-import org.infinispan.context.Flag
 import java.util.Arrays
 import java.util.concurrent.{TimeUnit, LinkedBlockingQueue, Executors}
+import org.infinispan.server.core.transport.netty.{ChannelBufferAdapter}
+import org.infinispan.server.core.Logging
 
 /**
  * // TODO: Document this
  *
  * // TODO: Transform to Netty independent code
+ * // TODO: maybe make it an object to be able to cache stuff without testng complaining
  *
  * @author Galder Zamarreño
  * @since 4.1
@@ -46,22 +48,37 @@
       ch
    }
 
-   def put(ch: Channel, name: String, k: Array[Byte], lifespan: Int, maxIdle: Int, v: Array[Byte]): Status = {
-      put(ch, 0xA0, 0x01, name, k, lifespan, maxIdle, v, null)
+   def put(ch: Channel, name: String, k: Array[Byte], lifespan: Int, maxIdle: Int, v: Array[Byte]): OperationStatus = {
+      put(ch, 0xA0, 0x01, name, k, lifespan, maxIdle, v, 0, 0)
    }
 
    def put(ch: Channel, name: String, k: Array[Byte], lifespan: Int, maxIdle: Int, v: Array[Byte],
-           flags: Set[Flag]): Status = {
-      put(ch, 0xA0, 0x01, name, k, lifespan, maxIdle, v, flags)
+           flags: Int): OperationStatus = {
+      put(ch, 0xA0, 0x01, name, k, lifespan, maxIdle, v, flags, 0)
    }
 
-   def putIfAbsent(ch: Channel, name: String, k: Array[Byte], lifespan: Int, maxIdle: Int, v: Array[Byte]): Status = {
-      put(ch, 0xA0, 0x05, name, k, lifespan, maxIdle, v, null)
+   def putIfAbsent(ch: Channel, name: String, k: Array[Byte], lifespan: Int, maxIdle: Int, v: Array[Byte]): OperationStatus = {
+      put(ch, 0xA0, 0x05, name, k, lifespan, maxIdle, v, 0, 0)
    }
 
+   def replace(ch: Channel, name: String, k: Array[Byte], lifespan: Int, maxIdle: Int, v: Array[Byte]): OperationStatus = {
+      put(ch, 0xA0, 0x07, name, k, lifespan, maxIdle, v, 0, 0)
+   }
+
+   def replaceIfUnmodified(ch: Channel, name: String, k: Array[Byte], lifespan: Int, maxIdle: Int, v: Array[Byte],
+                           version: Long): OperationStatus = {
+      put(ch, 0xA0, 0x09, name, k, lifespan, maxIdle, v, 0, version)
+   }
+
+   def removeIfUnmodified(ch: Channel, name: String, k: Array[Byte], lifespan: Int, maxIdle: Int, v: Array[Byte],
+                           version: Long): OperationStatus = {
+      put(ch, 0xA0, 0x0D, name, k, lifespan, maxIdle, v, 0, version)
+   }
+
+   // TODO: change name of this method since it's more polivalent than just a put
    def put(ch: Channel, magic: Int, code: Byte, name: String, k: Array[Byte], lifespan: Int, maxIdle: Int,
-           v: Array[Byte], flags: Set[Flag]): Status = {
-      val writeFuture = ch.write(new Op(magic, code, name, k, lifespan, maxIdle, v, flags))
+           v: Array[Byte], flags: Int, version: Long): OperationStatus = {
+      val writeFuture = ch.write(new Op(magic, code, name, k, lifespan, maxIdle, v, flags, version))
       writeFuture.awaitUninterruptibly
       assertTrue(writeFuture.isSuccess)
       // Get the handler instance to retrieve the answer.
@@ -69,30 +86,78 @@
       handler.getResponse.status
    }
 
-   def get(ch: Channel, name: String, k: Array[Byte], flags: Set[Flag]): (Status.Status, Array[Byte]) = {
-      val writeFuture = ch.write(new Op(0xA0, 0x03, name, k, 0, 0, null, flags))
+   def get(ch: Channel, name: String, k: Array[Byte], flags: Int): (OperationStatus, Array[Byte]) = {
+      val (getSt, actual, version) = get(ch, 0x03, name, k, 0)
+      (getSt, actual)
+   }
+
+   def containsKey(ch: Channel, name: String, k: Array[Byte], flags: Int): OperationStatus = {
+      val (containsKeySt, actual, version) = get(ch, 0x0F, name, k, 0)
+      containsKeySt
+   }
+
+   def getWithVersion(ch: Channel, name: String, k: Array[Byte], flags: Int): (OperationStatus, Array[Byte], Long) = {
+      get(ch, 0x11, name, k, 0)
+   }
+
+   def remove(ch: Channel, name: String, k: Array[Byte], flags: Int): OperationStatus = {
+      put(ch, 0xA0, 0x0B, name, k, 0, 0, null, 0, 0)
+   }
+
+   def get(ch: Channel, code: Byte, name: String, k: Array[Byte], flags: Int): (OperationStatus, Array[Byte], Long) = {
+      val writeFuture = ch.write(new Op(0xA0, code, name, k, 0, 0, null, flags, 0))
       writeFuture.awaitUninterruptibly
       assertTrue(writeFuture.isSuccess)
       // Get the handler instance to retrieve the answer.
       var handler = ch.getPipeline.getLast.asInstanceOf[ClientHandler]
-      val resp = handler.getResponse.asInstanceOf[RetrievalResponse]
-      (resp.status, resp.value)
+      if (code == 0x03) {
+         val resp = handler.getResponse.asInstanceOf[GetResponse]
+         (resp.status, if (resp.data == None) null else resp.data.get, 0)
+      } else if (code == 0x11) {
+         val resp = handler.getResponse.asInstanceOf[GetWithVersionResponse]
+         (resp.status, if (resp.data == None) null else resp.data.get, resp.version)
+      } else if (code == 0x0F) {
+         (handler.getResponse.status, null, 0)
+      } else {
+         (OperationNotExecuted, null, 0)
+      }
    }
 
-   def assertStatus(status: Status.Status, expected: Status.Status): Boolean = {
+   def clear(ch: Channel, name: String): OperationStatus = {
+      put(ch, 0xA0, 0x13, name, null, 0, 0, null, 0, 0)
+//      val writeFuture = ch.write(new Op(0xA0, , name, null, 0, 0, null, 0, 0))
+//      writeFuture.awaitUninterruptibly
+//      assertTrue(writeFuture.isSuccess)
+//      // Get the handler instance to retrieve the answer.
+//      var handler = ch.getPipeline.getLast.asInstanceOf[ClientHandler]
+//      handler.getResponse.status
+   }
+
+   def ping(ch: Channel, name: String): OperationStatus = {
+      put(ch, 0xA0, 0x17, name, null, 0, 0, null, 0, 0)
+//      val writeFuture = ch.write(new Op(0xA0, 0x13, name, null, 0, 0, null, 0, 0))
+//      writeFuture.awaitUninterruptibly
+//      assertTrue(writeFuture.isSuccess)
+//      // Get the handler instance to retrieve the answer.
+//      var handler = ch.getPipeline.getLast.asInstanceOf[ClientHandler]
+//      handler.getResponse.status
+   }
+
+
+   def assertStatus(status: OperationStatus, expected: OperationStatus): Boolean = {
       val isSuccess = status == expected
       assertTrue(isSuccess, "Status should have been '" + expected + "' but instead was: " + status)
       isSuccess
    }
 
-   def assertSuccess(status: Status.Status, expected: Array[Byte], actual: Array[Byte]): Boolean = {
+   def assertSuccess(status: OperationStatus, expected: Array[Byte], actual: Array[Byte]): Boolean = {
       assertStatus(status, Success)
       val isSuccess = Arrays.equals(expected, actual)
       assertTrue(isSuccess)
       isSuccess
    }
 
-   def assertKeyDoesNotExist(status: Status.Status, actual: Array[Byte]): Boolean = {
+   def assertKeyDoesNotExist(status: OperationStatus, actual: Array[Byte]): Boolean = {
       assertTrue(status == KeyDoesNotExist, "Status should have been 'KeyDoesNotExist' but instead was: " + status)
       assertNull(actual)
       status == KeyDoesNotExist
@@ -122,22 +187,25 @@
       val ret =
          msg match {
             case op: Op => {
-               val buffer = new NettyChannelBuffer(ChannelBuffers.dynamicBuffer)
+               val buffer = new ChannelBufferAdapter(ChannelBuffers.dynamicBuffer)
                buffer.writeByte(op.magic.asInstanceOf[Byte]) // magic
                buffer.writeUnsignedLong(idCounter.incrementAndGet) // message id
-               buffer.writeByte(41) // version
+               buffer.writeByte(10) // version
                buffer.writeByte(op.code) // opcode
                buffer.writeRangedBytes(op.cacheName.getBytes()) // cache name length + cache name
-               if (op.flags != null)
-                  buffer.writeUnsignedInt(Flags.fromContextFlags(op.flags)) // flags
-               else
-                  buffer.writeUnsignedInt(0) // flags
-
-               buffer.writeRangedBytes(op.key) // key length + key
-               if (op.value != null) {
-                  buffer.writeUnsignedInt(op.lifespan) // lifespan
-                  buffer.writeUnsignedInt(op.maxIdle) // maxIdle
-                  buffer.writeRangedBytes(op.value) // value length + value
+               buffer.writeUnsignedInt(op.flags) // flags
+               buffer.writeByte(0) // client intelligence
+               buffer.writeUnsignedInt(0) // topology id
+               if (op.code != 0x13 && op.code != 0x17) { // if it's a key based op... 
+                  buffer.writeRangedBytes(op.key) // key length + key
+                  if (op.value != null) {
+                     buffer.writeUnsignedInt(op.lifespan) // lifespan
+                     buffer.writeUnsignedInt(op.maxIdle) // maxIdle
+                     if (op.code == 0x09 || op.code == 0x0D) {
+                        buffer.writeLong(op.version)
+                     }
+                     buffer.writeRangedBytes(op.value) // value length + value
+                  }
                }
                buffer.getUnderlyingChannelBuffer
             }
@@ -150,24 +218,39 @@
 private object Decoder extends ReplayingDecoder[NoState] with Logging {
 
    override def decode(ctx: ChannelHandlerContext, ch: Channel, buffer: ChannelBuffer, state: NoState): Object = {
-      val buf = new NettyChannelBuffer(buffer)
+      val buf = new ChannelBufferAdapter(buffer)
       val magic = buf.readUnsignedByte
       val id = buf.readUnsignedLong
-      val opCode = OpCodes.apply(buf.readUnsignedByte)
-      val status = Status.apply(buf.readUnsignedByte)
+      // val opCode = OperationResolver.resolve(buf.readUnsignedByte)
+      val opCode = OperationResponse.apply(buf.readUnsignedByte)
+      val status = OperationStatus.apply(buf.readUnsignedByte)
+      val topologyChangeMarker = buf.readUnsignedByte
       val resp: Response =
          opCode match {
-            case PutResponse | PutIfAbsentResponse => new Response(id, opCode, status)
+//            case StatsResponse => {
+//               // TODO!!! Wait for outcome of mail
+//            }
+            case PutResponse | PutIfAbsentResponse | ReplaceResponse | ReplaceIfUnmodifiedResponse
+                 | RemoveResponse | RemoveIfUnmodifiedResponse | ContainsKeyResponse | ClearResponse | PingResponse =>
+               new Response(id, opCode, status)
+            case GetWithVersionResponse  => {
+               if (status == Success) {
+                  val version = buf.readLong
+                  val data = Some(buf.readRangedBytes)
+                  new GetWithVersionResponse(id, opCode, status, data, version)
+               } else{
+                  new GetWithVersionResponse(id, opCode, status, None, 0)
+               }
+            }
             case GetResponse => {
-               val value = {
-                  status match {
-                     case Success => buf.readRangedBytes
-                     case _ => null
-                  }
+               if (status == Success) {
+                  val data = Some(buf.readRangedBytes)
+                  new GetResponse(id, opCode, status, data)
+               } else{
+                  new GetResponse(id, opCode, status, None)
                }
-               new RetrievalResponse(id, opCode, status, value)
             }
-            case ErrorResponse => new ErrorResponse(id, opCode, status, buf.readString)
+            case ErrorResponse => new ErrorResponse(id, status, buf.readString)
          }
       resp
    }
@@ -179,7 +262,7 @@
 
 private class ClientHandler extends SimpleChannelUpstreamHandler {
 
-   private val answer = new LinkedBlockingQueue[Response]; 
+   private val answer = new LinkedBlockingQueue[Response];
 
    override def messageReceived(ctx: ChannelHandlerContext, e: MessageEvent) {
       val offered = answer.offer(e.getMessage.asInstanceOf[Response])
@@ -199,4 +282,5 @@
                  val lifespan: Int,
                  val maxIdle: Int,
                  val value: Array[Byte],
-                 val flags: Set[Flag])
\ No newline at end of file
+                 val flags: Int,
+                 val version: Long)
\ No newline at end of file

Modified: trunk/server/hotrod/src/test/scala/org/infinispan/server/hotrod/test/Utils.scala
===================================================================
--- trunk/server/hotrod/src/test/scala/org/infinispan/server/hotrod/test/Utils.scala	2010-03-25 10:49:02 UTC (rev 1619)
+++ trunk/server/hotrod/src/test/scala/org/infinispan/server/hotrod/test/Utils.scala	2010-03-25 11:46:48 UTC (rev 1620)
@@ -3,7 +3,8 @@
 import java.util.concurrent.atomic.AtomicInteger
 import org.infinispan.manager.CacheManager
 import java.lang.reflect.Method
-import org.infinispan.server.hotrod.{Logging, HotRodServer}
+import org.infinispan.server.hotrod.{HotRodServer}
+import org.infinispan.server.core.Logging
 
 /**
  * // TODO: Document this
@@ -17,12 +18,13 @@
 
    def host = "127.0.0.1"
 
-   def createHotRodServer(manager: CacheManager): HotRodServer = {
-      new HotRodServer(host, UniquePortThreadLocal.get.intValue, manager, 0, 0)
-   }
+   def startHotRodServer(manager: CacheManager): HotRodServer =
+      startHotRodServer(manager, UniquePortThreadLocal.get.intValue)
 
-   def createHotRodServer(manager: CacheManager, port: Int): HotRodServer = {
-      new HotRodServer(host, port, manager, 0, 0)
+   def startHotRodServer(manager: CacheManager, port: Int): HotRodServer = {
+      val server = new HotRodServer
+      server.start(host, port, manager, 0, 0)
+      server
    }
 
    def k(m: Method, prefix: String): Array[Byte] = {
@@ -42,6 +44,6 @@
 object Utils extends Logging
 
 object UniquePortThreadLocal extends ThreadLocal[Int] {
-   private val uniqueAddr = new AtomicInteger(11311)   
+   private val uniqueAddr = new AtomicInteger(11311)
    override def initialValue: Int = uniqueAddr.getAndAdd(100)
 }
\ No newline at end of file

Modified: trunk/server/memcached/src/main/scala/org/infinispan/server/memcached/MemcachedDecoder.scala
===================================================================
--- trunk/server/memcached/src/main/scala/org/infinispan/server/memcached/MemcachedDecoder.scala	2010-03-25 10:49:02 UTC (rev 1619)
+++ trunk/server/memcached/src/main/scala/org/infinispan/server/memcached/MemcachedDecoder.scala	2010-03-25 11:46:48 UTC (rev 1620)
@@ -5,13 +5,13 @@
 import org.infinispan.server.memcached.MemcachedOperation._
 import org.infinispan.context.Flag
 import java.util.concurrent.{TimeUnit, Executors, ScheduledExecutorService}
-import org.infinispan.{Version, CacheException, Cache}
 import java.io.{IOException, EOFException, StreamCorruptedException}
 import java.nio.channels.ClosedChannelException
 import java.util.concurrent.atomic.AtomicLong
 import org.infinispan.stats.Stats
 import org.infinispan.server.core.transport.{Channel, ChannelBuffers, ChannelHandlerContext, ChannelBuffer}
 import org.infinispan.server.core._
+import org.infinispan.{AdvancedCache, Version, CacheException, Cache}
 
 /**
  * // TODO: Document this
@@ -23,6 +23,7 @@
    import MemcachedDecoder._
 
    type SuitableParameters = MemcachedParameters
+   type SuitableHeader = RequestHeader
 
    private var scheduler: ScheduledExecutorService = _
    private var cache: Cache[String, MemcachedValue] = _
@@ -37,6 +38,19 @@
 
    override def readHeader(buffer: ChannelBuffer): RequestHeader = {
       val streamOp = readElement(buffer)
+//      val op = {
+//         try {
+//            MemcachedOperation.withName(streamOp)
+//         }
+//         catch {
+//            case nsee: NoSuchElementException => {
+//               val line = readLine(buffer) // Read rest of line to clear the operation
+//               throw new UnknownOperationException("Unknown operation: " + streamOp);
+//            }
+//         }
+//      }
+//      val op = MemcachedOperation.withName(streamOp)
+
       val op = OperationResolver.resolve(streamOp)
       if (op == None) {
          val line = readLine(buffer) // Read rest of line to clear the operation
@@ -45,36 +59,36 @@
       new RequestHeader(op.get)
    }
 
-   override def readKey(buffer: ChannelBuffer): String = {
+   override def readKey(header: RequestHeader, buffer: ChannelBuffer): String = {
       readElement(buffer)
    }
 
-   override def readKeys(buffer: ChannelBuffer): Array[String] = {
+   override def readKeys(header: RequestHeader, buffer: ChannelBuffer): Array[String] = {
       val line = readLine(buffer)
       line.trim.split(" +")
    }
 
-   override def readParameters(op: Enumeration#Value, buffer: ChannelBuffer): MemcachedParameters = {
+   override def readParameters(header: RequestHeader, buffer: ChannelBuffer): Option[MemcachedParameters] = {
       val line = readLine(buffer)
       if (!line.isEmpty) {
          trace("Operation parameters: {0}", line)
          val args = line.trim.split(" +")
          var index = 0
-         op match {
-            case DeleteRequest => {
+         header.op match {
+            case RemoveRequest => {
                val delayedDeleteTime = parseDelayedDeleteTime(index, args)
                val noReply = if (delayedDeleteTime == -1) parseNoReply(index, args) else false
-               new MemcachedParameters(null, -1, -1, -1, noReply, 0, "", 0)
+               Some(new MemcachedParameters(null, -1, -1, -1, noReply, 0, "", 0))
             }
             case IncrementRequest | DecrementRequest => {
                val delta = args(index)
                index += 1
-               new MemcachedParameters(null, -1, -1, -1, parseNoReply(index, args), 0, delta, 0) 
+               Some(new MemcachedParameters(null, -1, -1, -1, parseNoReply(index, args), 0, delta, 0)) 
             }
             case FlushAllRequest => {
                val flushDelay = args(index).toInt
                index += 1
-               new MemcachedParameters(null, -1, -1, -1, parseNoReply(index, args), 0, "", flushDelay)
+               Some(new MemcachedParameters(null, -1, -1, -1, parseNoReply(index, args), 0, "", flushDelay))
             }
             case _ => {
                val flags = getFlags(args(index))
@@ -85,7 +99,7 @@
                }
                index += 1
                val length = getLength(args(index))
-               val streamVersion = op match {
+               val streamVersion = header.op match {
                   case ReplaceIfUnmodifiedRequest => {
                      index += 1
                      getVersion(args(index))
@@ -97,16 +111,15 @@
                val data = new Array[Byte](length)
                buffer.readBytes(data, 0, data.length)
                readLine(buffer) // read the rest of line to clear CRLF after value Byte[]
-               new MemcachedParameters(data, lifespan, -1, streamVersion, noReply, flags, "", 0)
+               Some(new MemcachedParameters(data, lifespan, -1, streamVersion, noReply, flags, "", 0))
             }
          }
       } else {
-         // For example when delete <key> is sent without any further parameters
-         new MemcachedParameters(null, -1, -1, -1, false, 0, "", 0)
+         None // For example when delete <key> is sent without any further parameters, or flush_all without delay
       }
    }
 
-   override def createValue(params: MemcachedParameters, nextVersion: Long): MemcachedValue = {
+   override def createValue(header: SuitableHeader, params: MemcachedParameters, nextVersion: Long): MemcachedValue = {
       new MemcachedValue(params.data, nextVersion, params.flags)
    }
 
@@ -157,162 +170,200 @@
    protected def createCache: Cache[String, MemcachedValue] = cacheManager.getCache[String, MemcachedValue]
 
    override def handleCustomRequest(header: RequestHeader, ctx: ChannelHandlerContext,
-                                    buffer: ChannelBuffer, cache: Cache[String, MemcachedValue]) {
+                                    buffer: ChannelBuffer, cache: Cache[String, MemcachedValue]): AnyRef = {
+      val ch = ctx.getChannel
+      val buffers = ctx.getChannelBuffers
       header.op match {
          case AppendRequest | PrependRequest => {
-            val k = readKey(buffer)
-            val params = readParameters(header.op, buffer)
+            val k = readKey(header, buffer)
+            val params = readParameters(header, buffer)
             val prev = cache.get(k)
             if (prev != null) {
                val concatenated = header.op match {
-                  case AppendRequest => concat(prev.v, params.data);
-                  case PrependRequest => concat(params.data, prev.v);
+                  case AppendRequest => concat(prev.data, params.get.data);
+                  case PrependRequest => concat(params.get.data, prev.data);
                }
-               val next = createValue(concatenated, generateVersion(cache), params.flags)
+               val next = createValue(concatenated, generateVersion(cache), params.get.flags)
                val replaced = cache.replace(k, prev, next);
                if (replaced)
-                  sendResponse(header, ctx, None, None, Some(params), Some(prev))
+                  if (!params.get.noReply) sendReplaceResponse(header, ch, buffers, prev) else null
                else // If there's a concurrent modification on this key, treat it as we couldn't replace it
-                  sendResponse(header, ctx, None, None, Some(params), Some(null)) //
+                  if (!params.get.noReply) sendReplaceResponse(header, ch, buffers, null) else null
             } else {
-               sendResponse(header, ctx, None, None, Some(params), Some(null))
+               if (!params.get.noReply) sendReplaceResponse(header, ch, buffers, null) else null
             }
          }
          case IncrementRequest | DecrementRequest => {
-            val k = readKey(buffer)
-            val params = readParameters(header.op, buffer)
+            val k = readKey(header, buffer)
+            val params = readParameters(header, buffer)
             val prev = cache.get(k)
             if (prev != null) {
-               val prevCounter = new String(prev.v)
+               val prevCounter = new String(prev.data)
                val newCounter =
                   header.op match {
-                     case IncrementRequest => prevCounter.toLong + params.delta.toLong
+                     case IncrementRequest => prevCounter.toLong + params.get.delta.toLong
                      case DecrementRequest => {
-                        val candidateCounter = prevCounter.toLong - params.delta.toLong
+                        val candidateCounter = prevCounter.toLong - params.get.delta.toLong
                         if (candidateCounter < 0) 0 else candidateCounter
                      }
                   }
-               val next = createValue(newCounter.toString.getBytes, generateVersion(cache), params.flags)
+               val next = createValue(newCounter.toString.getBytes, generateVersion(cache), params.get.flags)
                var replaced = cache.replace(k, prev, next)
-               if (replaced)
-                  sendResponse(header, ctx, None, Some(next), Some(params), Some(prev))
-               else // If there's a concurrent modification on this key, the spec does not say what to do, so treat it as exceptional
+               if (replaced) {
+                  if (isStatsEnabled) if (header.op == IncrementRequest) incrHits.incrementAndGet() else decrHits.incrementAndGet
+                  if (!params.get.noReply) ch.write(buffers.wrappedBuffer((new String(next.data) + CRLF).getBytes))
+               } else {
+                  // If there's a concurrent modification on this key, the spec does not say what to do, so treat it as exceptional
                   throw new CacheException("Value modified since we retrieved from the cache, old value was " + prevCounter)
+               }
             } else {
-               sendResponse(header, ctx, None, None, Some(params), Some(null))
+               if (isStatsEnabled) if (header.op == IncrementRequest) incrMisses.incrementAndGet() else decrMisses.incrementAndGet
+               if (!params.get.noReply) ch.write(buffers.wrappedBuffer("NOT_FOUND\r\n".getBytes))
             }
          }
          case FlushAllRequest => {
-            val params = readParameters(header.op, buffer)
-            val flushFunction = (cache: Cache[String, MemcachedValue]) => cache.getAdvancedCache.withFlags(Flag.CACHE_MODE_LOCAL, Flag.SKIP_CACHE_STORE).clear
-            if (params.flushDelay == 0)
-               // cache.getAdvancedCache.withFlags(Flag.CACHE_MODE_LOCAL, Flag.SKIP_CACHE_STORE).clear
-               flushFunction(cache)
+            val params = readParameters(header, buffer)
+            val flushFunction = (cache: AdvancedCache[String, MemcachedValue]) => cache.withFlags(Flag.CACHE_MODE_LOCAL, Flag.SKIP_CACHE_STORE).clear
+            val flushDelay = if (params == None) 0 else params.get.flushDelay
+            if (flushDelay == 0)
+               flushFunction(cache.getAdvancedCache)
             else
-               scheduler.schedule(new DelayedFlushAll(cache, flushFunction), params.flushDelay, TimeUnit.SECONDS)
-            sendResponse(header, ctx, None, None, Some(params), None)
+               scheduler.schedule(new DelayedFlushAll(cache, flushFunction), flushDelay, TimeUnit.SECONDS)
+            if (params == None || !params.get.noReply) ch.write(buffers.wrappedBuffer("OK\r\n".getBytes))
          }
-         case VersionRequest => sendResponse(header, ctx, None, None, None, None)
-//         case StatsRequest => 
+         case VersionRequest => {
+            val sb = new StringBuilder
+            sb.append("VERSION ").append(Version.version).append(CRLF)
+            ch.write(buffers.wrappedBuffer(sb.toString.getBytes))
+         }
       }
+      null
    }
 
-   // todo: potentially move this up when implementing hotrod since only what's written might change, the rest of logic is likely to be the same
-   override def sendResponse(header: RequestHeader, ctx: ChannelHandlerContext,
-                             k: Option[String], v: Option[MemcachedValue],
-                             params: Option[MemcachedParameters], prev: Option[MemcachedValue]) {
-      val buffers = ctx.getChannelBuffers
-      val ch = ctx.getChannel
-      if (params == None || !params.get.noReply) {
-         header.op match {
-            case PutRequest => ch.write(buffers.wrappedBuffer("STORED\r\n".getBytes))
-            case GetRequest | GetWithVersionRequest => {
-               if (v.get != null)
-                  ch.write(buildGetResponse(header.op, ctx, k.get, v.get))
-               ch.write(buffers.wrappedBuffer("END\r\n".getBytes))
-            }
-            case PutIfAbsentRequest => {
-               if (prev.get == null)
-                  ch.write(buffers.wrappedBuffer("STORED\r\n".getBytes))
-               else
-                  ch.write(buffers.wrappedBuffer("NOT_STORED\r\n".getBytes))
-            }
-            case ReplaceRequest | AppendRequest | PrependRequest => {
-               if (prev.get == null)
-                  ch.write(buffers.wrappedBuffer("NOT_STORED\r\n".getBytes))
-               else
-                  ch.write(buffers.wrappedBuffer("STORED\r\n".getBytes))
-            }
-            case ReplaceIfUnmodifiedRequest => {
-               if (v != None && prev != None) {
-                  if (isStatsEnabled) replaceIfUnmodifiedHits.incrementAndGet
-                  ch.write(buffers.wrappedBuffer("STORED\r\n".getBytes))
-               } else if (v == None && prev != None) {
-                  if (isStatsEnabled) replaceIfUnmodifiedBadval.incrementAndGet
-                  ch.write(buffers.wrappedBuffer("EXISTS\r\n".getBytes))
-               } else {
-                  if (isStatsEnabled) replaceIfUnmodifiedMisses.incrementAndGet
-                  ch.write(buffers.wrappedBuffer("NOT_FOUND\r\n".getBytes))
-               }                  
-            }
-            case DeleteRequest => {
-               if (prev.get == null)
-                  ch.write(buffers.wrappedBuffer("NOT_FOUND\r\n".getBytes))
-               else
-                  ch.write(buffers.wrappedBuffer("DELETED\r\n".getBytes))
-            }
-            case IncrementRequest | DecrementRequest => {
-               if (prev.get == null) {
-                  if (isStatsEnabled) if (header.op == IncrementRequest) incrMisses.incrementAndGet() else decrMisses.incrementAndGet
-                  ch.write(buffers.wrappedBuffer("NOT_FOUND\r\n".getBytes))
-               } else {
-                  if (isStatsEnabled) if (header.op == IncrementRequest) incrHits.incrementAndGet() else decrHits.incrementAndGet
-                  ch.write(buffers.wrappedBuffer((new String(v.get.v) + CRLF).getBytes))
-               }
-            }
-            case FlushAllRequest => {
-               ch.write(buffers.wrappedBuffer("OK\r\n".getBytes))
-            }
-            case VersionRequest => {
-               val sb = new StringBuilder
-               sb.append("VERSION ").append(Version.version).append(CRLF)
-               ch.write(buffers.wrappedBuffer(sb.toString.getBytes))
-            }
-         }
+   override def sendPutResponse(header: RequestHeader, ch: Channel, buffers: ChannelBuffers): AnyRef = {
+      ch.write(buffers.wrappedBuffer("STORED\r\n".getBytes))
+      null
+   }
+
+   override def sendGetResponse(header: RequestHeader, ch: Channel, buffers: ChannelBuffers,
+                                k: String, v: MemcachedValue): AnyRef = {
+      if (v != null)
+         ch.write(buildGetResponse(header.op, buffers, k, v))
+      ch.write(buffers.wrappedBuffer("END\r\n".getBytes))
+      null
+   }
+
+   override def sendPutIfAbsentResponse(header: RequestHeader, ch: Channel, buffers: ChannelBuffers,
+                                        prev: MemcachedValue): AnyRef = {
+      if (prev == null)
+         ch.write(buffers.wrappedBuffer("STORED\r\n".getBytes))
+      else
+         ch.write(buffers.wrappedBuffer("NOT_STORED\r\n".getBytes))
+      null
+   }
+
+   override def sendReplaceResponse(header: RequestHeader, ch: Channel, buffers: ChannelBuffers,
+                                    prev: MemcachedValue): AnyRef = {
+      if (prev == null)
+         ch.write(buffers.wrappedBuffer("NOT_STORED\r\n".getBytes))
+      else
+         ch.write(buffers.wrappedBuffer("STORED\r\n".getBytes))
+      null
+   }
+
+   override def sendReplaceIfUnmodifiedResponse(header: RequestHeader, ch: Channel, buffers: ChannelBuffers,
+                                                v: Option[MemcachedValue], prev: Option[MemcachedValue]): AnyRef = {
+      if (v != None && prev != None) {
+         if (isStatsEnabled) replaceIfUnmodifiedHits.incrementAndGet
+         ch.write(buffers.wrappedBuffer("STORED\r\n".getBytes))
+      } else if (v == None && prev != None) {
+         if (isStatsEnabled) replaceIfUnmodifiedBadval.incrementAndGet
+         ch.write(buffers.wrappedBuffer("EXISTS\r\n".getBytes))
+      } else {
+         if (isStatsEnabled) replaceIfUnmodifiedMisses.incrementAndGet
+         ch.write(buffers.wrappedBuffer("NOT_FOUND\r\n".getBytes))
       }
+      null
    }
 
-   override def sendResponse(header: RequestHeader, ctx: ChannelHandlerContext, pairs: Map[String, MemcachedValue]) {
+   override def sendRemoveResponse(header: RequestHeader, ch: Channel, buffers: ChannelBuffers,
+                                   prev: MemcachedValue): AnyRef = {
+      if (prev == null)
+         ch.write(buffers.wrappedBuffer("NOT_FOUND\r\n".getBytes))
+      else
+         ch.write(buffers.wrappedBuffer("DELETED\r\n".getBytes))
+      null
+   }
+
+   override def sendMultiGetResponse(header: RequestHeader, ctx: ChannelHandlerContext,
+                                     pairs: Map[String, MemcachedValue]): AnyRef = {
       val buffers = ctx.getChannelBuffers
       val ch = ctx.getChannel
-         header.op match {
-            case GetRequest | GetWithVersionRequest => {
-               for ((k, v) <- pairs)
-                  ch.write(buildGetResponse(header.op, ctx, k, v))
-               ch.write(buffers.wrappedBuffer("END\r\n".getBytes))
-            }
+      header.op match {
+         case GetRequest | GetWithVersionRequest => {
+            for ((k, v) <- pairs)
+               ch.write(buildGetResponse(header.op, buffers, k, v))
+            ch.write(buffers.wrappedBuffer("END\r\n".getBytes))
+         }
       }
+      null
    }
+   
+//   override def sendCustomResponse(header: RequestHeader, ch: Channel, buffers: ChannelBuffers,
+//                                   v: Option[MemcachedValue], prev: Option[MemcachedValue]): AnyRef = {
+//      header.op match {
+//         case AppendRequest | PrependRequest => {
+//            sendReplaceResponse(header, ch, buffers, prev.get)
+//         }
+//         case IncrementRequest | DecrementRequest => {
+//            if (prev.get == null) {
+//               if (isStatsEnabled) if (header.op == IncrementRequest) incrMisses.incrementAndGet() else decrMisses.incrementAndGet
+//               ch.write(buffers.wrappedBuffer("NOT_FOUND\r\n".getBytes))
+//            } else {
+//               if (isStatsEnabled) if (header.op == IncrementRequest) incrHits.incrementAndGet() else decrHits.incrementAndGet
+//               ch.write(buffers.wrappedBuffer((new String(v.get.data) + CRLF).getBytes))
+//            }
+//         }
+//         case FlushAllRequest => {
+//            ch.write(buffers.wrappedBuffer("OK\r\n".getBytes))
+//         }
+//         case VersionRequest => {
+//            val sb = new StringBuilder
+//            sb.append("VERSION ").append(Version.version).append(CRLF)
+//            ch.write(buffers.wrappedBuffer(sb.toString.getBytes))
+//         }
+//      }
+//      null
+//   }
 
-   override def sendResponse(ctx: ChannelHandlerContext, t: Throwable) {
+   override def sendResponse(ctx: ChannelHandlerContext, t: Throwable): AnyRef = {
       val ch = ctx.getChannel
       val buffers = ctx.getChannelBuffers
+      val sb = new StringBuilder
       t match {
-         case uoe: UnknownOperationException => ch.write(buffers.wrappedBuffer("ERROR\r\n".getBytes))
-         case cce: ClosedChannelException => // no-op, only log
+         case se: ServerException => {
+            se.getCause match {
+               case uoe: UnknownOperationException => ch.write(buffers.wrappedBuffer("ERROR\r\n".getBytes))
+               case cce: ClosedChannelException => // no-op, only log
+               case _ => {
+                  t match {
+                     case ioe: IOException => sb.append("CLIENT_ERROR ")
+                     case _ => sb.append("SERVER_ERROR ")
+                  }
+                  sb.append(t).append(CRLF)
+                  ch.write(buffers.wrappedBuffer(sb.toString.getBytes))
+               }
+            }
+         }
          case _ => {
-            val sb = new StringBuilder
-            t match {
-               case ioe: IOException => sb.append("CLIENT_ERROR ")
-               case _ => sb.append("SERVER_ERROR ")
-            }
-            sb.append(t).append(CRLF)
+            sb.append("SERVER_ERROR ").append(t).append(CRLF)
             ch.write(buffers.wrappedBuffer(sb.toString.getBytes))
          }
       }
+      null
    }
 
-   def sendResponse(ctx: ChannelHandlerContext, stats: Stats) {
+   def sendResponse(header: RequestHeader, ctx: ChannelHandlerContext, stats: Stats): AnyRef = {
       var buffers = ctx.getChannelBuffers
       var ch = ctx.getChannel
       var sb = new StringBuilder
@@ -354,6 +405,7 @@
       writeStat("conn_yields", 0, sb, buffers, ch) // Unsupported
 
       ch.write(buffers.wrappedBuffer("END\r\n".getBytes))
+      null
    }
 
    private def writeStat(stat: String, value: Any, sb: StringBuilder, buffers: ChannelBuffers, ch: Channel) {
@@ -375,15 +427,15 @@
       new MemcachedValue(data, nextVersion, flags)
    }   
 
-   private def buildGetResponse(op: Enumeration#Value, ctx: ChannelHandlerContext,
+   private def buildGetResponse(op: Enumeration#Value, buffers: ChannelBuffers,
                                 k: String, v: MemcachedValue): ChannelBuffer = {
       val header = buildGetResponseHeader(k, v, op)
-      ctx.getChannelBuffers.wrappedBuffer(header.getBytes, v.v, CRLF.getBytes)
+      buffers.wrappedBuffer(header.getBytes, v.data, CRLF.getBytes)
    }
 
    private def buildGetResponseHeader(k: String, v: MemcachedValue, op: Enumeration#Value): String = {
       val sb = new StringBuilder
-      sb.append("VALUE ").append(k).append(" ").append(v.flags).append(" ").append(v.v.length).append(" ")
+      sb.append("VALUE ").append(k).append(" ").append(v.flags).append(" ").append(v.data.length).append(" ")
       if (op == GetWithVersionRequest)
          sb.append(v.version).append(" ")   
       sb.append(CRLF)
@@ -395,13 +447,28 @@
 object MemcachedDecoder extends Logging
 
 class MemcachedParameters(override val data: Array[Byte], override val lifespan: Int,
-                          override val maxIdle: Int, override val version: Long,
-                          val noReply: Boolean, val flags: Int, val delta: String,
-                          val flushDelay: Int) extends RequestParameters(data, lifespan, maxIdle, version)
+                          override val maxIdle: Int, override val streamVersion: Long,
+                          override val noReply: Boolean, val flags: Int, val delta: String,
+                          val flushDelay: Int) extends RequestParameters(data, lifespan, maxIdle, streamVersion, noReply)
 
+//object MemcachedOperation extends Enumeration(10) {
+//   val PutRequest = new Value("set")
+//   val PutIfAbsentRequest = new Value("add")
+//   val ReplaceRequest = new Value("replace")
+//   val ReplaceIfUnmodifiedRequest = new Value("cas")
+//   val AppendRequest = new Value("append")
+//   val PrependRequest = new Value("prepend")
+//   val GetRequest = new Value("get")
+//   val GetWithVersionRequest = new Value("gets")
+//   val DeleteRequest = new Value("delete")
+//   val IncrementRequest = new Value("incr")
+//   val DecrementRequest = new Value("decr")
+//   val FlushAllRequest = new Value("flush_all")
+//   val VersionRequest = new Value("version")
+//   val StatsRequest = new Value("stats")
+//}
+
 private class DelayedFlushAll(cache: Cache[String, MemcachedValue],
-                              flushFunction: Cache[String, MemcachedValue] => Unit) extends Runnable {
-   override def run() = flushFunction(cache)
-}
-
-
+                              flushFunction: AdvancedCache[String, MemcachedValue] => Unit) extends Runnable {
+   override def run() = flushFunction(cache.getAdvancedCache)
+}
\ No newline at end of file

Modified: trunk/server/memcached/src/main/scala/org/infinispan/server/memcached/MemcachedValue.scala
===================================================================
--- trunk/server/memcached/src/main/scala/org/infinispan/server/memcached/MemcachedValue.scala	2010-03-25 10:49:02 UTC (rev 1619)
+++ trunk/server/memcached/src/main/scala/org/infinispan/server/memcached/MemcachedValue.scala	2010-03-25 11:46:48 UTC (rev 1620)
@@ -1,6 +1,6 @@
 package org.infinispan.server.memcached
 
-import org.infinispan.server.core.Value
+import org.infinispan.server.core.CacheValue
 import org.infinispan.util.Util
 import java.io.{ObjectOutput, ObjectInput}
 
@@ -10,20 +10,20 @@
  * @since
  */
 // TODO: Make it a hardcoded Externalizer
-class MemcachedValue(override val v: Array[Byte], override val version: Long, val flags: Int)
-      extends Value(v, version) {
+class MemcachedValue(override val data: Array[Byte], override val version: Long, val flags: Int)
+      extends CacheValue(data, version) {
 
    override def toString = {
       new StringBuilder().append("MemcachedValue").append("{")
-         .append("v=").append(Util.printArray(v, false))
+         .append("data=").append(Util.printArray(data, false))
          .append(", version=").append(version)
          .append(", flags=").append(flags)
          .append("}").toString
    }
 
 //   override def readExternal(in: ObjectInput) {
-////      v = new Array[Byte](in.read())
-////      in.read(v)
+////      data = new Array[Byte](in.read())
+////      in.read(data)
 ////      version = in.readLong
 //      super.readExternal(in)
 //      flags = in.readInt
@@ -31,8 +31,8 @@
 //
 //   override def writeExternal(out: ObjectOutput) {
 //      super.writeExternal(out)
-////      out.write(v.length)
-////      out.write(v)
+////      out.write(data.length)
+////      out.write(data)
 ////      out.writeLong(version)
 //      out.writeInt(flags)
 //   }

Modified: trunk/server/memcached/src/main/scala/org/infinispan/server/memcached/OperationResolver.scala
===================================================================
--- trunk/server/memcached/src/main/scala/org/infinispan/server/memcached/OperationResolver.scala	2010-03-25 10:49:02 UTC (rev 1619)
+++ trunk/server/memcached/src/main/scala/org/infinispan/server/memcached/OperationResolver.scala	2010-03-25 11:46:48 UTC (rev 1620)
@@ -10,10 +10,11 @@
  * @since
  */
 // todo: maybe try to abstract this into something that can be shared betwen hr and memcached
+// todo(2): Do I need this at all? Simply move it to decoder!
 object OperationResolver extends Logging {
    // TODO: Rather than holding a map, check if the String could be passed as part of the Enumeration and whether this could be retrieved in a O(1) op
    private val operations = Map[String, Enumeration#Value](
-      "set" -> PutRequest, 
+      "set" -> PutRequest,
       "add" -> PutIfAbsentRequest,
       "replace" -> ReplaceRequest,
       "cas" -> ReplaceIfUnmodifiedRequest,
@@ -21,7 +22,7 @@
       "prepend" -> PrependRequest,
       "get" -> GetRequest,
       "gets" -> GetWithVersionRequest,
-      "delete" -> DeleteRequest,
+      "delete" -> RemoveRequest,
       "incr" -> IncrementRequest,
       "decr" -> DecrementRequest,
       "flush_all" -> FlushAllRequest,

Modified: trunk/server/memcached/src/test/scala/org/infinispan/server/memcached/test/MemcachedTestingUtil.scala
===================================================================
--- trunk/server/memcached/src/test/scala/org/infinispan/server/memcached/test/MemcachedTestingUtil.scala	2010-03-25 10:49:02 UTC (rev 1619)
+++ trunk/server/memcached/src/test/scala/org/infinispan/server/memcached/test/MemcachedTestingUtil.scala	2010-03-25 11:46:48 UTC (rev 1620)
@@ -47,9 +47,8 @@
       return new MemcachedClient(d, Arrays.asList(new InetSocketAddress(host, port)))
    }
 
-   def startMemcachedTextServer(cacheManager: CacheManager): MemcachedServer = {
+   def startMemcachedTextServer(cacheManager: CacheManager): MemcachedServer =
       startMemcachedTextServer(cacheManager, UniquePortThreadLocal.get.intValue)
-   }
 
    def startMemcachedTextServer(cacheManager: CacheManager, port: Int): MemcachedServer = {
       val server = new MemcachedServer



More information about the infinispan-commits mailing list