Author: scottbw
Date: Wed Feb 12 16:50:40 2014
New Revision: 1567675
URL: http://svn.apache.org/r1567675
Log:
Added the Redis implementation of the preferences SPI
Added:
wookie/trunk/wookie-services/wookie-redis/README
wookie/trunk/wookie-services/wookie-redis/src/
wookie/trunk/wookie-services/wookie-redis/src/main/
wookie/trunk/wookie-services/wookie-redis/src/main/java/
wookie/trunk/wookie-services/wookie-redis/src/main/java/org/
wookie/trunk/wookie-services/wookie-redis/src/main/java/org/apache/
wookie/trunk/wookie-services/wookie-redis/src/main/java/org/apache/wookie/
wookie/trunk/wookie-services/wookie-redis/src/main/java/org/apache/wookie/services/
wookie/trunk/wookie-services/wookie-redis/src/main/java/org/apache/wookie/services/redis/
wookie/trunk/wookie-services/wookie-redis/src/main/java/org/apache/wookie/services/redis/RedisPreferencesService.java
wookie/trunk/wookie-services/wookie-redis/src/test/
wookie/trunk/wookie-services/wookie-redis/src/test/java/
wookie/trunk/wookie-services/wookie-redis/src/test/java/org/
wookie/trunk/wookie-services/wookie-redis/src/test/java/org/apache/
wookie/trunk/wookie-services/wookie-redis/src/test/java/org/apache/wookie/
wookie/trunk/wookie-services/wookie-redis/src/test/java/org/apache/wookie/services/
wookie/trunk/wookie-services/wookie-redis/src/test/java/org/apache/wookie/services/redis/
wookie/trunk/wookie-services/wookie-redis/src/test/java/org/apache/wookie/services/redis/RedisPreferencesServiceTest.java
Modified:
wookie/trunk/wookie-services/wookie-redis/pom.xml
Added: wookie/trunk/wookie-services/wookie-redis/README
URL:
http://svn.apache.org/viewvc/wookie/trunk/wookie-services/wookie-redis/README?rev=1567675&view=auto
==============================================================================
--- wookie/trunk/wookie-services/wookie-redis/README (added)
+++ wookie/trunk/wookie-services/wookie-redis/README Wed Feb 12 16:50:40 2014
@@ -0,0 +1,9 @@
+This is a Redis implementation of the Wookie SPI
+
+To use it, place a file called org.apache.wookie.services.PreferencesService
in META-INF/services of swookie-server.
+
+This file should just contain the line:
+
+org.apache.wookie.services.redis.RedisPreferencesService
+
+This will make wookie-server start up using the Redis preferences
implemetnation instead of the default in-memory preferences store.
\ No newline at end of file
Modified: wookie/trunk/wookie-services/wookie-redis/pom.xml
URL:
http://svn.apache.org/viewvc/wookie/trunk/wookie-services/wookie-redis/pom.xml?rev=1567675&r1=1567674&r2=1567675&view=diff
==============================================================================
--- wookie/trunk/wookie-services/wookie-redis/pom.xml (original)
+++ wookie/trunk/wookie-services/wookie-redis/pom.xml Wed Feb 12 16:50:40 2014
@@ -48,6 +48,25 @@
<type>jar</type>
<scope>compile</scope>
</dependency>
+ <dependency>
+ <groupId>org.json</groupId>
+ <artifactId>json</artifactId>
+ <version>20131018</version>
+ <type>jar</type>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.7</version>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>uk.co.datumedge</groupId>
+ <artifactId>redis-launcher</artifactId>
+ <version>0.3</version>
+ <optional>true</optional>
+ </dependency>
</dependencies>
</project>
\ No newline at end of file
Added:
wookie/trunk/wookie-services/wookie-redis/src/main/java/org/apache/wookie/services/redis/RedisPreferencesService.java
URL:
http://svn.apache.org/viewvc/wookie/trunk/wookie-services/wookie-redis/src/main/java/org/apache/wookie/services/redis/RedisPreferencesService.java?rev=1567675&view=auto
==============================================================================
---
wookie/trunk/wookie-services/wookie-redis/src/main/java/org/apache/wookie/services/redis/RedisPreferencesService.java
(added)
+++
wookie/trunk/wookie-services/wookie-redis/src/main/java/org/apache/wookie/services/redis/RedisPreferencesService.java
Wed Feb 12 16:50:40 2014
@@ -0,0 +1,258 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wookie.services.redis;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.wookie.beans.IPreference;
+import org.apache.wookie.services.PreferencesService;
+import org.apache.wookie.services.impl.DefaultPreferenceImpl;
+import org.json.JSONObject;
+
+import redis.clients.jedis.Jedis;
+import redis.clients.jedis.JedisPool;
+import redis.clients.jedis.JedisPoolConfig;
+
+/**
+ * An implementation of a PreferencesService using Redis as the backend
+ */
+public class RedisPreferencesService implements PreferencesService {
+
+ /**
+ * The thread pool for jedis
+ */
+ private JedisPool pool;
+
+ public RedisPreferencesService(){
+ pool = new JedisPool(new JedisPoolConfig(), "localhost");
+ }
+
+ private IPreference getPreferenceObject(String token, String name){
+ //
+ // Get a Jedis from the pool
+ //
+ Jedis jedis = pool.getResource();
+
+ //
+ // Get the jedis key for this pref object
+ //
+ String key = getKey(token, name);
+
+ //
+ // Get the value from redis
+ //
+ String result = jedis.get(key);
+
+ //
+ // Release Jedis back to the pool
+ //
+ pool.returnResource(jedis);
+
+ //
+ // Convert the value back into an IPreference and return it
+ //
+ return rehydrate(result);
+ }
+
+ @Override
+ public void setPreference(String token, IPreference preference) {
+
+ //
+ // Check if the preference is null - if so, do nothing
+ // TODO throw an exception, or log a warning
+ //
+ if (preference == null) return;
+
+ //
+ // Get a Jedis from the pool
+ //
+ Jedis jedis = pool.getResource();
+
+ //
+ // Get the redis key to use for this pref
+ //
+ String key = getKey(token, preference.getName());
+
+ //
+ // If there is no existing tuple, add the key to the list of
keys for this token
+ //
+ if (getPreference(token, preference.getName()) == null){
+ jedis.lpush(token, key);
+ }
+
+ //
+ // Convert the IPreference into JSON for storage
+ //
+ String preferenceJson = dehydrate(preference);
+
+ //
+ // Store the preference
+ //
+ jedis.set(key, preferenceJson);
+
+ //
+ // Release Jedis back to the pool
+ //
+ pool.returnResource(jedis);
+ }
+
+ //////
+
+ @Override
+ public String getPreference(String token, String name) {
+ IPreference preference = getPreferenceObject(token, name);
+ if (preference == null) return null;
+ return preference.getValue();
+ }
+
+ @Override
+ public void setPreference(String token, String name, String value) {
+ DefaultPreferenceImpl pref = new DefaultPreferenceImpl(name,
value, false);
+ setPreference(token, pref);
+ }
+
+ @Override
+ public void setPreference(String token, String name, String value,
+ boolean readOnly) {
+ DefaultPreferenceImpl pref = new DefaultPreferenceImpl(name,
value, readOnly);
+ setPreference(token, pref);
+ }
+
+ //////
+
+
+ @Override
+ public Collection<IPreference> getPreferences(String token) {
+ //
+ // Get a Jedis from the pool
+ //
+ Jedis jedis = pool.getResource();
+
+ //
+ // Get the list of keys for the token
+ //
+ List<String> keys = jedis.lrange(token, 0, 999);
+ ArrayList<IPreference> preferences = new
ArrayList<IPreference>();
+ for (String key: keys){
+
+ //
+ // Get the IPreference for each key on the list and
+ // add it to the arraylist
+ //
+ String json = jedis.get(key);
+ IPreference pref = rehydrate(json);
+ preferences.add(pref);
+ }
+
+ //
+ // Release Jedis back to the pool
+ //
+ pool.returnResource(jedis);
+
+ //
+ // Return the arraylist
+ //
+ return preferences;
+ }
+
+ @Override
+ public void setPreferences(String token, Collection<IPreference>
preferences) {
+
+ //
+ // Clear the token
+ //
+ removePreferences(token);
+
+ //
+ // Get a Jedis from the pool
+ //
+ Jedis jedis = pool.getResource();
+
+ //
+ // Add the preferences to the list
+ //
+ if (preferences != null){
+ for (IPreference pref: preferences){
+ setPreference(token, pref);
+ }
+ }
+
+ //
+ // Release Jedis back to the pool
+ //
+ pool.returnResource(jedis);
+ }
+
+ @Override
+ public void removePreferences(String token) {
+ //
+ // Get a Jedis from the pool
+ //
+ Jedis jedis = pool.getResource();
+
+ //
+ // Remove everything linked from the preferences list
+ //
+ List<String> keys = jedis.lrange(token, 0, 999);
+ for (String key: keys){
+ jedis.del(key);
+ }
+
+ //
+ // Remove the existing preference list
+ //
+ jedis.del(token);
+
+ //
+ // Release Jedis back to the pool
+ //
+ pool.returnResource(jedis);
+ }
+
+ ////// Utilities
+
+ /**
+ * Convert a JSON string into an IPreference instance
+ */
+ private IPreference rehydrate(String input){
+ if (input == null) return null;
+ JSONObject json = new JSONObject(input);
+ DefaultPreferenceImpl pref = new
DefaultPreferenceImpl(json.getString("name"), json.getString("value"),
json.getBoolean("readOnly"));
+ return pref;
+ }
+
+ /**
+ * Convert an IPreference instance into a JSON String
+ */
+ private String dehydrate(IPreference pref){
+ JSONObject json = new JSONObject();
+ json.put("name", pref.getName());
+ json.put("value", pref.getValue());
+ json.put("readOnly", pref.isReadOnly());
+ return json.toString();
+ }
+
+ /**
+ * Gets the redis key to use for a combination of token and pref name
+ * @param token the token
+ * @param name the preference name
+ * @return the redis key to use for getting and setting the pref
+ */
+ private String getKey(String token, String name){
+ return "pref::" + token + "::" + name;
+ }
+
+}
Added:
wookie/trunk/wookie-services/wookie-redis/src/test/java/org/apache/wookie/services/redis/RedisPreferencesServiceTest.java
URL:
http://svn.apache.org/viewvc/wookie/trunk/wookie-services/wookie-redis/src/test/java/org/apache/wookie/services/redis/RedisPreferencesServiceTest.java?rev=1567675&view=auto
==============================================================================
---
wookie/trunk/wookie-services/wookie-redis/src/test/java/org/apache/wookie/services/redis/RedisPreferencesServiceTest.java
(added)
+++
wookie/trunk/wookie-services/wookie-redis/src/test/java/org/apache/wookie/services/redis/RedisPreferencesServiceTest.java
Wed Feb 12 16:50:40 2014
@@ -0,0 +1,229 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wookie.services.redis;
+
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Properties;
+
+import org.apache.wookie.services.impl.DefaultPreferenceImpl;
+import org.apache.wookie.beans.IPreference;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import redis.clients.jedis.Jedis;
+
+import uk.co.datumedge.redislauncher.LocalRedisServer;
+import uk.co.datumedge.redislauncher.RedisServer;
+
+public class RedisPreferencesServiceTest {
+
+ private static RedisServer redisServer;
+ private static RedisPreferencesService svc;
+
+ @BeforeClass
+ public static void setup() throws IOException, InterruptedException{
+ //
+ // Set the path to the Redis executable so we can start a test
instance
+ //
+ Properties props = System.getProperties();
+ props.setProperty("redislauncher.command",
"/usr/local/bin/redis-server");
+ redisServer = LocalRedisServer.newInstance();
+ redisServer.start();
+
+ svc = new RedisPreferencesService();
+ Jedis jedis = new Jedis("localhost");
+ jedis.flushDB();
+ }
+
+ @AfterClass
+ public static void tearDown() throws IOException, InterruptedException{
+ svc = null;
+ redisServer.stop();
+ }
+
+ @After
+ public void cleanUp(){
+ svc.removePreferences("token");
+ }
+
+ @Test
+ public void getNull(){
+ String result = svc.getPreference("token", "test-null");
+ assertEquals(null, result);
+ }
+
+ @Test
+ public void setAndGet(){
+ svc.setPreference("token", "test", "test");
+ String result = svc.getPreference("token", "test");
+ assertEquals("test", result);
+ }
+
+ @Test
+ public void setAndUpdate(){
+ svc.setPreference("token", "test", "test");
+ String result = svc.getPreference("token", "test");
+ assertEquals("test", result);
+ svc.setPreference("token", "test", "test-updated");
+ result = svc.getPreference("token", "test");
+ assertEquals("test-updated", result);
+ }
+
+ @Test
+ public void setAndGetByString(){
+ svc.setPreference("token", "test", "test-value", true);
+ Collection<IPreference> prefs = svc.getPreferences("token");
+ assertEquals(1, prefs.size());
+ IPreference pref = prefs.iterator().next();
+
+ assertEquals("test", pref.getName());
+ assertEquals("test-value", pref.getValue());
+ assertEquals(true, pref.isReadOnly());
+ }
+
+ @Test
+ public void setAndGetByObject(){
+ IPreference pref = new DefaultPreferenceImpl("test",
"test-value", true);
+ svc.setPreference("token", pref);
+ Collection<IPreference> prefs = svc.getPreferences("token");
+ assertEquals(1, prefs.size());
+ pref = prefs.iterator().next();
+
+ assertEquals("test", pref.getName());
+ assertEquals("test-value", pref.getValue());
+ assertEquals(true, pref.isReadOnly());
+ }
+
+ @Test
+ public void setAndGetByObjectNull(){
+ svc.setPreference("token", null);
+ Collection<IPreference> prefs = svc.getPreferences("token");
+ assertEquals(0, prefs.size());
+ }
+
+ @Test
+ public void setCollection(){
+ ArrayList<IPreference> preferences = new
ArrayList<IPreference>();
+ IPreference preference1 = new
DefaultPreferenceImpl("test-name1", "test-value1", true);
+ IPreference preference2 = new
DefaultPreferenceImpl("test-name2", "test-value2", false);
+ preferences.add(preference1);
+ preferences.add(preference2);
+
+ svc.setPreferences("token", preferences);
+
+ Collection<IPreference> returned = svc.getPreferences("token");
+ assertEquals(2, returned.size());
+ }
+
+ @Test
+ public void resetCollection(){
+ ArrayList<IPreference> preferences = new
ArrayList<IPreference>();
+ IPreference preference1 = new
DefaultPreferenceImpl("test-name1", "test-value1", true);
+ IPreference preference2 = new
DefaultPreferenceImpl("test-name2", "test-value2", false);
+ preferences.add(preference1);
+ preferences.add(preference2);
+
+ svc.setPreferences("token", preferences);
+
+ Collection<IPreference> returned = svc.getPreferences("token");
+ assertEquals(2, returned.size());
+
+ preferences.remove(preference2);
+ svc.setPreferences("token", preferences);
+ returned = svc.getPreferences("token");
+ assertEquals(1, returned.size());
+ }
+
+ @Test
+ public void setCollectionNull(){
+
+ svc.setPreferences("token", null);
+
+ Collection<IPreference> returned = svc.getPreferences("token");
+ assertEquals(0, returned.size());
+ }
+
+ @Test
+ public void resetCollectionNull(){
+ ArrayList<IPreference> preferences = new
ArrayList<IPreference>();
+ IPreference preference1 = new
DefaultPreferenceImpl("test-name1", "test-value1", true);
+ IPreference preference2 = new
DefaultPreferenceImpl("test-name2", "test-value2", false);
+ preferences.add(preference1);
+ preferences.add(preference2);
+
+ svc.setPreferences("token", preferences);
+
+ Collection<IPreference> returned = svc.getPreferences("token");
+ assertEquals(2, returned.size());
+
+ svc.setPreferences("token", null);
+ returned = svc.getPreferences("token");
+ assertEquals(0, returned.size());
+ }
+
+
+ @Test
+ public void setAndGetObject(){
+ IPreference preference = new DefaultPreferenceImpl("test-name",
"test-value", false);
+
+ svc.setPreference("token", preference);
+
+ String result = svc.getPreference("token", "test-name");
+
+ assertEquals("test-value", result);
+ }
+
+ @Test
+ public void setAndGetObjects(){
+
+ IPreference preference1 = new
DefaultPreferenceImpl("test-name", "test-value", false);
+ IPreference preference2 = new
DefaultPreferenceImpl("test-name2", "test-value2", false);
+
+ svc.setPreference("token", preference1);
+ svc.setPreference("token", preference2);
+
+ String result = svc.getPreference("token", "test-name");
+ assertEquals("test-value", result);
+
+ result = svc.getPreference("token", "test-name2");
+ assertEquals("test-value2", result);
+ }
+
+ @Test
+ public void getNothing(){
+
+ String result = svc.getPreference("token", "test-name3");
+
+ assertEquals(null, result);
+ }
+
+ @Test
+ public void setAndReset(){
+
+ svc.setPreference("token", "test-reset", "1");
+ svc.setPreference("token", "test-reset", "2");
+ assertEquals("2", svc.getPreference("token", "test-reset"));
+ assertEquals("2", svc.getPreference("token", "test-reset"));
+ svc.setPreference("token", "test-reset", "1");
+ assertEquals("1", svc.getPreference("token", "test-reset"));
+ assertEquals("1", svc.getPreference("token", "test-reset"));
+ }
+
+}