Merge branch 'master' of github.com:SpringSource/spring-data-keyvalue

This commit is contained in:
Costin Leau
2010-12-10 19:07:07 +02:00
7 changed files with 380 additions and 55 deletions

View File

@@ -127,7 +127,7 @@
<artifactId>com.springsource.bundlor.maven</artifactId>
</plugin>
<!-- For running Groovy/Spock tests
<!-- For running Groovy/Spock tests -->
<plugin>
<groupId>org.spockframework</groupId>
<artifactId>spock-maven</artifactId>
@@ -168,7 +168,7 @@
<version>2.7.7</version>
</dependency>
</dependencies>
</plugin> -->
</plugin>
</plugins>
</build>

View File

@@ -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.
*

View File

@@ -527,6 +527,25 @@ public class RiakTemplate extends AbstractRiakTemplate implements BucketKeyValue
*/
@SuppressWarnings({"unchecked"})
public <B, T, K> 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: <ol> <li>The type
* specified by <code>requiredType</code></li> <li>If that's null, try using the bucket name
* in which the object was stored</li> <li>If all else fails, use a {@link java.util.Map}</li>
* </ol>
*
* @param bucket
* @param key
* @param tag
* @param requiredType
* @return
*/
@SuppressWarnings({"unchecked"})
public <B, T, K> T linkWalkAsType(B bucket, K key, String tag, final Class<T> requiredType) {
final RestTemplate restTemplate = getRestTemplate();
final List<MediaType> types = new ArrayList<MediaType>();
types.add(MediaType.ALL);
@@ -540,7 +559,7 @@ public class RiakTemplate extends AbstractRiakTemplate implements BucketKeyValue
}
},
new ResponseExtractor<Object>() {
@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?

View File

@@ -0,0 +1,272 @@
/*
* Copyright (c) 2010 by J. Brisbin <jon@jbrisbin.com>
* 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 <jon@jbrisbin.com>
*/
@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
}
}

View File

@@ -1,11 +1,13 @@
/*
* Copyright (c) 2010 by J. Brisbin <jon@jbrisbin.com>
* 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")

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<import resource="classpath:/META-INF/spring/app-context.xml"/>
<bean id="qos" class="org.springframework.data.keyvalue.riak.core.RiakQosParameters"
p:durableWriteThreshold="all"
p:writeThreshold="all"/>
<bean id="riakTemplate"
class="org.springframework.data.keyvalue.riak.core.RiakKeyValueTemplate"
p:defaultQosParameters-ref="qos"/>
</beans>

View File

@@ -1,11 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright (c) 2010 by J. Brisbin <jon@jbrisbin.com>
~ 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.
-->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<import resource="classpath:/META-INF/spring/app-context.xml"/>
<bean id="qos" class="org.springframework.data.keyvalue.riak.core.RiakQosParameters"
p:durableWriteThreshold="all"
p:writeThreshold="all"/>
<bean id="riakTemplate"
class="org.springframework.data.keyvalue.riak.core.RiakKeyValueTemplate"/>
class="org.springframework.data.keyvalue.riak.core.RiakTemplate"
p:defaultQosParameters-ref="qos"/>
</beans>