diff --git a/spring-data-riak/pom.xml b/spring-data-riak/pom.xml
index 38f65f763..832cf13fd 100644
--- a/spring-data-riak/pom.xml
+++ b/spring-data-riak/pom.xml
@@ -127,7 +127,7 @@
com.springsource.bundlor.maven
-
org.spockframework
spock-maven
@@ -168,7 +168,7 @@
2.7.7
- -->
+
diff --git a/spring-data-riak/src/main/java/org/springframework/data/keyvalue/riak/core/AbstractRiakTemplate.java b/spring-data-riak/src/main/java/org/springframework/data/keyvalue/riak/core/AbstractRiakTemplate.java
index abf45a9fd..3ed61af18 100644
--- a/spring-data-riak/src/main/java/org/springframework/data/keyvalue/riak/core/AbstractRiakTemplate.java
+++ b/spring-data-riak/src/main/java/org/springframework/data/keyvalue/riak/core/AbstractRiakTemplate.java
@@ -168,6 +168,14 @@ public abstract class AbstractRiakTemplate extends RestGatewaySupport implements
this.useCache = useCache;
}
+ public QosParameters getDefaultQosParameters() {
+ return defaultQosParameters;
+ }
+
+ public void setDefaultQosParameters(QosParameters defaultQosParameters) {
+ this.defaultQosParameters = defaultQosParameters;
+ }
+
/**
* Extract the prefix from the URI for use in creating links.
*
diff --git a/spring-data-riak/src/main/java/org/springframework/data/keyvalue/riak/core/RiakTemplate.java b/spring-data-riak/src/main/java/org/springframework/data/keyvalue/riak/core/RiakTemplate.java
index ec7d1df40..a3abe7ba0 100644
--- a/spring-data-riak/src/main/java/org/springframework/data/keyvalue/riak/core/RiakTemplate.java
+++ b/spring-data-riak/src/main/java/org/springframework/data/keyvalue/riak/core/RiakTemplate.java
@@ -527,6 +527,25 @@ public class RiakTemplate extends AbstractRiakTemplate implements BucketKeyValue
*/
@SuppressWarnings({"unchecked"})
public T linkWalk(B bucket, K key, String tag) {
+ return (T) linkWalkAsType(bucket, key, tag, null);
+ }
+
+ /**
+ * Use Riak's link walking mechanism to retrieve a multipart message that will be decoded like
+ * they were individual objects (e.g. using the built-in HttpMessageConverters of
+ * RestTemplate) and return the result as a list of objects of one of: The type
+ * specified by requiredType If that's null, try using the bucket name
+ * in which the object was stored If all else fails, use a {@link java.util.Map}
+ *
+ *
+ * @param bucket
+ * @param key
+ * @param tag
+ * @param requiredType
+ * @return
+ */
+ @SuppressWarnings({"unchecked"})
+ public T linkWalkAsType(B bucket, K key, String tag, final Class requiredType) {
final RestTemplate restTemplate = getRestTemplate();
final List types = new ArrayList();
types.add(MediaType.ALL);
@@ -540,7 +559,7 @@ public class RiakTemplate extends AbstractRiakTemplate implements BucketKeyValue
}
},
new ResponseExtractor() {
- @SuppressWarnings({"unchecked", "unchecked"})
+ @SuppressWarnings({"unchecked"})
public Object extractData(ClientHttpResponse response) throws
IOException {
String contentType = ((List) response.getHeaders().get("Content-Type")).get(0)
@@ -575,12 +594,17 @@ public class RiakTemplate extends AbstractRiakTemplate implements BucketKeyValue
break;
}
}
- Class clazz = Map.class;
- if (null != bucketName) {
+ Class> clazz = requiredType;
+ if (null == clazz && null != bucketName) {
try {
clazz = Class.forName(bucketName);
} catch (ClassNotFoundException e) {
+ // Default to a Map. We know that will work.
+ clazz = Map.class;
}
+ } else {
+ // Default to a Map. We know that will work.
+ clazz = Map.class;
}
// Can convert message?
diff --git a/spring-data-riak/src/test/groovy/org/springframework/data/keyvalue/riak/core/RiakKeyValueTemplateSpec.groovy b/spring-data-riak/src/test/groovy/org/springframework/data/keyvalue/riak/core/RiakKeyValueTemplateSpec.groovy
new file mode 100644
index 000000000..ae0d8cb58
--- /dev/null
+++ b/spring-data-riak/src/test/groovy/org/springframework/data/keyvalue/riak/core/RiakKeyValueTemplateSpec.groovy
@@ -0,0 +1,272 @@
+/*
+ * Copyright (c) 2010 by J. Brisbin
+ * Portions (c) 2010 by NPC International, Inc. or the
+ * original author(s).
+ *
+ * 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.springframework.data.keyvalue.riak.core
+
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.context.ApplicationContext
+import org.springframework.data.keyvalue.riak.mapreduce.JavascriptMapReduceOperation
+import org.springframework.data.keyvalue.riak.mapreduce.MapReduceJob
+import org.springframework.data.keyvalue.riak.mapreduce.RiakMapReducePhase
+import org.springframework.test.context.ContextConfiguration
+import spock.lang.Shared
+import spock.lang.Specification
+
+/**
+ * @author J. Brisbin
+ */
+@ContextConfiguration(locations = "/org/springframework/data/RiakKeyValueTemplateTests.xml")
+class RiakKeyValueTemplateSpec extends Specification {
+
+ @Autowired
+ ApplicationContext appCtx
+ @Autowired
+ RiakKeyValueTemplate riak
+ int run = 1
+ @Shared def riakBin = System.properties["bamboo.RIAK_BIN"] ?: "/usr/sbin/riak"
+ @Shared def p
+
+ def setupSpec() {
+ p = "$riakBin start".execute()
+ p.waitFor()
+ Thread.sleep(2000)
+ }
+
+ def cleanupSpec() {
+ p = "$riakBin stop".execute()
+ p.waitFor()
+ }
+
+ def "Test Map object"() {
+
+ given:
+ def val = "value"
+ def objIn = [test: val, integer: 12]
+ riak.set("test:test", objIn)
+
+ when:
+ def objOut = riak.get("test:test")
+
+ then:
+ objOut.test == val
+
+ }
+
+ def "Test custom object"() {
+
+ given:
+ TestObject objIn = new TestObject()
+ riak.set("${TestObject.name}:test", objIn)
+
+ when:
+ TestObject objOut = riak.get("${TestObject.name}:test")
+
+ then:
+ objOut.test == "value"
+
+ }
+
+ def "Test getting bucket schema"() {
+
+ when:
+ def schema = riak.getBucketSchema("test", true)
+
+ then:
+ "test" == schema.props.name
+
+ }
+
+ def "Test updating bucket schema"() {
+
+ when:
+ def schema = riak.updateBucketSchema("test", [n_val: 2]).getBucketSchema("test")
+
+ then:
+ 2 == schema.props.n_val
+
+ }
+
+ def "Test get with metadata"() {
+
+ when:
+ def val = riak.getWithMetaData([bucket: "test", key: "test"], LinkedHashMap)
+
+ then:
+ val.metaData.properties["Server"].contains("WebMachine")
+
+ }
+
+ def "Test setting QosParameters"() {
+
+ given:
+ def obj = riak.get("test:test")
+
+ when:
+ def qos = new RiakQosParameters()
+ qos.durableWriteThreshold = "all"
+ riak.set("test:test", obj, qos)
+
+ then:
+ true
+
+ }
+
+ def "Test containsKey"() {
+
+ when:
+ def containsKey = riak.containsKey([bucket: "test", key: "test"])
+
+ then:
+ true == containsKey
+
+ }
+
+ def "Test linking"() {
+
+ given:
+ riak.link("${TestObject.name}:test", "test:test", "test")
+
+ when:
+ def val = riak.getWithMetaData("test:test", Map)
+ def result = val.metaData.properties["Link"].find { it.contains("riaktag=\"test\"") }
+
+ then:
+ null != result
+
+ }
+
+ def "Test link walking"() {
+
+ when:
+ def val = riak.linkWalk("test:test", "test")
+
+ then:
+ null != val
+ 1 == val.size()
+ val.get(0) instanceof TestObject
+
+ }
+
+ def "Test multiple get"() {
+
+ when:
+ def objs = riak.getValues([
+ new SimpleBucketKeyPair("test", "test"),
+ new SimpleBucketKeyPair(TestObject.name, "test")
+ ])
+
+ then:
+ 2 == objs.size()
+
+ }
+
+ def "Test getAndSet with Map"() {
+
+ given:
+ def i = run++
+ def newObj = [test: "value $i", integer: 12]
+
+ when:
+ def oldObj = riak.getAndSet("test:test", newObj)
+
+ then:
+ "value" == oldObj.test
+
+ }
+
+ def "Test setMultipleIfKeysNonExistent with Map"() {
+
+ given:
+ def testKey = new SimpleBucketKeyPair("test", "test")
+ def testKey2 = new SimpleBucketKeyPair(TestObject.name, "test")
+ def newObj = [:]
+ newObj[testKey] = [test: "value", integer: 12]
+ newObj[testKey2] = [test: "value", integer: 12]
+
+ when:
+ def secondObj = riak.setMultipleIfKeysNonExistent(newObj).get(testKey2)
+ secondObj.test = "newValue"
+ def updObj = [:]
+ updObj[testKey2] = secondObj
+ def thirdObj = riak.setMultipleIfKeysNonExistent(updObj).get(testKey2)
+
+ then:
+ "value" == thirdObj.test
+
+ }
+
+ def "Test Map/Reduce returning Integer"() {
+
+ given:
+ MapReduceJob job = riak.createMapReduceJob()
+ def mapJs = new JavascriptMapReduceOperation("function(v){ var o=Riak.mapValuesJson(v); return [1]; }")
+ def mapPhase = new RiakMapReducePhase("map", "javascript", mapJs)
+
+ def reduceJs = new JavascriptMapReduceOperation("function(v){ var s=Riak.reduceSum(v); return s; }")
+ def reducePhase = new RiakMapReducePhase("reduce", "javascript", reduceJs)
+
+ job.addInputs(["test"]).
+ addPhase(mapPhase).
+ addPhase(reducePhase)
+ println job.toJson()
+
+ when:
+ def result = riak.execute(job, Integer)
+
+ then:
+ 1 == result
+
+ }
+
+ def "Test Map/Reduce returning List"() {
+
+ given:
+ MapReduceJob job = riak.createMapReduceJob()
+ def mapJs = new JavascriptMapReduceOperation("function(v){ ejsLog('/tmp/mapred.log', 'map v: '+JSON.stringify(v)); var o=Riak.mapValuesJson(v); return [1]; }")
+ def mapPhase = new RiakMapReducePhase("map", "javascript", mapJs)
+
+ def reduceJs = new JavascriptMapReduceOperation("function(v){ ejsLog('/tmp/mapred.log', 'red v: '+JSON.stringify(v)); var s=Riak.reduceSum(v); return s; }")
+ def reducePhase = new RiakMapReducePhase("reduce", "javascript", reduceJs)
+
+ job.addInputs(["test"]).
+ addPhase(mapPhase).
+ addPhase(reducePhase)
+
+ when:
+ def result = riak.execute(job)
+
+ then:
+ 1 == result.size()
+ 1 == result[0]
+
+ }
+
+ def "Test deleteKeys"() {
+
+ given:
+ def testKey = new SimpleBucketKeyPair("test", "test")
+ def testKey2 = new SimpleBucketKeyPair(TestObject.name, "test")
+
+ when:
+ def deleted = riak.deleteKeys(testKey, testKey2)
+
+ then:
+ true == deleted
+
+ }
+
+}
\ No newline at end of file
diff --git a/spring-data-riak/src/test/groovy/org/springframework/data/keyvalue/riak/core/RiakTemplateSpec.groovy b/spring-data-riak/src/test/groovy/org/springframework/data/keyvalue/riak/core/RiakTemplateSpec.groovy
index 85898e401..82fd81625 100644
--- a/spring-data-riak/src/test/groovy/org/springframework/data/keyvalue/riak/core/RiakTemplateSpec.groovy
+++ b/spring-data-riak/src/test/groovy/org/springframework/data/keyvalue/riak/core/RiakTemplateSpec.groovy
@@ -1,11 +1,13 @@
/*
* Copyright (c) 2010 by J. Brisbin
+ * Portions (c) 2010 by NPC International, Inc. or the
+ * original author(s).
*
* 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
+ * 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,
@@ -33,19 +35,19 @@ class RiakTemplateSpec extends Specification {
@Autowired
ApplicationContext appCtx
@Autowired
- RiakKeyValueTemplate riak
+ RiakTemplate riak
int run = 1
- @Shared def riakBin = System.getenv("RIAK_BIN")
+ @Shared def riakBin = System.properties["bamboo.RIAK_BIN"] ?: "/usr/sbin/riak"
@Shared def p
def setupSpec() {
- p = "/usr/sbin/riak start".execute()
+ p = "$riakBin start".execute()
p.waitFor()
Thread.sleep(2000)
}
def cleanupSpec() {
- "/usr/sbin/riak stop".execute()
+ p = "$riakBin stop".execute()
p.waitFor()
}
@@ -54,10 +56,10 @@ class RiakTemplateSpec extends Specification {
given:
def val = "value"
def objIn = [test: val, integer: 12]
- riak.set("test:test", objIn)
+ riak.set("test", "test", objIn)
when:
- def objOut = riak.get("test:test")
+ def objOut = riak.get("test", "test")
then:
objOut.test == val
@@ -68,10 +70,10 @@ class RiakTemplateSpec extends Specification {
given:
TestObject objIn = new TestObject()
- riak.set("${TestObject.name}:test", objIn)
+ riak.set(TestObject.name, "test", objIn)
when:
- TestObject objOut = riak.get("${TestObject.name}:test")
+ TestObject objOut = riak.get(TestObject.name, "test")
then:
objOut.test == "value"
@@ -101,7 +103,7 @@ class RiakTemplateSpec extends Specification {
def "Test get with metadata"() {
when:
- def val = riak.getWithMetaData([bucket: "test", key: "test"], LinkedHashMap)
+ def val = riak.getWithMetaData("test", "test", LinkedHashMap)
then:
val.metaData.properties["Server"].contains("WebMachine")
@@ -111,12 +113,12 @@ class RiakTemplateSpec extends Specification {
def "Test setting QosParameters"() {
given:
- def obj = riak.get("test:test")
+ def obj = riak.get("test", "test")
when:
def qos = new RiakQosParameters()
qos.durableWriteThreshold = "all"
- riak.set("test:test", obj, qos)
+ riak.set("test", "test", obj, qos)
then:
true
@@ -126,7 +128,7 @@ class RiakTemplateSpec extends Specification {
def "Test containsKey"() {
when:
- def containsKey = riak.containsKey([bucket: "test", key: "test"])
+ def containsKey = riak.containsKey("test", "test")
then:
true == containsKey
@@ -136,10 +138,10 @@ class RiakTemplateSpec extends Specification {
def "Test linking"() {
given:
- riak.link("${TestObject.name}:test", "test:test", "test")
+ riak.link(TestObject.name, "test", "test", "test", "test")
when:
- def val = riak.getWithMetaData("test:test", Map)
+ def val = riak.getWithMetaData("test", "test", Map)
def result = val.metaData.properties["Link"].find { it.contains("riaktag=\"test\"") }
then:
@@ -150,7 +152,7 @@ class RiakTemplateSpec extends Specification {
def "Test link walking"() {
when:
- def val = riak.linkWalk("test:test", "test")
+ def val = riak.linkWalk("test", "test", "test")
then:
null != val
@@ -159,16 +161,15 @@ class RiakTemplateSpec extends Specification {
}
- def "Test multiple get"() {
+ def "Test link walking as type"() {
when:
- def objs = riak.getValues([
- new SimpleBucketKeyPair("test", "test"),
- new SimpleBucketKeyPair(TestObject.name, "test")
- ])
+ def val = riak.linkWalkAsType("test", "test", "test", Map)
then:
- 2 == objs.size()
+ null != val
+ 1 == val.size()
+ val.get(0) instanceof Map
}
@@ -179,42 +180,22 @@ class RiakTemplateSpec extends Specification {
def newObj = [test: "value $i", integer: 12]
when:
- def oldObj = riak.getAndSet("test:test", newObj)
+ def oldObj = riak.getAndSet("test", "test", newObj)
then:
"value" == oldObj.test
}
- def "Test setMultipleIfKeysNonExistent with Map"() {
-
- given:
- def testKey = new SimpleBucketKeyPair("test", "test")
- def testKey2 = new SimpleBucketKeyPair(TestObject.name, "test")
- def newObj = [:]
- newObj[testKey] = [test: "value", integer: 12]
- newObj[testKey2] = [test: "value", integer: 12]
-
- when:
- def secondObj = riak.setMultipleIfKeysNonExistent(newObj).get(testKey2)
- secondObj.test = "newValue"
- def updObj = [:]
- updObj[testKey2] = secondObj
- def thirdObj = riak.setMultipleIfKeysNonExistent(updObj).get(testKey2)
-
- then:
- "value" == thirdObj.test
-
- }
-
def "Test Map/Reduce returning Integer"() {
given:
MapReduceJob job = riak.createMapReduceJob()
- def mapJs = new JavascriptMapReduceOperation("function(v){ var o=Riak.mapValuesJson(v); return [1]; }")
+ def uuid = UUID.randomUUID().toString()
+ def mapJs = new JavascriptMapReduceOperation("function(v){ var uuid='$uuid'; ejsLog('/tmp/mapred.log', 'map input: '+JSON.stringify(v)); var o=Riak.mapValuesJson(v); return [1]; }")
def mapPhase = new RiakMapReducePhase("map", "javascript", mapJs)
- def reduceJs = new JavascriptMapReduceOperation("function(v){ var s=Riak.reduceSum(v); return s; }")
+ def reduceJs = new JavascriptMapReduceOperation("function(v){ var uuid='$uuid'; ejsLog('/tmp/mapred.log', 'reduce input: '+JSON.stringify(v)); var s=Riak.reduceSum(v); ejsLog('/tmp/mapred.log', 'reduce output: '+JSON.stringify(s)); return s; }")
def reducePhase = new RiakMapReducePhase("reduce", "javascript", reduceJs)
job.addInputs(["test"]).
@@ -234,10 +215,11 @@ class RiakTemplateSpec extends Specification {
given:
MapReduceJob job = riak.createMapReduceJob()
- def mapJs = new JavascriptMapReduceOperation("function(v){ ejsLog('/tmp/mapred.log', 'map v: '+JSON.stringify(v)); var o=Riak.mapValuesJson(v); return [1]; }")
+ def uuid = UUID.randomUUID().toString()
+ def mapJs = new JavascriptMapReduceOperation("function(v){ var uuid='$uuid'; ejsLog('/tmp/mapred.log', 'map input: '+JSON.stringify(v)); var o=Riak.mapValuesJson(v); return [1]; }")
def mapPhase = new RiakMapReducePhase("map", "javascript", mapJs)
- def reduceJs = new JavascriptMapReduceOperation("function(v){ ejsLog('/tmp/mapred.log', 'red v: '+JSON.stringify(v)); var s=Riak.reduceSum(v); return s; }")
+ def reduceJs = new JavascriptMapReduceOperation("function(v){ var uuid='$uuid'; ejsLog('/tmp/mapred.log', 'reduce input: '+JSON.stringify(v)); var s=Riak.reduceSum(v); ejsLog('/tmp/mapred.log', 'reduce output: '+JSON.stringify(s)); return s; }")
def reducePhase = new RiakMapReducePhase("reduce", "javascript", reduceJs)
job.addInputs(["test"]).
@@ -253,7 +235,7 @@ class RiakTemplateSpec extends Specification {
}
- def "Test deleteKeys"() {
+ def "Test delete key"() {
given:
def testKey = new SimpleBucketKeyPair("test", "test")
diff --git a/spring-data-riak/src/test/resources/org/springframework/data/RiakKeyValueTemplateTests.xml b/spring-data-riak/src/test/resources/org/springframework/data/RiakKeyValueTemplateTests.xml
new file mode 100644
index 000000000..43aafe1d5
--- /dev/null
+++ b/spring-data-riak/src/test/resources/org/springframework/data/RiakKeyValueTemplateTests.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
diff --git a/spring-data-riak/src/test/resources/org/springframework/data/RiakTemplateTests.xml b/spring-data-riak/src/test/resources/org/springframework/data/RiakTemplateTests.xml
index 9238a146e..e8ebcfb28 100644
--- a/spring-data-riak/src/test/resources/org/springframework/data/RiakTemplateTests.xml
+++ b/spring-data-riak/src/test/resources/org/springframework/data/RiakTemplateTests.xml
@@ -1,11 +1,34 @@
+
+
+
+ class="org.springframework.data.keyvalue.riak.core.RiakTemplate"
+ p:defaultQosParameters-ref="qos"/>