[infinispan-commits] Infinispan SVN: r1617 - in trunk: client and 14 other directories.
infinispan-commits at lists.jboss.org
infinispan-commits at lists.jboss.org
Wed Mar 24 07:03:03 EDT 2010
Author: mircea.markus
Date: 2010-03-24 07:03:01 -0400 (Wed, 24 Mar 2010)
New Revision: 1617
Added:
trunk/client/
trunk/client/hotrod-client/
trunk/client/hotrod-client/pom.xml
trunk/client/hotrod-client/src/
trunk/client/hotrod-client/src/main/
trunk/client/hotrod-client/src/main/java/
trunk/client/hotrod-client/src/main/java/hotrod/
trunk/client/hotrod-client/src/main/java/hotrod/ClientDisconnectedException.java
trunk/client/hotrod-client/src/main/java/hotrod/ClusterTopologyListener.java
trunk/client/hotrod-client/src/main/java/hotrod/Flag.java
trunk/client/hotrod-client/src/main/java/hotrod/HotRodClientException.java
trunk/client/hotrod-client/src/main/java/hotrod/HotRodException.java
trunk/client/hotrod-client/src/main/java/hotrod/RemoteCache.java
trunk/client/hotrod-client/src/main/java/hotrod/RemoteCacheManager.java
trunk/client/hotrod-client/src/main/java/hotrod/TimeoutException.java
trunk/client/hotrod-client/src/main/java/hotrod/VersionedEntry.java
trunk/client/hotrod-client/src/main/java/hotrod/impl/
trunk/client/hotrod-client/src/main/java/hotrod/impl/HotrodConstants.java
trunk/client/hotrod-client/src/main/java/hotrod/impl/InvalidResponseException.java
trunk/client/hotrod-client/src/main/java/hotrod/impl/RemoteCacheImpl.java
trunk/client/hotrod-client/src/main/java/hotrod/impl/RemoteCacheSpi.java
trunk/client/hotrod-client/src/main/java/hotrod/impl/Transport.java
trunk/client/hotrod-client/src/main/java/hotrod/impl/VersionedEntry.java
trunk/client/hotrod-client/src/main/java/hotrod/impl/transport/
trunk/client/hotrod-client/src/main/java/hotrod/impl/transport/TcpTransport.java
trunk/client/hotrod-client/src/main/java/hotrod/impl/transport/TransportException.java
trunk/client/hotrod-client/src/main/java/hotrod/impl/transport/TransportFactory.java
trunk/client/hotrod-client/src/main/java/hotrod/impl/transport/VHelper.java
trunk/client/hotrod-client/src/main/resources/
trunk/client/hotrod-client/src/main/resources/hotrod-client.properties
trunk/client/hotrod-client/src/test/
trunk/client/hotrod-client/src/test/java/
trunk/client/hotrod-client/src/test/java/org/
trunk/client/hotrod-client/src/test/java/org/infinispan/
trunk/client/hotrod-client/src/test/java/org/infinispan/client/
trunk/client/hotrod-client/src/test/java/org/infinispan/client/hotrod/
trunk/client/hotrod-client/src/test/java/org/infinispan/client/hotrod/HotRodClientIntegrationTest.java
trunk/client/hotrod-client/src/test/java/org/infinispan/client/hotrod/HotRodListenerTest.java
trunk/client/hotrod-client/src/test/java/org/infinispan/client/hotrod/VHelperTest.java
Modified:
trunk/pom.xml
Log:
added first hot rod client stub
Added: trunk/client/hotrod-client/pom.xml
===================================================================
--- trunk/client/hotrod-client/pom.xml (rev 0)
+++ trunk/client/hotrod-client/pom.xml 2010-03-24 11:03:01 UTC (rev 1617)
@@ -0,0 +1,33 @@
+<?xml version="1.0"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.infinispan</groupId>
+ <artifactId>infinispan-parent</artifactId>
+ <version>4.1.0-SNAPSHOT</version>
+ <relativePath>../../parent/pom.xml</relativePath>
+ </parent>
+
+ <artifactId>infinispan-client-hotrod</artifactId>
+ <name>Infinispan Client Hotrod Module</name>
+ <description>Infinispan client hotrod module</description>
+ <packaging>jar</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>infinispan-core</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>infinispan-core</artifactId>
+ <version>${project.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+</project>
Added: trunk/client/hotrod-client/src/main/java/hotrod/ClientDisconnectedException.java
===================================================================
--- trunk/client/hotrod-client/src/main/java/hotrod/ClientDisconnectedException.java (rev 0)
+++ trunk/client/hotrod-client/src/main/java/hotrod/ClientDisconnectedException.java 2010-03-24 11:03:01 UTC (rev 1617)
@@ -0,0 +1,13 @@
+package hotrod;
+
+/**
+ * // TODO: Document this
+ *
+ * @author mmarkus
+ * @since 4.1
+ */
+public class ClientDisconnectedException extends HotRodException {
+ public ClientDisconnectedException() {
+ super("Cannot call a method on the remote cache after RemoteCacheFactory.putForExternalRead has been called.");
+ }
+}
Added: trunk/client/hotrod-client/src/main/java/hotrod/ClusterTopologyListener.java
===================================================================
--- trunk/client/hotrod-client/src/main/java/hotrod/ClusterTopologyListener.java (rev 0)
+++ trunk/client/hotrod-client/src/main/java/hotrod/ClusterTopologyListener.java 2010-03-24 11:03:01 UTC (rev 1617)
@@ -0,0 +1,22 @@
+package hotrod;
+
+import java.util.List;
+
+/**
+ * // TODO: Document this
+ *
+ * @author mmarkus
+ * @since 4.1
+ */
+public interface ClusterTopologyListener {
+
+ //todo consider using inet address
+ public class Address {
+ private String host;
+ private int port;
+ }
+
+ public void nodeAdded(List<Address> currentTopology, Address addedNode);
+
+ public void nodeRemoved(List<Address> currentTopology, Address removedNode);
+}
Added: trunk/client/hotrod-client/src/main/java/hotrod/Flag.java
===================================================================
--- trunk/client/hotrod-client/src/main/java/hotrod/Flag.java (rev 0)
+++ trunk/client/hotrod-client/src/main/java/hotrod/Flag.java 2010-03-24 11:03:01 UTC (rev 1617)
@@ -0,0 +1,31 @@
+package hotrod;
+
+/**
+ * // TODO: Document this
+ *
+ * @author mmarkus
+ * @since 4.1
+ */
+public enum Flag {
+ ZERO_LOCK_ACQUISITION_TIMEOUT(0x0001),
+ CACHE_MODE_LOCAL(0x0002),
+ SKIP_LOCKING(0x0004),
+ FORCE_WRITE_LOCK(0x0008),
+ SKIP_CACHE_STATUS_CHECK(0x0010),
+ FORCE_ASYNCHRONOUS(0x0020),
+ FORCE_SYNCHRONOUS(0x0040),
+ SKIP_CACHE_STORE(0x0100),
+ FAIL_SILENTLY(0x0200),
+ SKIP_REMOTE_LOOKUP(0x0400),
+ PUT_FOR_EXTERNAL_READ(0x0800);
+
+ private int flagInt;
+
+ Flag(int flagInt) {
+ this.flagInt = flagInt;
+ }
+
+ public int getFlagInt() {
+ return flagInt;
+ }
+}
Added: trunk/client/hotrod-client/src/main/java/hotrod/HotRodClientException.java
===================================================================
--- trunk/client/hotrod-client/src/main/java/hotrod/HotRodClientException.java (rev 0)
+++ trunk/client/hotrod-client/src/main/java/hotrod/HotRodClientException.java 2010-03-24 11:03:01 UTC (rev 1617)
@@ -0,0 +1,35 @@
+package hotrod;
+
+/**
+ * // TODO: Document this
+ *
+ * @author mmarkus
+ * @since 4.1
+ */
+public class HotRodClientException extends HotRodException {
+ private long messageId;
+ private int errorStatusCode;
+
+ public HotRodClientException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public HotRodClientException(long messageId, int errorStatusCode) {
+ this.messageId = messageId;
+ this.errorStatusCode = errorStatusCode;
+ }
+
+
+ @Override
+ public String toString() {
+ return "HotRodServerException{" +
+ "messageId=" + messageId +
+ ", errorStatusCode=" + errorStatusCode +
+ "} " + super.toString();
+ }
+
+ @Override
+ public String getMessage() {
+ return toString() + "." + super.getMessage();
+ }
+}
Added: trunk/client/hotrod-client/src/main/java/hotrod/HotRodException.java
===================================================================
--- trunk/client/hotrod-client/src/main/java/hotrod/HotRodException.java (rev 0)
+++ trunk/client/hotrod-client/src/main/java/hotrod/HotRodException.java 2010-03-24 11:03:01 UTC (rev 1617)
@@ -0,0 +1,24 @@
+package hotrod;
+
+/**
+ * // TODO: Document this
+ *
+ * @author mmarkus
+ * @since 4.1
+ */
+public class HotRodException extends RuntimeException {
+ public HotRodException() {
+ }
+
+ public HotRodException(String message) {
+ super(message);
+ }
+
+ public HotRodException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public HotRodException(Throwable cause) {
+ super(cause);
+ }
+}
Added: trunk/client/hotrod-client/src/main/java/hotrod/RemoteCache.java
===================================================================
--- trunk/client/hotrod-client/src/main/java/hotrod/RemoteCache.java (rev 0)
+++ trunk/client/hotrod-client/src/main/java/hotrod/RemoteCache.java 2010-03-24 11:03:01 UTC (rev 1617)
@@ -0,0 +1,314 @@
+package hotrod;
+
+import org.infinispan.AdvancedCache;
+import org.infinispan.Cache;
+import org.infinispan.config.Configuration;
+import org.infinispan.util.concurrent.NotifyingFuture;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Provides remote reference to a Hot Rod server/cluster. It implements {@link org.infinispan.Cache}, but given its
+ * nature (remote) some operations are not supported. All these unsupported operations are being overridden within this
+ * interface and documented as such.
+ * <p/>
+ * <b>New operations</b>: besides the operations inherited from {@link org.infinispan.Cache}, RemoteCache also adds new
+ * operations to optimize/reduce network traffic: e.g. versioned put operation.
+ * <p/>
+ * <b>Concurrency</b>: implementors of this interface will support multi-threaded access, similar to the way {@link
+ * org.infinispan.Cache} supports it.
+ * <p/>
+ * <b>Return values</b>: previous existing values for certain {@link java.util.Map} operations are not being returned,
+ * but null will always be returned instead. E.g. {@link java.util.Map#put(Object, Object)} returns the previous value
+ * associated to the supplied key. In case of RemoteCache, this will always return null.
+ * <p/>
+ * <b>Synthetic operations</b>: Certain aggregate operations are being implemented based on other Hot Rod operations.
+ * E.g. all the {@link java.util.Map#putAll(java.util.Map)} is implemented through multiple individual puts. This means
+ * that the these operations are not atomic and that they are costly, e.g. as the number of network round-trips is not
+ * one, but the size of the added map. All these synthetic operations are documented as such and should be used
+ *
+ * @author Mircea.Markus at jboss.com
+ * @since 4.1
+ */
+public interface RemoteCache<K, V> extends Cache<K, V> {
+
+
+ /**
+ * Removes the given entry only if its version matches the supplied version. A typical use case looks like this:
+ * <pre>
+ * VersionedEntry ve = remoteCache.getVersionedEntry(key);
+ * //some processing
+ * remoteCache.remove(key, ve.getVersion();
+ * </pre>
+ * Lat call (remove) will make sure that the entry will only be removed if it hasn't been changed in between.
+ *
+ * @return true if the entry has been removed
+ * @see VersionedEntry
+ * @see #getVersionedEntry(Object)
+ */
+ boolean remove(Object key, long version);
+
+ /**
+ * @see #remove(Object, Object)
+ */
+ NotifyingFuture<Boolean> removeAsync(Object key, long version);
+
+ /**
+ * Removes the given value only if its version matches the supplied version. See {@link #remove(Object, long)} for a
+ * sample usage.
+ *
+ * @return true if the method has been replaced
+ * @see #getVersionedEntry(Object)
+ * @see VersionedEntry
+ */
+ boolean replace(K key, V newValue, long version);
+
+ /**
+ * @see #replace(Object, Object, long)
+ */
+ boolean replace(K key, V newValue, long version, long lifespan, TimeUnit unit);
+
+ /**
+ * @see #replace(Object, Object, long)
+ */
+ boolean replace(K key, V newValue, long version, long lifespan, TimeUnit lifespanUnit, long maxIdleTime, TimeUnit maxIdleTimeUnit);
+
+ /**
+ * @see #replace(Object, Object, long)
+ */
+ NotifyingFuture<Boolean> replaceAsync(K key, V newValue, long version);
+
+ /**
+ * @see #replace(Object, Object, long)
+ */
+ NotifyingFuture<Boolean> replaceAsync(K key, V newValue, long version, long lifespan, TimeUnit unit);
+
+ /**
+ * @see #replace(Object, Object, long)
+ */
+ NotifyingFuture<Boolean> replaceAsync(K key, V newValue, long version, long lifespan, TimeUnit lifespanUnit, long maxIdle, TimeUnit maxIdleUnit);
+
+
+ /**
+ * Returns the {@link VersionedEntry} associated to the supplied key param, or null if it doesn't exist.
+ */
+ VersionedEntry getVersionedEntry(K key);
+
+
+ /**
+ * Operation might be supported for smart clients that will be able to register for topology changes.
+ *
+ * @throws UnsupportedOperationException
+ */
+ @Override
+ void addListener(Object listener);
+
+ /**
+ * @throws UnsupportedOperationException
+ * @see #addListener(Object)
+ */
+ @Override
+ void removeListener(Object listener);
+
+ /**
+ * @throws UnsupportedOperationException
+ * @see #addListener(Object)
+ */
+ @Override
+ Set<Object> getListeners();
+
+ /**
+ * @throws UnsupportedOperationException
+ */
+ @Override
+ int size();
+
+ /**
+ * @throws UnsupportedOperationException
+ */
+ @Override
+ boolean isEmpty();
+
+ /**
+ * @throws UnsupportedOperationException
+ */
+ @Override
+ boolean containsValue(Object value);
+
+ /**
+ * @throws UnsupportedOperationException
+ */
+ @Override
+ Set<K> keySet();
+
+ /**
+ * @throws UnsupportedOperationException
+ */
+ @Override
+ Collection<V> values();
+
+ /**
+ * @throws UnsupportedOperationException
+ */
+ @Override
+ Set<Entry<K, V>> entrySet();
+
+ /**
+ * @throws UnsupportedOperationException
+ */
+ @Override
+ void evict(K key);
+
+ /**
+ * @throws UnsupportedOperationException
+ */
+ @Override
+ Configuration getConfiguration();
+
+ /**
+ * @throws UnsupportedOperationException
+ */
+ @Override
+ boolean startBatch();
+
+ /**
+ * @throws UnsupportedOperationException
+ */
+ @Override
+ void endBatch(boolean successful);
+
+ /**
+ * This operation is not supported. Consider using {@link #remove(Object, long)} instead.
+ *
+ * @throws UnsupportedOperationException
+ */
+ @Override
+ boolean remove(Object key, Object value);
+
+ /**
+ * This operation is not supported. Consider using {@link #removeAsync(Object, long)} instead.
+ *
+ * @throws UnsupportedOperationException
+ */
+ @Override
+ NotifyingFuture<Boolean> removeAsync(Object key, Object value);
+
+ /**
+ * This operation is not supported. Consider using {@link #replace(Object, Object, long)} instead.
+ *
+ * @throws UnsupportedOperationException
+ */
+ @Override
+ boolean replace(K key, V oldValue, V newValue);
+
+ /**
+ * This operation is not supported. Consider using {@link #replace(Object, Object, long, long, TimeUnit)} instead.
+ *
+ * @throws UnsupportedOperationException
+ */
+ @Override
+ boolean replace(K key, V oldValue, V value, long lifespan, TimeUnit unit);
+
+ /**
+ * This operation is not supported. Consider using {@link #replace(Object, Object, long, long, TimeUnit, long,
+ * TimeUnit)} instead.
+ *
+ * @throws UnsupportedOperationException
+ */
+ @Override
+ boolean replace(K key, V oldValue, V value, long lifespan, TimeUnit lifespanUnit, long maxIdleTime, TimeUnit maxIdleTimeUnit);
+
+ /**
+ * This operation is not supported. Consider using {@link #replaceAsync(Object, Object, long)} instead.
+ *
+ * @throws UnsupportedOperationException
+ */
+ @Override
+ NotifyingFuture<Boolean> replaceAsync(K key, V oldValue, V newValue);
+
+ /**
+ * This operation is not supported. Consider using {@link #replaceAsync(Object, Object, long, long, TimeUnit)}
+ * instead.
+ *
+ * @throws UnsupportedOperationException
+ */
+ @Override
+ NotifyingFuture<Boolean> replaceAsync(K key, V oldValue, V newValue, long lifespan, TimeUnit unit);
+
+ /**
+ * This operation is not supported. Consider using {@link #replaceAsync(Object, Object, long, long, TimeUnit, long,
+ * TimeUnit)} instead.
+ *
+ * @throws UnsupportedOperationException
+ */
+ @Override
+ NotifyingFuture<Boolean> replaceAsync(K key, V oldValue, V newValue, long lifespan, TimeUnit lifespanUnit, long maxIdle, TimeUnit maxIdleUnit);
+
+ /**
+ * This operation is not supported.
+ *
+ * @throws UnsupportedOperationException
+ */
+ @Override
+ AdvancedCache<K, V> getAdvancedCache();
+
+ /**
+ * This operation is not supported.
+ *
+ * @throws UnsupportedOperationException
+ */
+ @Override
+ void compact();
+
+
+ /**
+ * Synthetic operation. The client iterates over the set of keys and calls put for each one of them. This results in
+ * operation not being atomic (if a failure happens after few puts it is not rolled back) and costly (for each key in
+ * the parameter map a remote call is performed).
+ */
+ @Override
+ void putAll(Map<? extends K, ? extends V> map, long lifespan, TimeUnit unit);
+
+ /**
+ * Synthetic operation.
+ *
+ * @see #putAll(java.util.Map, long, java.util.concurrent.TimeUnit)
+ */
+ @Override
+ void putAll(Map<? extends K, ? extends V> map, long lifespan, TimeUnit lifespanUnit, long maxIdleTime, TimeUnit maxIdleTimeUnit);
+
+ /**
+ * Synthetic operation.
+ *
+ * @see #putAll(java.util.Map, long, java.util.concurrent.TimeUnit)
+ */
+ @Override
+ NotifyingFuture<Void> putAllAsync(Map<? extends K, ? extends V> data);
+
+ /**
+ * Synthetic operation.
+ *
+ * @see #putAll(java.util.Map, long, java.util.concurrent.TimeUnit)
+ */
+ @Override
+ NotifyingFuture<Void> putAllAsync(Map<? extends K, ? extends V> data, long lifespan, TimeUnit unit);
+
+ /**
+ * Synthetic operation.
+ *
+ * @see #putAll(java.util.Map, long, java.util.concurrent.TimeUnit)
+ */
+ @Override
+ NotifyingFuture<Void> putAllAsync(Map<? extends K, ? extends V> data, long lifespan, TimeUnit lifespanUnit, long maxIdle, TimeUnit maxIdleUnit);
+
+ /**
+ * Synthetic operation.
+ *
+ * @see #putAll(java.util.Map, long, java.util.concurrent.TimeUnit)
+ */
+ @Override
+ void putAll(Map<? extends K, ? extends V> m);
+}
Added: trunk/client/hotrod-client/src/main/java/hotrod/RemoteCacheManager.java
===================================================================
--- trunk/client/hotrod-client/src/main/java/hotrod/RemoteCacheManager.java (rev 0)
+++ trunk/client/hotrod-client/src/main/java/hotrod/RemoteCacheManager.java 2010-03-24 11:03:01 UTC (rev 1617)
@@ -0,0 +1,79 @@
+package hotrod;
+
+import hotrod.impl.RemoteCacheSpi;
+import org.infinispan.lifecycle.Lifecycle;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Properties;
+
+/**
+ * // TODO: Document this
+ *
+ * @author mmarkus
+ * @since 4.1
+ */
+public class RemoteCacheManager implements Lifecycle {
+
+ private Properties props;
+
+ /**
+ * Build a cache manager based on supplied given properties.
+ * TODO - add a list of all possible configuration parameters here
+ */
+ public RemoteCacheManager(Properties props) {
+ this.props = props;
+ }
+
+ /**
+ * Same as {@link #RemoteCacheManager(java.util.Properties)}, but it will try to lookup the config properties in the
+ * classpath, in a file named <tt>hotrod-client.properties</tt>.
+ * @throws HotRodClientException if such a file cannot be found in the classpath
+ */
+ public RemoteCacheManager() {
+ ClassLoader loader = Thread.currentThread().getContextClassLoader();
+ InputStream stream = loader.getResourceAsStream("hotrod-client.properties");
+ loadFromStream(stream);
+ }
+
+ /**
+ * Same as {@link #RemoteCacheManager(java.util.Properties)}, but it will try to lookup the config properties in
+ * supplied URL.
+ * @throws HotRodClientException if properties could not be loaded
+ */
+ public RemoteCacheManager(URL config) {
+ try {
+ loadFromStream(config.openStream());
+ } catch (IOException e) {
+ throw new HotRodClientException("Could not read URL:" + config, e);
+ }
+ }
+
+ private void loadFromStream(InputStream stream) {
+ props = new Properties();
+ try {
+ props.load(stream);
+ } catch (IOException e) {
+ throw new HotRodClientException("Issues configuring from client hotrod-client.properties",e);
+ }
+ }
+
+ public RemoteCacheSpi getRemoteCache(String remoteCacheName) {
+ return null;
+ }
+
+ public RemoteCacheSpi getDefaultRemoteCache() {
+ return null;
+ }
+
+ @Override
+ public void start() {
+ // TODO: Customise this generated block
+ }
+
+ @Override
+ public void stop() {
+ // TODO: Customise this generated block
+ }
+}
Added: trunk/client/hotrod-client/src/main/java/hotrod/TimeoutException.java
===================================================================
--- trunk/client/hotrod-client/src/main/java/hotrod/TimeoutException.java (rev 0)
+++ trunk/client/hotrod-client/src/main/java/hotrod/TimeoutException.java 2010-03-24 11:03:01 UTC (rev 1617)
@@ -0,0 +1,10 @@
+package hotrod;
+
+/**
+ * // TODO: Document this
+ *
+ * @author mmarkus
+ * @since 4.1
+ */
+public class TimeoutException extends HotRodException {
+}
Added: trunk/client/hotrod-client/src/main/java/hotrod/VersionedEntry.java
===================================================================
--- trunk/client/hotrod-client/src/main/java/hotrod/VersionedEntry.java (rev 0)
+++ trunk/client/hotrod-client/src/main/java/hotrod/VersionedEntry.java 2010-03-24 11:03:01 UTC (rev 1617)
@@ -0,0 +1,13 @@
+package hotrod;
+
+import java.util.Map;
+
+/**
+ * // TODO: Document this
+ *
+ * @author Mircea.Markus at jboss.com
+ * @since 4.1
+ */
+public interface VersionedEntry extends Map.Entry{
+ public long getVersion();
+}
Added: trunk/client/hotrod-client/src/main/java/hotrod/impl/HotrodConstants.java
===================================================================
--- trunk/client/hotrod-client/src/main/java/hotrod/impl/HotrodConstants.java (rev 0)
+++ trunk/client/hotrod-client/src/main/java/hotrod/impl/HotrodConstants.java 2010-03-24 11:03:01 UTC (rev 1617)
@@ -0,0 +1,61 @@
+package hotrod.impl;
+
+/**
+ * // TODO: Document this
+ *
+ * @author mmarkus
+ * @since 4.1
+ */
+public interface HotrodConstants {
+
+ public static final short REQUEST_MAGIC = 0xA0;
+ public static final short RESPONSE_MAGIC = 0xA1;
+
+ public static final byte HOTROD_VERSION = 0x01;
+
+ //requests
+ public static final byte PUT_REQUEST = 0x01;
+ public static final byte GET_REQUEST = 0x03;
+ public static final byte PUT_IF_ABSENT_REQUEST = 0x05;
+ public static final byte REPLACE_REQUEST = 0x07;
+ public static final byte REPLACE_IF_UNMODIFIED_REQUEST = 0x09;
+ public static final byte REMOVE_REQUEST = 0x0B;
+ public static final byte REMOVE_IF_UNMODIFIED_REQUEST = 0x0D;
+ public static final byte CONTAINS_KEY_REQUEST = 0x0F;
+ public static final byte PUT_FOR_EXTERNAL_READ_REQUEST = 0x11;
+ public static final byte GET_WITH_CAS_REQUEST = 0x13;
+ public static final byte EVICT_REQUEST = 0x15;
+ public static final byte CLEAR_REQUEST = 0x17;
+ public static final byte STATS_REQUEST = 0x19;
+ public static final byte QUIT_REQUEST = 0x1B;
+ public static final byte EVENT_REGISTRATION_REQUEST = 0x1D;
+
+ //responses
+ public static final byte PUT_RESPONSE = 0x02;
+ public static final byte GET_RESPONSE = 0x04;
+ public static final byte PUT_IF_ABSENT_RESPONSE = 0x06;
+ public static final byte REPLACE_RESPONSE = 0x08;
+ public static final byte REPLACE_IF_UNMODIFIED_RESPONSE = 0x0A;
+ public static final byte REMOVE_RESPONSE = 0x0C;
+ public static final byte REMOVE_IF_UNMODIFIED_RESPONSE = 0x0E;
+ public static final byte CONTAINS_KEY_RESPONSE = 0x10;
+ public static final byte PUT_FOR_EXTERNAL_READ_RESPONSE = 0x12;
+ public static final byte GET_WITH_CAS_RESPONSE = 0x14;
+ public static final byte EVICT_RESPONSE = 0x16;
+ public static final byte CLEAR_RESPONSE = 0x18;
+ public static final byte STATS_RESPONSE = 0x1A;
+ public static final byte QUIT_RESPONSE = 0x1C;
+ public static final byte EVENT_REGISTRATION_RESPONSE = 0x1E;
+
+ //response status
+ public static final byte NO_ERROR_STATUS = 0x00;
+ public static final int INVALID_MAGIC_OR_MESSAGE_ID_STATUS = 0x81;
+ public static final int REQUEST_PARSING_ERROR_STATUS = 0x84;
+ public static final byte NOT_PUT_REMOVED_REPLACED_STATUS = 0x01;
+ public static final int UNKNOWN_COMMAND_STATUS = 0x82;
+ public static final int SERVER_ERROR_STATUS = 0x85;
+ public static final int KEY_DOES_NOT_EXIST_STATUS = 0x02;
+ public static final int UNKNOWN_VERSION_STATUS = 0x83;
+ public static final int COMMAND_TIMEOUT_STATUS = 0x86;
+
+}
Added: trunk/client/hotrod-client/src/main/java/hotrod/impl/InvalidResponseException.java
===================================================================
--- trunk/client/hotrod-client/src/main/java/hotrod/impl/InvalidResponseException.java (rev 0)
+++ trunk/client/hotrod-client/src/main/java/hotrod/impl/InvalidResponseException.java 2010-03-24 11:03:01 UTC (rev 1617)
@@ -0,0 +1,26 @@
+package hotrod.impl;
+
+import hotrod.HotRodException;
+
+/**
+ * // TODO: Document this
+ *
+ * @author mmarkus
+ * @since 4.1
+ */
+public class InvalidResponseException extends HotRodException {
+ public InvalidResponseException() {
+ }
+
+ public InvalidResponseException(String message) {
+ super(message);
+ }
+
+ public InvalidResponseException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public InvalidResponseException(Throwable cause) {
+ super(cause);
+ }
+}
Added: trunk/client/hotrod-client/src/main/java/hotrod/impl/RemoteCacheImpl.java
===================================================================
--- trunk/client/hotrod-client/src/main/java/hotrod/impl/RemoteCacheImpl.java (rev 0)
+++ trunk/client/hotrod-client/src/main/java/hotrod/impl/RemoteCacheImpl.java 2010-03-24 11:03:01 UTC (rev 1617)
@@ -0,0 +1,257 @@
+package hotrod.impl;
+
+import hotrod.ClusterTopologyListener;
+import hotrod.Flag;
+import hotrod.HotRodClientException;
+import hotrod.TimeoutException;
+import hotrod.impl.VersionedEntry;
+import hotrod.impl.RemoteCacheSpi;
+import hotrod.RemoteCacheManager;
+import hotrod.impl.transport.TransportFactory;
+
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * // TODO: Document this
+ *
+ * @author mmarkus
+ * @since 4.1
+ */
+public class RemoteCacheImpl implements RemoteCacheSpi, HotrodConstants {
+
+ private final String cacheName;
+ private final byte[] cacheNameBytes;
+ private static final AtomicLong MSG_ID = new AtomicLong();
+ private TransportFactory transportFactory;
+
+ public RemoteCacheImpl(String cacheName, TransportFactory transportFactory) {
+ this.cacheName = cacheName;
+ cacheNameBytes = cacheName.getBytes(); //todo add charset here
+ this.transportFactory = transportFactory;
+ }
+
+ public byte[] get(byte[] key) {
+ Transport transport = getTransport();
+ try {
+ byte status = sendKeyOperation(key, transport, GET_REQUEST);
+ if (status == KEY_DOES_NOT_EXIST_STATUS) {
+ return null;
+ }
+ if (status == NO_ERROR_STATUS) {
+ int responseLength = transport.readVInt();
+ byte[] result = new byte[responseLength];
+ return transport.readByteArray(result);
+ }
+ } finally {
+ transport.release();
+ }
+ throw new IllegalStateException("We should not reach here!");
+ }
+
+ public boolean remove(byte[] key) {
+ Transport transport = getTransport();
+ try {
+ byte status = sendKeyOperation(key, transport, REMOVE_REQUEST);
+ if (status == KEY_DOES_NOT_EXIST_STATUS) {
+ return false;
+ } else if (status == NO_ERROR_STATUS) {
+ return true;
+ }
+ } finally {
+ transport.release();
+ }
+ throw new IllegalStateException("We should not reach here!");
+ }
+
+ public boolean contains(byte[] key) {
+ Transport transport = getTransport();
+ try {
+ byte status = sendKeyOperation(key, transport, CONTAINS_KEY_REQUEST);
+ if (status == KEY_DOES_NOT_EXIST_STATUS) {
+ return false;
+ } else if (status == NO_ERROR_STATUS) {
+ return true;
+ }
+ } finally {
+ transport.release();
+ }
+ throw new IllegalStateException("We should not reach here!");
+ }
+
+ public VersionedEntry getVersionedCacheEntry(byte[] key) {
+ Transport transport = getTransport();
+ try {
+ byte status = sendKeyOperation(key, transport, GET_WITH_CAS_REQUEST);
+ if (status == KEY_DOES_NOT_EXIST_STATUS) {
+ return null;
+ }
+ if (status == NO_ERROR_STATUS) {
+ long cas = transport.readVLong();
+ int responseLength = transport.readVInt();
+ byte[] value = new byte[responseLength];
+ return new VersionedEntry(cas, key, value);
+ }
+ } finally {
+ transport.release();
+ }
+ throw new IllegalStateException("We should not reach here!");
+ }
+
+ //[header][key length][key][lifespan][max idle][value length][value]
+ public void put(byte[] key, byte[] value) {
+ Transport transport = getTransport();
+ try {
+ byte status = sendPutOperation(key, value, transport, PUT_REQUEST);
+ if (status != NO_ERROR_STATUS) {
+ throw new InvalidResponseException("Unexpected response status: " + Integer.toHexString(status));
+ }
+ } finally {
+ transport.release();
+ }
+ }
+
+ public boolean putIfAbsent(byte[] key, byte[] value) {
+ Transport transport = getTransport();
+ try {
+ byte status = sendPutOperation(key, value, transport, PUT_IF_ABSENT_REQUEST);
+ if (status == NO_ERROR_STATUS) {
+ return true;
+ } else if (status == NOT_PUT_REMOVED_REPLACED_STATUS) {
+ return false;
+ }
+ } finally {
+ transport.release();
+ }
+ throw new IllegalStateException("We should not reach here!");
+ }
+
+ public boolean replace(byte[] key, byte[] value) {
+ return false;
+ }
+
+ public VersionedOperationResponse replaceIfUnmodified(byte[] key, byte[] value, long version) {
+ return null; // TODO: Customise this generated block
+ }
+
+ public VersionedOperationResponse removeIfUnmodified(byte[] key, long version) {
+ return null; // TODO: Customise this generated block
+ }
+
+ public void putForExternalRead(byte[] key, byte[] value) {
+ // TODO: Customise this generated block
+ }
+
+ public boolean evict(byte[] key) {
+ return false; // TODO: Customise this generated block
+ }
+
+ public void clear() {
+ // TODO: Customise this generated block
+ }
+
+ public String stats() {
+ return null; // TODO: Customise this generated block
+ }
+
+ public String stats(String paramName) {
+ return null; // TODO: Customise this generated block
+ }
+
+ public void addClusterTopologyListener(ClusterTopologyListener listener) {
+ // TODO: Customise this generated block
+ }
+
+ public boolean removeClusterTopologyListener(ClusterTopologyListener listener) {
+ return false; // TODO: Customise this generated block
+ }
+
+ public RemoteCacheManager getRemoteCacheFactory() {
+ return null; // TODO: Customise this generated block
+ }
+
+ public Transport getTransport() {
+ return transportFactory.getTransport();
+ }
+
+
+ private byte sendKeyOperation(byte[] key, Transport transport, byte code) {
+ long messageId = writeHeader(transport, code);
+ transport.writeByteArray(key);
+ transport.flush();
+ byte status = readHeaderAndValidate(transport, messageId, code);
+
+ //this will make sure that we don't have an error
+ processResponseStatus(status, messageId);
+ return status;
+ }
+
+ private byte sendPutOperation(byte[] key, byte[] value, Transport transport, byte code) {
+ long messageId = writeHeader(transport, code);
+ transport.writeByteArray(key);
+ //todo - lifespan and max_idle
+ transport.writeVInt(0); //lifespan
+ transport.writeVInt(0); //max_idle
+ transport.writeByteArray(value);
+ transport.flush();
+ byte status = readHeaderAndValidate(transport, messageId, code);
+ processResponseStatus(status, messageId);
+ return status;
+ }
+
+ /*
+ * Magic | MessageId | Version | Opcode | CacheNameLength | CacheName | Flags
+ */
+ private long writeHeader(Transport transport, byte operationCode, Flag... flags) {
+ transport.appendUnsignedByte(REQUEST_MAGIC);
+ long messageId = MSG_ID.incrementAndGet();
+ transport.writeVLong(messageId);
+ transport.writeByteArray(HOTROD_VERSION, operationCode);
+ transport.writeVInt(cacheNameBytes.length);
+ transport.writeByteArray(cacheNameBytes);
+ int flagInt = 0;
+ for (Flag flag: flags) {
+ flagInt = flag.getFlagInt() | flagInt;
+ }
+ transport.writeVInt(flagInt);
+ return messageId;
+ }
+
+ private byte readHeaderAndValidate(Transport transport, long messageId, byte opCode) {
+ byte magic = transport.readByte();
+ if (magic != RESPONSE_MAGIC) {
+ throw new InvalidResponseException("Invalid magic number. Expected " + RESPONSE_MAGIC + " and received " + Integer.toHexString(magic));
+ }
+ long receivedMessageId = transport.readVLong();
+ if (receivedMessageId != messageId) {
+ throw new InvalidResponseException("Invalid message id. Expected " + messageId + " and received " + Long.toHexString(receivedMessageId));
+ }
+ byte receivedOpCode = transport.readByte();
+ if (receivedOpCode != opCode) {
+ throw new InvalidResponseException("Invalid response operation. Expected " + opCode + " and received " + Integer.toHexString(receivedOpCode));
+ }
+ return transport.readByte();
+ }
+
+ private void processResponseStatus(byte status, long messageId) {
+ switch ((int)status) {
+ case INVALID_MAGIC_OR_MESSAGE_ID_STATUS:
+ case REQUEST_PARSING_ERROR_STATUS:
+ case UNKNOWN_COMMAND_STATUS:
+ case SERVER_ERROR_STATUS:
+ case UNKNOWN_VERSION_STATUS: {
+ throw new HotRodClientException(messageId, status);
+ }
+ case COMMAND_TIMEOUT_STATUS: {
+ throw new TimeoutException();
+ }
+ case NO_ERROR_STATUS:
+ case KEY_DOES_NOT_EXIST_STATUS: {
+ //don't do anything, these are correct responses
+ break;
+ }
+ default: {
+ throw new IllegalStateException("Unknown status: " + Integer.toHexString(status));
+ }
+ }
+ }
+}
Added: trunk/client/hotrod-client/src/main/java/hotrod/impl/RemoteCacheSpi.java
===================================================================
--- trunk/client/hotrod-client/src/main/java/hotrod/impl/RemoteCacheSpi.java (rev 0)
+++ trunk/client/hotrod-client/src/main/java/hotrod/impl/RemoteCacheSpi.java 2010-03-24 11:03:01 UTC (rev 1617)
@@ -0,0 +1,72 @@
+package hotrod.impl;
+
+import hotrod.ClusterTopologyListener;
+import hotrod.RemoteCacheManager;
+import hotrod.impl.VersionedEntry;
+
+/**
+ * // TODO: Document this
+ *
+ * - TODO - add timeout support
+ * - TODO - add flags support
+ * - TODO - enforce encoding and add such tests
+ *
+ * @author mmarkus
+ * @since 4.1
+ */
+public interface RemoteCacheSpi {
+
+ public enum VersionedOperationResponse {
+ SUCCESS(true), NO_SUCH_KEY(false), MODIFIED_KEY(false);
+ private boolean isModified;
+
+ VersionedOperationResponse(boolean modified) {
+ isModified = modified;
+ }
+
+ public boolean isUpdated() {
+ return isModified;
+ }
+ }
+
+ public byte[] get(byte[] key);
+
+ public boolean remove(byte[] key);
+
+ public boolean contains(byte[] key);
+
+ public VersionedEntry getVersionedCacheEntry(byte[] key);
+
+ /**
+ * @return true if this there is an entry for that key in the cache(which is overwritten now), false otherwise.
+ */
+ public void put(byte[] key, byte[] value);
+
+ public boolean putIfAbsent(byte[] key, byte[] value);
+
+ public boolean replace(byte[] key, byte[] value);
+
+ public VersionedOperationResponse replaceIfUnmodified(byte[] key, byte[] value, long version);
+
+ public VersionedOperationResponse removeIfUnmodified(byte[] key, long version);
+
+ public void putForExternalRead(byte[] key, byte[] value);
+
+ /**
+ * @param key the key to be evicted.
+ * @return true if the key was evicted, false if it does not exist or could not be evicted.
+ */
+ public boolean evict(byte[] key);
+
+ public void clear();
+
+ public String stats();
+
+ public String stats(String paramName);
+
+ public void addClusterTopologyListener(ClusterTopologyListener listener);
+
+ public boolean removeClusterTopologyListener(ClusterTopologyListener listener);
+
+ public RemoteCacheManager getRemoteCacheFactory();
+}
Added: trunk/client/hotrod-client/src/main/java/hotrod/impl/Transport.java
===================================================================
--- trunk/client/hotrod-client/src/main/java/hotrod/impl/Transport.java (rev 0)
+++ trunk/client/hotrod-client/src/main/java/hotrod/impl/Transport.java 2010-03-24 11:03:01 UTC (rev 1617)
@@ -0,0 +1,37 @@
+package hotrod.impl;
+
+/**
+ * // TODO: Document this
+ *
+ * @author mmarkus
+ * @since 4.1
+ */
+public interface Transport {
+
+ public void writeByteArray(byte... toAppend);
+
+ /**
+ * Treats the tailing byte as an unsigned byte.
+ */
+ public void appendUnsignedByte(short requestMagic);
+
+ public void writeVInt(int length);
+
+ public void writeVLong(long l);
+
+ public long readVLong();
+
+ public int readVInt();
+
+ public void flush();
+
+ public byte readByte();
+
+ public void release();
+
+ /**
+ * reads an vint which is size; then an array having that size.
+ * @param bufferToFill
+ */
+ public byte[] readByteArray(byte[] bufferToFill);
+}
Added: trunk/client/hotrod-client/src/main/java/hotrod/impl/VersionedEntry.java
===================================================================
--- trunk/client/hotrod-client/src/main/java/hotrod/impl/VersionedEntry.java (rev 0)
+++ trunk/client/hotrod-client/src/main/java/hotrod/impl/VersionedEntry.java 2010-03-24 11:03:01 UTC (rev 1617)
@@ -0,0 +1,55 @@
+package hotrod.impl;
+
+import java.util.Arrays;
+
+/**
+* // TODO: Document this
+*
+* @author mmarkus
+* @since 4.1
+*/
+public class VersionedEntry {
+ private final long version;
+ private final byte[] key;
+ private final byte[] value;
+
+ public VersionedEntry(long version, byte[] key, byte[] value) {
+ this.version = version;
+ this.key = key;
+ this.value = value;
+ }
+
+ public long getVersion() {
+ return version;
+ }
+
+ public byte[] getKey() {
+ return key;
+ }
+
+ public byte[] getValue() {
+ return value;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ VersionedEntry that = (VersionedEntry) o;
+
+ if (version != that.version) return false;
+ if (!Arrays.equals(key, that.key)) return false;
+ if (!Arrays.equals(value, that.value)) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = (int) (version ^ (version >>> 32));
+ result = 31 * result + (key != null ? Arrays.hashCode(key) : 0);
+ result = 31 * result + (value != null ? Arrays.hashCode(value) : 0);
+ return result;
+ }
+}
Added: trunk/client/hotrod-client/src/main/java/hotrod/impl/transport/TcpTransport.java
===================================================================
--- trunk/client/hotrod-client/src/main/java/hotrod/impl/transport/TcpTransport.java (rev 0)
+++ trunk/client/hotrod-client/src/main/java/hotrod/impl/transport/TcpTransport.java 2010-03-24 11:03:01 UTC (rev 1617)
@@ -0,0 +1,128 @@
+package hotrod.impl.transport;
+
+import hotrod.impl.Transport;
+
+import java.io.IOException;
+import java.net.Socket;
+import java.util.logging.Logger;
+
+/**
+ * // TODO: Document this
+ *
+ * @author mmarkus
+ * @since 4.1
+ */
+public class TcpTransport implements Transport {
+
+ public static final Logger log = Logger.getLogger(TcpTransport.class.getName());
+
+ private String host;
+ private int port;
+ private Socket socket;
+
+ public void appendUnsignedByte(short requestMagic) {
+ try {
+ socket.getOutputStream().write(requestMagic);
+ } catch (IOException e) {
+ throw new TransportException(e);
+ }
+ }
+
+ public void writeVInt(int length) {
+ try {
+ VHelper.writeVInt(length, socket.getOutputStream());
+ } catch (IOException e) {
+ throw new TransportException(e);
+ }
+ }
+
+ public void writeVLong(long l) {
+ try {
+ VHelper.writeVLong(l, socket.getOutputStream());
+ } catch (IOException e) {
+ throw new TransportException(e);
+ }
+ }
+
+ public long readVLong() {
+ try {
+ return VHelper.readVLong(socket.getInputStream());
+ } catch (IOException e) {
+ throw new TransportException(e);
+ }
+ }
+
+ public int readVInt() {
+ try {
+ return VHelper.readVInt(socket.getInputStream());
+ } catch (IOException e) {
+ throw new TransportException(e);
+ }
+ }
+
+ public TcpTransport(String host, int port) {
+ this.host = host;
+ this.port = port;
+ }
+
+ public void connect() {
+ try {
+ socket = new Socket(host, port);
+ } catch (IOException e) {
+ throw new TransportException("Problems establishing initial connection", e);
+ }
+ }
+
+ public void writeByteArray(byte... toAppend) {
+ try {
+ socket.getOutputStream().write(toAppend);
+ } catch (IOException e) {
+ throw new TransportException("Problems writing data to stream", e);
+ }
+ }
+
+ public void flush() {
+ try {
+ socket.getOutputStream().flush();
+ } catch (IOException e) {
+ throw new TransportException(e);
+ }
+ }
+
+ public byte readByte() {
+ int resultInt;
+ try {
+ resultInt = socket.getInputStream().read();
+ } catch (IOException e) {
+ throw new TransportException(e);
+ }
+ if (resultInt == -1) {
+ throw new TransportException("End of stream reached!");
+ }
+ return (byte) resultInt;
+ }
+
+ public void release() {
+ try {
+ socket.close();
+ } catch (IOException e) {
+ log.warning("Issues closing socket:" + e.getMessage());
+ }
+ }
+
+ public byte[] readByteArray(byte[] bufferToFill) {
+ int size;
+ try {
+ size = socket.getInputStream().read(bufferToFill);
+ } catch (IOException e) {
+ throw new TransportException(e);
+ }
+ if (size == -1) {
+ throw new RuntimeException("End of stream reached!");
+ }
+ if (size != bufferToFill.length) {
+ throw new TransportException("Expected " + bufferToFill.length + " bytes but only could read " + size + " bytes!");
+ }
+ return bufferToFill;
+ }
+}
Added: trunk/client/hotrod-client/src/main/java/hotrod/impl/transport/TransportException.java
===================================================================
--- trunk/client/hotrod-client/src/main/java/hotrod/impl/transport/TransportException.java (rev 0)
+++ trunk/client/hotrod-client/src/main/java/hotrod/impl/transport/TransportException.java 2010-03-24 11:03:01 UTC (rev 1617)
@@ -0,0 +1,26 @@
+package hotrod.impl.transport;
+
+import hotrod.HotRodException;
+
+/**
+ * // TODO: Document this
+ *
+ * @author mmarkus
+ * @since 4.1
+ */
+public class TransportException extends HotRodException {
+ public TransportException() {
+ }
+
+ public TransportException(String message) {
+ super(message);
+ }
+
+ public TransportException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public TransportException(Throwable cause) {
+ super(cause);
+ }
+}
\ No newline at end of file
Added: trunk/client/hotrod-client/src/main/java/hotrod/impl/transport/TransportFactory.java
===================================================================
--- trunk/client/hotrod-client/src/main/java/hotrod/impl/transport/TransportFactory.java (rev 0)
+++ trunk/client/hotrod-client/src/main/java/hotrod/impl/transport/TransportFactory.java 2010-03-24 11:03:01 UTC (rev 1617)
@@ -0,0 +1,18 @@
+package hotrod.impl.transport;
+
+import hotrod.impl.Transport;
+import hotrod.impl.transport.TcpTransport;
+
+/**
+ * // TODO: Document this
+ *
+ * @author mmarkus
+ * @since 4.1
+ */
+public class TransportFactory {
+
+ public Transport getTransport() {
+ return new TcpTransport("a",1);
+ }
+
+}
Added: trunk/client/hotrod-client/src/main/java/hotrod/impl/transport/VHelper.java
===================================================================
--- trunk/client/hotrod-client/src/main/java/hotrod/impl/transport/VHelper.java (rev 0)
+++ trunk/client/hotrod-client/src/main/java/hotrod/impl/transport/VHelper.java 2010-03-24 11:03:01 UTC (rev 1617)
@@ -0,0 +1,102 @@
+package hotrod.impl.transport;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * // TODO: Document this
+ *
+ * @author mmarkus
+ * @since 4.1
+ */
+public class VHelper {
+ private static final int MAX_VINT_BYTES = 5;
+ private static final int MAX_VLONG_BYTES = 9;
+
+ public static int readVInt(InputStream is) {
+ int result = 0;
+ for (int i = 0; i < MAX_VINT_BYTES; i++) {
+ int aByte = nextByte(is);
+ boolean hasMore = (aByte & 128) > 0;
+ aByte &= 127; //remove leading byte
+ result = result | (aByte << (i*7));
+ if (!hasMore) break;
+ }
+ if (result < 0)
+ throw new TransportException("negative number read: " + result);
+ return result;
+ }
+
+ public static void writeVInt(int toWrite, OutputStream os) {
+ boolean hasMore;
+ do {
+ int currentByte = toWrite & 0x0000007F;
+ toWrite = toWrite >> 7;
+ hasMore = toWrite > 0;
+ if (hasMore) {
+ currentByte |= 128;
+ }
+ writeByte(os, currentByte);
+ } while (hasMore);
+ }
+
+ private static void writeByte(OutputStream os, int currentByte) {
+ try {
+ os.write(currentByte);
+ } catch (IOException e) {
+ throw new TransportException(e);
+ }
+ }
+
+ private static int nextByte(InputStream is) {
+ try {
+ int result = is.read();
+ if (result < 0) {
+ throw new TransportException("Unexpected end of stream " + result);
+ }
+ return result;
+ } catch (IOException e) {
+ throw new TransportException(e);
+ }
+ }
+
+ public static long readVLong(InputStream is) {
+ long result = 0;
+ for (int i = 0; i < MAX_VLONG_BYTES; i++) {
+ long aByte = nextByte(is);
+ boolean hasMore = (aByte & 128) > 0;
+ aByte &= 127; //remove leading byte
+ result = result | (aByte << (i*7));
+ if (!hasMore) break;
+ }
+ if (result < 0)
+ throw new TransportException("negative number read: " + result);
+ return result;
+ }
+
+
+ public static void writeVLong(long toWrite, OutputStream os) {
+ boolean hasMore;
+ do {
+ long currentByte = toWrite & 0x000000000000007F;
+ toWrite = toWrite >> 7;
+ hasMore = toWrite > 0;
+ if (hasMore) {
+ currentByte |= 128;
+ }
+ writeByte(os, (int)currentByte);
+ } while (hasMore);
+ }
+
+ public static void main(String[] args) {
+ long zero = 0;
+ long aByte = 1;
+ long shift = 35;
+ System.out.println((zero | (aByte << 35)));
+ long a = 1l<<18;
+ long b = 1l<<17;
+ long ab = a * b;
+ System.out.println(ab);
+ }
+}
Added: trunk/client/hotrod-client/src/main/resources/hotrod-client.properties
===================================================================
--- trunk/client/hotrod-client/src/main/resources/hotrod-client.properties (rev 0)
+++ trunk/client/hotrod-client/src/main/resources/hotrod-client.properties 2010-03-24 11:03:01 UTC (rev 1617)
@@ -0,0 +1 @@
+hotrod-servers=127.0.0.1:8998:127.0.0.2:6723
\ No newline at end of file
Added: trunk/client/hotrod-client/src/test/java/org/infinispan/client/hotrod/HotRodClientIntegrationTest.java
===================================================================
--- trunk/client/hotrod-client/src/test/java/org/infinispan/client/hotrod/HotRodClientIntegrationTest.java (rev 0)
+++ trunk/client/hotrod-client/src/test/java/org/infinispan/client/hotrod/HotRodClientIntegrationTest.java 2010-03-24 11:03:01 UTC (rev 1617)
@@ -0,0 +1,274 @@
+package org.infinispan.client.hotrod;
+
+import hotrod.ClientDisconnectedException;
+import hotrod.ClusterTopologyListener;
+import hotrod.impl.VersionedEntry;
+import hotrod.impl.RemoteCacheSpi;
+import hotrod.RemoteCacheManager;
+import org.infinispan.Cache;
+import org.infinispan.config.Configuration;
+import org.infinispan.test.MultipleCacheManagersTest;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.Test;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static junit.framework.Assert.assertEquals;
+
+
+/**
+ * // TODO: Document this
+ *
+ * @author mmarkus
+ * @since 4.1
+ */
+ at Test (testName = "client.hotrod.HotRodClientIntegrationTest", groups = "functional", enabled = false)
+public class HotRodClientIntegrationTest extends MultipleCacheManagersTest {
+
+ private static final String CACHE_NAME = "replSync";
+ private Cache cache;
+ private Cache defaultCache;
+
+ RemoteCacheSpi defaultRemoteCacheSpi;
+ RemoteCacheSpi remoteCacheSpi;
+
+ @Override
+ protected void createCacheManagers() throws Throwable {
+ Configuration replSync = getDefaultClusteredConfig(Configuration.CacheMode.REPL_SYNC);
+ createClusteredCaches(2, CACHE_NAME, replSync);
+
+ //pass the config file to the cache
+ RemoteCacheManager cacheManager = new RemoteCacheManager();
+ defaultRemoteCacheSpi = cacheManager.getDefaultRemoteCache();
+ remoteCacheSpi = cacheManager.getRemoteCache(CACHE_NAME);
+ }
+
+ @AfterClass
+ public void testDestroyRemoteCacheFactory() {
+ RemoteCacheManager cacheManager = remoteCacheSpi.getRemoteCacheFactory();
+ cacheManager.stop();
+ try {
+ remoteCacheSpi.get("aKey".getBytes());
+ assert false;
+ } catch (ClientDisconnectedException e) {}
+ try {
+ remoteCacheSpi.clear();
+ assert false;
+ } catch (ClientDisconnectedException e) {}
+ try {
+ remoteCacheSpi.evict("aKey".getBytes());
+ assert false;
+ } catch (ClientDisconnectedException e) {}
+ try {
+ remoteCacheSpi.getVersionedCacheEntry("aKey".getBytes());
+ assert false;
+ } catch (ClientDisconnectedException e) {}
+ try {
+ remoteCacheSpi.addClusterTopologyListener(null);
+ assert false;
+ } catch (ClientDisconnectedException e) {}
+ try {
+ remoteCacheSpi.removeClusterTopologyListener(null);
+ assert false;
+ } catch (ClientDisconnectedException e) {}
+ try {
+ remoteCacheSpi.put("aKey".getBytes(), "aValue".getBytes());
+ assert false;
+ } catch (ClientDisconnectedException e) {}
+ try {
+ remoteCacheSpi.putForExternalRead("aKey".getBytes(), "aValue".getBytes());
+ assert false;
+ } catch (ClientDisconnectedException e) {}
+ try {
+ remoteCacheSpi.putIfAbsent("aKey".getBytes(), "aValue".getBytes());
+ assert false;
+ } catch (ClientDisconnectedException e) {}
+ try {
+ remoteCacheSpi.remove("aKey".getBytes());
+ assert false;
+ } catch (ClientDisconnectedException e) {}
+ try {
+ remoteCacheSpi.removeIfUnmodified("aKey".getBytes(), 12321L);
+ assert false;
+ } catch (ClientDisconnectedException e) {}
+ try {
+ remoteCacheSpi.replaceIfUnmodified("aKey".getBytes(), "aNewValue".getBytes(), 12321L);
+ assert false;
+ } catch (ClientDisconnectedException e) {}
+ try {
+ remoteCacheSpi.replace("aKey".getBytes(), "aNewValue".getBytes());
+ assert false;
+ } catch (ClientDisconnectedException e) {}
+ }
+
+ @AfterClass (alwaysRun = true)
+ @Override
+ protected void destroy() {
+ TestTopologyListener listener = new TestTopologyListener();
+ remoteCacheSpi.addClusterTopologyListener(listener);
+ super.destroy();
+ assert listener.invocationCount == 2;
+ }
+
+ public void testPut() {
+ remoteCacheSpi.put("aKey".getBytes(), "aValue".getBytes());
+ assertEquals("aValue", get(cache, "aKey"));
+ defaultRemoteCacheSpi.put("otherKey".getBytes(), "otherValue".getBytes());
+ assertEquals("otherValue", get(defaultCache, "otherKey"));
+
+ assert Arrays.equals("aKey".getBytes(), remoteCacheSpi.get("aValue".getBytes()));
+ assert Arrays.equals("otherKey".getBytes(), remoteCacheSpi.get("otherKey".getBytes()));
+ }
+
+ public void testRemove() {
+ remoteCacheSpi.put("aKey".getBytes(), "aValue".getBytes());
+ assert Arrays.equals("aKey".getBytes(), remoteCacheSpi.get("aValue".getBytes()));
+
+ assert get(cache, "aKey").equals("aValue");
+ assertEquals(true, remoteCacheSpi.remove("aKey".getBytes()));
+ assert remoteCacheSpi.remove("aKey".getBytes());
+ assert get(cache,"aKey") == null;
+ assert !remoteCacheSpi.remove("aKey".getBytes());
+ }
+
+ public void testContains() {
+ assert !remoteCacheSpi.contains("aKey".getBytes());
+ remoteCacheSpi.put("aKey".getBytes(), "aValue".getBytes());
+ assert !remoteCacheSpi.contains("aKey".getBytes());
+ }
+
+ public void testGetVersionedCacheEntry() {
+ assert null == remoteCacheSpi.getVersionedCacheEntry("aKey".getBytes());
+ remoteCacheSpi.put("aKey".getBytes(), "aValue".getBytes());
+ VersionedEntry entry = remoteCacheSpi.getVersionedCacheEntry("aKey".getBytes());
+ assert entry != null;
+ assert Arrays.equals(entry.getKey(), "aKey".getBytes());
+ assert Arrays.equals(entry.getValue(), "aValue".getBytes());
+
+ //now put the same value
+ remoteCacheSpi.put("aKey".getBytes(), "aValue".getBytes());
+ VersionedEntry entry2 = remoteCacheSpi.getVersionedCacheEntry("aKey".getBytes());
+ assert Arrays.equals(entry2.getKey(), "aKey".getBytes());
+ assert Arrays.equals(entry2.getValue(), "aValue".getBytes());
+
+ assert entry2.getVersion() != entry.getVersion();
+ assert !entry.equals(entry2);
+
+ //now put a different value
+ remoteCacheSpi.put("aKey".getBytes(), "anotherValue".getBytes());
+ VersionedEntry entry3 = remoteCacheSpi.getVersionedCacheEntry("aKey".getBytes());
+ assert Arrays.equals(entry3.getKey(), "aKey".getBytes());
+ assert Arrays.equals(entry3.getValue(), "anotherValue".getBytes());
+ assert entry3.getVersion() != entry2.getVersion();
+ assert !entry3.equals(entry2);
+ }
+
+ public void testReplace() {
+ assert !remoteCacheSpi.replace("aKey".getBytes(), "anotherValue".getBytes());
+ remoteCacheSpi.put("aKey".getBytes(), "aValue".getBytes());
+ assert remoteCacheSpi.replace("aKey".getBytes(), "anotherValue".getBytes());
+ assert get(cache, "aKey").equals("anotherValue");
+ }
+
+ public void testReplaceIfUnmodified() {
+ RemoteCacheSpi.VersionedOperationResponse response = remoteCacheSpi.replaceIfUnmodified("aKey".getBytes(), "aValue".getBytes(), 12321212l);
+ assert response == RemoteCacheSpi.VersionedOperationResponse.NO_SUCH_KEY;
+ assert !response.isUpdated();
+
+ remoteCacheSpi.put("aKey".getBytes(), "aValue".getBytes());
+ VersionedEntry entry = remoteCacheSpi.getVersionedCacheEntry("aKey".getBytes());
+ response = remoteCacheSpi.replaceIfUnmodified("aKey".getBytes(), "aNewValue".getBytes(), entry.getVersion());
+ assert response == RemoteCacheSpi.VersionedOperationResponse.SUCCESS;
+ assert response.isUpdated();
+
+ VersionedEntry entry2 = remoteCacheSpi.getVersionedCacheEntry("aKey".getBytes());
+ assert entry2.getVersion() != entry.getVersion();
+ assert Arrays.equals(entry2.getKey(), "aKey".getBytes());
+ assert Arrays.equals(entry2.getValue(), "aNewValue".getBytes());
+
+ response = remoteCacheSpi.replaceIfUnmodified("aKey".getBytes(), "aNewValue".getBytes(), entry.getVersion());
+ assert response == RemoteCacheSpi.VersionedOperationResponse.MODIFIED_KEY;
+ assert !response.isUpdated();
+ }
+
+ public void testRemoveIfUnmodified() {
+ RemoteCacheSpi.VersionedOperationResponse response = remoteCacheSpi.removeIfUnmodified("aKey".getBytes(), 12321212l);
+ assert response == RemoteCacheSpi.VersionedOperationResponse.NO_SUCH_KEY;
+ assert !response.isUpdated();
+
+ remoteCacheSpi.put("aKey".getBytes(), "aValue".getBytes());
+ VersionedEntry entry = remoteCacheSpi.getVersionedCacheEntry("aKey".getBytes());
+ response = remoteCacheSpi.removeIfUnmodified("aKey".getBytes(), entry.getVersion());
+ assert response == RemoteCacheSpi.VersionedOperationResponse.SUCCESS;
+ assert response.isUpdated();
+ assert !cache.containsKey("aKey".getBytes());
+
+ remoteCacheSpi.put("aKey".getBytes(), "aValueNew".getBytes());
+
+ VersionedEntry entry2 = remoteCacheSpi.getVersionedCacheEntry("aKey".getBytes());
+ assert entry2.getVersion() != entry.getVersion();
+ assert Arrays.equals(entry2.getKey(), "aKey".getBytes());
+ assert Arrays.equals(entry2.getValue(), "aNewValue".getBytes());
+
+ response = remoteCacheSpi.removeIfUnmodified("aKey".getBytes(), entry.getVersion());
+ assert response == RemoteCacheSpi.VersionedOperationResponse.MODIFIED_KEY;
+ assert !response.isUpdated();
+ }
+
+ public void testPutIfAbsent() {
+ remoteCacheSpi.put("aKey".getBytes(), "aValue".getBytes());
+ assert !remoteCacheSpi.putIfAbsent("aKey".getBytes(), "anotherValue".getBytes());
+ assert get(cache, "aKey").equals("aValue");
+
+ assert cache.remove("aKey".getBytes()).equals("aValue".getBytes());
+ assert !remoteCacheSpi.contains("aKey".getBytes());
+
+ assert true : remoteCacheSpi.replace("aKey".getBytes(), "anotherValue".getBytes());
+ }
+
+ public void testPutForExternalRead() {
+ remoteCacheSpi.putForExternalRead("aKey".getBytes(), "aValue".getBytes());
+ remoteCacheSpi.putForExternalRead("aKey".getBytes(), "anotherValue".getBytes());
+ assert get(cache, "aKey").equals("aValue");
+
+ assert cache.remove("aKey".getBytes()).equals("aValue".getBytes());
+ assert !remoteCacheSpi.contains("aKey".getBytes());
+ }
+
+ public void testClear() {
+ remoteCacheSpi.put("aKey".getBytes(), "aValue".getBytes());
+ remoteCacheSpi.put("aKey2".getBytes(), "aValue".getBytes());
+ remoteCacheSpi.clear();
+ assert cache.isEmpty();
+ assert !remoteCacheSpi.contains("aKey".getBytes());
+ assert !remoteCacheSpi.contains("aKey2".getBytes());
+ }
+
+ public void testEvict() {
+ assert !remoteCacheSpi.evict("aKey".getBytes());
+ remoteCacheSpi.put("aKey".getBytes(), "aValue".getBytes());
+ assert remoteCacheSpi.evict("aKey".getBytes());
+ }
+
+ public void testStats() {
+ //todo implement
+ }
+
+ private Object get(Cache cache, String s) {
+ return new String((byte[])cache.get(s.getBytes()));
+ }
+
+ private static class TestTopologyListener implements ClusterTopologyListener {
+
+ private int invocationCount;
+
+ public void nodeAdded(List<Address> currentTopology, Address addedNode) {
+ // TODO: Customise this generated block
+ }
+
+ public void nodeRemoved(List<Address> currentTopology, Address removedNode) {
+ invocationCount++;
+ }
+ }
+}
Added: trunk/client/hotrod-client/src/test/java/org/infinispan/client/hotrod/HotRodListenerTest.java
===================================================================
--- trunk/client/hotrod-client/src/test/java/org/infinispan/client/hotrod/HotRodListenerTest.java (rev 0)
+++ trunk/client/hotrod-client/src/test/java/org/infinispan/client/hotrod/HotRodListenerTest.java 2010-03-24 11:03:01 UTC (rev 1617)
@@ -0,0 +1,13 @@
+package org.infinispan.client.hotrod;
+
+import org.testng.annotations.Test;
+
+/**
+ * // TODO: Document this
+ *
+ * @author mmarkus
+ * @since 4.1
+ */
+ at Test (testName = "client.hotrod.HotRodListenerTest", groups = "functional")
+public class HotRodListenerTest {
+}
Added: trunk/client/hotrod-client/src/test/java/org/infinispan/client/hotrod/VHelperTest.java
===================================================================
--- trunk/client/hotrod-client/src/test/java/org/infinispan/client/hotrod/VHelperTest.java (rev 0)
+++ trunk/client/hotrod-client/src/test/java/org/infinispan/client/hotrod/VHelperTest.java 2010-03-24 11:03:01 UTC (rev 1617)
@@ -0,0 +1,264 @@
+package org.infinispan.client.hotrod;
+
+import hotrod.impl.transport.VHelper;
+import org.testng.annotations.Test;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.util.Arrays;
+
+/**
+ * // TODO: Document this
+ *
+ * @author mmarkus
+ * @since 4.1
+ */
+ at Test(testName = "client.hotrod.VHelperTest", groups = "unit, functional")
+public class VHelperTest {
+
+ public void testString2Byte() {
+ str2byte("00000001", (byte) 1);
+ str2byte("00001001", (byte) 9);
+ str2byte("01111111", (byte) 127);
+ str2byte("11111111", (byte) -1);
+ str2byte("11111110", (byte) -2);
+ str2byte("10000001", (byte) -127);
+ str2byte("10000000", (byte) -128);
+ str2byte("11111011", (byte) -5);
+ }
+
+ public void testByte2String() {
+ byte2str((byte) 9, "00001001");
+ byte2str((byte) 1, "00000001");
+ byte2str((byte) 127, "01111111");
+ byte2str((byte) -1, "11111111");
+ byte2str((byte) -2, "11111110");
+ byte2str((byte) -127, "10000001");
+ byte2str((byte) -128, "10000000");
+ byte2str((byte) -5, "11111011");
+ }
+
+ public void testReadVInt1() {
+ assert 0 == VHelper.readVInt(getInputStream((byte) 0));
+ assert 1 == VHelper.readVInt(getInputStream((byte) 1));
+ assert 2 == VHelper.readVInt(getInputStream((byte) 2));
+
+ assert 127 == VHelper.readVInt(getInputStream((byte) 127));
+
+
+ byte[] nr128 = new byte[]{str2byte("10000000"), str2byte("00000001")};
+ assert 128 == VHelper.readVInt(getInputStream(nr128));
+
+
+ byte[] nr129 = new byte[]{str2byte("10000001"), str2byte("00000001")};
+ assert 129 == VHelper.readVInt(getInputStream(nr129));
+
+ byte[] nr130 = new byte[]{str2byte("10000010"), str2byte("00000001")};
+ assert 130 == VHelper.readVInt(getInputStream(nr130));
+
+ byte[] nr16383 = new byte[]{str2byte("11111111"), str2byte("01111111")};
+ assert 16383 == VHelper.readVInt(getInputStream(nr16383));
+
+ byte[] nr16384 = new byte[]{str2byte("10000000"), str2byte("10000000"), str2byte("00000001")};
+ assert 16384 == VHelper.readVInt(getInputStream(nr16384));
+
+ byte[] nr16385 = new byte[]{str2byte("10000001"), str2byte("10000000"), str2byte("00000001")};
+ assert 16385 == VHelper.readVInt(getInputStream(nr16385));
+
+ byte[] nr16393 = new byte[]{str2byte("10001001"), str2byte("10000000"), str2byte("00000001")};
+ assert 16393 == VHelper.readVInt(getInputStream(nr16393));
+
+ byte[] nr2pow28 = new byte[]{str2byte("10000000"), str2byte("10000000"), str2byte("10000000"), str2byte("10000000"), str2byte("00000001")};
+ assert (1 << 28) == VHelper.readVInt(getInputStream(nr2pow28));
+
+ byte[] nr2pow30 = new byte[]{str2byte("10000000"), str2byte("10000000"), str2byte("10000000"), str2byte("10000000"), str2byte("00000100")};
+ assert (1 << 30) == VHelper.readVInt(getInputStream(nr2pow30));
+
+ byte[] nr2pow30plus2 = new byte[]{str2byte("10000010"), str2byte("10000000"), str2byte("10000000"), str2byte("10000000"), str2byte("00000100")};
+ assert (1 << 30) + 2 == VHelper.readVInt(getInputStream(nr2pow30plus2));
+ }
+
+ public void testWriteVint() {
+ String[] written = writeVInt(0);
+ assert Arrays.equals(written, new String[]{"00000000"});
+
+ written = writeVInt(1);
+ assert Arrays.equals(written, new String[]{"00000001"});
+
+ written = writeVInt(127);
+ assert Arrays.equals(written, new String[]{"01111111"});
+
+ written = writeVInt(129);
+ assert Arrays.equals(written, new String[]{"10000001", "00000001"});
+
+ written = writeVInt(130);
+ assert Arrays.equals(written, new String[]{"10000010", "00000001"});
+
+ written = writeVInt(16383);
+ assert Arrays.equals(written, new String[]{"11111111", "01111111"});
+
+ written = writeVInt(16384);
+ assert Arrays.equals(written, new String[]{"10000000", "10000000", "00000001"});
+
+ written = writeVInt(16385);
+ assert Arrays.equals(written, new String[]{"10000001", "10000000", "00000001"});
+
+ written = writeVInt(1 << 28);
+ assert Arrays.equals(written, new String[]{"10000000", "10000000", "10000000", "10000000", "00000001"});
+
+ written = writeVInt(1 << 30);
+ assert Arrays.equals(written, new String[]{"10000000", "10000000", "10000000", "10000000", "00000100"});
+
+ written = writeVInt((1 << 30) + 2);
+ assert Arrays.equals(written, new String[]{"10000010", "10000000", "10000000", "10000000", "00000100"});
+ }
+
+ public void testReadVLong() {
+ assert 0 == VHelper.readVLong(getInputStream((byte) 0));
+ assert 1 == VHelper.readVLong(getInputStream((byte) 1));
+ assert 2 == VHelper.readVLong(getInputStream((byte) 2));
+
+ assert 127 == VHelper.readVLong(getInputStream((byte) 127));
+
+
+ byte[] nr128 = new byte[]{str2byte("10000000"), str2byte("00000001")};
+ assert 128 == VHelper.readVLong(getInputStream(nr128));
+
+
+ byte[] nr129 = new byte[]{str2byte("10000001"), str2byte("00000001")};
+ assert 129 == VHelper.readVLong(getInputStream(nr129));
+
+ byte[] nr130 = new byte[]{str2byte("10000010"), str2byte("00000001")};
+ assert 130 == VHelper.readVLong(getInputStream(nr130));
+
+ byte[] nr16383 = new byte[]{str2byte("11111111"), str2byte("01111111")};
+ assert 16383 == VHelper.readVLong(getInputStream(nr16383));
+
+ byte[] nr16384 = new byte[]{str2byte("10000000"), str2byte("10000000"), str2byte("00000001")};
+ assert 16384 == VHelper.readVLong(getInputStream(nr16384));
+
+ byte[] nr16385 = new byte[]{str2byte("10000001"), str2byte("10000000"), str2byte("00000001")};
+ assert 16385 == VHelper.readVLong(getInputStream(nr16385));
+
+ byte[] nr2pow28 = new byte[]{str2byte("10000000"), str2byte("10000000"), str2byte("10000000"), str2byte("10000000"), str2byte("00000001")};
+ assert (1 << 28) == VHelper.readVLong(getInputStream(nr2pow28));
+
+ byte[] nr2pow30 = new byte[]{str2byte("10000000"), str2byte("10000000"), str2byte("10000000"), str2byte("10000000"), str2byte("00000100")};
+ assert (1 << 30) == VHelper.readVLong(getInputStream(nr2pow30));
+
+ byte[] nr2pow30plus2 = new byte[]{str2byte("10000010"), str2byte("10000000"), str2byte("10000000"), str2byte("10000000"), str2byte("00000100")};
+ assert (1 << 30) + 2 == VHelper.readVLong(getInputStream(nr2pow30plus2));
+
+ byte[] nr2pow35 = new byte[]{str2byte("10000000"), str2byte("10000000"), str2byte("10000000"), str2byte("10000000"), str2byte("10000000"), str2byte("00000001")};
+ long expected = 1l << 35;
+ long obtained = VHelper.readVLong(getInputStream(nr2pow35));
+ assert expected == obtained : "expected " + expected + " but received " + obtained;
+
+
+ byte[] nr2pow42 = new byte[]{str2byte("10000000"), str2byte("10000000"), str2byte("10000000"), str2byte("10000000"), str2byte("10000000"), str2byte("10000000"), str2byte("00000001")};
+ expected = (long) (1 << 22) * (long) (1 << 20);
+ obtained = VHelper.readVLong(getInputStream(nr2pow42));
+ assert expected == obtained : "Expected " + expected + " but obtained " + obtained;
+
+ byte[] nr2pow56 = new byte[]{str2byte("10000000"), str2byte("10000000"), str2byte("10000000"), str2byte("10000000"), str2byte("10000000"), str2byte("10000000"), str2byte("10000000"), str2byte("10000000"), str2byte("00000001")};
+ expected = 1l << 56;
+ obtained = VHelper.readVLong(getInputStream(nr2pow56));
+ assert expected == obtained : "Expected " + expected + " but obtained " + obtained;
+ }
+
+ public void testWriteVLong() {
+ String[] written = writeVLong(0);
+ assert Arrays.equals(written, new String[]{"00000000"});
+
+ written = writeVLong(1);
+ assert Arrays.equals(written, new String[]{"00000001"});
+
+ written = writeVLong(127);
+ assert Arrays.equals(written, new String[]{"01111111"});
+
+ written = writeVLong(129);
+ assert Arrays.equals(written, new String[]{"10000001", "00000001"});
+
+ written = writeVLong(130);
+ assert Arrays.equals(written, new String[]{"10000010", "00000001"});
+
+ written = writeVLong(16383);
+ assert Arrays.equals(written, new String[]{"11111111", "01111111"});
+
+ written = writeVLong(16384);
+ assert Arrays.equals(written, new String[]{"10000000", "10000000", "00000001"});
+
+ written = writeVLong(16385);
+ assert Arrays.equals(written, new String[]{"10000001", "10000000", "00000001"});
+
+ written = writeVLong(1 << 28);
+ assert Arrays.equals(written, new String[]{"10000000", "10000000", "10000000", "10000000", "00000001"});
+
+ written = writeVLong(1 << 30);
+ assert Arrays.equals(written, new String[]{"10000000", "10000000", "10000000", "10000000", "00000100"});
+
+ written = writeVLong((1 << 30) + 2);
+ assert Arrays.equals(written, new String[]{"10000010", "10000000", "10000000", "10000000", "00000100"});
+
+ written = writeVLong((1l << 56) + 2);
+ assert Arrays.equals(written, new String[]{"10000010", "10000000", "10000000", "10000000", "10000000", "10000000", "10000000", "10000000", "00000001"});
+ }
+
+
+ private String[] writeVInt(int toWrite) {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream(5);
+ VHelper.writeVInt(toWrite, baos);
+ byte[] result = baos.toByteArray();
+ return toStringArray(result);
+ }
+
+ private String[] writeVLong(long toWrite) {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream(9);
+ VHelper.writeVLong(toWrite, baos);
+ byte[] result = baos.toByteArray();
+ return toStringArray(result);
+ }
+
+ private String[] toStringArray(byte[] result) {
+ String[] resultStr = new String[result.length];
+ for (int i = 0; i < resultStr.length; i++) {
+ resultStr[i] = byte2str(result[i]);
+ }
+ return resultStr;
+ }
+
+
+ private InputStream getInputStream(byte... bytes) {
+ return new ByteArrayInputStream(bytes);
+ }
+
+
+ private byte str2byte(String str, byte... check) {
+ assert str.length() == 8;
+ byte result = 0;
+ for (int i = 7; i >= 0; i--) {
+ assert str.charAt(i) == '0' || str.charAt(i) == '1';
+ boolean isOne = str.charAt(i) == '1';
+ byte mask = isOne ? ((byte) (1 << (7 - i))) : (byte) 0;
+ result |= mask;
+ }
+ if (check != null && check.length > 0) {
+ assert result == check[0] : "Expected " + check[0] + " but received " + result;
+ }
+ return result;
+ }
+
+ private String byte2str(byte aByte, String... expectedValue) {
+ String result = "";
+ for (int i = 0; i <= 7; i++) {
+ byte mask = (byte) (1 << (7 - i));
+ boolean isOne = (mask & aByte) != 0;
+ result += isOne ? "1" : "0";
+ }
+ if (expectedValue != null && expectedValue.length > 0) {
+ assert result.equals(expectedValue[0]) : "Expected " + expectedValue[0] + " but received " + result;
+ }
+ return result;
+ }
+}
Modified: trunk/pom.xml
===================================================================
--- trunk/pom.xml 2010-03-23 18:05:33 UTC (rev 1616)
+++ trunk/pom.xml 2010-03-24 11:03:01 UTC (rev 1617)
@@ -33,6 +33,7 @@
<module>server/core</module>
<module>server/memcached</module>
<!-- module>server/hotrod</module -->
+ <module>client/hotrod-client</module>
<module>jopr-plugin</module>
<module>demos/gui</module>
<module>demos/ec2</module>
More information about the infinispan-commits
mailing list