diff --git a/.gitignore b/.gitignore
new file mode 100644
index 000000000..de8921796
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,13 @@
+.DS_Store
+target
+bin
+build
+bin
+.gradle
+.springBeans
+.ant-targets-build.xml
+pom.xml
+src/ant/.ant-targets-upload-dist.xml
+*.iml
+*.ipr
+*.iws
diff --git a/.settings/org.maven.ide.eclipse.prefs b/.settings/org.maven.ide.eclipse.prefs
new file mode 100644
index 000000000..fc929aaef
--- /dev/null
+++ b/.settings/org.maven.ide.eclipse.prefs
@@ -0,0 +1,9 @@
+#Mon Oct 11 17:02:20 EDT 2010
+activeProfiles=
+eclipse.preferences.version=1
+fullBuildGoals=process-test-resources
+includeModules=false
+resolveWorkspaceProjects=true
+resourceFilterGoals=process-resources resources\:testResources
+skipCompilerPlugin=true
+version=1
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 000000000..2546282d0
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,140 @@
+// used for artifact names, building doc upload urls, etc.
+description = 'Spring Data Key Value'
+abbreviation = 'DATAKV'
+
+apply plugin: 'base'
+apply plugin: 'idea'
+
+buildscript {
+ repositories {
+// add(new org.apache.ivy.plugins.resolver.FileSystemResolver()) {
+// name = "local"
+// addIvyPattern "e:/work/i21/gradle-plugins/build/repo/[organisation].[module]-ivy-[revision].xml"
+// addArtifactPattern "e:/work/i21/gradle-plugins/build/repo/[organisation].[module]-[revision](-[classifier]).[ext]"
+// }
+
+ add(new org.apache.ivy.plugins.resolver.URLResolver()) {
+ name = "GitHub"
+ addIvyPattern 'http://cloud.github.com/downloads/costin/gradle-stuff/[organization].[module]-[artifact]-[revision].[ext]'
+ addArtifactPattern 'http://cloud.github.com/downloads/costin/gradle-stuff/[organization].[module]-[revision].[ext]'
+ }
+ mavenCentral()
+ mavenRepo name: "springsource-org-release", urls: "http://repository.springsource.com/maven/bundles/release"
+ mavenRepo name: "springsource-org-external", urls: "http://repository.springsource.com/maven/bundles/external"
+ }
+
+ dependencies {
+ classpath 'org.springframework:gradle-stuff:0.1-20110421'
+ classpath 'net.sf.docbook:docbook-xsl:1.75.2:ns-resources@zip'
+ }
+}
+
+allprojects {
+ group = 'org.springframework.data'
+ version = '1.0.0.BUILD-SNAPSHOT'
+
+ releaseBuild = version.endsWith('RELEASE')
+ snapshotBuild = version.endsWith('SNAPSHOT')
+
+
+ repositories {
+ mavenLocal()
+ mavenCentral()
+ // Public Spring artefacts
+ mavenRepo name: "springsource-org-release", urls: "http://repository.springsource.com/maven/bundles/release"
+ mavenRepo name: "spring-release", urls: "http://maven.springframework.org/release"
+ mavenRepo name: "spring-milestone", urls: "http://maven.springframework.org/milestone"
+ mavenRepo name: "spring-snapshot", urls: "http://maven.springframework.org/snapshot"
+ mavenRepo name: "sonatype-snapshot", urls: "http://oss.sonatype.org/content/repositories/snapshots"
+ mavenRepo name: "jboss", urls: "http://repository.jboss.org/maven2/"
+ mavenRepo name: "java.net", urls: "http://download.java.net/maven/2/"
+ }
+}
+
+javaprojects = subprojects.findAll {
+ project -> project.path.startsWith(':spring-data-')
+}
+
+configure(javaprojects) {
+ apply plugin: "java"
+ apply plugin: "maven"
+ apply plugin: 'eclipse' // `gradle eclipse` to generate .classpath/.project
+ apply plugin: 'idea' // `gradle idea` to generate .ipr/.iml
+ apply plugin: 'docbook'
+ apply plugin: 'bundlor' // all core projects should be OSGi-compliant
+
+ bundlor.useProjectProps = true
+ [compileJava, compileTestJava]*.options*.compilerArgs = ["-Xlint:-serial"]
+
+ // Common dependencies
+ dependencies {
+ // Logging
+ compile "org.slf4j:slf4j-api:$slf4jVersion"
+ compile "org.slf4j:jcl-over-slf4j:$slf4jVersion"
+ runtime "log4j:log4j:$log4jVersion"
+ runtime "org.slf4j:slf4j-log4j12:$slf4jVersion"
+ // Spring Framework
+ compile("org.springframework:spring-core:$springVersion") {
+ exclude module: "commons-logging"
+ }
+ compile "org.springframework:spring-beans:$springVersion"
+ compile "org.springframework:spring-context:$springVersion"
+ compile "org.springframework:spring-context-support:$springVersion"
+ compile "org.springframework:spring-tx:$springVersion"
+ // Jackson JSON Mapper
+ compile "org.codehaus.jackson:jackson-mapper-asl:$jacksonVersion"
+ // Testing
+ testCompile "junit:junit:$junitVersion"
+ testCompile "org.springframework:spring-test:$springVersion"
+ testCompile "org.mockito:mockito-all:$mockitoVersion"
+ }
+
+ apply from: "$rootDir/maven.gradle"
+}
+
+ideaProject {
+ withXml { provider ->
+ provider.node.component.find { it.@name == 'VcsDirectoryMappings' }.mapping.@vcs = 'Git'
+ }
+}
+
+task wrapper(type: Wrapper) {
+ gradleVersion = '0.9.2'
+ description = "Generate the Gradle wrapper"
+ group = "Distribution"
+}
+
+// Distribution tasks
+task dist(type: Zip) {
+ description = "Generate the ZIP Distribution"
+ group = "Distribution"
+ dependsOn subprojects*.tasks*.matching { task -> task.name == 'assemble' }
+
+ evaluationDependsOn(':docs')
+
+ def zipRootDir = "${project.name}-$version"
+ into(zipRootDir) {
+ from('/docs/src/info') {
+ include '*.txt'
+ }
+ from('/docs/build/') {
+ into 'docs'
+ include 'reference/**/*'
+ include 'api/**/*'
+ }
+ into('dist') {
+ from javaprojects.collect {project -> project.libsDir }
+ }
+ }
+ doLast {
+ ant.checksum(file: archivePath, algorithm: 'SHA1', fileext: '.sha1')
+ }
+}
+
+task uploadDist(type: org.springframework.gradle.tasks.S3DistroUpload, dependsOn: dist) {
+ description = "Upload the ZIP Distribution"
+ group = "Distribution"
+ archiveFile = dist.archivePath
+ projectKey = 'DATAKV'
+ projectName = 'Spring Data Key Value'
+}
\ No newline at end of file
diff --git a/docs/build.gradle b/docs/build.gradle
new file mode 100644
index 000000000..ebdf04155
--- /dev/null
+++ b/docs/build.gradle
@@ -0,0 +1,136 @@
+import org.apache.tools.ant.filters.FixCrLfFilter
+import org.apache.tools.ant.filters.ReplaceTokens
+
+// -----------------------------------------------------------------------------
+// Configuration for the docs subproject
+// -----------------------------------------------------------------------------
+
+apply plugin: 'base'
+apply plugin: 'docbook'
+
+assemble.dependsOn = ['api', 'docbook']
+
+
+[docbookHtml, docbookFoPdf, docbookHtmlSingle]*.group = 'Documentation'
+[docbookHtml, docbookFoPdf, docbookHtmlSingle]*.sourceFileName = 'index.xml'
+[docbookHtml, docbookFoPdf, docbookHtmlSingle]*.sourceDirectory = new File(projectDir, 'src/reference/docbook')
+
+docbookHtml.stylesheet = new File(projectDir, 'src/reference/resources/xsl/html-custom.xsl')
+docbookHtmlSingle.stylesheet = new File(projectDir, 'src/reference/resources/xsl/html-single-custom.xsl')
+docbookFoPdf.stylesheet = new File(projectDir, 'src/reference/resources/xsl/pdf-custom.xsl')
+
+def imagesDir = new File(projectDir, 'src/reference/resources/images');
+docbookFoPdf.admonGraphicsPath = "${imagesDir}/admon"
+docbookFoPdf.imgSrcPath = "${imagesDir}"
+
+refSpec = copySpec {
+ into ('reference') {
+ from("$buildDir/docs")
+ from("$projectDir/src/reference/resources")
+ }
+ into ('reference/images') {
+ from (imagesDir)
+ }
+
+ p = new Properties()
+
+ for (e in project.properties) {
+ if (e.key != null && e.value != null)
+ p.setProperty(e.key, e.value.toString())
+ }
+
+ filter(ReplaceTokens, tokens: p)
+}
+
+task reference (type: Copy) {
+ dependsOn 'docbook'
+ description = "Builds aggregated DocBook"
+ group = "Documentation"
+ logger.info("Version is " + version)
+ destinationDir = buildDir
+ with(refSpec)
+}
+
+task api(type: Javadoc) {
+ group = "Documentation"
+ description = "Builds aggregated JavaDoc HTML for all core project classes."
+
+ // this task is a bit ugly to configure. it was a user contribution, and
+ // Hans tells me it's on the roadmap to redesign it.
+
+ srcDir = file("${projectDir}/src/api")
+ destinationDir = file("${buildDir}/api")
+ tmpDir = file("${buildDir}/api-work")
+
+ configure(options) {
+ stylesheetFile = file("${srcDir}/spring-javadoc.css")
+ links = ["http://static.springframework.org/spring/docs/3.0.x/javadoc-api"]
+ overview = "${srcDir}/overview.html"
+ docFilesSubDirs = true
+ outputLevel = org.gradle.external.javadoc.JavadocOutputLevel.QUIET
+ breakIterator = true
+ showFromProtected()
+ groups = [
+ 'Spring Data Key Value Core': ['org.springframework.data.keyvalue*'],
+ 'Spring Data Redis Support' : ['org.springframework.data.keyvalue.redis*'],
+ 'Spring Data Riak Support' : ['org.springframework.data.keyvalue.riak*']
+ ]
+
+ links = [
+ "http://static.springframework.org/spring/docs/3.0.x/javadoc-api",
+ "http://download.oracle.com/javase/6/docs/api/"
+ ]
+
+ exclude "org/springframework/data/keyvalue/redis/config/**"
+ }
+
+ title = "${rootProject.description} ${version} API"
+
+ // collect all the sources that will be included in the javadoc output
+ source javaprojects.collect {project ->
+ project.sourceSets.main.allJava
+ }
+
+ // collect all main classpaths to be able to resolve @see refs, etc.
+ // this collection also determines the set of projects that this
+ // task dependsOn, thus the runtimeClasspath is used to ensure all
+ // projects are included, not just *dependencies* of all classes.
+ // this is awkward and took me a while to figure out.
+ classpath = files(javaprojects.collect {project ->
+ project.sourceSets.main.runtimeClasspath
+ })
+
+ // copy the images from the doc-files dir over to the target
+ doLast { task ->
+ copy {
+ from file("${task.srcDir}/doc-files")
+ into file("${task.destinationDir}/doc-files")
+ }
+ }
+}
+
+apiSpec = copySpec {
+ into('api') {
+ from(api.destinationDir)
+ }
+}
+
+task docSiteLogin(type: org.springframework.gradle.tasks.Login) {
+ if (project.hasProperty('sshHost')) {
+ host = project.property('sshHost')
+ username = project.property('sshUsername')
+ key = project.property('sshPrivateKey')
+ }
+}
+
+// upload task
+task uploadApi(type: org.springframework.gradle.tasks.ScpUpload) {
+ dependsOn api, docbook
+ description = "Upload API Distribution"
+ group = "Distribution"
+ remoteDir = "./static.spring/spring-data/data-keyvalue/docs/${project.version}"
+ login = docSiteLogin
+
+ with(apiSpec)
+ with(refSpec)
+}
\ No newline at end of file
diff --git a/docs/src/api/doc-files/th-background.png b/docs/src/api/doc-files/th-background.png
new file mode 100644
index 000000000..72d65e771
Binary files /dev/null and b/docs/src/api/doc-files/th-background.png differ
diff --git a/docs/src/api/javadoc.options b/docs/src/api/javadoc.options
new file mode 100644
index 000000000..04964ca74
--- /dev/null
+++ b/docs/src/api/javadoc.options
@@ -0,0 +1,13 @@
+-breakiterator
+-header "Spring Data Key-Value"
+-source 1.6
+-protected
+-quiet
+-docfilessubdirs
+-group "Spring Data Key Value Core" "org.springframework.data.keyvalue*"
+-group "Spring Data Redis Support" "org.springframework.data.keyvalue.redis*"
+-group "Spring Data Riak Support" "org.springframework.data.keyvalue.riak*"
+-link http://static.springframework.org/spring/docs/3.0.x/javadoc-api
+-link http://download.oracle.com/javase/6/docs/api/
+-exclude org.springframework.data.keyvalue.redis.config
+
diff --git a/docs/src/api/overview.html b/docs/src/api/overview.html
new file mode 100644
index 000000000..d2bdf9b41
--- /dev/null
+++ b/docs/src/api/overview.html
@@ -0,0 +1,24 @@
+
+
+This document is the API specification for the Spring Data project.
+
+
+
+
+
+ If you are interested in commercial training, consultancy and
+ support for the Spring Data Framework,
+ SpringSource provides
+ such commercial support.
+
+
+
+
\ No newline at end of file
diff --git a/docs/src/api/spring-javadoc.css b/docs/src/api/spring-javadoc.css
new file mode 100644
index 000000000..1f009c4bc
--- /dev/null
+++ b/docs/src/api/spring-javadoc.css
@@ -0,0 +1,48 @@
+/* Spring-specific Javadoc style sheet rules */
+
+#overviewBody {
+
+}
+
+.code {
+ border: 1px solid black;
+ background-color: #F4F4F4;
+ padding: 5px;
+}
+
+/* Vanilla Javadoc style sheet rules */
+
+body {
+ font-family: Helvetica, Arial, sans-serif;
+ background-color: white;
+ font-size: 10pt;
+}
+
+td { font-size: 10pt; font-family: Helvetica, Arial, sans-serif }/* Javadoc style sheet */
+
+/* Define colors, fonts and other style attributes here to override the defaults */
+
+/* Page background color */
+body { background-color: #FFFFFF }
+
+/* Headings */
+h1 { font-size: 145% }
+
+/* Table colors */
+.TableHeadingColor { background: #CCCCFF } /* Dark mauve */
+.TableSubHeadingColor { background: #EEEEFF } /* Light mauve */
+.TableRowColor { background: #FFFFFF } /* White */
+
+/* Font used in left-hand frame lists */
+.FrameTitleFont { font-size: 100%; font-family: Helvetica, Arial, sans-serif }
+.FrameHeadingFont { font-size: 90%; font-family: Helvetica, Arial, sans-serif }
+.FrameItemFont { font-size: 90%; font-family: Helvetica, Arial, sans-serif }
+
+/* Navigation bar fonts and colors */
+.NavBarCell1 { background-color:#EEEEFF;} /* Light mauve */
+.NavBarCell1Rev { background-color:#00008B;} /* Dark Blue */
+.NavBarFont1 { font-family: Arial, Helvetica, sans-serif; color:#000000;}
+.NavBarFont1Rev { font-family: Arial, Helvetica, sans-serif; color:#FFFFFF;}
+
+.NavBarCell2 { font-family: Arial, Helvetica, sans-serif; background-color:#FFFFFF;}
+.NavBarCell3 { font-family: Arial, Helvetica, sans-serif; background-color:#FFFFFF;}
diff --git a/docs/src/info/apache-license.txt b/docs/src/info/apache-license.txt
new file mode 100644
index 000000000..261eeb9e9
--- /dev/null
+++ b/docs/src/info/apache-license.txt
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
diff --git a/docs/src/info/changelog.txt b/docs/src/info/changelog.txt
new file mode 100644
index 000000000..d2d5c4626
--- /dev/null
+++ b/docs/src/info/changelog.txt
@@ -0,0 +1,92 @@
+SPRING DATA KEY/VALUE INTEGRATION CHANGELOG
+===========================================
+http://www.springsource.org/spring-data
+
+Changes in version 1.0.0.M3 (2011-04-06)
+----------------------------------------
+
+Redis
+-----
+
+General
+* Added support for RJC (new Redis client)
+* Added dedicated SORT and SORT/GET support
+* Introduced HashMapper feature for mapping objects to and from maps
+* Improved exception hierarchy to be more consistent with Spring DAO
+* Made several Redis dependencies optional to eliminate unnecessary jars from the classpath
+
+Package o.s.d.k.redis.connection
+* Added support for indexes to RedisConnectionFactories
+* Added new key operations to KeyOperations (formerly KeyBound)
+* Improved handling of Jedis exceptions
+
+Package o.s.d.k.redis.core
+* Serializers are exposed to RedisCallback
+* Added missing operations (move, select) to RedisTemplate
+* Fixed the signature of various method
+
+Package o.s.d.k.redis.support.atomic
+* Fixed incorrect serialization leading to error for RedisAtomicInteger & RedisAtomicLong
+
+
+Changes in version 1.0.0.M2 (2011-02-10)
+----------------------------------------
+
+Redis
+-----
+
+General
+* Added PubSub support (message listener container and namespace)
+* Added JSON and Object/XML Mapping serializers
+* Completed support for Redis (2.2) commands
+* Improved documentation
+* Upgraded to Redis 2.2
+* Updraded to Jedis 1.5.2
+
+Package o.s.d.k.redis.connection
+* Added sort support
+* Added pipelining support
+* Added StringRedisConnection for String-focused operations
+* Renamed JedisConnectionFactory pooling to usePool
+* Renamed JredisConnectionFactory pooling to usePool
+
+Package o.s.d.k.redis.connection.jedis
+* Added support for Jedis rich exceptions
+* Added support for broken pooled connection
+
+Package o.s.d.k.redis.core
+* Fix serializationg bug for hash value inside RedisTemplate
+* Added injection for Redis operations ("views")
+
+Package o.s.d.k.redis.support
+* Refined AtomicInteger and AtomicLong constructors to use the backing store value as initial counter
+
+
+Riak
+----
+
+General
+* Important bug fixes
+* Fully asynchronous AsyncRiakTemplate object
+* Groovy DSL for Riak access using async template underneath
+
+
+Changes in version Riak 1.0.0.M1 (2010-12-15)
+---------------------------------------------
+General
+* Generified RiakTemplate for exception translation, serialization, and data access
+* Built-in HTTP REST client based on Spring 3.0 RestTemplate
+* java.io and Spring IO resource abstractions for reading/writing streams
+* java.io.File subclass that represents a Riak resource
+
+
+Changes in version Redis 1.0.0.M1 (2010-12-13)
+----------------------------------------------
+General
+* Configuration support for Redis Jedis and JRedis drivers/connectors
+* Connection package as low-level abstraction across multiple drivers
+* Exception translation
+* Generified RedisTemplate for exception translation and serialization support
+* Various serialization strategies
+* Atomic counter support classes
+* JDK Collection implementations on top of Redis
diff --git a/docs/src/info/notice.txt b/docs/src/info/notice.txt
new file mode 100644
index 000000000..e6900be90
--- /dev/null
+++ b/docs/src/info/notice.txt
@@ -0,0 +1,21 @@
+ ========================================================================
+ == NOTICE file corresponding to section 4 d of the Apache License, ==
+ == Version 2.0, in this case for the Spring Integration distribution. ==
+ ========================================================================
+
+ This product includes software developed by
+ the Apache Software Foundation (http://www.apache.org).
+
+ The end-user documentation included with a redistribution, if any,
+ must include the following acknowledgement:
+
+ "This product includes software developed by the Spring Framework
+ Project (http://www.springframework.org)."
+
+ Alternatively, this acknowledgement may appear in the software itself,
+ if and wherever such third-party acknowledgements normally appear.
+
+ The names "Spring", "Spring Framework", and "Spring Data" must
+ not be used to endorse or promote products derived from this software
+ without prior written permission. For written permission, please contact
+ enquiries@springsource.com.
diff --git a/docs/src/info/readme.txt b/docs/src/info/readme.txt
new file mode 100644
index 000000000..eb45a4e73
--- /dev/null
+++ b/docs/src/info/readme.txt
@@ -0,0 +1,17 @@
+SPRING DATASTORE KEY-VALUE 1.0.0 M2 (2010 02 10)
+------------------------------------------------
+
+Spring Datastore Key-Value is released under the terms of the Apache Software License Version 2.0 (see license.txt).
+
+
+DISTRIBUTION CONTENTS:
+
+The JARs are available in the 'dist' directory, and the source JARs are in the 'src' directory.
+
+The reference manual and javadoc are located in the 'docs' directory.
+
+
+ADDITIONAL RESOURCES:
+
+Spring Data Homepage: http://www.springsource.org/spring-data
+Spring Data Forum : http://forum.springsource.org/forumdisplay.php?f=80
diff --git a/docs/src/reference/docbook/appendix/appendix-schema.xml b/docs/src/reference/docbook/appendix/appendix-schema.xml
new file mode 100644
index 000000000..2e23ffcd8
--- /dev/null
+++ b/docs/src/reference/docbook/appendix/appendix-schema.xml
@@ -0,0 +1,13 @@
+
+
+ Spring Data Key Value Schema(s)
+
+ Spring Data - Redis support
+
+
+ FIXME: REDIS SCHEMA LOCATION/NAME CHANGED
+
+
+
+
+
diff --git a/docs/src/reference/docbook/appendix/introduction.xml b/docs/src/reference/docbook/appendix/introduction.xml
new file mode 100644
index 000000000..6d9d95050
--- /dev/null
+++ b/docs/src/reference/docbook/appendix/introduction.xml
@@ -0,0 +1,10 @@
+
+ Document structure
+
+
+ Various appendixes outside the reference documentation.
+
+
+ defines the schemas provided by Spring Data
+ Key Value.
+
\ No newline at end of file
diff --git a/docs/src/reference/docbook/index.xml b/docs/src/reference/docbook/index.xml
new file mode 100644
index 000000000..5e2782b6d
--- /dev/null
+++ b/docs/src/reference/docbook/index.xml
@@ -0,0 +1,80 @@
+
+
+
+
+ Spring Data Key-Value - Reference Documentation
+ Spring Data Key-Value ${version}
+ @version@
+ Spring Data Key-Value
+
+
+
+ Costin
+ Leau
+ SpringSource
+
+
+ Jon
+ Brisbin
+ SpringSource
+
+
+
+
+
+ Copies of this document may be made for your own use and for distribution
+ to others, provided that you do not charge any fee for such copies and
+ further provided that each copy contains this Copyright Notice, whether
+ distributed in print or electronically.
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/src/reference/docbook/introduction/getting-started.xml b/docs/src/reference/docbook/introduction/getting-started.xml
new file mode 100644
index 000000000..755444df9
--- /dev/null
+++ b/docs/src/reference/docbook/introduction/getting-started.xml
@@ -0,0 +1,110 @@
+
+
+ Getting Started
+
+ Learning a new framework is not always straight forward. In this section, we (the Spring Data team)
+ tried to provide, what we think is, an easy to follow guide for starting with Spring Data Key Value module.
+ Of course, feel free to create your own learning 'path' as you see fit and, if possible, please report back
+ any improvements to the documentation that can help others.
+
+
+ First Steps
+
+ As explained in , Spring Data Key Value (SDKV) provides integration
+ between Spring framework and key value (KV) stores. Thus, it is important to become acquainted with both of these
+ frameworks (storages or environments depending on how you want to name them). Throughout the SDKV documentation,
+ each section provides links to resources relevant however, it is best to become familiar with these topics beforehand.
+
+
+ Knowing Spring
+ Spring Data uses heavily Spring framework's core functionality,
+ such as the IoC container,
+ resource abstract or
+ AOP infrastructure. While it is not important
+ to know the Spring APIs, understanding the concepts behind them is. At a minimum, the idea behind IoC should be familiar.
+ These being said, the more knowledge one has about the Spring, the faster she will pick Spring Data Key Value.
+ Besides the very comprehensive (and sometimes disarming) documentation that explains in detail the Spring Framework,
+ there are a lot of articles, blog entries and books on the matter - take a look at the Spring framework
+ home page for more information. In general, this should be the starting point for
+ developers wanting to try Spring DKV.
+
+
+ Knowing NoSQL and Key Value stores
+ NoSQL stores have taken the storage world by storm. It is a vast domain with a plethora of solutions, terms and patterns (to make things worth even the
+ term itself has multiple meanings ).
+ While some of the principles are common, it is crucial that the user is familiar to some degree with the stores supported by SDKV.
+ The best way to get acquainted to this solutions is to read their documentation and follow their examples - it usually doesn't take more then 5-10 minutes
+ to go through them and if you are coming from an RDMBS-only background many times these exercises can be an eye opener.
+
+
+
+ Trying Out The Samples
+ Unfortunately the SDKV project is very young and there are no samples available yet. However we are working on them and plan to make them available
+ as soon as possible. In the meantime however, one can use our test suite as a code example (assuming the documentation is not enough) - we provide extensive
+ integration tests for our code base.
+
+
+
+
+
+
+ Need Help?
+
+ If you encounter issues or you are just looking for an advice, feel free to use one of the links below:
+
+
+
+ Professional Support
+ Professional, from-the-source support, with guaranteed response time, is available from SpringSource ,
+ the company behind Spring Data and Spring.
+
+
+
+
+
+ Following Development
+
+ For information on the Spring Data source code repository, nightly builds and snapshot artifacts please see the Spring Data home
+ page .
+
+ You can help make Spring Data best serve the needs of the Spring community by interacting with developers through the Spring Community
+ forums .
+ If you encounter a bug or want to suggest an improvement,
+ please create a ticket on the Spring Data issue tracker .
+ To stay up to date with the latest news and announcements in the Spring eco system, subscribe to the
+ Spring Community Portal .
+ Lastly, you can follow the SpringSource Data blog or the project team on Twitter
+ (Costin )
+
+
+
\ No newline at end of file
diff --git a/docs/src/reference/docbook/introduction/introduction.xml b/docs/src/reference/docbook/introduction/introduction.xml
new file mode 100644
index 000000000..3e11048f5
--- /dev/null
+++ b/docs/src/reference/docbook/introduction/introduction.xml
@@ -0,0 +1,15 @@
+
+
+
+
+ This document is the reference guide for Spring Data - Key Value Support.
+ It explains Key Value module concepts and semantics and the syntax for various
+ stores namespaces.
+
+ For an introduction to key value stores or Spring, or Spring Data examples, please refer to
+ - this documentation refers only to Spring Data Key Value Support and
+ assumes the user is familiar with the key value storages and Spring concepts.
+
+
+
+
\ No newline at end of file
diff --git a/docs/src/reference/docbook/introduction/requirements.xml b/docs/src/reference/docbook/introduction/requirements.xml
new file mode 100644
index 000000000..6f3c0198e
--- /dev/null
+++ b/docs/src/reference/docbook/introduction/requirements.xml
@@ -0,0 +1,11 @@
+
+ Requirements
+
+ Spring Data Key Value 1.x binaries requires JDK level 6.0 and above,
+ and Spring Framework
+ 3.0.x and above.
+
+ In terms of key value stores, Redis 2.0.x
+ and Riak 0.13 are required.
+
+
\ No newline at end of file
diff --git a/docs/src/reference/docbook/introduction/why-sd-kv.xml b/docs/src/reference/docbook/introduction/why-sd-kv.xml
new file mode 100644
index 000000000..4983b5023
--- /dev/null
+++ b/docs/src/reference/docbook/introduction/why-sd-kv.xml
@@ -0,0 +1,19 @@
+
+
+ Why Spring Data - Key Value?
+
+ The Spring Framework is the leading full-stack Java/JEE
+ application framework. It provides a lightweight container and a
+ non-invasive programming model enabled by the use of dependency
+ injection, AOP, and portable service abstractions.
+
+ NoSQL
+ storages provide an alternative to classical RDBMS for horizontal scalability
+ and speed. In terms of implementation, Key Value stores represent one of the
+ largest (and oldest) member in the NoSQL space.
+
+ The Spring Data Key Value (or SDKV) framework makes it easy to
+ write Spring applications that use a Key Value store by eliminating the redundant
+ tasks and boiler place code required for interacting with the store through
+ Spring's excellent infrastructure support.
+
\ No newline at end of file
diff --git a/docs/src/reference/docbook/preface.xml b/docs/src/reference/docbook/preface.xml
new file mode 100644
index 000000000..dd182d079
--- /dev/null
+++ b/docs/src/reference/docbook/preface.xml
@@ -0,0 +1,9 @@
+
+
+ Preface
+
+ The Spring Data Key-Value project applies core Spring concepts to the development of solutions using a key-value style data store.
+ We provide a "template" as a high-level abstraction for sending and receiving messages.
+ You will notice similarities to the JDBC support in the Spring Framework.
+
+
diff --git a/docs/src/reference/docbook/reference/introduction.xml b/docs/src/reference/docbook/reference/introduction.xml
new file mode 100644
index 000000000..1bba3527a
--- /dev/null
+++ b/docs/src/reference/docbook/reference/introduction.xml
@@ -0,0 +1,10 @@
+
+ Document structure
+
+ This part of the reference documentation explains the core functionality
+ offered by Spring Data Key Value.
+
+ introduces the Redis module feature set.
+ introduces the Riak module feature set.
+
+
\ No newline at end of file
diff --git a/docs/src/reference/docbook/reference/redis-messaging.xml b/docs/src/reference/docbook/reference/redis-messaging.xml
new file mode 100644
index 000000000..7bfbc8508
--- /dev/null
+++ b/docs/src/reference/docbook/reference/redis-messaging.xml
@@ -0,0 +1,200 @@
+
+
+ Redis Messaging/PubSub
+ Spring Data provides dedicated messaging integration for Redis,
+ very similar in functionality and naming to the JMS integration in
+ Spring Framework; in fact, users familiar with the JMS support in Spring, should
+ feel right at home.
+
+ Redis messaging can be roughly divided into two areas of functionality, namely
+ the production or publication and consumption or subscription of messages, hence the shortcut
+ pubsub (Publish/Subscribe). The
+ RedisTemplate class is used for message production.
+ For asynchronous reception similar to
+ Java EE's message-driven bean style, Spring Data provides a dedicated message
+ listener containers that is used to create Message-Driven POJOs
+ (MDPs) and for synchronous reception, the RedisConnection contract.
+
+ The package org.springframework.data.keyvalue.redis.connection and
+ org.springframework.data.keyvalue.redis.listener provide
+ the core functionality for using Redis messaging.
+
+
+ Sending/Publishing messages
+
+ To publish a message, one can use, as with the other operations, either the low-level
+ RedisConnection or the high-level RedisTemplate .
+ Both entities offer the publish method that accepts as argument the message
+ that needs to be sent as well as the destination channel. While RedisConnection
+ requires raw-data (array of bytes), the RedisTemplate allow arbitrary objects to be passed
+ in as messages:
+
+
+
+
+
+ Receiving/Subscribing for messages
+
+ On the receiving side, one can subscribe to one or multiple channels either by naming them directly or by using
+ pattern matching. The latter approach is quite useful as it not only allows multiple subscriptions to be created with
+ one command but to also listen on channels not yet created at subscription time (as long as match the pattern).
+
+
+ At the low-level, RedisConnection offers subscribe and
+ pSubscribe methods that map the Redis commands for subscribing by channel respectively by pattern.
+ Note that multiple channels or patterns can be used as arguments. To change the subscription of a connection or simply query
+ whether it is listening or not, RedisConnection
+ provides getSubscription and isSubscribed method.
+
+ Subscribing commands are synchronized and thus blocking. That is, calling subscribe on a connection will cause
+ the current thread to block as it will start waiting for messages - the thread will be released only if the subscription
+ is canceled, that is an additional thread invokes unsubscribe respectively pUnsubscribe
+ on the same connection. See message listener container below
+ for a solution to these problem.
+
+ As mentioned above, one subscribed a connection starts waiting for messages - no other commands can be invoked on it except
+ for adding new subscriptions or modifying/canceling the existing ones, that is invoking anything else then subscribe ,
+ pSubscribe , unsubscribe , pUnsubscribe or is illegal and will
+ through an exception.
+
+ In order to subscribe for messages, one needs to implement the MessageListener callback: each time
+ a new message arrives, the callback gets invoked and the user code executed through onMessage method.
+ The interface gives access not only to the actual message but to the channel it has been received through and the pattern (if any) used
+ by the subscription to match the channel. This information allows the callee to differentiate between various messages not just by content but
+ also through data.
+
+
+
+ Message Listener Containers
+
+ Due to its blocking nature, low-level subscription is not attractive as it requires connection and thread management for every single
+ listener. To alleviate this problem, Spring Data offers RedisMessageListenerContainer which does all the heavy lifting
+ on behalf of the user - users familiar with EJB and JMS should find the concepts familiar as it is designed as close as possible to the
+ support in Spring Framework and its message-driven POJOs (MDPs)
+
+ RedisMessageListenerContainer acts as a message listener container; it is used to receive messages from a
+ Redis channel and drive the MessageListener that are injected into
+ it. The listener container is responsible for all threading of message
+ reception and dispatches into the listener for processing. A message
+ listener container is the intermediary between an MDP and a messaging
+ provider, and takes care of registering to receive messages, resource acquisition and release,
+ exception conversion and suchlike. This allows you as an application
+ developer to write the (possibly complex) business logic associated with
+ receiving a message (and reacting to it), and delegates
+ boilerplate Redis infrastructure concerns to the framework.
+
+
+ Further more, to minimize the application footprint, RedisMessageListenerContainer performs allows one connection and one thread
+ to be shared by multiple listeners even though they do not share a subscription. Thus no matter how many listeners or channels an application tracks,
+ the runtime cost will remain the same through out its lifetime. Moreover, the container allows runtime configuration changes so one can add or remove
+ listeners while an application is running without the need for restart. Additionally, the container uses a lazy subscription approach, using a
+ RedisConnection only when needed - if all the listeners are unsubscribed, cleanup is automatically performed and the used
+ thread released.
+
+ To help with the asynch manner of messages, the container requires a java.util.concurrent.Executor (
+ or Spring's TaskExecutor ) for dispatching the messages. Depending on the load, the number of listeners or the runtime
+ environment, one should change or tweak the executor to better serve her needs - in particular in managed environments (such as app servers), it is
+ highly recommended to pick a a proper TaskExecutor to take advantage of its runtime.
+
+
+
+ The MessageListenerAdapter
+
+ The MessageListenerAdapter class is the
+ final component in Spring's asynchronous messaging support: in a
+ nutshell, it allows you to expose almost any class
+ as a MDP (there are of course some constraints).
+
+ Consider the following interface definition. Notice that although
+ the interface extends the
+ MessageListener interface,
+ it can still be used as a MDP via the use of the
+ MessageListenerAdapter class. Notice also how the
+ various message handling methods are strongly typed according to the
+ contents of the various
+ Message types that they can receive and
+ handle.
+
+ public interface MessageDelegate {
+
+ void handleMessage(String message);
+
+ void handleMessage(Map message);
+
+ void handleMessage(byte[] message);
+
+ void handleMessage(Serializable message);
+}
+
+ public class DefaultMessageDelegate implements MessageDelegate {
+ // implementation elided for clarity...
+}
+
+ In particular, note how the above implementation of the
+ MessageDelegate interface (the above
+ DefaultMessageDelegate class) has
+ no Redis dependencies at all. It truly is a POJO that
+ we will make into an MDP via the following configuration.
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:redis="http://www.springframework.org/schema/redis"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://www.springframework.org/schema/redis http://www.springframework.org/schema/redis/spring-redis.xsd" >
+
+ <!-- the default ConnectionFactory -->
+ <redis:listener-container>
+ <!-- the method attribute can be skipped as the default method name is "handleMessage" -->
+ <redis:listener ref="listener" method="handleMessage" topic="chatroom" />
+ </redis:listener-container>
+
+ <bean class="redisexample.DefaultMessageDelegate"/>
+ ...
+<beans>
+
+ The listener topic can be either a channel (e.g. topic="chatroom" ) or a pattern (e.g. topic="*room" )
+
+ The example above uses the Redis namespace to declare the message listener container and automatically register the POJOs as listeners. The full blown, beans definition
+ is displayed below:
+
+ <!-- this is the Message Driven POJO (MDP) -->
+<bean id="messageListener" class="org.springframework.data.keyvalue.redis.listener.adapter.MessageListenerAdapter">
+ <constructor-arg>
+ <bean class="redisexample.DefaultMessageDelegate"/>
+ </constructor-arg>
+</bean>
+
+<!-- and this is the message listener container... -->
+<bean id="redisContainer" class="org.springframework.data.keyvalue.redis.listener.RedisMessageListenerContainer">
+ <property name="connectionFactory" ref="connectionFactory"/>
+ <property name="messageListeners">
+ <!-- map of listeners and their associated topics (channels or/and patterns) -->
+ <map>
+ <entry key-ref="messageListener">
+ <bean class="org.springframework.data.keyvalue.redis.listener.ChannelTopic">
+ <constructor-arg value="chatroom">
+ </bean>
+ </entry>
+ </map>
+ </property>
+</bean>
+
+ Each time a message is received, the adapter automatically performs
+ translation (using the configured RedisSerializer )
+ between the low-level format and the required object type transparently. Any exception caused by the method invocation
+ is caught and handled by the container (by default, being logged).
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/src/reference/docbook/reference/redis.xml b/docs/src/reference/docbook/reference/redis.xml
new file mode 100644
index 000000000..df2ece116
--- /dev/null
+++ b/docs/src/reference/docbook/reference/redis.xml
@@ -0,0 +1,415 @@
+
+
+ Redis support
+
+ One of the key value stores supported by SDKV is Redis .
+ To quote the project home page:
+
+ Redis is an advanced key-value store. It is similar to memcached but the dataset is not volatile, and values can be strings,
+ exactly like in memcached, but also lists, sets, and ordered sets. All this data types can be manipulated with atomic operations
+ to push/pop elements, add/remove elements, perform server side union, intersection, difference between sets, and so forth.
+ Redis supports different kind of sorting abilities.
+
+ Spring Data Key Value provides easy configuration and access to Redis from Spring application. Offers both low-level and
+ high-level abstraction for interacting with the store, freeing the user from infrastructural concerns.
+
+
+
+ Redis Requirements
+ SDKV requires Redis 2.0 or above (Redis 2.2 is recommended) and Java SE 6.0 or above.
+ In terms of language bindings (or connectors), SDKV integrates with Jedis ,
+ JRedis and RJC , three popular open source Java libraries for Redis.
+ If you are aware of any other connector that we should be integrating is, please send us feedback.
+
+
+
+
+ Redis Support High Level View
+
+ The Redis support provides several components (in order of dependencies):
+
+ Low-Level Abstractions - for configuring and handling communication with Redis through the various connector libraries supported as
+ described in .
+ High-Level Abstractions - providing a generified, user friendly template classes for interacting with Redis.
+ explains the abstraction builds on top of the low-level Connection API to handle the
+ infrastructural concerns and object conversion.
+ Support Classes - that offer reusable components (built on the aforementioned abstractions) such as
+ java.util.Collection backed by Redis as documented in
+
+
+ For most tasks, the high-level abstractions and support services are the best choice. Note that at any point, one can move between layers - for example, it's very
+ easy to get a hold of the low level connection (or even the native libray) to communicate directly with Redis.
+
+
+
+ Connecting to Redis
+
+ One of the first tasks when using Redis and Spring is to connect to the store through the IoC container. To do that, a Java connector (or binding) is required;
+ currently SDKV has support for Jedis and JRedis. No matter the library one chooses, there only one set of SDKV API that one needs to use that behaves consistently
+ across all connectors, namely the org.springframework.data.keyvalue.redis.connection package and its
+ RedisConnection and RedisConnectionFactory interfaces for working respectively for retrieving active
+ connection to Redis.
+
+
+ RedisConnection and RedisConnectionFactory
+
+ RedisConnection provides the building block for Redis communication as it handles the communication with the Redis back-end.
+ It also automatically translates the underlying connecting library exceptions to Spring's consistent DAO exception
+ hierarchy so one can switch the connectors
+ without any code changes as the operation semantics remain the same.
+
+ For the corner cases where the native library API is required, RedisConnection provides a dedicated method
+ getNativeConnection which returns the raw, underlying object used for communication.
+
+ Active RedisConnection are created through RedisConnectionFactory . In addition, the factories act as
+ PersistenceExceptionTranslator meaning once declared, allow one to do transparent exception translation for example through the use of the
+ @Repository annotation and AOP. For more information see the dedicated
+ section in Spring Framework documentation.
+
+ Depending on the underlying configuration, the factory can return a new connection or an existing connection (in case a pool is used).
+
+
+ The easiest way to work with a RedisConnectionFactory is to configure the appropriate connector through the IoC container and
+ inject it into the using class.
+
+
+ Connector features
+
+ Unfortunately, currently, not connectors support all of Redis features - in particular JRedis does not have support for hashes yet though this is currently being worked on.
+ When invoking a method on the Connection API that is unsupported by the underlying library, a UnsupportedOperationException
+ is thrown.
+ This situation is likely to be fixed in the future, as the various connectors mature.
+
+
+
+
+ Configuring Jedis connector
+
+ Jedis is one of the connectors supported by the Key Value module through the
+ org.springframework.data.keyvalue.redis.connection.jedis package. In its simples form, the Jedis configuration looks as follow:
+
+
+
+
+
+
+ ]]>
+
+ For production use however, one might want to tweak the settings such as the host or password:
+
+
+
+
+
+ ]]>
+
+
+
+
+ Configuring JRedis connector
+
+ JRedis is another popular, open-source connector supported by SDKV through the
+ org.springframework.data.keyvalue.redis.connection.jredis package.
+ Since JRedis itself does not support (yet) Redis 2.x commands, SDKV uses an updated fork available
+ here .
+
+ A typical JRedis configuration can looks like this:
+
+
+
+
+
+ ]]>
+
+ As one can note, the configuration is quite similar to the Jedis one.
+
+ Currently, JRedis does not have support for binary keys. This forces the JredisConnection to perform encoding internally
+ (through base64 schema). In practice, this means it's safe to read/write arbitrary data however
+ the Redis key stored values will differ from the decoded ones, even in the simplest cases, since everything (no matter the format) is encoded. This will not be
+ the case for Redis values.
+ This issue is currently being addressed in the JRedis project and once fixed, will be incorporated by Spring Data Redis.
+
+
+
+
+
+ Configuring RJC connector
+
+ RJC is the third, open-source connector supported by SDKV through the
+ org.springframework.data.keyvalue.redis.connection.rjc package.
+
+ Similar to the other connectors, a typical RJC configuration can looks like this:
+
+
+
+
+
+ ]]>
+
+ As one can note, the configuration is quite similar to the Jredis or Jedis one.
+
+ Currently, RJC does not have support for binary keys. This forces the RjcConnection to perform encoding internally
+ (through base64 schema). In practice, this means it's safe to read/write arbitrary data however
+ the Redis key stored values will differ from the decoded ones, even in the simplest cases, since everything (no matter the format) is encoded. This will not be
+ the case for Redis values.
+ This issue is currently being addressed in the RJC project and once fixed, will be incorporated by Spring Data Redis.
+
+
+
+
+
+
+
+ Working with Objects through RedisTemplate
+
+ Most users are likely to use RedisTemplate and its coresponding package org.springframework.data.keyvalue.redis.core - the
+ template is in fact the central class of the Redis module due to its rich feature set.
+ The template offers a high-level abstraction for Redis interaction - while RedisConnection offer low level methods that accept and return
+ binary values (byte arrays), the template takes care of serialization and connection management, freeing the user from dealing with such details.
+
+ Moreover, the template provides operations views (following the grouping from Redis command reference )
+ that offer rich, generified interfaces for working against a certain type or certain key (through the KeyBound interfaces) as described below:
+
+
+ Operational views
+
+
+
+
+
+
+
+ Interface
+ Description
+
+
+
+
+
+
+
+ ValueOperations
+ Redis string (or value) operations
+
+
+ ListOperations
+ Redis list operations
+
+
+ SetOperations
+ Redis set operations
+
+
+ ZSetOperations
+ Redis zset (or sorted set) operations
+
+
+ HashOperations
+ Redis hash operations
+
+
+
+
+
+ BoundValueOperations
+ Redis string (or value) key bound operations
+
+
+ BoundListOperations
+ Redis list key bound operations
+
+
+ BoundSetOperations
+ Redis set key bound operations
+
+
+ BoundZSetOperations
+ Redis zset (or sorted set) key bound operations
+
+
+ BoundHashOperations
+ Redis hash key bound operations
+
+
+
+
+
+ Once configured, the template is thread-safe and can be reused across multiple instances.
+
+ Out of the box, RedisTemplate uses a Java-based serializer for most of its operations. This means that any object written or read by the template will be
+ serializer/deserialized through Java. The serialization mechanism can be easily changed on the template and the Redis module offers several implementations available in the
+ org.springframework.data.keyvalue.redis.serializer package - see for more information.
+ Note that the template requires all keys to be non-null - values can be null as long as the underlying
+ serializer accepts them; read the javadoc of each serializer for more information.
+
+ For cases where a certain template view is needed, one the view as a dependency and inject the template: the container will automatically perform the conversion
+ eliminating the opsFor[X] calls:
+
+
+
+
+
+
+
+
+
+ ...
+ ]]>
+
+ template;
+
+ // inject the template as ListOperations
+ @Autowired
+ private ListOperations listOps;
+
+ public void addLink(String userId, URL url) {
+ listOps.leftPush(userId, url.toExternalForm());
+ }
+}]]>
+
+
+
+ String-focused convenience classes
+
+ Since it's quite the keys and values stored in Redis can be java.lang.String , the Redis modules provides two extensions to RedisConnection
+ and RedisTemplate respectively the StringRedisConnection (and its DefaultStringRedisConnection implementation)
+ and StringRedisTemplate as a convenient one-stop solution
+ for intensive String operations. In addition to be bound to String keys, the template and the connection use the
+ StringRedisSerializer underneath which means the stored keys and values are human readable (assuming the same encoding is used both in Redis and your code).
+ For example:
+
+
+
+
+
+
+
+
+
+ ...
+ ]]>
+
+
+
+
+ As with the other Spring templates, RedisTemplate and StringRedisTemplate allow the developer to talk directly to Redis through
+ the RedisCallback interface: this gives complete control to the developer as it talks directly to the RedisConnection .
+
+
+ () {
+
+ public Object doInRedis(RedisConnection connection) throws DataAccessException {
+ Long size = connection.dbSize();
+ ...
+ }
+ });
+}]]>
+
+
+
+ Serializers
+
+ From the framework perspective, the data stored in Redis are just bytes. While Redis itself supports various types, for the most part these refer to the way the data is stored
+ rather then what it represents. It is up to the user to decide whether the information gets translated into Strings or any other objects. The conversion between the user (custom)
+ types and raw data (and vice-versa) is handled in SDKV Redis through the RedisSerializer interface
+ (package org.springframework.data.keyvalue.redis.serializer ) which as the name implies, takes care of the serialization process. Multiple implementations are
+ available out of the box, two of which have been already mentioned before in this documentation: the StringRedisSerializer and
+ the JdkSerializationRedisSerializer . However one can use OxmSerializer for Object/XML mapping through Spring 3
+ OXM support or JacksonJsonRedisSerializer for storing
+ data in JSON format. Do note that the storage format is not limited only to values - it can be used for keys, values or hashes
+ without any restrictions.
+
+
+
+
+
+ Support Classes
+
+ Package org.springframework.data.keyvalue.redis.support offers various reusable components that rely on Redis as a backing store. Curently the package contains
+ various JDK-based interface implementations on top of Redis such as atomic
+ counters and JDK Collections .
+
+ The atomic counters make it easy to wrap Redis key incrementation while the collections allow easy management of Redis keys with minimal storage exposure or API leakage: in particular
+ the RedisSet and RedisZSet interfaces offer easy access to the set operations supported by Redis such as
+ intersection and union while RedisList implements the List ,
+ Queue and Deque contracts (and their equivalent blocking siblings) on top of Redis, exposing the storage as a
+ FIFO (First-In-First-Out) , LIFO (Last-In-First-Out) or capped collection with minimal configuration:
+
+
+
+
+
+
+
+
+
+ ]]>
+
+ queue;
+
+ public void addTag(String tag) {
+ queue.push(tag);
+ }
+}]]>
+
+ As shown in the example above, the consuming code is decoupled from the actual storage implementation - in fact there is no indication that Redis is used underneath. This makes moving from
+ development to production environments transparent and highly increases testability (the Redis implementation can just as well be replaced with an in-memory one).
+
+
+
+ Roadmap ahead
+
+ Spring Data Redis project is in its early stages. We are interested in feedback, knowing what your use cases are, what are the common patters you encounter so that the Redis module
+ better serves your needs. Do contact us using the channels mentioned above, we are interested in hearing from you!
+
+
\ No newline at end of file
diff --git a/docs/src/reference/docbook/reference/riak.xml b/docs/src/reference/docbook/reference/riak.xml
new file mode 100644
index 000000000..6c5acdc66
--- /dev/null
+++ b/docs/src/reference/docbook/reference/riak.xml
@@ -0,0 +1,547 @@
+
+
+ Riak Support
+
+ Riak is a Key/Value datastore that supports Internet-scale data replication for high performance and high availability. Spring Data Key/Value (SDKV) provides access to the Riak datastore over the HTTP REST API using a built-in driver based on Spring 3.0's RestTemplate . In addition to making Key/Value datastore access easier from Java, the RiakTemplate has been designed, from the ground up, to be used from alternative JVM languages like Groovy or JRuby .
+
+ Since the SDKV support for Riak uses the stateless REST API, there are no connection factories to manage or other stateful objects to keep tabs on. The helper you'll spend the most time working with is likely the thread-safe RiakTemplate or RiakKeyValueTemplate . Your choice of which to use will depend on how you want to manage buckets and keys. SDKV supports two ways to interact with Riak. If you want to use the convention you're likely already familiar with, namely of storing an entry with a given key in a "bucket" by passing the bucket and key name separately, you'll want to use the RiakTemplate . If you want to use a single object to represent your bucket and key pair, you can use the RiakKeyValueTemplate . It supports a key object that is encoded using one of several different methods:
+
+ Using a String - You can concatenate two strings, separated by a colon: "mybucket:mykey".
+ Using a BucketKeyPair - You can pass an instance of BucketKeyPair , like SimpleBucketKeyPair .
+ Using a Map - You can pass a Map with keys for "bucket" and "key".
+
+
+
+
+ Configuring the RiakTemplate
+
+ This is likely the easiest path to using SDKV for Riak, as the bucket and key are passed separately. The examples that follow will assume you're using this version of the the template.
+
+ There are only two options you need to set to specify the Riak server to use in your RiakTemplate object: "defaultUri" and "mapReduceUri". Encoded with the URI should be placeholders for the bucket and the key, which will be filled in by the RestTemplate when the request is made.
+
+ You can also turn the internal, ETag-based object cache off by setting useCache="false" . It's generally recommended, however, to leave the internal cache on as the ETag matching will pick up any changes made to the entry on the Riak side and your application will benefit from greatly-increased performance for often-requested objects.
+
+
+
+
+
+
+ ]]>
+
+
+
+ Advanced Template Configuration
+
+ There are a couple additional properties on the RiakTemplate that can be changed from their defaults. If you want to specify your own ConversionService to use when converting objects for storage inside Riak, then set it on the "conversionService" property:
+
+
+
+
+
+
+
+ ]]>
+
+
+ Depending on the application, it might be useful to set default Quality-of-Service parameters. In Riak paralance, these are the "dw", "w", and "r" parameters . They can be set to an integer representing the number of vnodes that need to report having received the data before declaring the operation a success, or the string "one", "all", or (the default) "quorum". These values can be overridden by passing a different set of QosParameters to the set/get operation you're performing.
+
+
+
+
+
+
+
+ ]]>
+
+
+ You can also set a specific ClassLoader to use when loading objects from Riak. Just set the classLoader property:
+
+
+
+
+
+
+ ]]>
+
+
+
+
+
+
+
+ Working with Objects using the RiakTemplate
+
+ One of the primary goals of the SDKV project is to make accessing Key/Value stores easier for the developer by taking away the mundane tasks of basic IO, buffering, type conversion, exception handling, and sundry other logistical concerns so the developer can focus on creating great applications. SDKV for Riak works toward this goal by making basic persistence and data access as easy as using a Map .
+
+
+ Saving data into Riak
+
+ To store data in Riak, use one of the six different set methods:
+
+
+
+ Additionally, there is a setWithMetaData method that takes a Map of metadata that will be set as the outgoing HTTP headers. To set custom metadata , your key should be prefixed with X-Riak-Meta- e.g. X-Riak-Meta-Custom-Header .
+
+
+ Letting Riak generate the key
+
+ Riak has the ability to generate random IDs for you when storing objects. The RiakTemplate exposes this capability via the put method. It will return the ID it generated for you as a String .
+
+
+
+
+
+
+ Retrieving data from Riak
+
+ Retrieving data from Riak is just as easy. There are actually 13 different get methods on RiakTemplate that give the developer a wide range options for accessing and converting your data.
+
+ Assuming you've stored a POJO using an appropriate set method, you can retrieve that object from Riak using a get :
+
+
+
+
+
+
+ Linking Entries
+
+ Riak has the ability to link entries together using an arbitrary tag . This relationship information is stored in the Link header. The RiakTemplate exposes a method for linking entries together called link . Its usage is quite simple:
+
+ A link is uni-directional, so keep in mind that the bucket and key you pass first should be that of the child (or target) object and the second set of bucket/key pairs you pass to the link method is the source of the relationship. It's this second entry that will receive an updated Link header that points to the child or target entry.
+
+
+
+ Now, querying the metadata on the entry at sourcebucket:sourcekey will result in a Link header that points to the child object: </riak/childbucket/childkey>; riaktag="tagname"
+
+
+
+
+ Link Walking
+
+ When entries are linked together in Riak, those relationships can be efficiently traversed on the server using a feature called Link Walking . Rather than requesting each object in a link's relationship individually, a link walk pulls all the related objects at once and sends that data back to the client as MIME-encoded multipart data. As such, it requires special processing to convert those multiple entries into a List of objects, just as if you had used a get method. If you don't specify a type to convert the objects to, the linkWalk method will try to infer it from the bucket name. If the bucket name is not a valid class name, it will default to using a java.util.Map .
+
+ To link walk a relationship and return a list of custom POJOs, you would do something like this:
+ result = riak.linkWalk("sourcebucket", "sourcekey", "tagname", MyPojo.class);
+ ]]>
+
+
+
+
+
+ Map/Reduce
+
+ Riak supports Map/Reduce functionality in a couple different ways. You can specify the Javascript source to execute (termed "anonymous" Javascript), you can reference some Javascript already stored in Riak at a specfic bucket and key, or you can reference an Erlang module and function. The Map/Reduce support in SDKV covers all these bases by giving you meaningful abstractions over the Map/Reduce job that represent the various aspects of the Map/Reduce process.
+
+ At the highest level, every Map/Reduce request is represented by a MapReduceJob . The MapReduceJob represents the inputs , the phases , and the optional arg to send to Riak to execute the Map/Reduce job. The toJson method is responsible for serializing the entire job into the appropriate JSON data to send to Riak.
+
+
+
+
+ Defining Phases
+
+ Map/Reduce operations in Riak are broken up into phases. Phases contain a MapReduceOperation . There are currently two implementations to handle Javascript or Erlang M/R operations: JavascriptMapReduceOperation and ErlangMapReduceOperation .
+
+ An example Map/Reduce job defining a single "map" phase defined in anonymous Javascript might look like this:
+ bucket = new ArrayList() {{
+ add("mybucket");
+}};
+
+job.addInputs(bucket); // M/R the entire bucket
+
+MapReduceOperation mapOper = new JavascriptMapReduceOperation("function(v){ ...M/R function body... }");
+MapReducePhase mapPhase = new RiakMapReducePhase("map", "javascript", mapOper);
+
+job.addPhase(mapPhase);
+ ]]>
+
+
+
+
+ Executing and Working with the Result
+
+ To execute a configured job on your Riak server, use either the synchronous execute or asynchronous submit methods of your configured RiakTemplate :
+
+
+
+...or...
+
+List o = riak.execute(job, MyPojo.class); // Coerce to given type
+
+...or...
+
+Future> f = riak.submit(job); // Job runs in a separate thread
+ ]]>
+
+
+
+
+
+ Managing Bucket Properties
+
+ It's sometimes useful to manage settings like the Quality-of-Service parameters w and dw (write and durable write thresholds) and the n_val setting at the bucket level. It's also possible to list the keys in a particular bucket by calling the getBucketSchema method, passing true as the second parameter, which tells the RiakTemplate to list the keys.
+
+ To list the keys in a bucket, you would do something like this:
+
+ schema = riak.getBucketSchema("mybucket", true);
+List keys = schema.get("keys")
+for(String key : keys) {
+ ...do something with each key...
+}
+ ]]>
+
+
+ To update the bucket settings, pass a Map of properties:
+
+ props = new HashMap();
+props.put("n_val", 6);
+props.put("dw", 3);
+
+riak.updateBucketSchema("mybucket", props);
+ ]]>
+
+ Only the properties specified in the passed-in Map will be updated. Properties that have already been set in previous operations and not specified in this operation will be unaffected.
+
+
+
+
+
+ Asynchronous Access
+
+ SDKV for Riak also includes an asynchronous version of most of the methods available to the RiakTemplate , whose method calls are all synchronous. The asynchronous version of the template is called AsyncRiakTemplate .
+
+
+ Template Configuration
+
+ The AsyncRiakTemplate has the same basic configuration properties as the synchronous RiakTemplate . The only other property specific to the AsyncRiakTemplate you might want to configure is the thread pool the template uses to execute tasks asynchronously (by default a cached ThreadPoolExecutor ). Set your ExecutorService on the template's workerPool property.
+
+
+
+
+ Callbacks
+
+ Using the asynchronous Riak support in SDKV means you'll be relying on callbacks to execute your business logic when the requested operation is completed. All asynchronous operations follow a similar pattern:
+
+ They are named similarly to their synchronous counterparts.
+ They take a AsyncKeyValueStoreOperation<?, ?> as a final parameter.
+ They return a Future<?> .
+
+
+
+ To perform an asynchronous get on a JSON-serialized Map object which returns a custom object from the callback, you'd do something like:
+ future = riak.get("mybucket", "mykey", new AsyncKeyValueStoreOperation() {
+
+ MyObject obj = new MyObject();
+
+ MyObject completed(KeyValueStoreMetaData meta, Map result) {
+ obj.setName(result.get("name"));
+ return obj;
+ }
+
+ MyObject failed(Throwable error) {
+ obj.setError(error);
+ return obj;
+ }
+
+});
+
+// Maybe do other work while waiting...
+MyObject obj = future.get();
+ ]]>
+
+
+
+
+
+
+ Groovy Builder Support
+
+ If your application uses Groovy, either in a standalone context, or as part of a Grails application, then you could benefit from using the Groovy RiakBuilder that comes with SDKV for Riak. Underneath, it uses the AsyncRiakTemplate . To use the RiakBuilder , pass the constructor a configured AsyncRiakTemplate .
+
+ Instances of RiakBuilder are NOT thread-safe and should not be shared across threads.
+
+ The RiakBuilder implements an easy-to-use DSL for interacting with Riak. It doesn't implement the full set of methods available on the underlying AsyncRiakTemplate but a subset. The methods that the RiakBuilder responds to are:
+
+ set
+ setAsBytes
+ put
+ get
+ getAsBytes
+ getAsType
+ containsKey
+ delete
+ foreach
+
+
+
+
+ Riak DSL Usage
+
+ The following example illustrates the different uses of the Riak DSL, including batching requests together into a logical group, using a default bucket name (the node directly beneath riak will be considered the default bucket to use for the contained operations unless a different one is specified on the operation itself):
+ meta.key }}
+ put(value: [test: "value"]) { completed { v, meta -> meta.key }}
+ put(value: [test: "value"]) { completed { v, meta -> meta.key }}
+ put(value: [test: "value"]) { completed { v, meta -> meta.key }}
+
+ mapreduce {
+ query {
+ map(arg: [test: "arg", alist: [1, 2, 3, 4]]) {
+ source "function(v, keyInfo, arg){ return [1]; }"
+ }
+ reduce {
+ source "function(v){ return Riak.reduceSum(v); }"
+ }
+ }
+ failed { it.printStackTrace() }
+ }
+ }
+}
+def results = riak.results
+
+riak.foreach(bucket: "test") {
+ completed { v, meta ->
+ riak.delete(bucket: "test", key: meta.key)
+ }
+}
+ ]]>
+
+
+ Some important things to note from this example:
+
+ Each operation in the Riak DSL has two callbacks: completed and failed .
+ The completed closure is passed either the result object, or, if your closure is defined with two parameters, the result object and the metadata associated with that entry.
+ Operations can be enclosed in an arbitrarily-named closure which the builder interprets as a default bucket name (in this case, the node "test" tells the builder to use the bucket name "test" for a default, unless one is specified on one of the enclosed operations).
+ Each operation within a builder's execution will be accumulated inside the special results property. Code that needs to know the output of individual operations within the batch can get access to that object through this property. Note that this means that RiakBuilder instances are NOT thread-safe.
+
+
+
+ Even though the Riak DSL uses an asynchronous template underneath, all operations performed through the DSL will, by default, block until complete. To get a truly asynchronous operation, pass the parameter wait: 0 (or give a meaningful timeout in milliseconds to wait for the operation to complete) on the operation.
+
+
+ QosParameters on Riak DSL Operations
+
+ You can pass QosParameters to Riak DSL operations by simply defining them as parameters to the operation:
+
+
+
+
+
+ Working with Riak DSL Output
+
+ The output of DSL operations will either be passed to the configured completed callback, or be returned to the caller if no callback is specified. In the example above, the mapreduce operation has no completed closure. Therefore, the return of the reduce phase is simply passed back to the builder, which makes that output available on the special results property.
+
+ To gain access to the operation's results immediately, simply assign it to a variable:
+
+
+ If you add a non-zero wait value to the operation, "myobj" will contain a Future<?> rather than the result object itself.
+
+
+
+
+
+
+
+ Working with streams
+
+ SDKV for Riak includes a couple of useful helper objects to make reading and writing plain text or binary data in Riak really easy. If you want to store a file in Riak, then you can create a RiakOutputStream and simply write your data to it (making sure to call the "flush" method, which actually sends the data to Riak).
+
+
+
+ Reading data from Riak is similarly easy. SDKV provides a java.io.File subclass that represents a resource in Riak. There's also a Spring IO Resource abstraction called RiakResource that can be used anywhere a Resource is required. There's also an InputStream implementation called RiakInputStream .
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/src/reference/resources/css/highlight.css b/docs/src/reference/resources/css/highlight.css
new file mode 100644
index 000000000..ffefef72d
--- /dev/null
+++ b/docs/src/reference/resources/css/highlight.css
@@ -0,0 +1,35 @@
+/*
+ code highlight CSS resemblign the Eclipse IDE default color schema
+ @author Costin Leau
+*/
+
+.hl-keyword {
+ color: #7F0055;
+ font-weight: bold;
+}
+
+.hl-comment {
+ color: #3F5F5F;
+ font-style: italic;
+}
+
+.hl-multiline-comment {
+ color: #3F5FBF;
+ font-style: italic;
+}
+
+.hl-tag {
+ color: #3F7F7F;
+}
+
+.hl-attribute {
+ color: #7F007F;
+}
+
+.hl-value {
+ color: #2A00FF;
+}
+
+.hl-string {
+ color: #2A00FF;
+}
\ No newline at end of file
diff --git a/docs/src/reference/resources/css/manual.css b/docs/src/reference/resources/css/manual.css
new file mode 100644
index 000000000..77569070a
--- /dev/null
+++ b/docs/src/reference/resources/css/manual.css
@@ -0,0 +1,99 @@
+@IMPORT url("highlight.css");
+
+html {
+ padding: 0pt;
+ margin: 0pt;
+}
+
+body {
+ margin-left: 10%;
+ margin-right: 10%;
+ font-family: Arial, Sans-serif;
+}
+
+div {
+ margin: 0pt;
+}
+
+p {
+ text-align: justify;
+}
+
+hr {
+ border: 1px solid gray;
+ background: gray;
+}
+
+h1,h2,h3,h4 {
+ color: #234623;
+ font-family: Arial, Sans-serif;
+}
+
+pre {
+ line-height: 1.0;
+ color: black;
+}
+
+pre.programlisting {
+ font-size: 10pt;
+ padding: 7pt 3pt;
+ border: 1pt solid black;
+ background: #eeeeee;
+ clear: both;
+}
+
+div.table {
+ margin: 1em;
+ padding: 0.5em;
+ text-align: center;
+}
+
+div.table table {
+ display: table;
+ width: 100%;
+}
+
+div.table td {
+ padding-left: 7px;
+ padding-right: 7px;
+}
+
+.sidebar {
+ float: right;
+ margin: 10px 0 10px 30px;
+ padding: 10px 20px 20px 20px;
+ width: 33%;
+ border: 1px solid black;
+ background-color: #F4F4F4;
+ font-size: 14px;
+}
+
+.mediaobject {
+ padding-top: 30px;
+ padding-bottom: 30px;
+}
+
+.legalnotice {
+ font-family: Verdana, Arial, helvetica, sans-serif;
+ font-size: 12px;
+ font-style: italic;
+}
+
+p.releaseinfo {
+ font-size: 100%;
+ font-weight: bold;
+ font-family: Verdana, Arial, helvetica, sans-serif;
+ padding-top: 10px;
+}
+
+p.pubdate {
+ font-size: 120%;
+ font-weight: bold;
+ font-family: Verdana, Arial, helvetica, sans-serif;
+}
+
+span.productname {
+ font-size: 200%;
+ font-weight: bold;
+ font-family: Verdana, Arial, helvetica, sans-serif;
+}
diff --git a/docs/src/reference/resources/images/admon/blank.png b/docs/src/reference/resources/images/admon/blank.png
new file mode 100644
index 000000000..764bf4f0c
Binary files /dev/null and b/docs/src/reference/resources/images/admon/blank.png differ
diff --git a/docs/src/reference/resources/images/admon/caution.gif b/docs/src/reference/resources/images/admon/caution.gif
new file mode 100644
index 000000000..d9f5e5b1b
Binary files /dev/null and b/docs/src/reference/resources/images/admon/caution.gif differ
diff --git a/docs/src/reference/resources/images/admon/caution.png b/docs/src/reference/resources/images/admon/caution.png
new file mode 100644
index 000000000..5b7809ca4
Binary files /dev/null and b/docs/src/reference/resources/images/admon/caution.png differ
diff --git a/docs/src/reference/resources/images/admon/caution.tif b/docs/src/reference/resources/images/admon/caution.tif
new file mode 100644
index 000000000..4a282948c
Binary files /dev/null and b/docs/src/reference/resources/images/admon/caution.tif differ
diff --git a/docs/src/reference/resources/images/admon/draft.png b/docs/src/reference/resources/images/admon/draft.png
new file mode 100644
index 000000000..0084708c9
Binary files /dev/null and b/docs/src/reference/resources/images/admon/draft.png differ
diff --git a/docs/src/reference/resources/images/admon/home.gif b/docs/src/reference/resources/images/admon/home.gif
new file mode 100644
index 000000000..6784f5bb0
Binary files /dev/null and b/docs/src/reference/resources/images/admon/home.gif differ
diff --git a/docs/src/reference/resources/images/admon/home.png b/docs/src/reference/resources/images/admon/home.png
new file mode 100644
index 000000000..cbb711de7
Binary files /dev/null and b/docs/src/reference/resources/images/admon/home.png differ
diff --git a/docs/src/reference/resources/images/admon/important.gif b/docs/src/reference/resources/images/admon/important.gif
new file mode 100644
index 000000000..6795d9a81
Binary files /dev/null and b/docs/src/reference/resources/images/admon/important.gif differ
diff --git a/docs/src/reference/resources/images/admon/important.png b/docs/src/reference/resources/images/admon/important.png
new file mode 100644
index 000000000..ad57f6f72
Binary files /dev/null and b/docs/src/reference/resources/images/admon/important.png differ
diff --git a/docs/src/reference/resources/images/admon/important.tif b/docs/src/reference/resources/images/admon/important.tif
new file mode 100644
index 000000000..184de6371
Binary files /dev/null and b/docs/src/reference/resources/images/admon/important.tif differ
diff --git a/docs/src/reference/resources/images/admon/next.gif b/docs/src/reference/resources/images/admon/next.gif
new file mode 100644
index 000000000..aa1516e69
Binary files /dev/null and b/docs/src/reference/resources/images/admon/next.gif differ
diff --git a/docs/src/reference/resources/images/admon/next.png b/docs/src/reference/resources/images/admon/next.png
new file mode 100644
index 000000000..45835bf89
Binary files /dev/null and b/docs/src/reference/resources/images/admon/next.png differ
diff --git a/docs/src/reference/resources/images/admon/note.gif b/docs/src/reference/resources/images/admon/note.gif
new file mode 100644
index 000000000..f329d359e
Binary files /dev/null and b/docs/src/reference/resources/images/admon/note.gif differ
diff --git a/docs/src/reference/resources/images/admon/note.png b/docs/src/reference/resources/images/admon/note.png
new file mode 100644
index 000000000..ad57f6f72
Binary files /dev/null and b/docs/src/reference/resources/images/admon/note.png differ
diff --git a/docs/src/reference/resources/images/admon/note.tif b/docs/src/reference/resources/images/admon/note.tif
new file mode 100644
index 000000000..08644d6b5
Binary files /dev/null and b/docs/src/reference/resources/images/admon/note.tif differ
diff --git a/docs/src/reference/resources/images/admon/prev.gif b/docs/src/reference/resources/images/admon/prev.gif
new file mode 100644
index 000000000..64ca8f3c7
Binary files /dev/null and b/docs/src/reference/resources/images/admon/prev.gif differ
diff --git a/docs/src/reference/resources/images/admon/prev.png b/docs/src/reference/resources/images/admon/prev.png
new file mode 100644
index 000000000..cf24654f8
Binary files /dev/null and b/docs/src/reference/resources/images/admon/prev.png differ
diff --git a/docs/src/reference/resources/images/admon/tip.gif b/docs/src/reference/resources/images/admon/tip.gif
new file mode 100644
index 000000000..823f2b417
Binary files /dev/null and b/docs/src/reference/resources/images/admon/tip.gif differ
diff --git a/docs/src/reference/resources/images/admon/tip.png b/docs/src/reference/resources/images/admon/tip.png
new file mode 100644
index 000000000..ad57f6f72
Binary files /dev/null and b/docs/src/reference/resources/images/admon/tip.png differ
diff --git a/docs/src/reference/resources/images/admon/tip.tif b/docs/src/reference/resources/images/admon/tip.tif
new file mode 100644
index 000000000..4a3d8c75f
Binary files /dev/null and b/docs/src/reference/resources/images/admon/tip.tif differ
diff --git a/docs/src/reference/resources/images/admon/toc-blank.png b/docs/src/reference/resources/images/admon/toc-blank.png
new file mode 100644
index 000000000..6ffad17a0
Binary files /dev/null and b/docs/src/reference/resources/images/admon/toc-blank.png differ
diff --git a/docs/src/reference/resources/images/admon/toc-minus.png b/docs/src/reference/resources/images/admon/toc-minus.png
new file mode 100644
index 000000000..abbb020c8
Binary files /dev/null and b/docs/src/reference/resources/images/admon/toc-minus.png differ
diff --git a/docs/src/reference/resources/images/admon/toc-plus.png b/docs/src/reference/resources/images/admon/toc-plus.png
new file mode 100644
index 000000000..941312ce0
Binary files /dev/null and b/docs/src/reference/resources/images/admon/toc-plus.png differ
diff --git a/docs/src/reference/resources/images/admon/up.gif b/docs/src/reference/resources/images/admon/up.gif
new file mode 100644
index 000000000..aabc2d016
Binary files /dev/null and b/docs/src/reference/resources/images/admon/up.gif differ
diff --git a/docs/src/reference/resources/images/admon/up.png b/docs/src/reference/resources/images/admon/up.png
new file mode 100644
index 000000000..07634de26
Binary files /dev/null and b/docs/src/reference/resources/images/admon/up.png differ
diff --git a/docs/src/reference/resources/images/admon/warning.gif b/docs/src/reference/resources/images/admon/warning.gif
new file mode 100644
index 000000000..c6acdec60
Binary files /dev/null and b/docs/src/reference/resources/images/admon/warning.gif differ
diff --git a/docs/src/reference/resources/images/admon/warning.png b/docs/src/reference/resources/images/admon/warning.png
new file mode 100644
index 000000000..ef3e10f40
Binary files /dev/null and b/docs/src/reference/resources/images/admon/warning.png differ
diff --git a/docs/src/reference/resources/images/admon/warning.tif b/docs/src/reference/resources/images/admon/warning.tif
new file mode 100644
index 000000000..7b6611ec7
Binary files /dev/null and b/docs/src/reference/resources/images/admon/warning.tif differ
diff --git a/docs/src/reference/resources/images/callouts/1.png b/docs/src/reference/resources/images/callouts/1.png
new file mode 100644
index 000000000..7d473430b
Binary files /dev/null and b/docs/src/reference/resources/images/callouts/1.png differ
diff --git a/docs/src/reference/resources/images/callouts/10.png b/docs/src/reference/resources/images/callouts/10.png
new file mode 100644
index 000000000..997bbc824
Binary files /dev/null and b/docs/src/reference/resources/images/callouts/10.png differ
diff --git a/docs/src/reference/resources/images/callouts/11.png b/docs/src/reference/resources/images/callouts/11.png
new file mode 100644
index 000000000..ce47dac3f
Binary files /dev/null and b/docs/src/reference/resources/images/callouts/11.png differ
diff --git a/docs/src/reference/resources/images/callouts/12.png b/docs/src/reference/resources/images/callouts/12.png
new file mode 100644
index 000000000..31daf4e2f
Binary files /dev/null and b/docs/src/reference/resources/images/callouts/12.png differ
diff --git a/docs/src/reference/resources/images/callouts/13.png b/docs/src/reference/resources/images/callouts/13.png
new file mode 100644
index 000000000..14021a89c
Binary files /dev/null and b/docs/src/reference/resources/images/callouts/13.png differ
diff --git a/docs/src/reference/resources/images/callouts/14.png b/docs/src/reference/resources/images/callouts/14.png
new file mode 100644
index 000000000..64014b75f
Binary files /dev/null and b/docs/src/reference/resources/images/callouts/14.png differ
diff --git a/docs/src/reference/resources/images/callouts/15.png b/docs/src/reference/resources/images/callouts/15.png
new file mode 100644
index 000000000..0d65765fc
Binary files /dev/null and b/docs/src/reference/resources/images/callouts/15.png differ
diff --git a/docs/src/reference/resources/images/callouts/2.png b/docs/src/reference/resources/images/callouts/2.png
new file mode 100644
index 000000000..5d09341b2
Binary files /dev/null and b/docs/src/reference/resources/images/callouts/2.png differ
diff --git a/docs/src/reference/resources/images/callouts/3.png b/docs/src/reference/resources/images/callouts/3.png
new file mode 100644
index 000000000..ef7b70047
Binary files /dev/null and b/docs/src/reference/resources/images/callouts/3.png differ
diff --git a/docs/src/reference/resources/images/callouts/4.png b/docs/src/reference/resources/images/callouts/4.png
new file mode 100644
index 000000000..adb8364eb
Binary files /dev/null and b/docs/src/reference/resources/images/callouts/4.png differ
diff --git a/docs/src/reference/resources/images/callouts/5.png b/docs/src/reference/resources/images/callouts/5.png
new file mode 100644
index 000000000..4d7eb4600
Binary files /dev/null and b/docs/src/reference/resources/images/callouts/5.png differ
diff --git a/docs/src/reference/resources/images/callouts/6.png b/docs/src/reference/resources/images/callouts/6.png
new file mode 100644
index 000000000..0ba694af6
Binary files /dev/null and b/docs/src/reference/resources/images/callouts/6.png differ
diff --git a/docs/src/reference/resources/images/callouts/7.png b/docs/src/reference/resources/images/callouts/7.png
new file mode 100644
index 000000000..472e96f8a
Binary files /dev/null and b/docs/src/reference/resources/images/callouts/7.png differ
diff --git a/docs/src/reference/resources/images/callouts/8.png b/docs/src/reference/resources/images/callouts/8.png
new file mode 100644
index 000000000..5e60973c2
Binary files /dev/null and b/docs/src/reference/resources/images/callouts/8.png differ
diff --git a/docs/src/reference/resources/images/callouts/9.png b/docs/src/reference/resources/images/callouts/9.png
new file mode 100644
index 000000000..a0676d26c
Binary files /dev/null and b/docs/src/reference/resources/images/callouts/9.png differ
diff --git a/docs/src/reference/resources/images/logo.png b/docs/src/reference/resources/images/logo.png
new file mode 100644
index 000000000..a9f6d959e
Binary files /dev/null and b/docs/src/reference/resources/images/logo.png differ
diff --git a/docs/src/reference/resources/images/xdev-spring_logo.jpg b/docs/src/reference/resources/images/xdev-spring_logo.jpg
new file mode 100644
index 000000000..622962ee3
Binary files /dev/null and b/docs/src/reference/resources/images/xdev-spring_logo.jpg differ
diff --git a/docs/src/reference/resources/xsl/fopdf.xsl b/docs/src/reference/resources/xsl/fopdf.xsl
new file mode 100644
index 000000000..4b3692f19
--- /dev/null
+++ b/docs/src/reference/resources/xsl/fopdf.xsl
@@ -0,0 +1,449 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ,
+
+
+
+
+ (
+
+ )
+
+
+
+ Copyright © 2010-2011
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -5em
+ -5em
+
+
+
+
+
+
+
+
+
+
+ Spring Data Key Value ( )
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+
+ 1
+ 1
+ 0
+
+
+
+
+
+ book toc
+
+
+
+ 2
+
+
+
+
+
+
+
+
+
+ 0
+ 0
+ 0
+
+
+ 5mm
+ 10mm
+ 10mm
+
+ 15mm
+ 10mm
+ 0mm
+
+ 18mm
+ 18mm
+
+
+ 0pc
+
+
+
+
+ justify
+ false
+
+
+ 11
+ 8
+
+
+ 1.4
+
+
+
+
+
+
+ 0.8em
+
+
+
+
+
+ 17.4cm
+
+
+
+ 4pt
+ 4pt
+ 4pt
+ 4pt
+
+
+
+ 0.1pt
+ 0.1pt
+
+
+
+
+ 1
+
+
+
+
+
+
+
+ left
+ bold
+
+
+ pt
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0.8em
+ 0.8em
+ 0.8em
+
+
+ pt
+
+ 0.1em
+ 0.1em
+ 0.1em
+
+
+ 0.6em
+ 0.6em
+ 0.6em
+
+
+ pt
+
+ 0.1em
+ 0.1em
+ 0.1em
+
+
+ 0.4em
+ 0.4em
+ 0.4em
+
+
+ pt
+
+ 0.1em
+ 0.1em
+ 0.1em
+
+
+
+
+ bold
+
+
+ pt
+
+ false
+ 0.4em
+ 0.6em
+ 0.8em
+
+
+
+
+
+
+
+
+ pt
+
+
+
+
+ 1em
+ 1em
+ 1em
+ #444444
+ solid
+ 0.1pt
+ 0.5em
+ 0.5em
+ 0.5em
+ 0.5em
+ 0.5em
+ 0.5em
+
+
+
+ 1
+
+ #F0F0F0
+
+
+
+
+
+ 0
+ 1
+
+
+ 90
+
+
+
+
+ '1'
+ src/docbkx/resources/images/admons/
+
+
+
+
+
+ figure after
+ example before
+ equation before
+ table before
+ procedure before
+
+
+
+ 1
+
+
+
+ 0.8em
+ 0.8em
+ 0.8em
+ 0.1em
+ 0.1em
+ 0.1em
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/src/reference/resources/xsl/highlight-fo.xsl b/docs/src/reference/resources/xsl/highlight-fo.xsl
new file mode 100644
index 000000000..f0b5dd941
--- /dev/null
+++ b/docs/src/reference/resources/xsl/highlight-fo.xsl
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/src/reference/resources/xsl/highlight.xsl b/docs/src/reference/resources/xsl/highlight.xsl
new file mode 100644
index 000000000..c63c4765c
--- /dev/null
+++ b/docs/src/reference/resources/xsl/highlight.xsl
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/src/reference/resources/xsl/html-custom.xsl b/docs/src/reference/resources/xsl/html-custom.xsl
new file mode 100644
index 000000000..575267e3c
--- /dev/null
+++ b/docs/src/reference/resources/xsl/html-custom.xsl
@@ -0,0 +1,145 @@
+
+
+
+
+
+
+
+
+
+ '5'
+ '1'
+
+
+ 1
+
+
+ 1
+
+
+ 1
+ 0
+ 1
+
+
+
+ images/admon/
+ .png
+
+ 120
+ images/callouts/
+ .png
+
+
+ css/manual.css
+ text/css
+ book toc,title
+
+ text-align: left
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 3
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Begin Google Analytics code
+
+
+ End Google Analytics code
+
+
+
+
+ Begin LoopFuse code
+
+
+ End LoopFuse code
+
+
+
\ No newline at end of file
diff --git a/docs/src/reference/resources/xsl/html-single-custom.xsl b/docs/src/reference/resources/xsl/html-single-custom.xsl
new file mode 100644
index 000000000..264d9a81f
--- /dev/null
+++ b/docs/src/reference/resources/xsl/html-single-custom.xsl
@@ -0,0 +1,142 @@
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+ 1
+
+
+ 1
+ 0
+ 1
+
+
+
+ images/admon/
+ .png
+
+ 120
+ images/callouts/
+ .png
+
+
+ css/manual.css
+ text/css
+ book toc,title
+
+ text-align: left
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Begin Google Analytics code
+
+
+End Google Analytics code
+
+
+
+
+Begin LoopFuse code
+
+
+End LoopFuse code
+
+
+
\ No newline at end of file
diff --git a/docs/src/reference/resources/xsl/html.xsl b/docs/src/reference/resources/xsl/html.xsl
new file mode 100644
index 000000000..2b0f8d6e2
--- /dev/null
+++ b/docs/src/reference/resources/xsl/html.xsl
@@ -0,0 +1,107 @@
+
+
+
+
+
+
+
+
+
+
+ 0
+ 0
+ 1
+
+
+
+
+
+ book toc
+
+
+
+ 3
+
+
+
+
+ 1
+
+
+
+
+
+
+ 1
+
+
+ 90
+
+
+
+
+ 1
+ images/admons/
+
+
+
+ figure after
+ example before
+ equation before
+ table before
+ procedure before
+
+
+
+ ,
+
+
+
+ ( )
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/src/reference/resources/xsl/html_chunk.xsl b/docs/src/reference/resources/xsl/html_chunk.xsl
new file mode 100644
index 000000000..29b35d281
--- /dev/null
+++ b/docs/src/reference/resources/xsl/html_chunk.xsl
@@ -0,0 +1,221 @@
+
+
+
+
+
+
+
+
+
+ '5'
+ '1'
+ 0
+ 0
+ 1
+
+
+
+ book toc
+ qandaset toc
+
+
+ 3
+
+
+ 1
+
+
+
+
+ 1
+ 90
+
+
+
+
+ 1
+ images/admons/
+
+
+
+ figure after
+ example before
+ equation before
+ table before
+ procedure before
+
+
+
+ ,
+
+
+
+ ( )
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/src/reference/resources/xsl/pdf-custom.xsl b/docs/src/reference/resources/xsl/pdf-custom.xsl
new file mode 100644
index 000000000..2b2290622
--- /dev/null
+++ b/docs/src/reference/resources/xsl/pdf-custom.xsl
@@ -0,0 +1,522 @@
+
+
+
+
+
+
+
+
+
+
+ '1'
+ images/admon/
+ .png
+
+
+
+
+ 24pt
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -5em
+ -5em
+
+
+
+
+
+ book toc,title
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ please define productname in your docbook file!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+ 0
+ 1
+ 1
+
+
+
+
+ 0
+ 0
+ 0
+
+
+
+ false
+
+
+ 11
+ 8
+
+
+ 1.4
+
+
+
+ left
+ bold
+
+
+ pt
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0.8em
+ 0.8em
+ 0.8em
+
+
+ pt
+
+ 0.1em
+ 0.1em
+ 0.1em
+
+
+ 0.6em
+ 0.6em
+ 0.6em
+
+
+ pt
+
+ 0.1em
+ 0.1em
+ 0.1em
+
+
+ 0.4em
+ 0.4em
+ 0.4em
+
+
+ pt
+
+ 0.1em
+ 0.1em
+ 0.1em
+
+
+ 0.3em
+ 0.3em
+ 0.3em
+
+
+ pt
+
+ 0.1em
+ 0.1em
+ 0.1em
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 4pt
+ 4pt
+ 4pt
+ 4pt
+
+
+
+ 0.1pt
+ 0.1pt
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ pt
+
+
+
+
+ 1em
+ 1em
+ 1em
+ 0.1em
+ 0.1em
+ 0.1em
+
+ #444444
+ solid
+ 0.1pt
+ 0.5em
+ 0.5em
+ 0.5em
+ 0.5em
+ 0.5em
+ 0.5em
+
+
+
+ 1
+
+ #F0F0F0
+
+
+
+ 0.1em
+ 0.1em
+ 0.1em
+ 0.1em
+ 0.1em
+ 0.1em
+
+
+
+ 0.5em
+ 0.5em
+ 0.5em
+ 0.1em
+ 0.1em
+ 0.1em
+ always
+
+
+
+
+
+ normal
+ italic
+
+
+ pt
+
+ false
+ 0.1em
+ 0.1em
+ 0.1em
+
+
+
+
+
+ 0
+ 1
+
+
+ 90
+
+
+
+
+
+ figure after
+ example after
+ equation before
+ table before
+ procedure before
+
+
+
+ 1
+
+ 0pt
+
+
+ 3
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 000000000..f5a5999b1
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1,20 @@
+## Dependecies Version
+
+# Logging
+log4jVersion = 1.2.16
+slf4jVersion = 1.6.1
+
+# Common libraries
+springVersion = 3.0.5.RELEASE
+jacksonVersion = 1.6.4
+
+# Testing
+junitVersion = 4.8.1
+mockitoVersion = 1.8.5
+
+
+# --------------------
+# Project wide version
+# --------------------
+springDataKeyValueVersion=1.0.0.BUILD-SNAPSHOT
+version = 'springDataKeyValueVersion'
\ No newline at end of file
diff --git a/gradlew b/gradlew
new file mode 100755
index 000000000..d8809f151
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,168 @@
+#!/bin/bash
+
+##############################################################################
+## ##
+## Gradle wrapper script for UN*X ##
+## ##
+##############################################################################
+
+# Uncomment those lines to set JVM options. GRADLE_OPTS and JAVA_OPTS can be used together.
+# GRADLE_OPTS="$GRADLE_OPTS -Xmx512m"
+# JAVA_OPTS="$JAVA_OPTS -Xmx512m"
+
+GRADLE_APP_NAME=Gradle
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+ echo "$*"
+}
+
+die ( ) {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+esac
+
+# Attempt to set JAVA_HOME if it's not already set.
+if [ -z "$JAVA_HOME" ] ; then
+ if $darwin ; then
+ [ -z "$JAVA_HOME" -a -d "/Library/Java/Home" ] && export JAVA_HOME="/Library/Java/Home"
+ [ -z "$JAVA_HOME" -a -d "/System/Library/Frameworks/JavaVM.framework/Home" ] && export JAVA_HOME="/System/Library/Frameworks/JavaVM.framework/Home"
+ else
+ javaExecutable="`which javac`"
+ [ -z "$javaExecutable" -o "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ] && die "JAVA_HOME not set and cannot find javac to deduce location, please set JAVA_HOME."
+ # readlink(1) is not available as standard on Solaris 10.
+ readLink=`which readlink`
+ [ `expr "$readLink" : '\([^ ]*\)'` = "no" ] && die "JAVA_HOME not set and readlink not available, please set JAVA_HOME."
+ javaExecutable="`readlink -f \"$javaExecutable\"`"
+ javaHome="`dirname \"$javaExecutable\"`"
+ javaHome=`expr "$javaHome" : '\(.*\)/bin'`
+ export JAVA_HOME="$javaHome"
+ fi
+fi
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched.
+if $cygwin ; then
+ [ -n "$JAVACMD" ] && JAVACMD=`cygpath --unix "$JAVACMD"`
+ [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+fi
+
+STARTER_MAIN_CLASS=org.gradle.wrapper.GradleWrapperMain
+CLASSPATH=`dirname "$0"`/gradle/wrapper/gradle-wrapper.jar
+WRAPPER_PROPERTIES=`dirname "$0"`/gradle/wrapper/gradle-wrapper.properties
+# Determine the Java command to use to start the JVM.
+if [ -z "$JAVACMD" ] ; then
+ if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ else
+ JAVACMD="java"
+ fi
+fi
+if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+if [ -z "$JAVA_HOME" ] ; then
+ warn "JAVA_HOME environment variable is not set"
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query businessSystem maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add GRADLE_APP_NAME to the JAVA_OPTS as -Xdock:name
+if $darwin; then
+ JAVA_OPTS="$JAVA_OPTS -Xdock:name=$GRADLE_APP_NAME"
+# we may also want to set -Xdock:image
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ JAVA_HOME=`cygpath --path --mixed "$JAVA_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+GRADLE_APP_BASE_NAME=`basename "$0"`
+
+exec "$JAVACMD" $JAVA_OPTS $GRADLE_OPTS \
+ -classpath "$CLASSPATH" \
+ -Dorg.gradle.appname="$GRADLE_APP_BASE_NAME" \
+ -Dorg.gradle.wrapper.properties="$WRAPPER_PROPERTIES" \
+ $STARTER_MAIN_CLASS \
+ "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 000000000..4855abb88
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,82 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem ##
+@rem Gradle startup script for Windows ##
+@rem ##
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Uncomment those lines to set JVM options. GRADLE_OPTS and JAVA_OPTS can be used together.
+@rem set GRADLE_OPTS=%GRADLE_OPTS% -Xmx512m
+@rem set JAVA_OPTS=%JAVA_OPTS% -Xmx512m
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.\
+
+@rem Find java.exe
+set JAVA_EXE=java.exe
+if not defined JAVA_HOME goto init
+
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+echo.
+goto end
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set STARTER_MAIN_CLASS=org.gradle.wrapper.GradleWrapperMain
+set CLASSPATH=%DIRNAME%\gradle\wrapper\gradle-wrapper.jar
+set WRAPPER_PROPERTIES=%DIRNAME%\gradle\wrapper\gradle-wrapper.properties
+
+set GRADLE_OPTS=%JAVA_OPTS% %GRADLE_OPTS% -Dorg.gradle.wrapper.properties="%WRAPPER_PROPERTIES%"
+
+@rem Execute Gradle
+"%JAVA_EXE%" %GRADLE_OPTS% -classpath "%CLASSPATH%" %STARTER_MAIN_CLASS% %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+if not "%OS%"=="Windows_NT" echo 1 > nul | choice /n /c:1
+
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit "%ERRORLEVEL%"
+exit /b "%ERRORLEVEL%"
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
\ No newline at end of file
diff --git a/maven.gradle b/maven.gradle
new file mode 100644
index 000000000..996d1b693
--- /dev/null
+++ b/maven.gradle
@@ -0,0 +1,119 @@
+apply plugin: 'maven'
+
+// Create a source jar for uploading
+task sourceJar(type: Jar, dependsOn: classes) {
+ classifier = 'sources'
+ from sourceSets.main.allSource
+}
+
+// Create a javadoc jar for uploading
+task javadocJar(type: Jar, dependsOn: javadoc) {
+ classifier = 'javadoc'
+ from javadoc.destinationDir
+}
+
+artifacts {
+ archives sourceJar
+ archives javadocJar
+}
+
+// Configuration for SpringSource s3 maven deployer
+configurations {
+ deployerJars
+}
+dependencies {
+ deployerJars "org.springframework.build.aws:org.springframework.build.aws.maven:3.0.0.RELEASE"
+}
+
+// Remove the archive configuration from the runtime configuration, so that anything added to archives
+// (such as the source jar) is no longer included in the runtime classpath
+configurations.default.extendsFrom = [configurations.runtime] as Set
+// Add the main jar into the default configuration
+artifacts { 'default' jar }
+
+gradle.taskGraph.whenReady {graph ->
+ if (graph.hasTask(uploadArchives)) {
+ // check properties defined and fail early
+ s3AccessKey
+ s3SecretAccessKey
+ }
+}
+
+def deployer = null
+
+uploadArchives {
+ description = "Maven deploy of archives artifacts to SpringSource Maven repos" // url appended below
+ group = "Distribution"
+ // Maven deployment
+ def releaseRepositoryUrl = "file://${project.properties.mavenSyncRepoDir}"
+ def milestoneRepositoryUrl = 's3://maven.springframework.org/milestone'
+ def snapshotRepositoryUrl = 's3://maven.springframework.org/snapshot'
+
+ // add a configuration with a classpath that includes our s3 maven deployer
+ configurations { deployerJars }
+ dependencies {
+ deployerJars "org.springframework.build.aws:org.springframework.build.aws.maven:3.0.0.RELEASE"
+ }
+
+ deployer = repositories.mavenDeployer {
+ configuration = configurations.deployerJars
+ // releaseBuild
+ if (releaseBuild) {
+ logger.info("Deploying to local Maven repo " + releaseRepositoryUrl)
+ // "mavenSyncRepoDir" should be set in properties
+ repository(url: releaseRepositoryUrl)
+ } else {
+ s3credentials = [userName: project.properties.s3AccessKey, passphrase: project.properties.s3SecretAccessKey]
+ repository(url: milestoneRepositoryUrl) {
+ authentication(s3credentials)
+ }
+ snapshotRepository(url: snapshotRepositoryUrl) {
+ authentication(s3credentials)
+ }
+ }
+ }
+
+ customizePom(deployer.pom)
+}
+
+install {
+ customizePom(repositories.mavenInstaller.pom)
+}
+
+def customizePom(pom) {
+ def optionalDeps = ['log4j','jsr250-api']
+
+ //pom.scopeMappings.addMapping(10, configurations.provided, 'provided')
+ pom.whenConfigured { p ->
+ // Remove test scope dependencies from published poms
+ p.dependencies = p.dependencies.findAll {it.scope != 'test'}
+
+ // Flag optional deps
+
+ p.dependencies.findAll { dep ->
+ optionalDeps.contains(dep.artifactId) ||
+ dep.groupId.startsWith('org.slf4j')
+ }*.optional = true
+
+ }
+
+ pom.project {
+ licenses {
+ license {
+ name 'The Apache Software License, Version 2.0'
+ url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
+ distribution 'repo'
+ }
+ }
+
+ // similar to Spring's configuration
+ dependencies {
+ dependency {
+ artifactId = groupId = 'commons-logging'
+ scope = 'compile'
+ optional = 'true'
+ version = '1.1.1'
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/settings.gradle b/settings.gradle
new file mode 100644
index 000000000..78739438f
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1,8 @@
+rootProject.name = 'spring-data-key-value'
+
+include 'docs'
+include "spring-data-keyvalue-core",
+ "spring-data-redis",
+ "spring-data-riak"
+
+docs = findProject(':docs')
\ No newline at end of file
diff --git a/spring-data-keyvalue-core/.classpath b/spring-data-keyvalue-core/.classpath
new file mode 100644
index 000000000..e49979c1c
--- /dev/null
+++ b/spring-data-keyvalue-core/.classpath
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/spring-data-keyvalue-core/.project b/spring-data-keyvalue-core/.project
new file mode 100644
index 000000000..145c84059
--- /dev/null
+++ b/spring-data-keyvalue-core/.project
@@ -0,0 +1,17 @@
+
+
+ spring-data-core
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/spring-data-keyvalue-core/.settings/org.eclipse.jdt.core.prefs b/spring-data-keyvalue-core/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 000000000..f924903e3
--- /dev/null
+++ b/spring-data-keyvalue-core/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,13 @@
+#
+#Thu Apr 21 21:26:44 EEST 2011
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.compliance=1.5
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.source=1.5
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
diff --git a/spring-data-keyvalue-core/build.gradle b/spring-data-keyvalue-core/build.gradle
new file mode 100644
index 000000000..e69de29bb
diff --git a/spring-data-keyvalue-core/src/main/java/org/springframework/data/keyvalue/UncategorizedKeyvalueStoreException.java b/spring-data-keyvalue-core/src/main/java/org/springframework/data/keyvalue/UncategorizedKeyvalueStoreException.java
new file mode 100644
index 000000000..c65d6ac1f
--- /dev/null
+++ b/spring-data-keyvalue-core/src/main/java/org/springframework/data/keyvalue/UncategorizedKeyvalueStoreException.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2010 the original author or authors.
+ *
+ * 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;
+
+import org.springframework.dao.UncategorizedDataAccessException;
+
+public class UncategorizedKeyvalueStoreException extends UncategorizedDataAccessException {
+
+ public UncategorizedKeyvalueStoreException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+
+}
diff --git a/spring-data-keyvalue-core/template.mf b/spring-data-keyvalue-core/template.mf
new file mode 100644
index 000000000..d553c5f67
--- /dev/null
+++ b/spring-data-keyvalue-core/template.mf
@@ -0,0 +1,19 @@
+Bundle-SymbolicName: org.springframework.data.keyvalue
+Bundle-Name: Spring data Key-Value
+Bundle-Vendor: SpringSource
+Bundle-ManifestVersion: 2
+Import-Package:
+ sun.reflect;version="0";resolution:=optional
+Import-Template:
+ org.springframework.beans.*;version="[3.0.0, 4.0.0)",
+ org.springframework.core.*;version="[3.0.0, 4.0.0)",
+ org.springframework.dao.*;version="[3.0.0, 4.0.0)",
+ org.springframework.util.*;version="[3.0.0, 4.0.0)",
+ org.springframework.data.core.*;version="[1.0.0, 2.0.0)",
+ org.springframework.data.core.*;version="[1.0.0, 2.0.0)",
+ org.springframework.data.persistence.*;version="[1.0.0, 2.0.0)",
+ org.aopalliance.*;version="[1.0.0, 2.0.0)";resolution:=optional,
+ org.apache.commons.logging.*;version="[1.1.1, 2.0.0)",
+ org.w3c.dom.*;version="0"
+
+
diff --git a/spring-data-redis/.classpath b/spring-data-redis/.classpath
new file mode 100644
index 000000000..3848cd547
--- /dev/null
+++ b/spring-data-redis/.classpath
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/spring-data-redis/.gitignore b/spring-data-redis/.gitignore
new file mode 100644
index 000000000..7ee4e668b
--- /dev/null
+++ b/spring-data-redis/.gitignore
@@ -0,0 +1,2 @@
+
+*.log
\ No newline at end of file
diff --git a/spring-data-redis/.project b/spring-data-redis/.project
new file mode 100644
index 000000000..7ab2483ad
--- /dev/null
+++ b/spring-data-redis/.project
@@ -0,0 +1,16 @@
+
+
+ spring-data-redis
+
+
+
+ org.eclipse.jdt.core.javanature
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+
diff --git a/spring-data-redis/.settings/org.eclipse.jdt.core.prefs b/spring-data-redis/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 000000000..9811d21e9
--- /dev/null
+++ b/spring-data-redis/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,13 @@
+#
+#Fri Jul 01 15:44:20 EEST 2011
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.source=1.6
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
diff --git a/spring-data-redis/build.gradle b/spring-data-redis/build.gradle
new file mode 100644
index 000000000..cd6427bf6
--- /dev/null
+++ b/spring-data-redis/build.gradle
@@ -0,0 +1,17 @@
+repositories {
+ mavenRepo name: "ext-snapshots", urls: "http://springframework.svn.sourceforge.net/svnroot/springframework/repos/repo-ext/"
+}
+
+dependencies {
+ compile project(":spring-data-keyvalue-core")
+ compile "redis.clients:jedis:$jedisVersion"
+ compile("org.jredis:jredis-anthonylauzon:$jredisVersion") { optional = true }
+ compile("org.idevlab:rjc:$rjcVersion") { optional = true }
+ compile("org.springframework:spring-oxm:$springVersion") { optional = true }
+ compile("commons-beanutils:commons-beanutils-core:1.8.3") { optional = true }
+ testCompile("javax.annotation:jsr250-api:1.0") { optional = true }
+ testCompile("com.thoughtworks.xstream:xstream:1.3") { optional = true }
+}
+
+sourceCompatibility = 1.6
+targetCompatibility = 1.6
\ No newline at end of file
diff --git a/spring-data-redis/gradle.properties b/spring-data-redis/gradle.properties
new file mode 100644
index 000000000..74a43fc38
--- /dev/null
+++ b/spring-data-redis/gradle.properties
@@ -0,0 +1,13 @@
+# Dependencies properties
+jedisVersion = 2.0.0
+jredisVersion = 03122010
+rjcVersion= 0.6.4
+
+
+# Manifest properties
+
+## OSGi ranges
+spring.range = "[3.0.0, 4.0.0)"
+jedis.range = "[2.0.0, 2.0.0]"
+jackson.range = "[1.6, 2.0.0)"
+rjc.range = "[0.6.4, 0.6.4]"
diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/RedisConnectionFailureException.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/RedisConnectionFailureException.java
new file mode 100644
index 000000000..4a49658cb
--- /dev/null
+++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/RedisConnectionFailureException.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2010-2011 the original author or authors.
+ *
+ * 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.redis;
+
+import org.springframework.dao.DataAccessResourceFailureException;
+
+/**
+ * Fatal exception thrown when the Redis connection fails completely.
+ *
+ * @author Mark Pollack
+ */
+public class RedisConnectionFailureException extends DataAccessResourceFailureException {
+
+ public RedisConnectionFailureException(String msg) {
+ super(msg);
+ }
+
+ public RedisConnectionFailureException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+}
diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/RedisSystemException.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/RedisSystemException.java
new file mode 100644
index 000000000..b72123868
--- /dev/null
+++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/RedisSystemException.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2010-2011 the original author or authors.
+ *
+ * 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.redis;
+
+import org.springframework.data.keyvalue.UncategorizedKeyvalueStoreException;
+
+/**
+ * Exception thrown when we can't classify a Redis exception into one of Spring generic data access exceptions.
+ *
+ * @author Costin Leau
+ */
+public class RedisSystemException extends UncategorizedKeyvalueStoreException {
+
+ public RedisSystemException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+}
diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/config/RedisCollectionParser.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/config/RedisCollectionParser.java
new file mode 100644
index 000000000..c806f8dcb
--- /dev/null
+++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/config/RedisCollectionParser.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2011 the original author or authors.
+ *
+ * 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.redis.config;
+
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.xml.AbstractSimpleBeanDefinitionParser;
+import org.springframework.data.keyvalue.redis.support.collections.RedisCollectionFactoryBean;
+import org.springframework.util.StringUtils;
+import org.w3c.dom.Element;
+
+/**
+ * Parser for the Redis <collection> element.
+ *
+ * @author Costin Leau
+ */
+public class RedisCollectionParser extends AbstractSimpleBeanDefinitionParser {
+
+ @Override
+ protected Class> getBeanClass(Element element) {
+ return RedisCollectionFactoryBean.class;
+ }
+
+ @Override
+ protected void postProcess(BeanDefinitionBuilder beanDefinition, Element element) {
+ String template = element.getAttribute("template");
+ if (StringUtils.hasText(template)) {
+ beanDefinition.addPropertyReference("template", template);
+ }
+ }
+
+ @Override
+ protected boolean isEligibleAttribute(String attributeName) {
+ return super.isEligibleAttribute(attributeName) && (!"template".equals(attributeName));
+ }
+}
diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/config/RedisListenerContainerParser.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/config/RedisListenerContainerParser.java
new file mode 100644
index 000000000..8dca98e68
--- /dev/null
+++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/config/RedisListenerContainerParser.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2011 the original author or authors.
+ *
+ * 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.redis.config;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.support.ManagedMap;
+import org.springframework.beans.factory.xml.AbstractSimpleBeanDefinitionParser;
+import org.springframework.beans.factory.xml.ParserContext;
+import org.springframework.data.keyvalue.redis.listener.ChannelTopic;
+import org.springframework.data.keyvalue.redis.listener.PatternTopic;
+import org.springframework.data.keyvalue.redis.listener.RedisMessageListenerContainer;
+import org.springframework.data.keyvalue.redis.listener.Topic;
+import org.springframework.data.keyvalue.redis.listener.adapter.MessageListenerAdapter;
+import org.springframework.util.Assert;
+import org.springframework.util.StringUtils;
+import org.springframework.util.xml.DomUtils;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+
+/**
+ * Parser for the Redis <listener-container> element.
+ *
+ * @author Costin Leau
+ */
+class RedisListenerContainerParser extends AbstractSimpleBeanDefinitionParser {
+
+ @Override
+ protected Class getBeanClass(Element element) {
+ return RedisMessageListenerContainer.class;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
+ // parse attributes (but replace the value assignment with references)
+ NamedNodeMap attributes = element.getAttributes();
+
+ for (int x = 0; x < attributes.getLength(); x++) {
+ Attr attribute = (Attr) attributes.item(x);
+ if (isEligibleAttribute(attribute, parserContext)) {
+ String propertyName = extractPropertyName(attribute.getLocalName());
+ Assert.state(StringUtils.hasText(propertyName),
+ "Illegal property name returned from 'extractPropertyName(String)': cannot be null or empty.");
+ builder.addPropertyReference(propertyName, attribute.getValue());
+ }
+ }
+
+ String phase = element.getAttribute("phase");
+ if (StringUtils.hasText(phase)) {
+ builder.addPropertyValue("phase", phase);
+ }
+
+ postProcess(builder, element);
+
+ // parse nested listeners
+ List listDefs = DomUtils.getChildElementsByTagName(element, "listener");
+
+ if (!listDefs.isEmpty()) {
+ ManagedMap> listeners = new ManagedMap>(
+ listDefs.size());
+ for (Element listElement : listDefs) {
+ Object[] listenerDefinition = parseListener(listElement);
+ listeners.put((BeanDefinition) listenerDefinition[0],
+ (Collection extends BeanDefinition>) listenerDefinition[1]);
+ }
+
+ builder.addPropertyValue("messageListeners", listeners);
+ }
+ }
+
+ @Override
+ protected boolean isEligibleAttribute(String attributeName) {
+ return (!"phase".equals(attributeName));
+ }
+
+ /**
+ * Parses a listener definition. Returns the listener bean reference definition (as the array first entry) and its associated topics (also as bean definitions).
+ *
+ * @param element
+ * @return
+ */
+ private Object[] parseListener(Element element) {
+ Object[] ret = new Object[2];
+
+ BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MessageListenerAdapter.class);
+ builder.addConstructorArgReference(element.getAttribute("ref"));
+
+ String method = element.getAttribute("method");
+ if (StringUtils.hasText(method)){
+ builder.addPropertyValue("defaultListenerMethod", method);
+ }
+
+ String serializer = element.getAttribute("serializer");
+ if (StringUtils.hasText(serializer)){
+ builder.addPropertyReference("serializer", serializer);
+ }
+
+ // assemble topics
+ Collection topics = new ArrayList();
+
+ // get topic
+ String xTopics = element.getAttribute("topic");
+ if (StringUtils.hasText(xTopics)) {
+ String[] array = StringUtils.delimitedListToStringArray(xTopics, " ");
+
+ for (String string : array) {
+ topics.add(string.contains("*") ? new PatternTopic(string) : new ChannelTopic(string));
+ }
+ }
+ ret[0] = builder.getBeanDefinition();
+ ret[1] = topics;
+
+ return ret;
+ }
+
+ @Override
+ protected boolean shouldGenerateId() {
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/config/RedisNamespaceHandler.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/config/RedisNamespaceHandler.java
new file mode 100644
index 000000000..2a136f377
--- /dev/null
+++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/config/RedisNamespaceHandler.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2011 the original author or authors.
+ *
+ * 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.redis.config;
+
+import org.springframework.beans.factory.xml.NamespaceHandler;
+import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
+
+/**
+ * {@link NamespaceHandler} for Spring Data Redis namespace.
+ *
+ * @author Costin Leau
+ */
+class RedisNamespaceHandler extends NamespaceHandlerSupport {
+
+ @Override
+ public void init() {
+ registerBeanDefinitionParser("listener-container", new RedisListenerContainerParser());
+ registerBeanDefinitionParser("collection", new RedisCollectionParser());
+ }
+}
diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/DataType.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/DataType.java
new file mode 100644
index 000000000..f1db9881e
--- /dev/null
+++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/DataType.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2010-2011 the original author or authors.
+ *
+ * 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.redis.connection;
+
+import java.util.EnumSet;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Enumeration of the Redis data types.
+ *
+ * @author Costin Leau
+ */
+public enum DataType {
+
+ NONE("none"), STRING("string"), LIST("list"), SET("set"), ZSET("zset"), HASH("hash");
+
+ private static final Map codeLookup = new ConcurrentHashMap(6);
+
+ static {
+ for (DataType type : EnumSet.allOf(DataType.class))
+ codeLookup.put(type.code, type);
+
+ }
+
+ private final String code;
+
+ DataType(String name) {
+ this.code = name;
+ }
+
+ /**
+ * Returns the code associated with the current enum.
+ *
+ * @return code of this enum
+ */
+ public String code() {
+ return code;
+ }
+
+ /**
+ * Utility method for converting an enum code to an actual enum.
+ *
+ * @param code enum code
+ * @return actual enum corresponding to the given code
+ */
+ public static DataType fromCode(String code) {
+ DataType data = codeLookup.get(code);
+ if (data == null)
+ throw new IllegalArgumentException("unknown data type code");
+ return data;
+ }
+}
diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/DefaultMessage.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/DefaultMessage.java
new file mode 100644
index 000000000..1fd622577
--- /dev/null
+++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/DefaultMessage.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2011 the original author or authors.
+ *
+ * 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.redis.connection;
+
+
+/**
+ * Default message implementation.
+ *
+ * @author Costin Leau
+ */
+public class DefaultMessage implements Message {
+
+ private final byte[] channel;
+ private final byte[] body;
+ private String toString;
+
+ public DefaultMessage(byte[] channel, byte[] body) {
+ this.body = body;
+ this.channel = channel;
+ }
+
+ @Override
+ public byte[] getChannel() {
+ return (channel != null ? channel.clone() : null);
+ }
+
+ @Override
+ public byte[] getBody() {
+ return (body != null ? body.clone() : null);
+ }
+
+ @Override
+ public String toString() {
+ if (toString == null){
+ toString = new String(body);
+ }
+ return toString;
+ }
+}
diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/DefaultSortParameters.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/DefaultSortParameters.java
new file mode 100644
index 000000000..62a34bba1
--- /dev/null
+++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/DefaultSortParameters.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2010-2011 the original author or authors.
+ *
+ * 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 byPattern 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.redis.connection;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ * Default implementation for {@link SortParameters}.
+ *
+ * @author Costin Leau
+ */
+public class DefaultSortParameters implements SortParameters {
+
+ private byte[] byPattern;
+ private Range limit;
+ private final List getPattern = new ArrayList(4);
+ private Order order;
+ private Boolean alphabetic;
+
+ /**
+ * Constructs a new DefaultSortParameters instance.
+ */
+ public DefaultSortParameters() {
+ this(null, null, null, null, null);
+ }
+
+ /**
+ * Constructs a new DefaultSortParameters instance.
+ *
+ * @param limit
+ * @param order
+ * @param alphabetic
+ */
+ public DefaultSortParameters(Range limit, Order order, Boolean alphabetic) {
+ this(null, limit, null, order, alphabetic);
+ }
+
+ /**
+ * Constructs a new DefaultSortParameters instance.
+ *
+ * @param byPattern
+ * @param limit
+ * @param getPattern
+ * @param order
+ * @param alphabetic
+ */
+ public DefaultSortParameters(byte[] byPattern, Range limit, byte[][] getPattern, Order order, Boolean alphabetic) {
+ super();
+ this.byPattern = byPattern;
+ this.limit = limit;
+ this.order = order;
+ this.alphabetic = alphabetic;
+ setGetPattern(getPattern);
+ }
+
+ @Override
+ public byte[] getByPattern() {
+ return byPattern;
+ }
+
+ public void setByPattern(byte[] byPattern) {
+ this.byPattern = byPattern;
+ }
+
+ @Override
+ public Range getLimit() {
+ return limit;
+ }
+
+ public void setLimit(Range limit) {
+ this.limit = limit;
+ }
+
+ @Override
+ public byte[][] getGetPattern() {
+ return getPattern.toArray(new byte[getPattern.size()][]);
+ }
+
+ public void addGetPattern(byte[] gPattern) {
+ getPattern.add(gPattern);
+ }
+
+ public void setGetPattern(byte[][] gPattern) {
+ getPattern.clear();
+
+ for (byte[] bs : gPattern) {
+ getPattern.add(bs);
+ }
+ }
+
+ @Override
+ public Order getOrder() {
+ return order;
+ }
+
+ public void setOrder(Order order) {
+ this.order = order;
+ }
+
+ @Override
+ public Boolean isAlphabetic() {
+ return alphabetic;
+ }
+
+ public void setAlphabetic(Boolean alphabetic) {
+ this.alphabetic = alphabetic;
+ }
+
+ //
+ // builder like methods
+ //
+
+ public DefaultSortParameters order(Order order) {
+ setOrder(order);
+ return this;
+ }
+
+ public DefaultSortParameters alpha() {
+ setAlphabetic(true);
+ return this;
+ }
+
+ public DefaultSortParameters asc() {
+ setOrder(Order.ASC);
+ return this;
+ }
+
+ public DefaultSortParameters desc() {
+ setOrder(Order.DESC);
+ return this;
+ }
+
+ public DefaultSortParameters numeric() {
+ setAlphabetic(false);
+ return this;
+ }
+
+ public DefaultSortParameters get(byte[] pattern) {
+ addGetPattern(pattern);
+ return this;
+ }
+
+ public DefaultSortParameters by(byte[] pattern) {
+ setByPattern(pattern);
+ return this;
+ }
+
+ public DefaultSortParameters limit(long start, long count) {
+ setLimit(new Range(start, count));
+ return this;
+ }
+}
\ No newline at end of file
diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/DefaultStringRedisConnection.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/DefaultStringRedisConnection.java
new file mode 100644
index 000000000..61b973ed3
--- /dev/null
+++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/DefaultStringRedisConnection.java
@@ -0,0 +1,1155 @@
+/*
+ * Copyright 2011 the original author or authors.
+ *
+ * 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.redis.connection;
+
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import org.springframework.data.keyvalue.redis.RedisSystemException;
+import org.springframework.data.keyvalue.redis.serializer.RedisSerializer;
+import org.springframework.data.keyvalue.redis.serializer.SerializationUtils;
+import org.springframework.data.keyvalue.redis.serializer.StringRedisSerializer;
+import org.springframework.util.Assert;
+
+/**
+ * Default implementation of {@link StringRedisConnection}.
+ *
+ * @author Costin Leau
+ */
+public class DefaultStringRedisConnection implements StringRedisConnection {
+
+ private final RedisConnection delegate;
+ private final RedisSerializer serializer;
+
+ /**
+ * Constructs a new DefaultStringRedisConnection instance.
+ * Uses {@link StringRedisSerializer} as underlying serializer.
+ *
+ * @param connection Redis connection
+ */
+ public DefaultStringRedisConnection(RedisConnection connection) {
+ Assert.notNull(connection, "connection is required");
+ this.delegate = connection;
+ this.serializer = new StringRedisSerializer();
+ }
+
+ /**
+ * Constructs a new DefaultStringRedisConnection instance.
+ *
+ * @param connection Redis connection
+ * @param serializer String serializer
+ */
+ public DefaultStringRedisConnection(RedisConnection connection, RedisSerializer serializer) {
+ Assert.notNull(connection, "connection is required");
+ Assert.notNull(connection, "serializer is required");
+ this.delegate = connection;
+ this.serializer = serializer;
+ }
+
+ public Long append(byte[] key, byte[] value) {
+ return delegate.append(key, value);
+ }
+
+ public void bgSave() {
+ delegate.bgSave();
+ }
+
+ public void bgWriteAof() {
+ delegate.bgWriteAof();
+ }
+
+ public List bLPop(int timeout, byte[]... keys) {
+ return delegate.bLPop(timeout, keys);
+ }
+
+ public List bRPop(int timeout, byte[]... keys) {
+ return delegate.bRPop(timeout, keys);
+ }
+
+ public byte[] bRPopLPush(int timeout, byte[] srcKey, byte[] dstKey) {
+ return delegate.bRPopLPush(timeout, srcKey, dstKey);
+ }
+
+ public void close() throws RedisSystemException {
+ delegate.close();
+ }
+
+ public Long dbSize() {
+ return delegate.dbSize();
+ }
+
+ public Long decr(byte[] key) {
+ return delegate.decr(key);
+ }
+
+ public Long decrBy(byte[] key, long value) {
+ return delegate.decrBy(key, value);
+ }
+
+ public Long del(byte[]... keys) {
+ return delegate.del(keys);
+ }
+
+ public void discard() {
+ delegate.discard();
+ }
+
+ public byte[] echo(byte[] message) {
+ return delegate.echo(message);
+ }
+
+ public List exec() {
+ return delegate.exec();
+ }
+
+ public Boolean exists(byte[] key) {
+ return delegate.exists(key);
+ }
+
+ public Boolean expire(byte[] key, long seconds) {
+ return delegate.expire(key, seconds);
+ }
+
+ public Boolean expireAt(byte[] key, long unixTime) {
+ return delegate.expireAt(key, unixTime);
+ }
+
+ public void flushAll() {
+ delegate.flushAll();
+ }
+
+ public void flushDb() {
+ delegate.flushDb();
+ }
+
+ public byte[] get(byte[] key) {
+ return delegate.get(key);
+ }
+
+ public Boolean getBit(byte[] key, long offset) {
+ return delegate.getBit(key, offset);
+ }
+
+ public List getConfig(String pattern) {
+ return delegate.getConfig(pattern);
+ }
+
+ public Object getNativeConnection() {
+ return delegate.getNativeConnection();
+ }
+
+ public byte[] getRange(byte[] key, long start, long end) {
+ return delegate.getRange(key, start, end);
+ }
+
+ public byte[] getSet(byte[] key, byte[] value) {
+ return delegate.getSet(key, value);
+ }
+
+ public Subscription getSubscription() {
+ return delegate.getSubscription();
+ }
+
+ public Boolean hDel(byte[] key, byte[] field) {
+ return delegate.hDel(key, field);
+ }
+
+ public Boolean hExists(byte[] key, byte[] field) {
+ return delegate.hExists(key, field);
+ }
+
+ public byte[] hGet(byte[] key, byte[] field) {
+ return delegate.hGet(key, field);
+ }
+
+ public Map hGetAll(byte[] key) {
+ return delegate.hGetAll(key);
+ }
+
+ public Long hIncrBy(byte[] key, byte[] field, long delta) {
+ return delegate.hIncrBy(key, field, delta);
+ }
+
+ public Set hKeys(byte[] key) {
+ return delegate.hKeys(key);
+ }
+
+ public Long hLen(byte[] key) {
+ return delegate.hLen(key);
+ }
+
+ public List hMGet(byte[] key, byte[]... fields) {
+ return delegate.hMGet(key, fields);
+ }
+
+ public void hMSet(byte[] key, Map hashes) {
+ delegate.hMSet(key, hashes);
+ }
+
+ public Boolean hSet(byte[] key, byte[] field, byte[] value) {
+ return delegate.hSet(key, field, value);
+ }
+
+ public Boolean hSetNX(byte[] key, byte[] field, byte[] value) {
+ return delegate.hSetNX(key, field, value);
+ }
+
+ public List hVals(byte[] key) {
+ return delegate.hVals(key);
+ }
+
+ public Long incr(byte[] key) {
+ return delegate.incr(key);
+ }
+
+ public Long incrBy(byte[] key, long value) {
+ return delegate.incrBy(key, value);
+ }
+
+ public Properties info() {
+ return delegate.info();
+ }
+
+ public boolean isClosed() {
+ return delegate.isClosed();
+ }
+
+ public boolean isQueueing() {
+ return delegate.isQueueing();
+ }
+
+ public boolean isSubscribed() {
+ return delegate.isSubscribed();
+ }
+
+ public Set keys(byte[] pattern) {
+ return delegate.keys(pattern);
+ }
+
+ public Long lastSave() {
+ return delegate.lastSave();
+ }
+
+ public byte[] lIndex(byte[] key, long index) {
+ return delegate.lIndex(key, index);
+ }
+
+ public Long lInsert(byte[] key, Position where, byte[] pivot, byte[] value) {
+ return delegate.lInsert(key, where, pivot, value);
+ }
+
+ public Long lLen(byte[] key) {
+ return delegate.lLen(key);
+ }
+
+ public byte[] lPop(byte[] key) {
+ return delegate.lPop(key);
+ }
+
+ public Long lPush(byte[] key, byte[] value) {
+ return delegate.lPush(key, value);
+ }
+
+ public Long lPushX(byte[] key, byte[] value) {
+ return delegate.lPushX(key, value);
+ }
+
+ public List lRange(byte[] key, long start, long end) {
+ return delegate.lRange(key, start, end);
+ }
+
+ public Long lRem(byte[] key, long count, byte[] value) {
+ return delegate.lRem(key, count, value);
+ }
+
+ public void lSet(byte[] key, long index, byte[] value) {
+ delegate.lSet(key, index, value);
+ }
+
+ public void lTrim(byte[] key, long start, long end) {
+ delegate.lTrim(key, start, end);
+ }
+
+ public List mGet(byte[]... keys) {
+ return delegate.mGet(keys);
+ }
+
+ public void mSet(Map tuple) {
+ delegate.mSet(tuple);
+ }
+
+ public void mSetNX(Map tuple) {
+ delegate.mSetNX(tuple);
+ }
+
+ public void multi() {
+ delegate.multi();
+ }
+
+ public Boolean persist(byte[] key) {
+ return delegate.persist(key);
+ }
+
+ public Boolean move(byte[] key, int dbIndex) {
+ return delegate.move(key, dbIndex);
+ }
+
+ public String ping() {
+ return delegate.ping();
+ }
+
+ public void pSubscribe(MessageListener listener, byte[]... patterns) {
+ delegate.pSubscribe(listener, patterns);
+ }
+
+ public Long publish(byte[] channel, byte[] message) {
+ return delegate.publish(channel, message);
+ }
+
+ public byte[] randomKey() {
+ return delegate.randomKey();
+ }
+
+ public void rename(byte[] oldName, byte[] newName) {
+ delegate.rename(oldName, newName);
+ }
+
+ public Boolean renameNX(byte[] oldName, byte[] newName) {
+ return delegate.renameNX(oldName, newName);
+ }
+
+ public void resetConfigStats() {
+ delegate.resetConfigStats();
+ }
+
+ public byte[] rPop(byte[] key) {
+ return delegate.rPop(key);
+ }
+
+ public byte[] rPopLPush(byte[] srcKey, byte[] dstKey) {
+ return delegate.rPopLPush(srcKey, dstKey);
+ }
+
+ public Long rPush(byte[] key, byte[] value) {
+ return delegate.rPush(key, value);
+ }
+
+ public Long rPushX(byte[] key, byte[] value) {
+ return delegate.rPushX(key, value);
+ }
+
+ public Boolean sAdd(byte[] key, byte[] value) {
+ return delegate.sAdd(key, value);
+ }
+
+ public void save() {
+ delegate.save();
+ }
+
+ public Long sCard(byte[] key) {
+ return delegate.sCard(key);
+ }
+
+ public Set sDiff(byte[]... keys) {
+ return delegate.sDiff(keys);
+ }
+
+ public void sDiffStore(byte[] destKey, byte[]... keys) {
+ delegate.sDiffStore(destKey, keys);
+ }
+
+ public void select(int dbIndex) {
+ delegate.select(dbIndex);
+ }
+
+ public void set(byte[] key, byte[] value) {
+ delegate.set(key, value);
+ }
+
+ public void setBit(byte[] key, long offset, boolean value) {
+ delegate.setBit(key, offset, value);
+ }
+
+ public void setConfig(String param, String value) {
+ delegate.setConfig(param, value);
+ }
+
+ public void setEx(byte[] key, long seconds, byte[] value) {
+ delegate.setEx(key, seconds, value);
+ }
+
+ public Boolean setNX(byte[] key, byte[] value) {
+ return delegate.setNX(key, value);
+ }
+
+ public void setRange(byte[] key, byte[] value, long start) {
+ delegate.setRange(key, value, start);
+ }
+
+ public void shutdown() {
+ delegate.shutdown();
+ }
+
+ public Set sInter(byte[]... keys) {
+ return delegate.sInter(keys);
+ }
+
+ public void sInterStore(byte[] destKey, byte[]... keys) {
+ delegate.sInterStore(destKey, keys);
+ }
+
+ public Boolean sIsMember(byte[] key, byte[] value) {
+ return delegate.sIsMember(key, value);
+ }
+
+ public Set sMembers(byte[] key) {
+ return delegate.sMembers(key);
+ }
+
+ public Boolean sMove(byte[] srcKey, byte[] destKey, byte[] value) {
+ return delegate.sMove(srcKey, destKey, value);
+ }
+
+ public Long sort(byte[] key, SortParameters params, byte[] storeKey) {
+ return delegate.sort(key, params, storeKey);
+ }
+
+ public List sort(byte[] key, SortParameters params) {
+ return delegate.sort(key, params);
+ }
+
+ public byte[] sPop(byte[] key) {
+ return delegate.sPop(key);
+ }
+
+ public byte[] sRandMember(byte[] key) {
+ return delegate.sRandMember(key);
+ }
+
+ public Boolean sRem(byte[] key, byte[] value) {
+ return delegate.sRem(key, value);
+ }
+
+ public Long strLen(byte[] key) {
+ return delegate.strLen(key);
+ }
+
+ public void subscribe(MessageListener listener, byte[]... channels) {
+ delegate.subscribe(listener, channels);
+ }
+
+ public Set sUnion(byte[]... keys) {
+ return delegate.sUnion(keys);
+ }
+
+ public void sUnionStore(byte[] destKey, byte[]... keys) {
+ delegate.sUnionStore(destKey, keys);
+ }
+
+ public Long ttl(byte[] key) {
+ return delegate.ttl(key);
+ }
+
+ public DataType type(byte[] key) {
+ return delegate.type(key);
+ }
+
+ public void unwatch() {
+ delegate.unwatch();
+ }
+
+ public void watch(byte[]... keys) {
+ delegate.watch(keys);
+ }
+
+ public Boolean zAdd(byte[] key, double score, byte[] value) {
+ return delegate.zAdd(key, score, value);
+ }
+
+ public Long zCard(byte[] key) {
+ return delegate.zCard(key);
+ }
+
+ public Long zCount(byte[] key, double min, double max) {
+ return delegate.zCount(key, min, max);
+ }
+
+ public Double zIncrBy(byte[] key, double increment, byte[] value) {
+ return delegate.zIncrBy(key, increment, value);
+ }
+
+ public Long zInterStore(byte[] destKey, Aggregate aggregate, int[] weights, byte[]... sets) {
+ return delegate.zInterStore(destKey, aggregate, weights, sets);
+ }
+
+ public Long zInterStore(byte[] destKey, byte[]... sets) {
+ return delegate.zInterStore(destKey, sets);
+ }
+
+ public Set zRange(byte[] key, long start, long end) {
+ return delegate.zRange(key, start, end);
+ }
+
+ public Set zRangeByScore(byte[] key, double min, double max, long offset, long count) {
+ return delegate.zRangeByScore(key, min, max, offset, count);
+ }
+
+ public Set zRangeByScore(byte[] key, double min, double max) {
+ return delegate.zRangeByScore(key, min, max);
+ }
+
+ public Set zRangeByScoreWithScores(byte[] key, double min, double max, long offset, long count) {
+ return delegate.zRangeByScoreWithScores(key, min, max, offset, count);
+ }
+
+ public Set zRangeByScoreWithScores(byte[] key, double min, double max) {
+ return delegate.zRangeByScoreWithScores(key, min, max);
+ }
+
+ public Set zRangeWithScores(byte[] key, long start, long end) {
+ return delegate.zRangeWithScores(key, start, end);
+ }
+
+ public Set zRevRangeByScore(byte[] key, double min, double max, long offset, long count) {
+ return delegate.zRevRangeByScore(key, min, max, offset, count);
+ }
+
+ public Set zRevRangeByScore(byte[] key, double min, double max) {
+ return delegate.zRevRangeByScore(key, min, max);
+ }
+
+ public Set zRevRangeByScoreWithScores(byte[] key, double min, double max, long offset, long count) {
+ return delegate.zRevRangeByScoreWithScores(key, min, max, offset, count);
+ }
+
+ public Set zRevRangeByScoreWithScores(byte[] key, double min, double max) {
+ return delegate.zRevRangeByScoreWithScores(key, min, max);
+ }
+
+ public Long zRank(byte[] key, byte[] value) {
+ return delegate.zRank(key, value);
+ }
+
+ public Boolean zRem(byte[] key, byte[] value) {
+ return delegate.zRem(key, value);
+ }
+
+ public Long zRemRange(byte[] key, long start, long end) {
+ return delegate.zRemRange(key, start, end);
+ }
+
+ public Long zRemRangeByScore(byte[] key, double min, double max) {
+ return delegate.zRemRangeByScore(key, min, max);
+ }
+
+ public Set zRevRange(byte[] key, long start, long end) {
+ return delegate.zRevRange(key, start, end);
+ }
+
+ public Set zRevRangeWithScores(byte[] key, long start, long end) {
+ return delegate.zRevRangeWithScores(key, start, end);
+ }
+
+ public Long zRevRank(byte[] key, byte[] value) {
+ return delegate.zRevRank(key, value);
+ }
+
+ public Double zScore(byte[] key, byte[] value) {
+ return delegate.zScore(key, value);
+ }
+
+ public Long zUnionStore(byte[] destKey, Aggregate aggregate, int[] weights, byte[]... sets) {
+ return delegate.zUnionStore(destKey, aggregate, weights, sets);
+ }
+
+ public Long zUnionStore(byte[] destKey, byte[]... sets) {
+ return delegate.zUnionStore(destKey, sets);
+ }
+
+ //
+ // String methods
+ //
+
+ private byte[] serialize(String data) {
+ return serializer.serialize(data);
+ }
+
+ private byte[][] serializeMulti(String... keys) {
+ byte[][] ret = new byte[keys.length][];
+
+ for (int i = 0; i < ret.length; i++) {
+ ret[i] = serializer.serialize(keys[i]);
+ }
+
+ return ret;
+ }
+
+ private Map serialize(Map hashes) {
+ Map ret = new LinkedHashMap(hashes.size());
+
+ for (Map.Entry entry : hashes.entrySet()) {
+ ret.put(serializer.serialize(entry.getKey()), serializer.serialize(entry.getValue()));
+ }
+
+ return ret;
+ }
+
+
+ private List deserialize(List data) {
+ return SerializationUtils.deserialize(data, serializer);
+ }
+
+ private Set deserialize(Set data) {
+ return SerializationUtils.deserialize(data, serializer);
+ }
+
+ private String deserialize(byte[] data) {
+ return serializer.deserialize(data);
+ }
+
+ private Set deserializeTuple(Set data) {
+ if (data == null) {
+ return null;
+ }
+ Set result = new LinkedHashSet(data.size());
+ for (Tuple raw : data) {
+ result.add(new DefaultStringTuple(raw, serializer.deserialize(raw.getValue())));
+ }
+
+ return result;
+ }
+
+ @Override
+ public Long append(String key, String value) {
+ return delegate.append(serialize(key), serialize(value));
+ }
+
+ @Override
+ public List bLPop(int timeout, String... keys) {
+ return deserialize(delegate.bLPop(timeout, serializeMulti(keys)));
+ }
+
+ @Override
+ public List bRPop(int timeout, String... keys) {
+ return deserialize(delegate.bRPop(timeout, serializeMulti(keys)));
+ }
+
+ @Override
+ public String bRPopLPush(int timeout, String srcKey, String dstKey) {
+ return deserialize(delegate.bRPopLPush(timeout, serialize(srcKey), serialize(dstKey)));
+ }
+
+ @Override
+ public Long decr(String key) {
+ return delegate.decr(serialize(key));
+ }
+
+ @Override
+ public Long decrBy(String key, long value) {
+ return delegate.decrBy(serialize(key), value);
+ }
+
+ @Override
+ public Long del(String... keys) {
+ return delegate.del(serializeMulti(keys));
+ }
+
+ @Override
+ public String echo(String message) {
+ return deserialize(delegate.echo(serialize(message)));
+ }
+
+ @Override
+ public Boolean exists(String key) {
+ return delegate.exists(serialize(key));
+ }
+
+ @Override
+ public Boolean expire(String key, long seconds) {
+ return delegate.expire(serialize(key), seconds);
+ }
+
+ @Override
+ public Boolean expireAt(String key, long unixTime) {
+ return delegate.expireAt(serialize(key), unixTime);
+ }
+
+ @Override
+ public String get(String key) {
+ return deserialize(delegate.get(serialize(key)));
+ }
+
+ @Override
+ public Boolean getBit(String key, long offset) {
+ return delegate.getBit(serialize(key), offset);
+ }
+
+ @Override
+ public String getRange(String key, long start, long end) {
+ return deserialize(delegate.getRange(serialize(key), start, end));
+ }
+
+ @Override
+ public String getSet(String key, String value) {
+ return deserialize(delegate.getSet(serialize(key), serialize(value)));
+ }
+
+ @Override
+ public Boolean hDel(String key, String field) {
+ return delegate.hDel(serialize(key), serialize(field));
+ }
+
+ @Override
+ public Boolean hExists(String key, String field) {
+ return delegate.hExists(serialize(key), serialize(field));
+ }
+
+ @Override
+ public String hGet(String key, String field) {
+ return deserialize(delegate.hGet(serialize(key), serialize(field)));
+ }
+
+ @Override
+ public Map hGetAll(String key) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Long hIncrBy(String key, String field, long delta) {
+ return delegate.hIncrBy(serialize(key), serialize(field), delta);
+ }
+
+ @Override
+ public Set hKeys(String key) {
+ return deserialize(delegate.hKeys(serialize(key)));
+ }
+
+ @Override
+ public Long hLen(String key) {
+ return delegate.hLen(serialize(key));
+ }
+
+ @Override
+ public List hMGet(String key, String... fields) {
+ return deserialize(delegate.hMGet(serialize(key), serializeMulti(fields)));
+ }
+
+
+ @Override
+ public void hMSet(String key, Map hashes) {
+ delegate.hMSet(serialize(key), serialize(hashes));
+ }
+
+ @Override
+ public Boolean hSet(String key, String field, String value) {
+ return delegate.hSet(serialize(key), serialize(field), serialize(value));
+ }
+
+ @Override
+ public Boolean hSetNX(String key, String field, String value) {
+ return delegate.hSetNX(serialize(key), serialize(field), serialize(value));
+ }
+
+ @Override
+ public List hVals(String key) {
+ return deserialize(delegate.hVals(serialize(key)));
+ }
+
+ @Override
+ public Long incr(String key) {
+ return delegate.incr(serialize(key));
+ }
+
+ @Override
+ public Long incrBy(String key, long value) {
+ return delegate.incrBy(serialize(key), value);
+ }
+
+ @Override
+ public Collection keys(String pattern) {
+ return deserialize(delegate.keys(serialize(pattern)));
+ }
+
+ @Override
+ public String lIndex(String key, long index) {
+ return deserialize(delegate.lIndex(serialize(key), index));
+ }
+
+ @Override
+ public Long lInsert(String key, Position where, String pivot, String value) {
+ return delegate.lInsert(serialize(key), where, serialize(pivot), serialize(value));
+ }
+
+ @Override
+ public Long lLen(String key) {
+ return delegate.lLen(serialize(key));
+ }
+
+ @Override
+ public String lPop(String key) {
+ return deserialize(delegate.lPop(serialize(key)));
+ }
+
+ @Override
+ public Long lPush(String key, String value) {
+ return delegate.lPush(serialize(key), serialize(value));
+ }
+
+ @Override
+ public Long lPushX(String key, String value) {
+ return delegate.lPushX(serialize(key), serialize(value));
+ }
+
+ @Override
+ public List lRange(String key, long start, long end) {
+ return deserialize(delegate.lRange(serialize(key), start, end));
+ }
+
+ @Override
+ public Long lRem(String key, long count, String value) {
+ return delegate.lRem(serialize(key), count, serialize(value));
+ }
+
+ @Override
+ public void lSet(String key, long index, String value) {
+ delegate.lSet(serialize(key), index, serialize(value));
+ }
+
+ @Override
+ public void lTrim(String key, long start, long end) {
+ delegate.lTrim(serialize(key), start, end);
+ }
+
+ @Override
+ public List mGet(String... keys) {
+ return deserialize(delegate.mGet(serializeMulti(keys)));
+ }
+
+ @Override
+ public void mSetNXString(Map tuple) {
+ delegate.mSetNX(serialize(tuple));
+ }
+
+ @Override
+ public void mSetString(Map tuple) {
+ delegate.mSet(serialize(tuple));
+ }
+
+ @Override
+ public Boolean persist(String key) {
+ return delegate.persist(serialize(key));
+ }
+
+ @Override
+ public Boolean move(String key, int dbIndex) {
+ return delegate.move(serialize(key), dbIndex);
+ }
+
+ @Override
+ public void pSubscribe(MessageListener listener, String... patterns) {
+ delegate.pSubscribe(listener, serializeMulti(patterns));
+ }
+
+ @Override
+ public Long publish(String channel, String message) {
+ return delegate.publish(serialize(channel), serialize(message));
+ }
+
+ @Override
+ public void rename(String oldName, String newName) {
+ delegate.rename(serialize(oldName), serialize(newName));
+ }
+
+ @Override
+ public Boolean renameNX(String oldName, String newName) {
+ return delegate.renameNX(serialize(oldName), serialize(newName));
+ }
+
+ @Override
+ public String rPop(String key) {
+ return deserialize(delegate.rPop(serialize(key)));
+ }
+
+ @Override
+ public String rPopLPush(String srcKey, String dstKey) {
+ return deserialize(delegate.rPopLPush(serialize(srcKey), serialize(dstKey)));
+ }
+
+ @Override
+ public Long rPush(String key, String value) {
+ return delegate.rPush(serialize(key), serialize(value));
+ }
+
+ @Override
+ public Long rPushX(String key, String value) {
+ return delegate.rPushX(serialize(key), serialize(value));
+ }
+
+ @Override
+ public Boolean sAdd(String key, String value) {
+ return delegate.sAdd(serialize(key), serialize(value));
+ }
+
+ @Override
+ public Long sCard(String key) {
+ return delegate.sCard(serialize(key));
+ }
+
+ @Override
+ public Set sDiff(String... keys) {
+ return deserialize(delegate.sDiff(serializeMulti(keys)));
+ }
+
+ @Override
+ public void sDiffStore(String destKey, String... keys) {
+ delegate.sDiffStore(serialize(destKey), serializeMulti(keys));
+ }
+
+ @Override
+ public void set(String key, String value) {
+ delegate.set(serialize(key), serialize(value));
+ }
+
+ @Override
+ public void setBit(String key, long offset, boolean value) {
+ delegate.setBit(serialize(key), offset, value);
+ }
+
+ @Override
+ public void setEx(String key, long seconds, String value) {
+ delegate.setEx(serialize(key), seconds, serialize(value));
+ }
+
+ @Override
+ public Boolean setNX(String key, String value) {
+ return delegate.setNX(serialize(key), serialize(value));
+ }
+
+ @Override
+ public void setRange(String key, String value, long start) {
+ delegate.setRange(serialize(key), serialize(value), start);
+ }
+
+ @Override
+ public Set sInter(String... keys) {
+ return deserialize(delegate.sInter(serializeMulti(keys)));
+ }
+
+ @Override
+ public void sInterStore(String destKey, String... keys) {
+ delegate.sInterStore(serialize(destKey), serializeMulti(keys));
+ }
+
+ @Override
+ public Boolean sIsMember(String key, String value) {
+ return delegate.sIsMember(serialize(key), serialize(value));
+ }
+
+ @Override
+ public Set sMembers(String key) {
+ return deserialize(delegate.sMembers(serialize(key)));
+ }
+
+ @Override
+ public Boolean sMove(String srcKey, String destKey, String value) {
+ return delegate.sMove(serialize(srcKey), serialize(destKey), serialize(value));
+ }
+
+ @Override
+ public Long sort(String key, SortParameters params, String storeKey) {
+ return delegate.sort(serialize(key), params, serialize(storeKey));
+ }
+
+ @Override
+ public List sort(String key, SortParameters params) {
+ return deserialize(delegate.sort(serialize(key), params));
+ }
+
+ @Override
+ public String sPop(String key) {
+ return deserialize(delegate.sPop(serialize(key)));
+ }
+
+ @Override
+ public String sRandMember(String key) {
+ return deserialize(delegate.sRandMember(serialize(key)));
+ }
+
+ @Override
+ public Boolean sRem(String key, String value) {
+ return delegate.sRem(serialize(key), serialize(value));
+ }
+
+ @Override
+ public Long strLen(String key) {
+ return delegate.strLen(serialize(key));
+ }
+
+ @Override
+ public void subscribe(MessageListener listener, String... channels) {
+ delegate.subscribe(listener, serializeMulti(channels));
+ }
+
+ @Override
+ public Set sUnion(String... keys) {
+ return deserialize(delegate.sUnion(serializeMulti(keys)));
+ }
+
+ @Override
+ public void sUnionStore(String destKey, String... keys) {
+ delegate.sUnionStore(serialize(destKey), serializeMulti(keys));
+ }
+
+ @Override
+ public Long ttl(String key) {
+ return delegate.ttl(serialize(key));
+ }
+
+ @Override
+ public DataType type(String key) {
+ return delegate.type(serialize(key));
+ }
+
+ @Override
+ public Boolean zAdd(String key, double score, String value) {
+ return delegate.zAdd(serialize(key), score, serialize(value));
+ }
+
+ @Override
+ public Long zCard(String key) {
+ return delegate.zCard(serialize(key));
+ }
+
+ @Override
+ public Long zCount(String key, double min, double max) {
+ return delegate.zCount(serialize(key), min, max);
+ }
+
+ @Override
+ public Double zIncrBy(String key, double increment, String value) {
+ return delegate.zIncrBy(serialize(key), increment, serialize(value));
+ }
+
+ @Override
+ public Long zInterStore(String destKey, Aggregate aggregate, int[] weights, String... sets) {
+ return delegate.zInterStore(serialize(destKey), aggregate, weights, serializeMulti(sets));
+ }
+
+ @Override
+ public Long zInterStore(String destKey, String... sets) {
+ return delegate.zInterStore(serialize(destKey), serializeMulti(sets));
+ }
+
+ @Override
+ public Set zRange(String key, long start, long end) {
+ return deserialize(delegate.zRange(serialize(key), start, end));
+ }
+
+ @Override
+ public Set zRangeByScore(String key, double min, double max, long offset, long count) {
+ return deserialize(delegate.zRangeByScore(serialize(key), min, max, offset, count));
+ }
+
+ @Override
+ public Set zRangeByScore(String key, double min, double max) {
+ return deserialize(delegate.zRangeByScore(serialize(key), min, max));
+ }
+
+ @Override
+ public Set zRangeByScoreWithScores(String key, double min, double max, long offset, long count) {
+ return deserializeTuple(delegate.zRangeByScoreWithScores(serialize(key), min, max, offset, count));
+ }
+
+ @Override
+ public Set zRangeByScoreWithScores(String key, double min, double max) {
+ return deserializeTuple(delegate.zRangeByScoreWithScores(serialize(key), min, max));
+ }
+
+ @Override
+ public Set zRangeWithScores(String key, long start, long end) {
+ return deserializeTuple(delegate.zRangeWithScores(serialize(key), start, end));
+ }
+
+ @Override
+ public Long zRank(String key, String value) {
+ return delegate.zRank(serialize(key), serialize(value));
+ }
+
+ @Override
+ public Boolean zRem(String key, String value) {
+ return delegate.zRem(serialize(key), serialize(value));
+ }
+
+ @Override
+ public Long zRemRange(String key, long start, long end) {
+ return delegate.zRemRange(serialize(key), start, end);
+ }
+
+ @Override
+ public Long zRemRangeByScore(String key, double min, double max) {
+ return delegate.zRemRangeByScore(serialize(key), min, max);
+ }
+
+ @Override
+ public Set zRevRange(String key, long start, long end) {
+ return deserialize(delegate.zRevRange(serialize(key), start, end));
+ }
+
+ @Override
+ public Set zRevRangeWithScores(String key, long start, long end) {
+ return deserializeTuple(delegate.zRevRangeWithScores(serialize(key), start, end));
+ }
+
+ @Override
+ public Long zRevRank(String key, String value) {
+ return delegate.zRevRank(serialize(key), serialize(value));
+ }
+
+ @Override
+ public Double zScore(String key, String value) {
+ return delegate.zScore(serialize(key), serialize(value));
+ }
+
+ @Override
+ public Long zUnionStore(String destKey, Aggregate aggregate, int[] weights, String... sets) {
+ return delegate.zUnionStore(serialize(destKey), aggregate, weights, serializeMulti(sets));
+ }
+
+ @Override
+ public Long zUnionStore(String destKey, String... sets) {
+ return delegate.zUnionStore(serialize(destKey), serializeMulti(sets));
+ }
+
+ @Override
+ public List closePipeline() {
+ return delegate.closePipeline();
+ }
+
+ @Override
+ public boolean isPipelined() {
+ return delegate.isPipelined();
+ }
+
+ @Override
+ public void openPipeline() {
+ delegate.openPipeline();
+ }
+}
\ No newline at end of file
diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/DefaultStringTuple.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/DefaultStringTuple.java
new file mode 100644
index 000000000..9ed234216
--- /dev/null
+++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/DefaultStringTuple.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2011 the original author or authors.
+ *
+ * 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.redis.connection;
+
+import org.springframework.data.keyvalue.redis.connection.RedisZSetCommands.Tuple;
+import org.springframework.data.keyvalue.redis.connection.StringRedisConnection.StringTuple;
+
+/**
+ * Default implementation for {@link StringTuple} interface.
+ *
+ * @author Costin Leau
+ */
+public class DefaultStringTuple extends DefaultTuple implements StringTuple {
+
+ private final String valueAsString;
+
+ /**
+ * Constructs a new DefaultStringTuple instance.
+ *
+ * @param value
+ * @param score
+ */
+ public DefaultStringTuple(byte[] value, String valueAsString, Double score) {
+ super(value, score);
+ this.valueAsString = valueAsString;
+
+ }
+
+ /**
+ * Constructs a new DefaultStringTuple instance.
+ *
+ * @param tuple
+ * @param valueAsString
+ */
+ public DefaultStringTuple(Tuple tuple, String valueAsString) {
+ super(tuple.getValue(), tuple.getScore());
+ this.valueAsString = valueAsString;
+ }
+
+ @Override
+ public String getValueAsString() {
+ return valueAsString;
+ }
+}
diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/DefaultTuple.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/DefaultTuple.java
new file mode 100644
index 000000000..e9c366fda
--- /dev/null
+++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/DefaultTuple.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2010-2011 the original author or authors.
+ *
+ * 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.redis.connection;
+
+import org.springframework.data.keyvalue.redis.connection.RedisZSetCommands.Tuple;
+
+/**
+ * Default implementation for {@link Tuple} interface.
+ *
+ * @author Costin Leau
+ */
+public class DefaultTuple implements Tuple {
+
+ private final Double score;
+ private final byte[] value;
+
+
+ /**
+ * Constructs a new DefaultTuple instance.
+ *
+ * @param value
+ * @param score
+ */
+ public DefaultTuple(byte[] value, Double score) {
+ this.score = score;
+ this.value = value;
+ }
+
+ @Override
+ public Double getScore() {
+ return score;
+ }
+
+ @Override
+ public byte[] getValue() {
+ return value;
+ }
+}
diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/Message.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/Message.java
new file mode 100644
index 000000000..0a1b17010
--- /dev/null
+++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/Message.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2011 the original author or authors.
+ *
+ * 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.redis.connection;
+
+import java.io.Serializable;
+
+/**
+ * Class encapsulating a Redis message body and its properties.
+ *
+ * @author Costin Leau
+ */
+public interface Message extends Serializable {
+
+ /**
+ * Returns the body (or the payload) of the message.
+ *
+ * @return message body
+ */
+ byte[] getBody();
+
+ /**
+ * Returns the channel associated with the message.
+ *
+ * @return message channel.
+ */
+ byte[] getChannel();
+}
diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/MessageListener.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/MessageListener.java
new file mode 100644
index 000000000..6e75495f0
--- /dev/null
+++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/MessageListener.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2011 the original author or authors.
+ *
+ * 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.redis.connection;
+
+/**
+ * Listener of messages published in Redis.
+ *
+ * @author Costin Leau
+ */
+public interface MessageListener {
+
+ /**
+ * Callback for processing received objects through Redis.
+ *
+ * @param message message
+ * @param pattern pattern matching the channel (if specified) - can be null
+ */
+ void onMessage(Message message, byte[] pattern);
+}
diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/RedisCommands.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/RedisCommands.java
new file mode 100644
index 000000000..072439633
--- /dev/null
+++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/RedisCommands.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2010-2011 the original author or authors.
+ *
+ * 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.redis.connection;
+
+
+/**
+ * Interface for the commands supported by Redis.
+ *
+ * @author Costin Leau
+ */
+public interface RedisCommands extends RedisKeyCommands, RedisStringCommands, RedisListCommands, RedisSetCommands,
+ RedisZSetCommands, RedisHashCommands, RedisTxCommands, RedisPubSubCommands, RedisConnectionCommands,
+ RedisServerCommands {
+}
\ No newline at end of file
diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/RedisConnection.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/RedisConnection.java
new file mode 100644
index 000000000..6f9f0a2fd
--- /dev/null
+++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/RedisConnection.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2010-2011 the original author or authors.
+ *
+ * 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.redis.connection;
+
+import java.util.List;
+
+import org.springframework.dao.DataAccessException;
+
+/**
+ * A connection to a Redis server. Acts as an common abstraction across various
+ * Redis client libraries (or drivers). Additionally performs exception translation
+ * between the underlying Redis client library and Spring DAO exceptions.
+ *
+ * The methods follow as much as possible the Redis names and conventions.
+ *
+ * @author Costin Leau
+ */
+public interface RedisConnection extends RedisCommands {
+
+ /**
+ * Closes (or quits) the connection.
+ *
+ * @throws DataAccessException
+ */
+ void close() throws DataAccessException;
+
+ /**
+ * Indicates whether the underlying connection is closed or not.
+ *
+ * @return true if the connection is closed, false otherwise.
+ */
+ boolean isClosed();
+
+ /**
+ * Returns the native connection (the underlying library/driver object).
+ *
+ * @return underlying, native object
+ */
+ Object getNativeConnection();
+
+ /**
+ * Indicates whether the connection is in "queue"(or "MULTI") mode or not.
+ * When queueing, all commands are postponed until EXEC or DISCARD commands
+ * are issued.
+ * Since in queueing no results are returned, the connection will return NULL
+ * on all operations that interact with the data.
+ *
+ * @return true if the connection is in queue/MULTI mode, false otherwise
+ */
+ boolean isQueueing();
+
+ /**
+ * Indicates whether the connection is currently pipelined or not.
+ *
+ * @return true if the connection is pipelined, false otherwise
+ * @see #openPipeline()
+ * @see #isQueueing()
+ */
+ boolean isPipelined();
+
+ /**
+ * Activates the pipeline mode for this connection. When pipelined, all commands return null
+ * (the reply is read at the end through {@link #closePipeline()}.
+ * Calling this method when the connection is already pipelined has no effect.
+ *
+ * Pipelining is used for issuing commands without requesting the response right away but rather
+ * at the end of the batch. While somewhat similar to MULTI, pipelining does not
+ * guarantee atomicity - it only tries to improve performance when issuing a lot of
+ * commands (such as in batching scenarios).
+ *
+ * Note:
Consider doing some performance testing before using this feature since
+ * in many cases the performance benefits are minimal yet the impact on usage are not.
+ *
+ * @see #multi()
+ */
+ void openPipeline();
+
+ /**
+ * Executes the commands in the pipeline and returns their result.
+ * If the connection is not pipelined, an empty collection is returned.
+ *
+ * @return the result of the executed commands.
+ */
+ List closePipeline();
+}
\ No newline at end of file
diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/RedisConnectionCommands.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/RedisConnectionCommands.java
new file mode 100644
index 000000000..f3a3ac104
--- /dev/null
+++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/RedisConnectionCommands.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2011 the original author or authors.
+ *
+ * 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.redis.connection;
+
+
+/**
+ * Connection-specific commands supported by Redis.
+ *
+ * @author Costin Leau
+ */
+public interface RedisConnectionCommands {
+
+ public abstract void select(int dbIndex);
+
+ public abstract byte[] echo(byte[] message);
+
+ public abstract String ping();
+
+}
\ No newline at end of file
diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/RedisConnectionFactory.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/RedisConnectionFactory.java
new file mode 100644
index 000000000..e7ff2beff
--- /dev/null
+++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/RedisConnectionFactory.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2010-2011 the original author or authors.
+ *
+ * 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.redis.connection;
+
+import org.springframework.dao.support.PersistenceExceptionTranslator;
+
+/**
+ * Thread-safe factory of Redis connections.
+ *
+ * @author Costin Leau
+ */
+public interface RedisConnectionFactory extends PersistenceExceptionTranslator {
+
+ /**
+ * Provides a suitable connection for interacting with Redis.
+ *
+ * @return connection for interacting with Redis.
+ */
+ RedisConnection getConnection();
+}
diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/RedisHashCommands.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/RedisHashCommands.java
new file mode 100644
index 000000000..6437627f9
--- /dev/null
+++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/RedisHashCommands.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2010-2011 the original author or authors.
+ *
+ * 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.redis.connection;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Hash-specific commands supported by Redis.
+ *
+ * @author Costin Leau
+ */
+public interface RedisHashCommands {
+
+ Boolean hSet(byte[] key, byte[] field, byte[] value);
+
+ Boolean hSetNX(byte[] key, byte[] field, byte[] value);
+
+ byte[] hGet(byte[] key, byte[] field);
+
+ List hMGet(byte[] key, byte[]... fields);
+
+ void hMSet(byte[] key, Map hashes);
+
+ Long hIncrBy(byte[] key, byte[] field, long delta);
+
+ Boolean hExists(byte[] key, byte[] field);
+
+ Boolean hDel(byte[] key, byte[] field);
+
+ Long hLen(byte[] key);
+
+ Set hKeys(byte[] key);
+
+ List hVals(byte[] key);
+
+ Map hGetAll(byte[] key);
+}
diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/RedisInvalidSubscriptionException.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/RedisInvalidSubscriptionException.java
new file mode 100644
index 000000000..485a87bae
--- /dev/null
+++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/RedisInvalidSubscriptionException.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2011 the original author or authors.
+ *
+ * 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.redis.connection;
+
+import org.springframework.dao.InvalidDataAccessResourceUsageException;
+
+/**
+ * Exception thrown when subscribing to an expired/dead {@link Subscription}.
+ *
+ * @author Costin Leau
+ */
+public class RedisInvalidSubscriptionException extends InvalidDataAccessResourceUsageException {
+
+ /**
+ * Constructs a new RedisInvalidSubscriptionException instance.
+ *
+ * @param msg
+ * @param cause
+ */
+ public RedisInvalidSubscriptionException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+
+ /**
+ * Constructs a new RedisInvalidSubscriptionException instance.
+ *
+ * @param msg
+ */
+ public RedisInvalidSubscriptionException(String msg) {
+ super(msg);
+ }
+}
diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/RedisKeyCommands.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/RedisKeyCommands.java
new file mode 100644
index 000000000..41d047c35
--- /dev/null
+++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/RedisKeyCommands.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2011 the original author or authors.
+ *
+ * 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.redis.connection;
+
+import java.util.List;
+import java.util.Set;
+
+
+/**
+ * Key-specific commands supported by Redis.
+ *
+ * @author Costin Leau
+ */
+public interface RedisKeyCommands {
+
+ public abstract Boolean exists(byte[] key);
+
+ public abstract Long del(byte[]... keys);
+
+ public abstract DataType type(byte[] key);
+
+ public abstract Set keys(byte[] pattern);
+
+ public abstract byte[] randomKey();
+
+ public abstract void rename(byte[] oldName, byte[] newName);
+
+ public abstract Boolean renameNX(byte[] oldName, byte[] newName);
+
+ public abstract Boolean expire(byte[] key, long seconds);
+
+ public abstract Boolean expireAt(byte[] key, long unixTime);
+
+ public abstract Boolean persist(byte[] key);
+
+ public abstract Boolean move(byte[] key, int dbIndex);
+
+ public abstract Long ttl(byte[] key);
+
+ // sort commands
+ public abstract List sort(byte[] key, SortParameters params);
+
+ public abstract Long sort(byte[] key, SortParameters params, byte[] storeKey);
+
+}
\ No newline at end of file
diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/RedisListCommands.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/RedisListCommands.java
new file mode 100644
index 000000000..deee6298e
--- /dev/null
+++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/RedisListCommands.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2010-2011 the original author or authors.
+ *
+ * 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.redis.connection;
+
+import java.util.List;
+
+/**
+ * List-specific commands supported by Redis.
+ *
+ * @author Costin Leau
+ */
+public interface RedisListCommands {
+
+ /**
+ * List insertion position.
+ */
+ public enum Position {
+ BEFORE, AFTER
+ }
+
+ Long rPush(byte[] key, byte[] value);
+
+ Long lPush(byte[] key, byte[] value);
+
+ Long rPushX(byte[] key, byte[] value);
+
+ Long lPushX(byte[] key, byte[] value);
+
+ Long lLen(byte[] key);
+
+ List lRange(byte[] key, long begin, long end);
+
+ void lTrim(byte[] key, long begin, long end);
+
+ byte[] lIndex(byte[] key, long index);
+
+ Long lInsert(byte[] key, Position where, byte[] pivot, byte[] value);
+
+ void lSet(byte[] key, long index, byte[] value);
+
+ Long lRem(byte[] key, long count, byte[] value);
+
+ byte[] lPop(byte[] key);
+
+ byte[] rPop(byte[] key);
+
+ List bLPop(int timeout, byte[]... keys);
+
+ List bRPop(int timeout, byte[]... keys);
+
+ byte[] rPopLPush(byte[] srcKey, byte[] dstKey);
+
+ byte[] bRPopLPush(int timeout, byte[] srcKey, byte[] dstKey);
+}
diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/RedisPubSubCommands.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/RedisPubSubCommands.java
new file mode 100644
index 000000000..64772fe0d
--- /dev/null
+++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/RedisPubSubCommands.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2011 the original author or authors.
+ *
+ * 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.redis.connection;
+
+/**
+ * PubSub-specific Redis commands.
+ *
+ * @author Costin Leau
+ */
+public interface RedisPubSubCommands {
+
+ /**
+ * Indicates whether the current connection is subscribed (to at least one channel)
+ * or not.
+ *
+ * @return true if the connection is subscribed, false otherwise
+ */
+ boolean isSubscribed();
+
+ /**
+ * Returns the current subscription for this connection or null if the connection is
+ * not subscribed.
+ *
+ * @return the current subscription, null if none is available
+ */
+ Subscription getSubscription();
+
+ /**
+ * Publishes the given message to the given channel.
+ *
+ * @param channel the channel to publish to
+ * @param message message to publish
+ * @return the number of clients that received the message
+ */
+ Long publish(byte[] channel, byte[] message);
+
+ /**
+ * Subscribes the connection to the given channels.
+ * Once subscribed, a connection
+ * enters listening mode and can only subscribe to other channels or unsubscribe.
+ * No other commands are accepted until the connection is unsubscribed.
+ *
+ * Note that this operation is blocking and the current thread starts waiting
+ * for new messages immediately.
+ *
+ * @param listener message listener
+ * @param channels channel names
+ */
+ void subscribe(MessageListener listener, byte[]... channels);
+
+ /**
+ * Subscribes the connection to all channels matching the given patterns.
+ * Once subscribed, a connection
+ * enters listening mode and can only subscribe to other channels or unsubscribe.
+ * No other commands are accepted until the connection is unsubscribed.
+ *
+ * Note that this operation is blocking and the current thread starts waiting
+ * for new messages immediately.
+ *
+ * @param listener message listener
+ * @param patterns channel name patterns
+ */
+ void pSubscribe(MessageListener listener, byte[]... patterns);
+}
\ No newline at end of file
diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/RedisServerCommands.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/RedisServerCommands.java
new file mode 100644
index 000000000..09e236225
--- /dev/null
+++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/RedisServerCommands.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2011 the original author or authors.
+ *
+ * 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.redis.connection;
+
+import java.util.List;
+import java.util.Properties;
+
+/**
+ * Server-specific commands supported by Redis.
+ *
+ * @author Costin Leau
+ */
+public interface RedisServerCommands {
+
+ void bgWriteAof();
+
+ void bgSave();
+
+ Long lastSave();
+
+ void save();
+
+ Long dbSize();
+
+ void flushDb();
+
+ void flushAll();
+
+ Properties info();
+
+ void shutdown();
+
+ List getConfig(String pattern);
+
+ void setConfig(String param, String value);
+
+ void resetConfigStats();
+}
diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/RedisSetCommands.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/RedisSetCommands.java
new file mode 100644
index 000000000..b7ef2401e
--- /dev/null
+++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/RedisSetCommands.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2010-2011 the original author or authors.
+ *
+ * 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.redis.connection;
+
+import java.util.Set;
+
+/**
+ * Set-specific commands supported by Redis.
+ *
+ * @author Costin Leau
+ */
+public interface RedisSetCommands {
+
+ Boolean sAdd(byte[] key, byte[] value);
+
+ Boolean sRem(byte[] key, byte[] value);
+
+ byte[] sPop(byte[] key);
+
+ Boolean sMove(byte[] srcKey, byte[] destKey, byte[] value);
+
+ Long sCard(byte[] key);
+
+ Boolean sIsMember(byte[] key, byte[] value);
+
+ Set sInter(byte[]... keys);
+
+ void sInterStore(byte[] destKey, byte[]... keys);
+
+ Set sUnion(byte[]... keys);
+
+ void sUnionStore(byte[] destKey, byte[]... keys);
+
+ Set sDiff(byte[]... keys);
+
+ void sDiffStore(byte[] destKey, byte[]... keys);
+
+ Set sMembers(byte[] key);
+
+ byte[] sRandMember(byte[] key);
+}
diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/RedisStringCommands.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/RedisStringCommands.java
new file mode 100644
index 000000000..d763774ae
--- /dev/null
+++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/RedisStringCommands.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2010-2011 the original author or authors.
+ *
+ * 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.redis.connection;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * String/Value-specific commands supported by Redis.
+ *
+ * @author Costin Leau
+ */
+public interface RedisStringCommands {
+
+ byte[] get(byte[] key);
+
+ byte[] getSet(byte[] key, byte[] value);
+
+ List mGet(byte[]... keys);
+
+ void set(byte[] key, byte[] value);
+
+ Boolean setNX(byte[] key, byte[] value);
+
+ void setEx(byte[] key, long seconds, byte[] value);
+
+ void mSet(Map tuple);
+
+ void mSetNX(Map tuple);
+
+ Long incr(byte[] key);
+
+ Long incrBy(byte[] key, long value);
+
+ Long decr(byte[] key);
+
+ Long decrBy(byte[] key, long value);
+
+ Long append(byte[] key, byte[] value);
+
+ byte[] getRange(byte[] key, long begin, long end);
+
+ void setRange(byte[] key, byte[] value, long offset);
+
+ Boolean getBit(byte[] key, long offset);
+
+ void setBit(byte[] key, long offset, boolean value);
+
+ Long strLen(byte[] key);
+}
diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/RedisSubscribedConnectionException.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/RedisSubscribedConnectionException.java
new file mode 100644
index 000000000..bcc93bab7
--- /dev/null
+++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/RedisSubscribedConnectionException.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2011 the original author or authors.
+ *
+ * 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.redis.connection;
+
+import org.springframework.dao.InvalidDataAccessApiUsageException;
+
+/**
+ * Exception thrown when issuing commands on a connection that is subscribed and waiting
+ * for events.
+ *
+ * @author Costin Leau
+ * @see org.springframework.data.keyvalue.redis.connection.RedisPubSubCommands
+ */
+public class RedisSubscribedConnectionException extends InvalidDataAccessApiUsageException {
+
+ /**
+ * Constructs a new RedisSubscribedConnectionException instance.
+ *
+ * @param msg
+ * @param cause
+ */
+ public RedisSubscribedConnectionException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+
+ /**
+ * Constructs a new RedisSubscribedConnectionException instance.
+ *
+ * @param msg
+ */
+ public RedisSubscribedConnectionException(String msg) {
+ super(msg);
+ }
+}
diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/RedisTxCommands.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/RedisTxCommands.java
new file mode 100644
index 000000000..73f82f600
--- /dev/null
+++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/RedisTxCommands.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2010-2011 the original author or authors.
+ *
+ * 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.redis.connection;
+
+import java.util.List;
+
+
+/**
+ * Transaction/Batch specific commands supported by Redis.
+ *
+ * @author Costin Leau
+ */
+public interface RedisTxCommands {
+
+ void multi();
+
+ List exec();
+
+ void discard();
+
+ void watch(byte[]... keys);
+
+ void unwatch();
+}
diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/RedisZSetCommands.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/RedisZSetCommands.java
new file mode 100644
index 000000000..ff6073b8c
--- /dev/null
+++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/RedisZSetCommands.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2010-2011 the original author or authors.
+ *
+ * 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.redis.connection;
+
+import java.util.Set;
+
+
+/**
+ * ZSet(SortedSet)-specific commands supported by Redis.
+ *
+ * @author Costin Leau
+ */
+public interface RedisZSetCommands {
+
+ /**
+ * Sort aggregation operations.
+ */
+ public enum Aggregate {
+ SUM, MIN, MAX;
+ }
+
+ /**
+ * ZSet tuple.
+ */
+ public interface Tuple {
+ byte[] getValue();
+
+ Double getScore();
+ }
+
+ Boolean zAdd(byte[] key, double score, byte[] value);
+
+ Boolean zRem(byte[] key, byte[] value);
+
+ Double zIncrBy(byte[] key, double increment, byte[] value);
+
+ Long zRank(byte[] key, byte[] value);
+
+ Long zRevRank(byte[] key, byte[] value);
+
+ Set zRange(byte[] key, long begin, long end);
+
+ Set zRangeWithScores(byte[] key, long begin, long end);
+
+ Set zRangeByScore(byte[] key, double min, double max);
+
+ Set zRangeByScoreWithScores(byte[] key, double min, double max);
+
+ Set zRangeByScore(byte[] key, double min, double max, long offset, long count);
+
+ Set zRangeByScoreWithScores(byte[] key, double min, double max, long offset, long count);
+
+ Set zRevRange(byte[] key, long begin, long end);
+
+ Set zRevRangeWithScores(byte[] key, long begin, long end);
+
+ Set zRevRangeByScore(byte[] key, double min, double max);
+
+ Set zRevRangeByScoreWithScores(byte[] key, double min, double max);
+
+ Set zRevRangeByScore(byte[] key, double min, double max, long offset, long count);
+
+ Set zRevRangeByScoreWithScores(byte[] key, double min, double max, long offset, long count);
+
+ Long zCount(byte[] key, double min, double max);
+
+ Long zCard(byte[] key);
+
+ Double zScore(byte[] key, byte[] value);
+
+ Long zRemRange(byte[] key, long begin, long end);
+
+ Long zRemRangeByScore(byte[] key, double min, double max);
+
+ Long zUnionStore(byte[] destKey, byte[]... sets);
+
+ Long zUnionStore(byte[] destKey, Aggregate aggregate, int[] weights, byte[]... sets);
+
+ Long zInterStore(byte[] destKey, byte[]... sets);
+
+ Long zInterStore(byte[] destKey, Aggregate aggregate, int[] weights, byte[]... sets);
+}
\ No newline at end of file
diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/SortParameters.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/SortParameters.java
new file mode 100644
index 000000000..ca69f3315
--- /dev/null
+++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/SortParameters.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2010-2011 the original author or authors.
+ *
+ * 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.redis.connection;
+
+/**
+ * Entity containing the parameters for the SORT operation.
+ *
+ * @author Costin Leau
+ */
+public interface SortParameters {
+
+ /**
+ * Sorting order.
+ */
+ public enum Order {
+ ASC, DESC
+ }
+
+ /**
+ * Utility class wrapping the 'LIMIT' setting.
+ *
+ */
+ static class Range {
+ private final long start;
+ private final long count;
+
+ public Range(long start, long count) {
+ this.start = start;
+ this.count = count;
+ }
+
+ public long getStart() {
+ return start;
+ }
+
+ public long getCount() {
+ return count;
+ }
+ }
+
+ /**
+ * Returns the sorting order. Can be null if nothing is specified.
+ *
+ * @return sorting order
+ */
+ Order getOrder();
+
+ /**
+ * Indicates if the sorting is numeric (default) or alphabetical (lexicographical).
+ * Can be null if nothing is specified.
+ *
+ * @return the type of sorting
+ */
+ Boolean isAlphabetic();
+
+ /**
+ * Returns the pattern (if set) for sorting by external keys (BY ).
+ * Can be null if nothing is specified.
+ *
+ * @return BY pattern.
+ */
+ byte[] getByPattern();
+
+ /**
+ * Returns the pattern (if set) for retrieving external keys (GET ).
+ * Can be null if nothing is specified.
+ *
+ * @return GET pattern.
+ */
+ byte[][] getGetPattern();
+
+ /**
+ * Returns the sorting limit (range or pagination).
+ * Can be null if nothing is specified.
+ *
+ * @return sorting limit/range
+ */
+ Range getLimit();
+}
\ No newline at end of file
diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/StringRedisConnection.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/StringRedisConnection.java
new file mode 100644
index 000000000..fc7c170aa
--- /dev/null
+++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/StringRedisConnection.java
@@ -0,0 +1,245 @@
+/*
+ * Copyright 2011 the original author or authors.
+ *
+ * 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.redis.connection;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.springframework.data.keyvalue.redis.core.RedisCallback;
+import org.springframework.data.keyvalue.redis.core.StringRedisTemplate;
+import org.springframework.data.keyvalue.redis.serializer.RedisSerializer;
+
+/**
+ * Convenience extension of {@link RedisConnection} that accepts and returns {@link String}s instead of
+ * byte arrays. Uses a {@link RedisSerializer} underneath to perform the conversion.
+ *
+ * @author Costin Leau
+ * @see RedisCallback
+ * @see RedisSerializer
+ * @see StringRedisTemplate
+ */
+public interface StringRedisConnection extends RedisConnection {
+
+ /**
+ * String-friendly ZSet tuple.
+ */
+ public interface StringTuple extends Tuple {
+ String getValueAsString();
+ }
+
+ Boolean exists(String key);
+
+ Long del(String... keys);
+
+ DataType type(String key);
+
+ Collection keys(String pattern);
+
+ void rename(String oldName, String newName);
+
+ Boolean renameNX(String oldName, String newName);
+
+ Boolean expire(String key, long seconds);
+
+ Boolean expireAt(String key, long unixTime);
+
+ Boolean persist(String key);
+
+ Boolean move(String key, int dbIndex);
+
+ Long ttl(String key);
+
+ String echo(String message);
+
+ // sort commands
+ List sort(String key, SortParameters params);
+
+ Long sort(String key, SortParameters params, String storeKey);
+
+ String get(String key);
+
+ String getSet(String key, String value);
+
+ List mGet(String... keys);
+
+ void set(String key, String value);
+
+ Boolean setNX(String key, String value);
+
+ void setEx(String key, long seconds, String value);
+
+ void mSetString(Map tuple);
+
+ void mSetNXString(Map tuple);
+
+ Long incr(String key);
+
+ Long incrBy(String key, long value);
+
+ Long decr(String key);
+
+ Long decrBy(String key, long value);
+
+ Long append(String key, String value);
+
+ String getRange(String key, long start, long end);
+
+ void setRange(String key, String value, long offset);
+
+ Boolean getBit(String key, long offset);
+
+ void setBit(String key, long offset, boolean value);
+
+ Long strLen(String key);
+
+ Long rPush(String key, String value);
+
+ Long lPush(String key, String value);
+
+ Long rPushX(String key, String value);
+
+ Long lPushX(String key, String value);
+
+ Long lLen(String key);
+
+ List lRange(String key, long start, long end);
+
+ void lTrim(String key, long start, long end);
+
+ String lIndex(String key, long index);
+
+ Long lInsert(String key, Position where, String pivot, String value);
+
+ void lSet(String key, long index, String value);
+
+ Long lRem(String key, long count, String value);
+
+ String lPop(String key);
+
+ String rPop(String key);
+
+ List bLPop(int timeout, String... keys);
+
+ List bRPop(int timeout, String... keys);
+
+ String rPopLPush(String srcKey, String dstKey);
+
+ String bRPopLPush(int timeout, String srcKey, String dstKey);
+
+ Boolean sAdd(String key, String value);
+
+ Boolean sRem(String key, String value);
+
+ String sPop(String key);
+
+ Boolean sMove(String srcKey, String destKey, String value);
+
+ Long sCard(String key);
+
+ Boolean sIsMember(String key, String value);
+
+ Set sInter(String... keys);
+
+ void sInterStore(String destKey, String... keys);
+
+ Set sUnion(String... keys);
+
+ void sUnionStore(String destKey, String... keys);
+
+ Set sDiff(String... keys);
+
+ void sDiffStore(String destKey, String... keys);
+
+ Set sMembers(String key);
+
+ String sRandMember(String key);
+
+ Boolean zAdd(String key, double score, String value);
+
+ Boolean zRem(String key, String value);
+
+ Double zIncrBy(String key, double increment, String value);
+
+ Long zRank(String key, String value);
+
+ Long zRevRank(String key, String value);
+
+ Set zRange(String key, long start, long end);
+
+ Set zRangeWithScores(String key, long start, long end);
+
+ Set zRevRange(String key, long start, long end);
+
+ Set zRevRangeWithScores(String key, long start, long end);
+
+ Set zRangeByScore(String key, double min, double max);
+
+ Set zRangeByScoreWithScores(String key, double min, double max);
+
+ Set zRangeByScore(String key, double min, double max, long offset, long count);
+
+ Set zRangeByScoreWithScores(String key, double min, double max, long offset, long count);
+
+ Long zCount(String key, double min, double max);
+
+ Long zCard(String key);
+
+ Double zScore(String key, String value);
+
+ Long zRemRange(String key, long start, long end);
+
+ Long zRemRangeByScore(String key, double min, double max);
+
+ Long zUnionStore(String destKey, String... sets);
+
+ Long zUnionStore(String destKey, Aggregate aggregate, int[] weights, String... sets);
+
+ Long zInterStore(String destKey, String... sets);
+
+ Long zInterStore(String destKey, Aggregate aggregate, int[] weights, String... sets);
+
+ Boolean hSet(String key, String field, String value);
+
+ Boolean hSetNX(String key, String field, String value);
+
+ String hGet(String key, String field);
+
+ List hMGet(String key, String... fields);
+
+ void hMSet(String key, Map hashes);
+
+ Long hIncrBy(String key, String field, long delta);
+
+ Boolean hExists(String key, String field);
+
+ Boolean hDel(String key, String field);
+
+ Long hLen(String key);
+
+ Set hKeys(String key);
+
+ List hVals(String key);
+
+ Map hGetAll(String key);
+
+ Long publish(String channel, String message);
+
+ void subscribe(MessageListener listener, String... channels);
+
+ void pSubscribe(MessageListener listener, String... patterns);
+}
\ No newline at end of file
diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/Subscription.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/Subscription.java
new file mode 100644
index 000000000..bdad9ae35
--- /dev/null
+++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/Subscription.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2011 the original author or authors.
+ *
+ * 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.redis.connection;
+
+import java.util.Collection;
+
+/**
+ * Subscription for Redis channels. Just like the underlying {@link RedisConnection},
+ * it should not be used by multiple threads.
+ *
+ * Note that once a subscription died, it cannot accept any more subscriptions.
+ *
+ * @author Costin Leau
+ */
+public interface Subscription {
+
+ /**
+ * Adds the given channels to the current subscription.
+ *
+ * @param channels channel names
+ */
+ void subscribe(byte[]... channels) throws RedisInvalidSubscriptionException;
+
+ /**
+ * Adds the given channel patterns to the current subscription.
+ *
+ * @param patterns channel patterns
+ */
+ void pSubscribe(byte[]... patterns) throws RedisInvalidSubscriptionException;
+
+ /**
+ * Cancels the current subscription for all channels given by name.
+ */
+ void unsubscribe();
+
+ /**
+ * Cancels the current subscription for all given channels.
+ *
+ * @param channels channel names
+ */
+ void unsubscribe(byte[]... channels);
+
+ /**
+ * Cancels the subscription for all channels matched by patterns.
+ */
+ void pUnsubscribe();
+
+ /**
+ * Cancels the subscription for all channels matching the given patterns.
+ *
+ * @param patterns
+ */
+ void pUnsubscribe(byte[]... patterns);
+
+ /**
+ * Returns the (named) channels for this subscription.
+ *
+ * @return collection of named channels
+ */
+ Collection getChannels();
+
+ /**
+ * Returns the channel patters for this subscription.
+ *
+ * @return collection of channel patterns
+ */
+ Collection getPatterns();
+
+ /**
+ * Returns the listener used for this subscription.
+ *
+ * @return the listener used for this subscription.
+ */
+ MessageListener getListener();
+
+ /**
+ * Indicates whether this subscription is still 'alive'
+ * or not.
+ *
+ * @return true if the subscription still applies, false otherwise.
+ */
+ boolean isAlive();
+}
\ No newline at end of file
diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/jedis/JedisConnection.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/jedis/JedisConnection.java
new file mode 100644
index 000000000..363e7c920
--- /dev/null
+++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/jedis/JedisConnection.java
@@ -0,0 +1,2350 @@
+/*
+ * Copyright 2010-2011 the original author or authors.
+ *
+ * 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.redis.connection.jedis;
+
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import org.springframework.dao.DataAccessException;
+import org.springframework.data.keyvalue.UncategorizedKeyvalueStoreException;
+import org.springframework.data.keyvalue.redis.connection.DataType;
+import org.springframework.data.keyvalue.redis.connection.MessageListener;
+import org.springframework.data.keyvalue.redis.connection.RedisConnection;
+import org.springframework.data.keyvalue.redis.connection.RedisSubscribedConnectionException;
+import org.springframework.data.keyvalue.redis.connection.SortParameters;
+import org.springframework.data.keyvalue.redis.connection.Subscription;
+import org.springframework.util.ReflectionUtils;
+
+import redis.clients.jedis.BinaryJedis;
+import redis.clients.jedis.BinaryJedisPubSub;
+import redis.clients.jedis.BinaryTransaction;
+import redis.clients.jedis.Client;
+import redis.clients.jedis.Jedis;
+import redis.clients.jedis.Pipeline;
+import redis.clients.jedis.SortingParams;
+import redis.clients.jedis.Transaction;
+import redis.clients.jedis.ZParams;
+import redis.clients.jedis.exceptions.JedisConnectionException;
+import redis.clients.jedis.exceptions.JedisException;
+import redis.clients.util.Pool;
+
+/**
+ * {@code RedisConnection} implementation on top of Jedis library.
+ *
+ * @author Costin Leau
+ */
+public class JedisConnection implements RedisConnection {
+
+ private static final Field CLIENT_FIELD;
+
+ static {
+ CLIENT_FIELD = ReflectionUtils.findField(BinaryJedis.class, "client", Client.class);
+ ReflectionUtils.makeAccessible(CLIENT_FIELD);
+ }
+
+ private final Jedis jedis;
+ private final Client client;
+ private final BinaryTransaction transaction;
+ private final Pool pool;
+ /** flag indicating whether the connection needs to be dropped or not */
+ private boolean broken = false;
+
+ private volatile JedisSubscription subscription;
+ private volatile Pipeline pipeline;
+ private final int dbIndex;
+
+ /**
+ * Constructs a new JedisConnection instance.
+ *
+ * @param jedis Jedis entity
+ */
+ public JedisConnection(Jedis jedis) {
+ this(jedis, null, 0);
+ }
+
+ /**
+ *
+ * Constructs a new JedisConnection instance backed by a jedis pool.
+ *
+ * @param jedis
+ * @param pool can be null, if no pool is used
+ */
+ public JedisConnection(Jedis jedis, Pool pool, int dbIndex) {
+ this.jedis = jedis;
+ // extract underlying connection for batch operations
+ client = (Client) ReflectionUtils.getField(CLIENT_FIELD, jedis);
+ transaction = new Transaction(client);
+
+ this.pool = pool;
+
+ this.dbIndex = dbIndex;
+
+ // select the db
+ if (dbIndex > 0) {
+ select(dbIndex);
+ }
+ }
+
+ protected DataAccessException convertJedisAccessException(Exception ex) {
+ if (ex instanceof JedisException) {
+ // check connection flag
+ if (ex instanceof JedisConnectionException) {
+ broken = true;
+ }
+ return JedisUtils.convertJedisAccessException((JedisException) ex);
+ }
+ if (ex instanceof IOException) {
+ return JedisUtils.convertJedisAccessException((IOException) ex);
+ }
+
+ return new UncategorizedKeyvalueStoreException("Unknown jedis exception", ex);
+ }
+
+ @Override
+ public void close() throws DataAccessException {
+ // return the connection to the pool
+ try {
+ if (pool != null) {
+ if (broken) {
+ pool.returnBrokenResource(jedis);
+ }
+ else {
+ // reset the connection
+ if (dbIndex > 0) {
+ select(0);
+ }
+
+ pool.returnResource(jedis);
+ }
+ }
+ } catch (Exception ex) {
+ pool.returnBrokenResource(jedis);
+ }
+
+ if (pool != null) {
+ return;
+ }
+
+ // else close the connection normally
+ try {
+ if (isQueueing()) {
+ client.quit();
+ client.disconnect();
+ return;
+ }
+ jedis.quit();
+ jedis.disconnect();
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Jedis getNativeConnection() {
+ return jedis;
+ }
+
+ @Override
+ public boolean isClosed() {
+ try {
+ return !jedis.isConnected();
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public boolean isQueueing() {
+ return client.isInMulti();
+ }
+
+ @Override
+ public boolean isPipelined() {
+ return (pipeline != null);
+ }
+
+ @Override
+ public void openPipeline() {
+ if (pipeline == null) {
+ pipeline = jedis.pipelined();
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public List closePipeline() {
+ if (pipeline != null) {
+ List execute = pipeline.syncAndReturnAll();
+ if (execute != null && !execute.isEmpty()) {
+ return execute;
+ }
+ }
+ return Collections.emptyList();
+ }
+
+ @Override
+ public List sort(byte[] key, SortParameters params) {
+
+ SortingParams sortParams = JedisUtils.convertSortParams(params);
+
+ try {
+ if (isQueueing()) {
+ if (sortParams != null) {
+ transaction.sort(key, sortParams);
+ }
+ else {
+ transaction.sort(key);
+ }
+
+ return null;
+ }
+ if (isPipelined()) {
+ if (sortParams != null) {
+ pipeline.sort(key, sortParams);
+ }
+ else {
+ pipeline.sort(key);
+ }
+
+ return null;
+ }
+ return (sortParams != null ? jedis.sort(key, sortParams) : jedis.sort(key));
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long sort(byte[] key, SortParameters params, byte[] sortKey) {
+
+ SortingParams sortParams = JedisUtils.convertSortParams(params);
+
+ try {
+ if (isQueueing()) {
+ if (sortParams != null) {
+ transaction.sort(key, sortParams, sortKey);
+ }
+ else {
+ transaction.sort(key, sortKey);
+ }
+
+ return null;
+ }
+ if (isPipelined()) {
+ if (sortParams != null) {
+ pipeline.sort(key, sortParams, sortKey);
+ }
+ else {
+ pipeline.sort(key, sortKey);
+ }
+
+ return null;
+ }
+ return (sortParams != null ? jedis.sort(key, sortParams, sortKey) : jedis.sort(key, sortKey));
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long dbSize() {
+ try {
+ if (isQueueing()) {
+ throw new UnsupportedOperationException();
+ }
+ if (isPipelined()) {
+ throw new UnsupportedOperationException();
+ }
+ return jedis.dbSize();
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+
+ @Override
+ public void flushDb() {
+ try {
+ if (isQueueing()) {
+ throw new UnsupportedOperationException();
+ }
+ if (isPipelined()) {
+ throw new UnsupportedOperationException();
+ }
+ jedis.flushDB();
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public void flushAll() {
+ try {
+ if (isQueueing()) {
+ throw new UnsupportedOperationException();
+ }
+ if (isPipelined()) {
+ throw new UnsupportedOperationException();
+ }
+ jedis.flushAll();
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public void bgSave() {
+ try {
+ if (isQueueing()) {
+ throw new UnsupportedOperationException();
+ }
+ if (isPipelined()) {
+ pipeline.bgsave();
+ return;
+ }
+ jedis.bgsave();
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public void bgWriteAof() {
+ try {
+ if (isQueueing()) {
+ throw new UnsupportedOperationException();
+ }
+ if (isPipelined()) {
+ pipeline.bgrewriteaof();
+ return;
+ }
+ jedis.bgrewriteaof();
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public void save() {
+ try {
+ if (isQueueing()) {
+ throw new UnsupportedOperationException();
+ }
+ if (isPipelined()) {
+ pipeline.save();
+ return;
+ }
+ jedis.save();
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public List getConfig(String param) {
+ try {
+ if (isQueueing()) {
+ throw new UnsupportedOperationException();
+ }
+ if (isPipelined()) {
+ pipeline.configGet(param);
+ return null;
+ }
+ return jedis.configGet(param);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Properties info() {
+ try {
+ if (isQueueing()) {
+ throw new UnsupportedOperationException();
+ }
+ if (isPipelined()) {
+ throw new UnsupportedOperationException();
+ }
+ return JedisUtils.info(jedis.info());
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long lastSave() {
+ try {
+ if (isQueueing()) {
+ throw new UnsupportedOperationException();
+ }
+ if (isPipelined()) {
+ pipeline.lastsave();
+ return null;
+ }
+ return jedis.lastsave();
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public void setConfig(String param, String value) {
+ try {
+ if (isQueueing()) {
+ throw new UnsupportedOperationException();
+ }
+ if (isPipelined()) {
+ pipeline.configSet(param, value);
+ return;
+ }
+ jedis.configSet(param, value);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+
+ @Override
+ public void resetConfigStats() {
+ try {
+ if (isQueueing()) {
+ throw new UnsupportedOperationException();
+ }
+ if (isPipelined()) {
+ pipeline.configResetStat();
+ return;
+ }
+ jedis.configResetStat();
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public void shutdown() {
+ try {
+ if (isQueueing()) {
+ throw new UnsupportedOperationException();
+ }
+ if (isPipelined()) {
+ throw new UnsupportedOperationException();
+ }
+ jedis.shutdown();
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public byte[] echo(byte[] message) {
+ try {
+ if (isQueueing()) {
+ throw new UnsupportedOperationException();
+ }
+ if (isPipelined()) {
+ pipeline.echo(message);
+ return null;
+ }
+ return jedis.echo(message);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public String ping() {
+ try {
+ if (isQueueing()) {
+ throw new UnsupportedOperationException();
+ }
+ if (isPipelined()) {
+ throw new UnsupportedOperationException();
+ }
+ return jedis.ping();
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long del(byte[]... keys) {
+ try {
+ if (isQueueing()) {
+ transaction.del(keys);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.del(keys);
+ return null;
+ }
+ return jedis.del(keys);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public void discard() {
+ try {
+ client.discard();
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public List exec() {
+ try {
+ if (isPipelined()) {
+ pipeline.exec();
+ return null;
+ }
+ return transaction.exec();
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Boolean exists(byte[] key) {
+ try {
+ if (isQueueing()) {
+ transaction.exists(key);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.exists(key);
+ return null;
+ }
+ return jedis.exists(key);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Boolean expire(byte[] key, long seconds) {
+ try {
+ if (isQueueing()) {
+ transaction.expire(key, (int) seconds);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.expire(key, (int) seconds);
+ return null;
+ }
+ return (jedis.expire(key, (int) seconds) == 1);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Boolean expireAt(byte[] key, long unixTime) {
+ try {
+ if (isQueueing()) {
+ transaction.expireAt(key, unixTime);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.expireAt(key, unixTime);
+ return null;
+ }
+ return (jedis.expireAt(key, unixTime) == 1);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Set keys(byte[] pattern) {
+ try {
+ if (isQueueing()) {
+ transaction.keys(pattern);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.keys(pattern);
+ return null;
+ }
+ return (jedis.keys(pattern));
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public void multi() {
+ if (isQueueing()) {
+ return;
+ }
+ try {
+ if (isPipelined()) {
+ pipeline.multi();
+ return;
+ }
+ jedis.multi();
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Boolean persist(byte[] key) {
+ try {
+ if (isQueueing()) {
+ client.persist(key);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.persist(key);
+ return null;
+ }
+ return (jedis.persist(key) == 1);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Boolean move(byte[] key, int dbIndex) {
+ try {
+ if (isQueueing()) {
+ client.move(key, dbIndex);
+ return null;
+ }
+ if (isPipelined()) {
+ client.move(key, dbIndex);
+ return null;
+ }
+ return (jedis.move(key, dbIndex) == 1);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public byte[] randomKey() {
+ try {
+ if (isQueueing()) {
+ throw new UnsupportedOperationException();
+ }
+ if (isPipelined()) {
+ throw new UnsupportedOperationException();
+ }
+ return jedis.randomBinaryKey();
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public void rename(byte[] oldName, byte[] newName) {
+ try {
+ if (isQueueing()) {
+ transaction.rename(oldName, newName);
+ return;
+ }
+ if (isPipelined()) {
+ pipeline.rename(oldName, newName);
+ return;
+ }
+ jedis.rename(oldName, newName);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Boolean renameNX(byte[] oldName, byte[] newName) {
+ try {
+ if (isQueueing()) {
+ transaction.renamenx(oldName, newName);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.renamenx(oldName, newName);
+ return null;
+ }
+ return (jedis.renamenx(oldName, newName) == 1);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public void select(int dbIndex) {
+ try {
+ if (isQueueing()) {
+ throw new UnsupportedOperationException();
+ }
+ if (isPipelined()) {
+ throw new UnsupportedOperationException();
+ }
+ jedis.select(dbIndex);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long ttl(byte[] key) {
+ try {
+ if (isQueueing()) {
+ transaction.ttl(key);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.ttl(key);
+ return null;
+ }
+ return jedis.ttl(key);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public DataType type(byte[] key) {
+ try {
+ if (isQueueing()) {
+ transaction.type(key);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.type(key);
+ return null;
+ }
+ return DataType.fromCode(jedis.type(key));
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public void unwatch() {
+ try {
+ jedis.unwatch();
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public void watch(byte[]... keys) {
+ if (isQueueing()) {
+ // ignore (as watch not allowed in multi)
+ return;
+ }
+ try {
+ for (byte[] key : keys) {
+ if (isPipelined()) {
+ pipeline.watch(key);
+ }
+ else {
+ jedis.watch(key);
+ }
+ }
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ //
+ // String commands
+ //
+
+ @Override
+ public byte[] get(byte[] key) {
+ try {
+ if (isQueueing()) {
+ transaction.get(key);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.get(key);
+ return null;
+ }
+
+ return jedis.get(key);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public void set(byte[] key, byte[] value) {
+ try {
+ if (isQueueing()) {
+ transaction.set(key, value);
+ return;
+ }
+ if (isPipelined()) {
+ pipeline.set(key, value);
+ return;
+ }
+ jedis.set(key, value);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+
+ @Override
+ public byte[] getSet(byte[] key, byte[] value) {
+ try {
+ if (isQueueing()) {
+ transaction.getSet(key, value);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.getSet(key, value);
+ return null;
+ }
+ return jedis.getSet(key, value);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long append(byte[] key, byte[] value) {
+ try {
+ if (isQueueing()) {
+ transaction.append(key, value);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.append(key, value);
+ return null;
+ }
+ return jedis.append(key, value);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public List mGet(byte[]... keys) {
+ try {
+ if (isQueueing()) {
+ transaction.mget(keys);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.mget(keys);
+ return null;
+ }
+ return jedis.mget(keys);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public void mSet(Map tuples) {
+ try {
+ if (isQueueing()) {
+ transaction.mset(JedisUtils.convert(tuples));
+ return;
+ }
+ if (isPipelined()) {
+ pipeline.mset(JedisUtils.convert(tuples));
+ return;
+ }
+ jedis.mset(JedisUtils.convert(tuples));
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public void mSetNX(Map tuples) {
+ try {
+ if (isQueueing()) {
+ transaction.msetnx(JedisUtils.convert(tuples));
+ return;
+ }
+ if (isPipelined()) {
+ pipeline.msetnx(JedisUtils.convert(tuples));
+ return;
+ }
+ jedis.msetnx(JedisUtils.convert(tuples));
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public void setEx(byte[] key, long time, byte[] value) {
+ try {
+ if (isQueueing()) {
+ transaction.setex(key, (int) time, value);
+ return;
+ }
+ if (isPipelined()) {
+ pipeline.setex(key, (int) time, value);
+ return;
+ }
+ jedis.setex(key, (int) time, value);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Boolean setNX(byte[] key, byte[] value) {
+ try {
+ if (isQueueing()) {
+ transaction.setnx(key, value);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.setnx(key, value);
+ return null;
+ }
+ return JedisUtils.convertCodeReply(jedis.setnx(key, value));
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public byte[] getRange(byte[] key, long start, long end) {
+ try {
+ if (isQueueing()) {
+ transaction.substr(key, (int) start, (int) end);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.substr(key, (int) start, (int) end);
+ return null;
+ }
+ return jedis.substr(key, (int) start, (int) end);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long decr(byte[] key) {
+ try {
+ if (isQueueing()) {
+ transaction.decr(key);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.decr(key);
+ return null;
+ }
+ return jedis.decr(key);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long decrBy(byte[] key, long value) {
+ try {
+ if (isQueueing()) {
+ transaction.decrBy(key, (int) value);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.decrBy(key, (int) value);
+ return null;
+ }
+ return jedis.decrBy(key, (int) value);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long incr(byte[] key) {
+ try {
+ if (isQueueing()) {
+ transaction.incr(key);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.incr(key);
+ return null;
+ }
+ return jedis.incr(key);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long incrBy(byte[] key, long value) {
+ try {
+ if (isQueueing()) {
+ transaction.incrBy(key, (int) value);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.incrBy(key, (int) value);
+ return null;
+ }
+ return jedis.incrBy(key, (int) value);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Boolean getBit(byte[] key, long offset) {
+ try {
+ if (isQueueing()) {
+ throw new UnsupportedOperationException();
+ }
+ if (isPipelined()) {
+ throw new UnsupportedOperationException();
+ }
+ return (jedis.getbit(key, offset) == 0 ? Boolean.FALSE : Boolean.TRUE);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public void setBit(byte[] key, long offset, boolean value) {
+ try {
+ if (isQueueing()) {
+ throw new UnsupportedOperationException();
+ }
+ if (isPipelined()) {
+ throw new UnsupportedOperationException();
+ }
+ jedis.setbit(key, offset, JedisUtils.asBit(value));
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public void setRange(byte[] key, byte[] value, long start) {
+ try {
+ if (isQueueing()) {
+ throw new UnsupportedOperationException();
+ }
+ if (isPipelined()) {
+ throw new UnsupportedOperationException();
+ }
+ jedis.setrange(key, start, value);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long strLen(byte[] key) {
+ try {
+ if (isQueueing()) {
+ transaction.strlen(key);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.strlen(key);
+ return null;
+ }
+ return jedis.strlen(key);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ //
+ // List commands
+ //
+
+ @Override
+ public Long lPush(byte[] key, byte[] value) {
+ try {
+ if (isQueueing()) {
+ transaction.lpush(key, value);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.lpush(key, value);
+ return null;
+ }
+ return jedis.lpush(key, value);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long rPush(byte[] key, byte[] value) {
+ try {
+ if (isQueueing()) {
+ transaction.rpush(key, value);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.rpush(key, value);
+ return null;
+ }
+ return jedis.rpush(key, value);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public List bLPop(int timeout, byte[]... keys) {
+ try {
+ if (isQueueing()) {
+ transaction.blpop(JedisUtils.bXPopArgs(timeout, keys));
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.blpop(JedisUtils.bXPopArgs(timeout, keys));
+ return null;
+ }
+ return jedis.blpop(timeout, keys);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public List bRPop(int timeout, byte[]... keys) {
+ try {
+ if (isQueueing()) {
+ transaction.brpop(JedisUtils.bXPopArgs(timeout, keys));
+ }
+ if (isPipelined()) {
+ pipeline.brpop(JedisUtils.bXPopArgs(timeout, keys));
+ return null;
+ }
+ return jedis.brpop(timeout, keys);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public byte[] lIndex(byte[] key, long index) {
+ try {
+ if (isQueueing()) {
+ transaction.lindex(key, (int) index);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.lindex(key, (int) index);
+ return null;
+ }
+ return jedis.lindex(key, (int) index);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long lInsert(byte[] key, Position where, byte[] pivot, byte[] value) {
+ try {
+ if (isQueueing()) {
+ transaction.linsert(key, JedisUtils.convertPosition(where), pivot, value);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.linsert(key, JedisUtils.convertPosition(where), pivot, value);
+ return null;
+ }
+ return jedis.linsert(key, JedisUtils.convertPosition(where), pivot, value);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long lLen(byte[] key) {
+ try {
+ if (isQueueing()) {
+ transaction.llen(key);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.llen(key);
+ return null;
+ }
+ return jedis.llen(key);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public byte[] lPop(byte[] key) {
+ try {
+ if (isQueueing()) {
+ transaction.lpop(key);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.lpop(key);
+ return null;
+ }
+ return jedis.lpop(key);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public List lRange(byte[] key, long start, long end) {
+ try {
+ if (isQueueing()) {
+ transaction.lrange(key, (int) start, (int) end);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.lrange(key, (int) start, (int) end);
+ return null;
+ }
+ return jedis.lrange(key, (int) start, (int) end);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long lRem(byte[] key, long count, byte[] value) {
+ try {
+ if (isQueueing()) {
+ transaction.lrem(key, (int) count, value);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.lrem(key, (int) count, value);
+ return null;
+ }
+ return jedis.lrem(key, (int) count, value);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public void lSet(byte[] key, long index, byte[] value) {
+ try {
+ if (isQueueing()) {
+ transaction.lset(key, (int) index, value);
+ return;
+ }
+ if (isPipelined()) {
+ pipeline.lset(key, (int) index, value);
+ return;
+ }
+ jedis.lset(key, (int) index, value);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public void lTrim(byte[] key, long start, long end) {
+ try {
+ if (isQueueing()) {
+ transaction.ltrim(key, (int) start, (int) end);
+ return;
+ }
+ if (isPipelined()) {
+ pipeline.ltrim(key, (int) start, (int) end);
+ return;
+ }
+ jedis.ltrim(key, (int) start, (int) end);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public byte[] rPop(byte[] key) {
+ try {
+ if (isQueueing()) {
+ transaction.rpop(key);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.rpop(key);
+ return null;
+ }
+ return jedis.rpop(key);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public byte[] rPopLPush(byte[] srcKey, byte[] dstKey) {
+ try {
+ if (isQueueing()) {
+ transaction.rpoplpush(srcKey, dstKey);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.rpoplpush(srcKey, dstKey);
+ return null;
+ }
+ return jedis.rpoplpush(srcKey, dstKey);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public byte[] bRPopLPush(int timeout, byte[] srcKey, byte[] dstKey) {
+ try {
+ if (isQueueing()) {
+ transaction.brpoplpush(srcKey, dstKey, timeout);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.brpoplpush(srcKey, dstKey, timeout);
+ return null;
+ }
+ return jedis.brpoplpush(srcKey, dstKey, timeout);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long lPushX(byte[] key, byte[] value) {
+ try {
+ if (isQueueing()) {
+ transaction.lpushx(key, value);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.lpushx(key, value);
+ return null;
+ }
+ return jedis.lpushx(key, value);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long rPushX(byte[] key, byte[] value) {
+ try {
+ if (isQueueing()) {
+ transaction.rpushx(key, value);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.rpushx(key, value);
+ return null;
+ }
+ return jedis.rpushx(key, value);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+
+ //
+ // Set commands
+ //
+
+ @Override
+ public Boolean sAdd(byte[] key, byte[] value) {
+ try {
+ if (isQueueing()) {
+ transaction.sadd(key, value);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.sadd(key, value);
+ return null;
+ }
+ return (jedis.sadd(key, value) == 1);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long sCard(byte[] key) {
+ try {
+ if (isQueueing()) {
+ transaction.scard(key);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.scard(key);
+ return null;
+ }
+ return jedis.scard(key);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Set sDiff(byte[]... keys) {
+ try {
+ if (isQueueing()) {
+ transaction.sdiff(keys);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.sdiff(keys);
+ return null;
+ }
+ return jedis.sdiff(keys);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public void sDiffStore(byte[] destKey, byte[]... keys) {
+ try {
+ if (isQueueing()) {
+ transaction.sdiffstore(destKey, keys);
+ return;
+ }
+ if (isPipelined()) {
+ pipeline.sdiffstore(destKey, keys);
+ return;
+ }
+ jedis.sdiffstore(destKey, keys);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Set sInter(byte[]... keys) {
+ try {
+ if (isQueueing()) {
+ transaction.sinter(keys);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.sinter(keys);
+ return null;
+ }
+ return jedis.sinter(keys);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public void sInterStore(byte[] destKey, byte[]... keys) {
+ try {
+ if (isQueueing()) {
+ transaction.sinterstore(destKey, keys);
+ return;
+ }
+ if (isPipelined()) {
+ pipeline.sinterstore(destKey, keys);
+ return;
+ }
+ jedis.sinterstore(destKey, keys);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Boolean sIsMember(byte[] key, byte[] value) {
+ try {
+ if (isQueueing()) {
+ transaction.sismember(key, value);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.sismember(key, value);
+ return null;
+ }
+ return jedis.sismember(key, value);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Set sMembers(byte[] key) {
+ try {
+ if (isQueueing()) {
+ transaction.smembers(key);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.smembers(key);
+ return null;
+ }
+ return jedis.smembers(key);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Boolean sMove(byte[] srcKey, byte[] destKey, byte[] value) {
+ try {
+ if (isQueueing()) {
+ transaction.smove(srcKey, destKey, value);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.smove(srcKey, destKey, value);
+ return null;
+ }
+ return JedisUtils.convertCodeReply(jedis.smove(srcKey, destKey, value));
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public byte[] sPop(byte[] key) {
+ try {
+ if (isQueueing()) {
+ transaction.spop(key);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.spop(key);
+ return null;
+ }
+ return jedis.spop(key);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public byte[] sRandMember(byte[] key) {
+ try {
+ if (isQueueing()) {
+ transaction.srandmember(key);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.srandmember(key);
+ return null;
+ }
+ return jedis.srandmember(key);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Boolean sRem(byte[] key, byte[] value) {
+ try {
+ if (isQueueing()) {
+ transaction.srem(key, value);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.srem(key, value);
+ return null;
+ }
+ return JedisUtils.convertCodeReply(jedis.srem(key, value));
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Set sUnion(byte[]... keys) {
+ try {
+ if (isQueueing()) {
+ transaction.sunion(keys);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.sunion(keys);
+ return null;
+ }
+ return jedis.sunion(keys);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public void sUnionStore(byte[] destKey, byte[]... keys) {
+ try {
+ if (isQueueing()) {
+ transaction.sunionstore(destKey, keys);
+ return;
+ }
+ if (isPipelined()) {
+ pipeline.sunionstore(destKey, keys);
+ return;
+ }
+ jedis.sunionstore(destKey, keys);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ //
+ // ZSet commands
+ //
+
+ @Override
+ public Boolean zAdd(byte[] key, double score, byte[] value) {
+ try {
+ if (isQueueing()) {
+ transaction.zadd(key, score, value);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.zadd(key, score, value);
+ return null;
+ }
+ return JedisUtils.convertCodeReply(jedis.zadd(key, score, value));
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long zCard(byte[] key) {
+ try {
+ if (isQueueing()) {
+ transaction.zcard(key);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.zcard(key);
+ return null;
+ }
+ return jedis.zcard(key);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long zCount(byte[] key, double min, double max) {
+ try {
+ if (isQueueing()) {
+ transaction.zcount(key, min, max);
+ return null;
+ }
+ if (isQueueing()) {
+ pipeline.zcount(key, min, max);
+ return null;
+ }
+ return jedis.zcount(key, min, max);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Double zIncrBy(byte[] key, double increment, byte[] value) {
+ try {
+ if (isQueueing()) {
+ transaction.zincrby(key, increment, value);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.zincrby(key, increment, value);
+ return null;
+ }
+ return jedis.zincrby(key, increment, value);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long zInterStore(byte[] destKey, Aggregate aggregate, int[] weights, byte[]... sets) {
+ try {
+ ZParams zparams = new ZParams().weights(weights).aggregate(
+ redis.clients.jedis.ZParams.Aggregate.valueOf(aggregate.name()));
+
+ if (isQueueing()) {
+ transaction.zinterstore(destKey, zparams, sets);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.zinterstore(destKey, zparams, sets);
+ return null;
+ }
+ return jedis.zinterstore(destKey, zparams, sets);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long zInterStore(byte[] destKey, byte[]... sets) {
+ try {
+ if (isQueueing()) {
+ transaction.zinterstore(destKey, sets);
+ return null;
+ }
+ if (isQueueing()) {
+ pipeline.zinterstore(destKey, sets);
+ return null;
+ }
+ return jedis.zinterstore(destKey, sets);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Set zRange(byte[] key, long start, long end) {
+ try {
+ if (isQueueing()) {
+ transaction.zrange(key, (int) start, (int) end);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.zrange(key, (int) start, (int) end);
+ return null;
+ }
+ return jedis.zrange(key, (int) start, (int) end);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Set zRangeWithScores(byte[] key, long start, long end) {
+ try {
+ if (isQueueing()) {
+ transaction.zrangeWithScores(key, (int) start, (int) end);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.zrangeWithScores(key, (int) start, (int) end);
+ return null;
+ }
+ return JedisUtils.convertJedisTuple(jedis.zrangeWithScores(key, (int) start, (int) end));
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Set zRangeByScore(byte[] key, double min, double max) {
+ try {
+ if (isQueueing()) {
+ transaction.zrangeByScore(key, min, max);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.zrangeByScore(key, min, max);
+ return null;
+ }
+ return jedis.zrangeByScore(key, min, max);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Set zRangeByScoreWithScores(byte[] key, double min, double max) {
+ try {
+ if (isQueueing()) {
+ transaction.zrangeByScoreWithScores(key, min, max);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.zrangeByScoreWithScores(key, min, max);
+ return null;
+ }
+ return JedisUtils.convertJedisTuple(jedis.zrangeByScoreWithScores(key, min, max));
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Set zRevRangeWithScores(byte[] key, long start, long end) {
+ try {
+ if (isQueueing()) {
+ transaction.zrevrangeWithScores(key, (int) start, (int) end);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.zrevrangeWithScores(key, (int) start, (int) end);
+ return null;
+ }
+ return JedisUtils.convertJedisTuple(jedis.zrevrangeWithScores(key, (int) start, (int) end));
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Set zRangeByScore(byte[] key, double min, double max, long offset, long count) {
+ try {
+ if (isQueueing()) {
+ transaction.zrangeByScore(key, min, max, (int) offset, (int) count);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.zrangeByScore(key, min, max, (int) offset, (int) count);
+ return null;
+ }
+ return jedis.zrangeByScore(key, min, max, (int) offset, (int) count);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Set zRangeByScoreWithScores(byte[] key, double min, double max, long offset, long count) {
+ try {
+ if (isQueueing()) {
+ transaction.zrangeByScoreWithScores(key, min, max, (int) offset, (int) count);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.zrangeByScoreWithScores(key, min, max, (int) offset, (int) count);
+ return null;
+ }
+ return JedisUtils.convertJedisTuple(jedis.zrangeByScoreWithScores(key, min, max, (int) offset, (int) count));
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Set zRevRangeByScore(byte[] key, double min, double max, long offset, long count) {
+ try {
+ if (isQueueing()) {
+ throw new UnsupportedOperationException();
+ }
+ if (isPipelined()) {
+ throw new UnsupportedOperationException();
+ }
+ throw new UnsupportedOperationException();
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Set zRevRangeByScore(byte[] key, double min, double max) {
+ try {
+ if (isQueueing()) {
+ throw new UnsupportedOperationException();
+ }
+ if (isPipelined()) {
+ throw new UnsupportedOperationException();
+ }
+ throw new UnsupportedOperationException();
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Set zRevRangeByScoreWithScores(byte[] key, double min, double max, long offset, long count) {
+ try {
+ if (isQueueing()) {
+ throw new UnsupportedOperationException();
+ }
+ if (isPipelined()) {
+ throw new UnsupportedOperationException();
+ }
+ throw new UnsupportedOperationException();
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Set zRevRangeByScoreWithScores(byte[] key, double min, double max) {
+ try {
+ if (isQueueing()) {
+ throw new UnsupportedOperationException();
+ }
+ if (isPipelined()) {
+ throw new UnsupportedOperationException();
+ }
+ throw new UnsupportedOperationException();
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long zRank(byte[] key, byte[] value) {
+ try {
+ if (isQueueing()) {
+ transaction.zrank(key, value);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.zrank(key, value);
+ return null;
+ }
+ return jedis.zrank(key, value);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Boolean zRem(byte[] key, byte[] value) {
+ try {
+ if (isQueueing()) {
+ transaction.zrem(key, value);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.zrem(key, value);
+ return null;
+ }
+ return JedisUtils.convertCodeReply(jedis.zrem(key, value));
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long zRemRange(byte[] key, long start, long end) {
+ try {
+ if (isQueueing()) {
+ transaction.zremrangeByRank(key, (int) start, (int) end);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.zremrangeByRank(key, (int) start, (int) end);
+ return null;
+ }
+ return jedis.zremrangeByRank(key, (int) start, (int) end);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long zRemRangeByScore(byte[] key, double min, double max) {
+ try {
+ if (isQueueing()) {
+ transaction.zremrangeByScore(key, min, max);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.zremrangeByScore(key, min, max);
+ return null;
+ }
+ return jedis.zremrangeByScore(key, min, max);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Set zRevRange(byte[] key, long start, long end) {
+ try {
+ if (isQueueing()) {
+ transaction.zrevrange(key, (int) start, (int) end);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.zrevrange(key, (int) start, (int) end);
+ return null;
+ }
+ return jedis.zrevrange(key, (int) start, (int) end);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long zRevRank(byte[] key, byte[] value) {
+ try {
+ if (isQueueing()) {
+ transaction.zrevrank(key, value);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.zrevrank(key, value);
+ return null;
+ }
+ return jedis.zrevrank(key, value);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Double zScore(byte[] key, byte[] value) {
+ try {
+ if (isQueueing()) {
+ transaction.zscore(key, value);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.zscore(key, value);
+ return null;
+ }
+ return jedis.zscore(key, value);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long zUnionStore(byte[] destKey, Aggregate aggregate, int[] weights, byte[]... sets) {
+ try {
+ ZParams zparams = new ZParams().weights(weights).aggregate(
+ redis.clients.jedis.ZParams.Aggregate.valueOf(aggregate.name()));
+
+ if (isQueueing()) {
+ transaction.zunionstore(destKey, zparams, sets);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.zunionstore(destKey, zparams, sets);
+ return null;
+ }
+ return jedis.zunionstore(destKey, zparams, sets);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long zUnionStore(byte[] destKey, byte[]... sets) {
+ try {
+ if (isQueueing()) {
+ transaction.zunionstore(destKey, sets);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.zunionstore(destKey, sets);
+ return null;
+ }
+ return jedis.zunionstore(destKey, sets);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ //
+ // Hash commands
+ //
+
+ @Override
+ public Boolean hSet(byte[] key, byte[] field, byte[] value) {
+ try {
+ if (isQueueing()) {
+ transaction.hset(key, field, value);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.hset(key, field, value);
+ return null;
+ }
+ return JedisUtils.convertCodeReply(jedis.hset(key, field, value));
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Boolean hSetNX(byte[] key, byte[] field, byte[] value) {
+ try {
+ if (isQueueing()) {
+ transaction.hsetnx(key, field, value);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.hsetnx(key, field, value);
+ return null;
+ }
+ return JedisUtils.convertCodeReply(jedis.hsetnx(key, field, value));
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Boolean hDel(byte[] key, byte[] field) {
+ try {
+ if (isQueueing()) {
+ transaction.hdel(key, field);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.hdel(key, field);
+ return null;
+ }
+ return JedisUtils.convertCodeReply(jedis.hdel(key, field));
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Boolean hExists(byte[] key, byte[] field) {
+ try {
+ if (isQueueing()) {
+ transaction.hexists(key, field);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.hexists(key, field);
+ return null;
+ }
+ return jedis.hexists(key, field);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public byte[] hGet(byte[] key, byte[] field) {
+ try {
+ if (isQueueing()) {
+ transaction.hget(key, field);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.hget(key, field);
+ return null;
+ }
+ return jedis.hget(key, field);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Map hGetAll(byte[] key) {
+ try {
+ if (isQueueing()) {
+ transaction.hgetAll(key);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.hgetAll(key);
+ return null;
+ }
+ return jedis.hgetAll(key);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long hIncrBy(byte[] key, byte[] field, long delta) {
+ try {
+ if (isQueueing()) {
+ transaction.hincrBy(key, field, (int) delta);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.hincrBy(key, field, (int) delta);
+ return null;
+ }
+ return jedis.hincrBy(key, field, (int) delta);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Set hKeys(byte[] key) {
+ try {
+ if (isQueueing()) {
+ transaction.hkeys(key);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.hkeys(key);
+ return null;
+ }
+ return jedis.hkeys(key);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long hLen(byte[] key) {
+ try {
+ if (isQueueing()) {
+ transaction.hlen(key);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.hlen(key);
+ return null;
+ }
+ return jedis.hlen(key);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public List hMGet(byte[] key, byte[]... fields) {
+ try {
+ if (isQueueing()) {
+ transaction.hmget(key, fields);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.hmget(key, fields);
+ return null;
+ }
+ return jedis.hmget(key, fields);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public void hMSet(byte[] key, Map tuple) {
+ try {
+ if (isQueueing()) {
+ transaction.hmset(key, tuple);
+ return;
+ }
+ if (isPipelined()) {
+ pipeline.hmset(key, tuple);
+ return;
+ }
+ jedis.hmset(key, tuple);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public List hVals(byte[] key) {
+ try {
+ if (isQueueing()) {
+ transaction.hvals(key);
+ return null;
+ }
+ if (isPipelined()) {
+ pipeline.hvals(key);
+ return null;
+ }
+ return new ArrayList(jedis.hvals(key));
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+
+ //
+ // Pub/Sub functionality
+ //
+ @Override
+ public Long publish(byte[] channel, byte[] message) {
+ try {
+ if (isQueueing()) {
+ throw new UnsupportedOperationException();
+ }
+ if (isPipelined()) {
+ pipeline.publish(channel, message);
+ return null;
+ }
+ return jedis.publish(channel, message);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Subscription getSubscription() {
+ return subscription;
+ }
+
+ @Override
+ public boolean isSubscribed() {
+ return (subscription != null && subscription.isAlive());
+ }
+
+ @Override
+ public void pSubscribe(MessageListener listener, byte[]... patterns) {
+ if (isSubscribed()) {
+ throw new RedisSubscribedConnectionException(
+ "Connection already subscribed; use the connection Subscription to cancel or add new channels");
+ }
+
+ try {
+ if (isQueueing()) {
+ throw new UnsupportedOperationException();
+ }
+ if (isPipelined()) {
+ throw new UnsupportedOperationException();
+ }
+
+ BinaryJedisPubSub jedisPubSub = JedisUtils.adaptPubSub(listener);
+
+ subscription = new JedisSubscription(listener, jedisPubSub, null, patterns);
+ jedis.psubscribe(jedisPubSub, patterns);
+
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ @Override
+ public void subscribe(MessageListener listener, byte[]... channels) {
+ if (isSubscribed()) {
+ throw new RedisSubscribedConnectionException(
+ "Connection already subscribed; use the connection Subscription to cancel or add new channels");
+ }
+
+ try {
+ if (isQueueing()) {
+ throw new UnsupportedOperationException();
+ }
+ if (isPipelined()) {
+ throw new UnsupportedOperationException();
+ }
+
+ BinaryJedisPubSub jedisPubSub = JedisUtils.adaptPubSub(listener);
+
+ subscription = new JedisSubscription(listener, jedisPubSub, channels, null);
+ jedis.subscribe(jedisPubSub, channels);
+
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
+ private void checkSubscription() {
+ if (isSubscribed()) {
+ throw new RedisSubscribedConnectionException("Cannot execute command - connection is subscribed");
+ }
+ }
+}
\ No newline at end of file
diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/jedis/JedisConnectionFactory.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/jedis/JedisConnectionFactory.java
new file mode 100644
index 000000000..1f41fbb6b
--- /dev/null
+++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/jedis/JedisConnectionFactory.java
@@ -0,0 +1,303 @@
+/*
+ * Copyright 2010-2011 the original author or authors.
+ *
+ * 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.redis.connection.jedis;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.dao.DataAccessException;
+import org.springframework.dao.DataAccessResourceFailureException;
+import org.springframework.data.keyvalue.redis.connection.RedisConnection;
+import org.springframework.data.keyvalue.redis.connection.RedisConnectionFactory;
+import org.springframework.util.Assert;
+import org.springframework.util.StringUtils;
+
+import redis.clients.jedis.Jedis;
+import redis.clients.jedis.JedisPool;
+import redis.clients.jedis.JedisPoolConfig;
+import redis.clients.jedis.JedisShardInfo;
+import redis.clients.jedis.Protocol;
+
+/**
+ * Connection factory creating Jedis based connections.
+ *
+ * @author Costin Leau
+ */
+public class JedisConnectionFactory implements InitializingBean, DisposableBean, RedisConnectionFactory {
+
+ private final static Log log = LogFactory.getLog(JedisConnectionFactory.class);
+
+ private JedisShardInfo shardInfo;
+ private String hostName = "localhost";
+ private int port = Protocol.DEFAULT_PORT;
+ private int timeout = Protocol.DEFAULT_TIMEOUT;
+ private String password;
+
+ private boolean usePool = true;
+ private JedisPool pool = null;
+ private JedisPoolConfig poolConfig = new JedisPoolConfig();
+
+ private int dbIndex = 0;
+
+ /**
+ * Constructs a new JedisConnectionFactory instance
+ * with default settings (default connection pooling, no shard information).
+ */
+ public JedisConnectionFactory() {
+ }
+
+ /**
+ * Constructs a new JedisConnectionFactory instance.
+ * Will override the other connection parameters passed to the factory.
+ *
+ * @param shardInfo shard information
+ */
+ public JedisConnectionFactory(JedisShardInfo shardInfo) {
+ this.shardInfo = shardInfo;
+ }
+
+ /**
+ * Constructs a new JedisConnectionFactory instance using
+ * the given pool configuration.
+ *
+ * @param poolConfig pool configuration
+ */
+ public JedisConnectionFactory(JedisPoolConfig poolConfig) {
+ this.poolConfig = poolConfig;
+ }
+
+
+ /**
+ * Returns a Jedis instance to be used as a Redis connection.
+ * The instance can be newly created or retrieved from a pool.
+ *
+ * @return Jedis instance ready for wrapping into a {@link RedisConnection}.
+ */
+ protected Jedis fetchJedisConnector() {
+ try {
+ if (usePool && pool != null) {
+ return pool.getResource();
+ }
+ Jedis jedis = new Jedis(getShardInfo());
+ // force initialization (see Jedis issue #82)
+ jedis.connect();
+ return jedis;
+ } catch (Exception ex) {
+ throw new DataAccessResourceFailureException("Cannot get Jedis connection", ex);
+ }
+ }
+
+ /**
+ * Post process a newly retrieved connection. Useful for decorating or executing
+ * initialization commands on a new connection.
+ * This implementation simply returns the connection.
+ *
+ * @param connection
+ * @return processed connection
+ */
+ protected JedisConnection postProcessConnection(JedisConnection connection) {
+ return connection;
+ }
+
+ public void afterPropertiesSet() {
+ if (shardInfo == null) {
+ shardInfo = new JedisShardInfo(hostName, port);
+
+ if (StringUtils.hasLength(password)) {
+ shardInfo.setPassword(password);
+ }
+
+ if (timeout > 0) {
+ shardInfo.setTimeout(timeout);
+ }
+ }
+
+ if (usePool) {
+ pool = new JedisPool(poolConfig, shardInfo.getHost(), shardInfo.getPort(), shardInfo.getTimeout(),
+ shardInfo.getPassword());
+ }
+ }
+
+ public void destroy() {
+ if (usePool && pool != null) {
+ try {
+ pool.destroy();
+ } catch (Exception ex) {
+ log.warn("Cannot properly close Jedis pool", ex);
+ }
+ pool = null;
+ }
+ }
+
+ public JedisConnection getConnection() {
+ Jedis jedis = fetchJedisConnector();
+ return postProcessConnection((usePool ? new JedisConnection(jedis, pool, dbIndex) : new JedisConnection(jedis,
+ null, dbIndex)));
+ }
+
+ @Override
+ public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
+ return JedisUtils.convertJedisAccessException(ex);
+ }
+
+ /**
+ * Returns the Redis hostName.
+ *
+ * @return Returns the hostName
+ */
+ public String getHostName() {
+ return hostName;
+ }
+
+ /**
+ * Sets the Redis hostName.
+ *
+ * @param hostName The hostName to set.
+ */
+ public void setHostName(String hostName) {
+ this.hostName = hostName;
+ }
+
+ /**
+ * Returns the password used for authenticating with the Redis server.
+ *
+ * @return password for authentication
+ */
+ public String getPassword() {
+ return password;
+ }
+
+ /**
+ * Sets the password used for authenticating with the Redis server.
+ *
+ * @param password the password to set
+ */
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ /**
+ * Returns the port used to connect to the Redis instance.
+ *
+ * @return Redis port.
+ */
+ public int getPort() {
+ return port;
+
+ }
+
+ /**
+ * Sets the port used to connect to the Redis instance.
+ *
+ * @param port Redis port
+ */
+ public void setPort(int port) {
+ this.port = port;
+ }
+
+ /**
+ * Returns the shardInfo.
+ *
+ * @return Returns the shardInfo
+ */
+ public JedisShardInfo getShardInfo() {
+ return shardInfo;
+ }
+
+ /**
+ * Sets the shard info for this factory.
+ *
+ * @param shardInfo The shardInfo to set.
+ */
+ public void setShardInfo(JedisShardInfo shardInfo) {
+ this.shardInfo = shardInfo;
+ }
+
+ /**
+ * Returns the timeout.
+ *
+ * @return Returns the timeout
+ */
+ public int getTimeout() {
+ return timeout;
+ }
+
+ /**
+ * @param timeout The timeout to set.
+ */
+ public void setTimeout(int timeout) {
+ this.timeout = timeout;
+ }
+
+ /**
+ * Indicates the use of a connection pool.
+ *
+ * @return Returns the use of connection pooling.
+ */
+ public boolean getUsePool() {
+ return usePool;
+ }
+
+ /**
+ * Turns on or off the use of connection pooling.
+ *
+ * @param usePool The usePool to set.
+ */
+ public void setUsePool(boolean usePool) {
+ this.usePool = usePool;
+ }
+
+ /**
+ * Returns the poolConfig.
+ *
+ * @return Returns the poolConfig
+ */
+ public JedisPoolConfig getPoolConfig() {
+ return poolConfig;
+ }
+
+ /**
+ * Sets the pool configuration for this factory.
+ *
+ * @param poolConfig The poolConfig to set.
+ */
+ public void setPoolConfig(JedisPoolConfig poolConfig) {
+ this.poolConfig = poolConfig;
+ }
+
+
+ /**
+ * Returns the index of the database.
+ *
+ * @return Returns the database index
+ */
+ public int getDatabase() {
+ return dbIndex;
+ }
+
+ /**
+ * Sets the index of the database used by this connection factory.
+ * Default is 0.
+ *
+ * @param index database index
+ */
+ public void setDatabase(int index) {
+ Assert.isTrue(index >= 0, "invalid DB index (a positive index required)");
+ this.dbIndex = index;
+ }
+}
\ No newline at end of file
diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/jedis/JedisMessageListener.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/jedis/JedisMessageListener.java
new file mode 100644
index 000000000..92151968a
--- /dev/null
+++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/jedis/JedisMessageListener.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2011 the original author or authors.
+ *
+ * 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.redis.connection.jedis;
+
+import org.springframework.data.keyvalue.redis.connection.DefaultMessage;
+import org.springframework.data.keyvalue.redis.connection.MessageListener;
+import org.springframework.util.Assert;
+
+import redis.clients.jedis.BinaryJedisPubSub;
+
+/**
+ * MessageListener adapter on top of Jedis.
+ *
+ * @author Costin Leau
+ */
+class JedisMessageListener extends BinaryJedisPubSub {
+
+ private final MessageListener listener;
+
+ JedisMessageListener(MessageListener listener) {
+ Assert.notNull(listener, "message listener is required");
+ this.listener = listener;
+ }
+
+ @Override
+ public void onMessage(byte[] channel, byte[] message) {
+ listener.onMessage(new DefaultMessage(channel, message), null);
+ }
+
+ @Override
+ public void onPMessage(byte[] pattern, byte[] channel, byte[] message) {
+ listener.onMessage(new DefaultMessage(channel, message), pattern);
+ }
+
+ @Override
+ public void onPSubscribe(byte[] pattern, int subscribedChannels) {
+ // no-op
+ }
+
+ @Override
+ public void onPUnsubscribe(byte[] pattern, int subscribedChannels) {
+ // no-op
+ }
+
+ @Override
+ public void onSubscribe(byte[] channel, int subscribedChannels) {
+ // no-op
+ }
+
+ @Override
+ public void onUnsubscribe(byte[] channel, int subscribedChannels) {
+ // no-op
+ }
+}
\ No newline at end of file
diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/jedis/JedisSubscription.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/jedis/JedisSubscription.java
new file mode 100644
index 000000000..a2be1371a
--- /dev/null
+++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/jedis/JedisSubscription.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2011 the original author or authors.
+ *
+ * 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.redis.connection.jedis;
+
+import org.springframework.data.keyvalue.redis.connection.MessageListener;
+import org.springframework.data.keyvalue.redis.connection.util.AbstractSubscription;
+
+import redis.clients.jedis.BinaryJedisPubSub;
+
+/**
+ * Jedis specific subscription.
+ *
+ * @author Costin Leau
+ */
+class JedisSubscription extends AbstractSubscription {
+
+ private final BinaryJedisPubSub jedisPubSub;
+
+ JedisSubscription(MessageListener listener, BinaryJedisPubSub jedisPubSub, byte[][] channels, byte[][] patterns) {
+ super(listener, channels, patterns);
+ this.jedisPubSub = jedisPubSub;
+ }
+
+ @Override
+ protected void doClose() {
+ jedisPubSub.unsubscribe();
+ jedisPubSub.punsubscribe();
+ }
+
+ @Override
+ protected void doPsubscribe(byte[]... patterns) {
+ jedisPubSub.psubscribe(patterns);
+ }
+
+ @Override
+ protected void doPUnsubscribe(boolean all, byte[]... patterns) {
+ if (all) {
+ jedisPubSub.punsubscribe();
+ }
+ else {
+ jedisPubSub.punsubscribe(patterns);
+ }
+ }
+
+ @Override
+ protected void doSubscribe(byte[]... channels) {
+ jedisPubSub.subscribe(channels);
+ }
+
+ @Override
+ protected void doUnsubscribe(boolean all, byte[]... channels) {
+ if (all) {
+ jedisPubSub.unsubscribe();
+ }
+ else {
+ jedisPubSub.unsubscribe(channels);
+ }
+ }
+}
\ No newline at end of file
diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/jedis/JedisUtils.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/jedis/JedisUtils.java
new file mode 100644
index 000000000..f02e30fd8
--- /dev/null
+++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/jedis/JedisUtils.java
@@ -0,0 +1,233 @@
+/*
+ * Copyright 2010-2011 the original author or authors.
+ *
+ * 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.redis.connection.jedis;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.concurrent.TimeoutException;
+
+import org.springframework.dao.DataAccessException;
+import org.springframework.dao.InvalidDataAccessApiUsageException;
+import org.springframework.data.keyvalue.redis.RedisConnectionFailureException;
+import org.springframework.data.keyvalue.redis.RedisSystemException;
+import org.springframework.data.keyvalue.redis.connection.DefaultTuple;
+import org.springframework.data.keyvalue.redis.connection.MessageListener;
+import org.springframework.data.keyvalue.redis.connection.SortParameters;
+import org.springframework.data.keyvalue.redis.connection.RedisListCommands.Position;
+import org.springframework.data.keyvalue.redis.connection.RedisZSetCommands.Tuple;
+import org.springframework.data.keyvalue.redis.connection.SortParameters.Order;
+import org.springframework.data.keyvalue.redis.connection.SortParameters.Range;
+import org.springframework.util.Assert;
+
+import redis.clients.jedis.BinaryJedisPubSub;
+import redis.clients.jedis.Protocol;
+import redis.clients.jedis.SortingParams;
+import redis.clients.jedis.BinaryClient.LIST_POSITION;
+import redis.clients.jedis.exceptions.JedisConnectionException;
+import redis.clients.jedis.exceptions.JedisDataException;
+import redis.clients.jedis.exceptions.JedisException;
+
+/**
+ * Helper class featuring methods for Jedis connection handling, providing support for exception translation.
+ *
+ * @author Costin Leau
+ */
+public abstract class JedisUtils {
+
+ private static final String OK_CODE = "OK";
+ private static final String OK_MULTI_CODE = "+OK";
+ private static final byte[] ONE = new byte[] { 1 };
+ private static final byte[] ZERO = new byte[] { 0 };
+
+ /**
+ * Converts the given, native Jedis exception to Spring's DAO hierarchy.
+ *
+ * @param ex Jedis exception
+ * @return converted exception
+ */
+ public static DataAccessException convertJedisAccessException(JedisException ex) {
+ if (ex instanceof JedisDataException) {
+ return new InvalidDataAccessApiUsageException(ex.getMessage(), ex);
+ }
+ if (ex instanceof JedisConnectionException) {
+ return new RedisConnectionFailureException(ex.getMessage(), ex);
+ }
+
+ // fallback to invalid data exception
+ return new InvalidDataAccessApiUsageException(ex.getMessage(), ex);
+ }
+
+ /**
+ * Converts the given, native, runtime Jedis exception to Spring's DAO hierarchy.
+ *
+ * @param ex Jedis runtime/unchecked exception
+ * @return converted exception
+ */
+ public static DataAccessException convertJedisAccessException(RuntimeException ex) {
+ if (ex instanceof JedisException) {
+ return convertJedisAccessException((JedisException) ex);
+ }
+
+ return new RedisSystemException("Unknown exception", ex);
+ }
+
+ static DataAccessException convertJedisAccessException(IOException ex) {
+ if (ex instanceof UnknownHostException) {
+ return new RedisConnectionFailureException("Unknown host " + ex.getMessage(), ex);
+ }
+ return new RedisConnectionFailureException("Could not connect to Redis server", ex);
+ }
+
+ static DataAccessException convertJedisAccessException(TimeoutException ex) {
+ throw new RedisConnectionFailureException("Jedis pool timed out. Could not get Redis Connection", ex);
+ }
+
+ static boolean isStatusOk(String status) {
+ return status != null && (OK_CODE.equals(status) || OK_MULTI_CODE.equals(status));
+ }
+
+ static Boolean convertCodeReply(Number code) {
+ return (code != null ? code.intValue() == 1 : null);
+ }
+
+ static Set convertJedisTuple(Set tuples) {
+ Set value = new LinkedHashSet(tuples.size());
+ for (redis.clients.jedis.Tuple tuple : tuples) {
+ value.add(new DefaultTuple(tuple.getBinaryElement(), tuple.getScore()));
+ }
+
+ return value;
+ }
+
+ static byte[][] convert(Map hgetAll) {
+ byte[][] result = new byte[hgetAll.size() * 2][];
+
+ int index = 0;
+ for (Map.Entry entry : hgetAll.entrySet()) {
+ result[index++] = entry.getKey();
+ result[index++] = entry.getValue();
+ }
+ return result;
+ }
+
+ static Map convert(String[] fields, String[] values) {
+ Map result = new LinkedHashMap(fields.length);
+
+ for (int i = 0; i < values.length; i++) {
+ result.put(fields[i], values[i]);
+ }
+ return result;
+ }
+
+ static String[] arrange(String[] keys, String[] values) {
+ String[] result = new String[keys.length * 2];
+
+ for (int i = 0; i < keys.length; i++) {
+ int index = i << 1;
+ result[index] = keys[i];
+ result[index + 1] = values[i];
+
+ }
+ return result;
+ }
+
+ static SortingParams convertSortParams(SortParameters params) {
+ SortingParams jedisParams = null;
+
+ if (params != null) {
+ jedisParams = new SortingParams();
+
+ byte[] byPattern = params.getByPattern();
+ if (byPattern != null) {
+ jedisParams.by(params.getByPattern());
+ }
+
+ byte[][] getPattern = params.getGetPattern();
+ if (getPattern != null) {
+ jedisParams.get(getPattern);
+ }
+
+ Range limit = params.getLimit();
+ if (limit != null) {
+ jedisParams.limit((int) limit.getStart(), (int) limit.getCount());
+ }
+ Order order = params.getOrder();
+ if (order != null && order.equals(Order.DESC)) {
+ jedisParams.desc();
+ }
+ Boolean isAlpha = params.isAlphabetic();
+ if (isAlpha != null && isAlpha) {
+ jedisParams.alpha();
+ }
+ }
+
+ return jedisParams;
+ }
+
+ static byte[] asBit(boolean value) {
+ return (value ? ONE : ZERO);
+ }
+
+ static LIST_POSITION convertPosition(Position where) {
+ Assert.notNull("list positions are mandatory");
+ return (Position.AFTER.equals(where) ? LIST_POSITION.AFTER : LIST_POSITION.BEFORE);
+ }
+
+ static Properties info(String string) {
+ Properties info = new Properties();
+ StringReader stringReader = new StringReader(string);
+ try {
+ info.load(stringReader);
+ } catch (Exception ex) {
+ throw new RedisSystemException("Cannot read Redis info", ex);
+ } finally {
+ stringReader.close();
+ }
+ return info;
+ }
+
+ static BinaryJedisPubSub adaptPubSub(MessageListener listener) {
+ return new JedisMessageListener(listener);
+ }
+
+ static String[] convert(byte[]... raw) {
+ String[] result = new String[raw.length];
+
+ for (int i = 0; i < raw.length; i++) {
+ result[i] = new String(raw[i]);
+ }
+
+ return result;
+ }
+
+ static byte[][] bXPopArgs(int timeout, byte[]... keys) {
+ final List args = new ArrayList();
+ for (final byte[] arg : keys) {
+ args.add(arg);
+ }
+ args.add(Protocol.toByteArray(timeout));
+ return args.toArray(new byte[args.size()][]);
+ }
+}
\ No newline at end of file
diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/jedis/package-info.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/jedis/package-info.java
new file mode 100644
index 000000000..40ce7c10d
--- /dev/null
+++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/jedis/package-info.java
@@ -0,0 +1,5 @@
+/**
+ * Connection package for Jedis library.
+ */
+package org.springframework.data.keyvalue.redis.connection.jedis;
+
diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/jredis/JredisConnection.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/jredis/JredisConnection.java
new file mode 100644
index 000000000..00433eee2
--- /dev/null
+++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/jredis/JredisConnection.java
@@ -0,0 +1,1140 @@
+/*
+ * Copyright 2010-2011 the original author or authors.
+ *
+ * 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.redis.connection.jredis;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import org.jredis.ClientRuntimeException;
+import org.jredis.JRedis;
+import org.jredis.RedisException;
+import org.jredis.Sort;
+import org.jredis.Query.Support;
+import org.jredis.ri.alphazero.JRedisService;
+import org.springframework.dao.DataAccessException;
+import org.springframework.data.keyvalue.UncategorizedKeyvalueStoreException;
+import org.springframework.data.keyvalue.redis.RedisSystemException;
+import org.springframework.data.keyvalue.redis.connection.DataType;
+import org.springframework.data.keyvalue.redis.connection.MessageListener;
+import org.springframework.data.keyvalue.redis.connection.RedisConnection;
+import org.springframework.data.keyvalue.redis.connection.SortParameters;
+import org.springframework.data.keyvalue.redis.connection.Subscription;
+import org.springframework.util.Assert;
+
+/**
+ * {@code RedisConnection} implementation on top of JRedis library.
+ *
+ * @author Costin Leau
+ */
+public class JredisConnection implements RedisConnection {
+
+ private final JRedis jredis;
+ private final boolean isPool;
+ private boolean isClosed = false;
+
+ /**
+ * Constructs a new JredisConnection instance.
+ *
+ * @param jredis JRedis connection
+ */
+ public JredisConnection(JRedis jredis) {
+ Assert.notNull(jredis, "a not-null instance required");
+ this.jredis = jredis;
+ // required since Jredis combines the pool and the connection under the same interface/class
+ this.isPool = (jredis instanceof JRedisService);
+ }
+
+ protected DataAccessException convertJredisAccessException(Exception ex) {
+ if (ex instanceof RedisException) {
+ return JredisUtils.convertJredisAccessException((RedisException) ex);
+ }
+
+ if (ex instanceof ClientRuntimeException) {
+ return JredisUtils.convertJredisAccessException((ClientRuntimeException) ex);
+ }
+
+ return new UncategorizedKeyvalueStoreException("Unknown JRedis exception", ex);
+ }
+
+ @Override
+ public void close() throws RedisSystemException {
+ isClosed = true;
+
+ // don't actually close the connection
+ // if a pool is used
+ if (!isPool) {
+ try {
+ jredis.quit();
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+ }
+
+ @Override
+ public JRedis getNativeConnection() {
+ return jredis;
+ }
+
+ @Override
+ public boolean isClosed() {
+ return isClosed;
+ }
+
+ @Override
+ public boolean isQueueing() {
+ return false;
+ }
+
+ @Override
+ public boolean isPipelined() {
+ return false;
+ }
+
+ @Override
+ public void openPipeline() {
+ throw new UnsupportedOperationException("Pipelining not supported by JRedis");
+ }
+
+ @Override
+ public List closePipeline() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public List sort(byte[] key, SortParameters params) {
+ Sort sort = jredis.sort(JredisUtils.decode(key));
+ JredisUtils.applySortingParams(sort, params, null);
+ try {
+ return sort.exec();
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long sort(byte[] key, SortParameters params, byte[] storeKey) {
+ Sort sort = jredis.sort(JredisUtils.decode(key));
+ JredisUtils.applySortingParams(sort, params, null);
+ try {
+ return Support.unpackValue(sort.exec());
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long dbSize() {
+ try {
+ return jredis.dbsize();
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public void flushDb() {
+ try {
+ jredis.flushdb();
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public void flushAll() {
+ try {
+ jredis.flushall();
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public byte[] echo(byte[] message) {
+ try {
+ return jredis.echo(message);
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public String ping() {
+ try {
+ jredis.ping();
+ return "PONG";
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public void bgSave() {
+ try {
+ jredis.bgsave();
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public void bgWriteAof() {
+ try {
+ jredis.bgrewriteaof();
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public void save() {
+ try {
+ jredis.save();
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public List getConfig(String pattern) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Properties info() {
+ try {
+ return JredisUtils.info(jredis.info());
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long lastSave() {
+ try {
+ return jredis.lastsave();
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public void setConfig(String param, String value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void resetConfigStats() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void shutdown() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Long del(byte[]... keys) {
+ try {
+ return jredis.del(JredisUtils.decodeMultiple(keys));
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public void discard() {
+ try {
+ jredis.discard();
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public List exec() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Boolean exists(byte[] key) {
+ try {
+ return jredis.exists(JredisUtils.decode(key));
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Boolean expire(byte[] key, long seconds) {
+ try {
+ return jredis.expire(JredisUtils.decode(key), (int) seconds);
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Boolean expireAt(byte[] key, long unixTime) {
+ try {
+ return jredis.expireat(JredisUtils.decode(key), unixTime);
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Set keys(byte[] pattern) {
+ try {
+ return JredisUtils.convertToSet(jredis.keys(JredisUtils.decode(pattern)));
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public void multi() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Boolean persist(byte[] key) {
+ throw new UnsupportedOperationException();
+ }
+
+
+ @Override
+ public Boolean move(byte[] key, int dbIndex) {
+ try {
+ return jredis.move(JredisUtils.decode(key), dbIndex);
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public byte[] randomKey() {
+ try {
+ return JredisUtils.encode(jredis.randomkey());
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public void rename(byte[] oldName, byte[] newName) {
+ try {
+ jredis.rename(JredisUtils.decode(oldName), JredisUtils.decode(newName));
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Boolean renameNX(byte[] oldName, byte[] newName) {
+ try {
+ return jredis.renamenx(JredisUtils.decode(oldName), JredisUtils.decode(newName));
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public void select(int dbIndex) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Long ttl(byte[] key) {
+ try {
+ return jredis.ttl(JredisUtils.decode(key));
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public DataType type(byte[] key) {
+ try {
+ return JredisUtils.convertDataType(jredis.type(JredisUtils.decode(key)));
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public void unwatch() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void watch(byte[]... keys) {
+ throw new UnsupportedOperationException();
+ }
+
+ //
+ // String operations
+ //
+
+ @Override
+ public byte[] get(byte[] key) {
+ try {
+ return jredis.get(JredisUtils.decode(key));
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public void set(byte[] key, byte[] value) {
+ try {
+ jredis.set(JredisUtils.decode(key), value);
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public byte[] getSet(byte[] key, byte[] value) {
+ try {
+ return jredis.getset(JredisUtils.decode(key), value);
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long append(byte[] key, byte[] value) {
+ try {
+ return jredis.append(JredisUtils.decode(key), value);
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public List mGet(byte[]... keys) {
+ try {
+ return jredis.mget(JredisUtils.decodeMultiple(keys));
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public void mSet(Map tuple) {
+ try {
+ jredis.mset(JredisUtils.decodeMap(tuple));
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public void mSetNX(Map tuple) {
+ try {
+ jredis.msetnx(JredisUtils.decodeMap(tuple));
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public void setEx(byte[] key, long seconds, byte[] value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Boolean setNX(byte[] key, byte[] value) {
+ try {
+ return jredis.setnx(JredisUtils.decode(key), value);
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public byte[] getRange(byte[] key, long start, long end) {
+ try {
+ return jredis.substr(JredisUtils.decode(key), start, end);
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long decr(byte[] key) {
+ try {
+ return jredis.decr(JredisUtils.decode(key));
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long decrBy(byte[] key, long value) {
+ try {
+ return jredis.decrby(JredisUtils.decode(key), (int) value);
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long incr(byte[] key) {
+ try {
+ return jredis.incr(JredisUtils.decode(key));
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long incrBy(byte[] key, long value) {
+ try {
+ return jredis.incrby(JredisUtils.decode(key), (int) value);
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Boolean getBit(byte[] key, long offset) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setBit(byte[] key, long offset, boolean value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setRange(byte[] key, byte[] value, long start) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Long strLen(byte[] key) {
+ throw new UnsupportedOperationException();
+ }
+
+ //
+ // List commands
+ //
+
+ @Override
+ public List bLPop(int timeout, byte[]... keys) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List bRPop(int timeout, byte[]... keys) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public byte[] lIndex(byte[] key, long index) {
+ try {
+ return jredis.lindex(JredisUtils.decode(key), index);
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long lLen(byte[] key) {
+ try {
+ return jredis.llen(JredisUtils.decode(key));
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public byte[] lPop(byte[] key) {
+ try {
+ return jredis.lpop(JredisUtils.decode(key));
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long lPush(byte[] key, byte[] value) {
+ try {
+ jredis.lpush(JredisUtils.decode(key), value);
+ return null;
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public List lRange(byte[] key, long start, long end) {
+ try {
+ List lrange = jredis.lrange(JredisUtils.decode(key), start, end);
+
+ return lrange;
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long lRem(byte[] key, long count, byte[] value) {
+ try {
+ return jredis.lrem(JredisUtils.decode(key), value, (int) count);
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public void lSet(byte[] key, long index, byte[] value) {
+ try {
+ jredis.lset(JredisUtils.decode(key), index, value);
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public void lTrim(byte[] key, long start, long end) {
+ try {
+ jredis.ltrim(JredisUtils.decode(key), start, end);
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public byte[] rPop(byte[] key) {
+ try {
+ return jredis.rpop(JredisUtils.decode(key));
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public byte[] rPopLPush(byte[] srcKey, byte[] dstKey) {
+ try {
+ return jredis.rpoplpush(JredisUtils.decode(srcKey), JredisUtils.decode(dstKey));
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long rPush(byte[] key, byte[] value) {
+ try {
+ jredis.rpush(JredisUtils.decode(key), value);
+ return null;
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long lInsert(byte[] key, Position where, byte[] pivot, byte[] value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public byte[] bRPopLPush(int timeout, byte[] srcKey, byte[] dstKey) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Long lPushX(byte[] key, byte[] value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Long rPushX(byte[] key, byte[] value) {
+ throw new UnsupportedOperationException();
+ }
+
+
+ //
+ // Set commands
+ //
+
+ @Override
+ public Boolean sAdd(byte[] key, byte[] value) {
+ try {
+ return jredis.sadd(JredisUtils.decode(key), value);
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long sCard(byte[] key) {
+ try {
+ return jredis.scard(JredisUtils.decode(key));
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Set sDiff(byte[]... keys) {
+ String destKey = JredisUtils.decode(keys[0]);
+ String[] sets = JredisUtils.decodeMultiple(Arrays.copyOfRange(keys, 1, keys.length));
+
+ try {
+ List result = jredis.sdiff(destKey, sets);
+ return new LinkedHashSet(result);
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public void sDiffStore(byte[] destKey, byte[]... keys) {
+ String destSet = JredisUtils.decode(destKey);
+ String[] sets = JredisUtils.decodeMultiple(keys);
+
+ try {
+ jredis.sdiffstore(destSet, sets);
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Set sInter(byte[]... keys) {
+ String set1 = JredisUtils.decode(keys[0]);
+ String[] sets = JredisUtils.decodeMultiple(Arrays.copyOfRange(keys, 1, keys.length));
+
+ try {
+ List result = jredis.sinter(set1, sets);
+ return new LinkedHashSet(result);
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public void sInterStore(byte[] destKey, byte[]... keys) {
+ String destSet = JredisUtils.decode(destKey);
+ String[] sets = JredisUtils.decodeMultiple(keys);
+
+ try {
+ jredis.sinterstore(destSet, sets);
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Boolean sIsMember(byte[] key, byte[] value) {
+ try {
+ return jredis.sismember(JredisUtils.decode(key), value);
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Set sMembers(byte[] key) {
+ try {
+ return new LinkedHashSet(jredis.smembers(JredisUtils.decode(key)));
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Boolean sMove(byte[] srcKey, byte[] destKey, byte[] value) {
+ try {
+ return jredis.smove(JredisUtils.decode(srcKey), JredisUtils.decode(destKey), value);
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public byte[] sPop(byte[] key) {
+ try {
+ return jredis.spop(JredisUtils.decode(key));
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public byte[] sRandMember(byte[] key) {
+ try {
+ return jredis.srandmember(JredisUtils.decode(key));
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Boolean sRem(byte[] key, byte[] value) {
+ try {
+ return jredis.srem(JredisUtils.decode(key), value);
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Set sUnion(byte[]... keys) {
+ String set1 = JredisUtils.decode(keys[0]);
+ String[] sets = JredisUtils.decodeMultiple(Arrays.copyOfRange(keys, 1, keys.length));
+
+ try {
+ return new LinkedHashSet(jredis.sunion(set1, sets));
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public void sUnionStore(byte[] destKey, byte[]... keys) {
+ String destSet = JredisUtils.decode(destKey);
+ String[] sets = JredisUtils.decodeMultiple(keys);
+
+ try {
+ jredis.sunionstore(destSet, sets);
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+
+ //
+ // ZSet commands
+ //
+
+ @Override
+ public Boolean zAdd(byte[] key, double score, byte[] value) {
+ try {
+ return jredis.zadd(JredisUtils.decode(key), score, value);
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long zCard(byte[] key) {
+ try {
+ return jredis.zcard(JredisUtils.decode(key));
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long zCount(byte[] key, double min, double max) {
+ try {
+ return jredis.zcount(JredisUtils.decode(key), min, max);
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Double zIncrBy(byte[] key, double increment, byte[] value) {
+ try {
+ return jredis.zincrby(JredisUtils.decode(key), increment, value);
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long zInterStore(byte[] destKey, Aggregate aggregate, int[] weights, byte[]... sets) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Long zInterStore(byte[] destKey, byte[]... sets) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Set zRange(byte[] key, long start, long end) {
+ try {
+ return new LinkedHashSet(jredis.zrange(JredisUtils.decode(key), start, end));
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Set zRangeWithScores(byte[] key, long start, long end) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Set zRangeByScore(byte[] key, double min, double max) {
+ try {
+ return new LinkedHashSet(jredis.zrangebyscore(JredisUtils.decode(key), min, max));
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Set zRangeByScoreWithScores(byte[] key, double min, double max) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Set zRangeByScore(byte[] key, double min, double max, long offset, long count) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Set zRangeByScoreWithScores(byte[] key, double min, double max, long offset, long count) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Set zRevRangeByScore(byte[] key, double min, double max, long offset, long count) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Set zRevRangeByScore(byte[] key, double min, double max) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Set zRevRangeByScoreWithScores(byte[] key, double min, double max, long offset, long count) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Set zRevRangeByScoreWithScores(byte[] key, double min, double max) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Long zRank(byte[] key, byte[] value) {
+ try {
+ return jredis.zrank(JredisUtils.decode(key), value);
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Boolean zRem(byte[] key, byte[] value) {
+ try {
+ return jredis.zrem(JredisUtils.decode(key), value);
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long zRemRange(byte[] key, long start, long end) {
+ try {
+ return jredis.zremrangebyrank(JredisUtils.decode(key), start, end);
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long zRemRangeByScore(byte[] key, double min, double max) {
+ try {
+ return jredis.zremrangebyscore(JredisUtils.decode(key), min, max);
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Set zRevRange(byte[] key, long start, long end) {
+ try {
+ return new LinkedHashSet(jredis.zrevrange(JredisUtils.decode(key), start, end));
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Set zRevRangeWithScores(byte[] key, long start, long end) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Long zRevRank(byte[] key, byte[] value) {
+ try {
+ return jredis.zrevrank(JredisUtils.decode(key), value);
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Double zScore(byte[] key, byte[] value) {
+ try {
+ return jredis.zscore(JredisUtils.decode(key), value);
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+
+ //
+ // Hash commands
+ //
+
+ @Override
+ public Long zUnionStore(byte[] destKey, Aggregate aggregate, int[] weights, byte[]... sets) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Long zUnionStore(byte[] destKey, byte[]... sets) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Boolean hDel(byte[] key, byte[] field) {
+ try {
+ return jredis.hdel(JredisUtils.decode(key), JredisUtils.decode(field));
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Boolean hExists(byte[] key, byte[] field) {
+ try {
+ return jredis.hexists(JredisUtils.decode(key), JredisUtils.decode(field));
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public byte[] hGet(byte[] key, byte[] field) {
+ try {
+ return jredis.hget(JredisUtils.decode(key), JredisUtils.decode(field));
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Map hGetAll(byte[] key) {
+ try {
+ return JredisUtils.encodeMap(jredis.hgetall(JredisUtils.decode(key)));
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long hIncrBy(byte[] key, byte[] field, long delta) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Set hKeys(byte[] key) {
+ try {
+ return new LinkedHashSet(JredisUtils.convertToSet(jredis.hkeys(JredisUtils.decode(key))));
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long hLen(byte[] key) {
+ try {
+ return jredis.hlen(JredisUtils.decode(key));
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public List hMGet(byte[] key, byte[]... fields) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void hMSet(byte[] key, Map values) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Boolean hSet(byte[] key, byte[] field, byte[] value) {
+ try {
+ return jredis.hset(JredisUtils.decode(key), JredisUtils.decode(field), value);
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ @Override
+ public Boolean hSetNX(byte[] key, byte[] field, byte[] value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List hVals(byte[] key) {
+ try {
+ return jredis.hvals(JredisUtils.decode(key));
+ } catch (Exception ex) {
+ throw convertJredisAccessException(ex);
+ }
+ }
+
+ //
+ // PubSub commands
+ //
+
+ @Override
+ public Subscription getSubscription() {
+ return null;
+ }
+
+ @Override
+ public boolean isSubscribed() {
+ return false;
+ }
+
+ @Override
+ public void pSubscribe(MessageListener listener, byte[]... patterns) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Long publish(byte[] channel, byte[] message) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void subscribe(MessageListener listener, byte[]... channels) {
+ throw new UnsupportedOperationException();
+ }
+}
\ No newline at end of file
diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/jredis/JredisConnectionFactory.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/jredis/JredisConnectionFactory.java
new file mode 100644
index 000000000..a52d377a1
--- /dev/null
+++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/jredis/JredisConnectionFactory.java
@@ -0,0 +1,246 @@
+/*
+ * Copyright 2010-2011 the original author or authors.
+ *
+ * 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.redis.connection.jredis;
+
+import org.jredis.ClientRuntimeException;
+import org.jredis.connector.Connection;
+import org.jredis.connector.ConnectionSpec;
+import org.jredis.connector.Connection.Socket.Property;
+import org.jredis.ri.alphazero.JRedisClient;
+import org.jredis.ri.alphazero.JRedisService;
+import org.jredis.ri.alphazero.connection.DefaultConnectionSpec;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.dao.DataAccessException;
+import org.springframework.data.keyvalue.redis.connection.RedisConnection;
+import org.springframework.data.keyvalue.redis.connection.RedisConnectionFactory;
+import org.springframework.util.Assert;
+import org.springframework.util.StringUtils;
+
+/**
+ * Connection factory using creating JRedis based connections.
+ *
+ * @author Costin Leau
+ */
+public class JredisConnectionFactory implements InitializingBean, DisposableBean, RedisConnectionFactory {
+
+ private ConnectionSpec connectionSpec;
+
+ private String hostName = "localhost";
+ private int port = DEFAULT_REDIS_PORT;
+ private String password = null;
+ private int timeout;
+
+ private boolean usePool = true;
+ private int dbIndex = DEFAULT_REDIS_DB;
+
+ private JRedisService pool = null;
+ // taken from JRedis code
+ private int poolSize = 5;
+
+ private static final int DEFAULT_REDIS_PORT = 6379;
+ private static final int DEFAULT_REDIS_DB = 0;
+ private static final byte[] DEFAULT_REDIS_PASSWORD = null;
+
+
+ /**
+ * Constructs a new JredisConnectionFactory instance.
+ */
+ public JredisConnectionFactory() {
+ }
+
+ /**
+ * Constructs a new JredisConnectionFactory instance.
+ * Will override the other connection parameters passed to the factory.
+ *
+ * @param connectionSpec already configured connection.
+ */
+ public JredisConnectionFactory(ConnectionSpec connectionSpec) {
+ this.connectionSpec = connectionSpec;
+ }
+
+ @Override
+ public void afterPropertiesSet() {
+ if (connectionSpec == null) {
+ Assert.hasText(hostName);
+ connectionSpec = DefaultConnectionSpec.newSpec(hostName, port, dbIndex, DEFAULT_REDIS_PASSWORD);
+ connectionSpec.setConnectionFlag(Connection.Flag.RELIABLE, false);
+
+ if (StringUtils.hasLength(password)) {
+ connectionSpec.setCredentials(password);
+ }
+
+ if (timeout > 0) {
+ connectionSpec.setSocketProperty(Property.SO_TIMEOUT, timeout);
+ }
+ }
+
+ if (usePool) {
+ int size = getPoolSize();
+ pool = new JRedisService(connectionSpec, size);
+ }
+ }
+
+
+ @Override
+ public void destroy() {
+ if (usePool && pool != null) {
+ pool.quit();
+ pool = null;
+ }
+ }
+
+
+ @Override
+ public RedisConnection getConnection() {
+ return postProcessConnection(new JredisConnection((usePool ? pool : new JRedisClient(connectionSpec))));
+ }
+
+
+ /**
+ * Post process a newly retrieved connection. Useful for decorating or executing
+ * initialization commands on a new connection.
+ * This implementation simply returns the connection.
+ *
+ * @param connection
+ * @return processed connection
+ */
+ protected RedisConnection postProcessConnection(JredisConnection connection) {
+ return connection;
+ }
+
+ @Override
+ public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
+ if (ex instanceof ClientRuntimeException) {
+ return JredisUtils.convertJredisAccessException((ClientRuntimeException) ex);
+ }
+ return null;
+ }
+
+
+ /**
+ * Returns the Redis host name of this factory.
+ *
+ * @return Returns the hostName
+ */
+ public String getHostName() {
+ return hostName;
+ }
+
+ /**
+ * Sets the Redis host name for this factory.
+ *
+ * @param hostName The hostName to set.
+ */
+ public void setHostName(String hostName) {
+ this.hostName = hostName;
+ }
+
+
+ /**
+ * Returns the Redis port.
+ *
+ * @return Returns the port
+ */
+ public int getPort() {
+ return port;
+ }
+
+ /**
+ * Sets the Redis port.
+ *
+ * @param port The port to set.
+ */
+ public void setPort(int port) {
+ this.port = port;
+ }
+
+ /**
+ * Returns the password used for authenticating with the Redis server.
+ *
+ * @return password for authentication
+ */
+ public String getPassword() {
+ return password;
+ }
+
+ /**
+ * Sets the password used for authenticating with the Redis server.
+ *
+ * @param password the password to set
+ */
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ /**
+ * Indicates the use of a connection pool.
+ *
+ * @return Returns the use of connection pooling.
+ */
+ public boolean getUsePool() {
+ return usePool;
+ }
+
+ /**
+ * Turns on or off the use of connection pooling.
+ *
+ * @param usePool The usePool to set.
+ */
+ public void setUsePool(boolean usePool) {
+ this.usePool = usePool;
+ }
+
+ /**
+ * Returns the pool size of this factory.
+ *
+ * @return Returns the poolSize
+ */
+ public int getPoolSize() {
+ return poolSize;
+ }
+
+ /**
+ * Sets the connection pool size of the underlying factory.
+ *
+ * @param poolSize The poolSize to set.
+ */
+ public void setPoolSize(int poolSize) {
+ Assert.isTrue(poolSize > 0, "pool size needs to be bigger then zero");
+ this.poolSize = poolSize;
+ usePool = true;
+ }
+
+ /**
+ * Returns the index of the database.
+ *
+ * @return Returns the database index
+ */
+ public int getDatabase() {
+ return dbIndex;
+ }
+
+ /**
+ * Sets the index of the database used by this connection factory.
+ * Can be between 0 (default) and 15.
+ *
+ * @param index database index
+ */
+ public void setDatabase(int index) {
+ Assert.isTrue(index >= 0, "invalid DB index (a positive index required)");
+ this.dbIndex = index;
+ }
+}
\ No newline at end of file
diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/jredis/JredisUtils.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/jredis/JredisUtils.java
new file mode 100644
index 000000000..9cb3dc146
--- /dev/null
+++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/jredis/JredisUtils.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2010-2011 the original author or authors.
+ *
+ * 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.redis.connection.jredis;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import org.jredis.ClientRuntimeException;
+import org.jredis.RedisException;
+import org.jredis.RedisType;
+import org.jredis.Sort;
+import org.springframework.dao.DataAccessException;
+import org.springframework.dao.InvalidDataAccessApiUsageException;
+import org.springframework.dao.InvalidDataAccessResourceUsageException;
+import org.springframework.data.keyvalue.redis.connection.DataType;
+import org.springframework.data.keyvalue.redis.connection.SortParameters;
+import org.springframework.data.keyvalue.redis.connection.SortParameters.Order;
+import org.springframework.data.keyvalue.redis.connection.SortParameters.Range;
+import org.springframework.data.keyvalue.redis.connection.util.DecodeUtils;
+
+/**
+ * Helper class featuring methods for JRedis connection handling, providing support for exception translation.
+ *
+ * @author Costin Leau
+ */
+public abstract class JredisUtils {
+
+ /**
+ * Converts the given, native JRedis exception to Spring's DAO hierarchy.
+ *
+ * @param ex JRedis exception
+ * @return converted exception
+ */
+ public static DataAccessException convertJredisAccessException(RedisException ex) {
+ return new InvalidDataAccessApiUsageException(ex.getMessage(), ex);
+ }
+
+ /**
+ * Converts the given, native JRedis exception to Spring's DAO hierarchy.
+ *
+ * @param ex JRedis exception
+ * @return converted exception
+ */
+ public static DataAccessException convertJredisAccessException(ClientRuntimeException ex) {
+ return new InvalidDataAccessResourceUsageException(ex.getMessage(), ex);
+ }
+
+ static DataType convertDataType(RedisType type) {
+ switch (type) {
+ case NONE:
+ return DataType.NONE;
+ case string:
+ return DataType.STRING;
+ case list:
+ return DataType.LIST;
+ case set:
+ return DataType.SET;
+ //case zset:
+ // return DataType.ZSET;
+ case hash:
+ return DataType.HASH;
+ }
+
+ return null;
+ }
+
+ static String decode(byte[] bytes) {
+ return DecodeUtils.decode(bytes);
+ }
+
+ static byte[] encode(String string) {
+ return DecodeUtils.encode(string);
+ }
+
+ static String[] decodeMultiple(byte[]... bytes) {
+ return DecodeUtils.decodeMultiple(bytes);
+ }
+
+ static Map encodeMap(Map map) {
+ return DecodeUtils.encodeMap(map);
+ }
+
+ static Map decodeMap(Map tuple) {
+ return DecodeUtils.decodeMap(tuple);
+ }
+
+ static Set convertToSet(Collection keys) {
+ return DecodeUtils.convertToSet(keys);
+ }
+
+ static Sort applySortingParams(Sort jredisSort, SortParameters params, byte[] storeKey) {
+ if (params != null) {
+ byte[] byPattern = params.getByPattern();
+ if (byPattern != null) {
+ jredisSort.BY(decode(byPattern));
+ }
+ byte[][] getPattern = params.getGetPattern();
+
+ if (getPattern != null && getPattern.length > 0) {
+ for (byte[] bs : getPattern) {
+ jredisSort.GET(decode(bs));
+ }
+ }
+ Range limit = params.getLimit();
+ if (limit != null) {
+ jredisSort.LIMIT(limit.getStart(), limit.getCount());
+ }
+ Order order = params.getOrder();
+ if (order != null && order.equals(Order.DESC)) {
+ jredisSort.DESC();
+ }
+ Boolean isAlpha = params.isAlphabetic();
+ if (isAlpha != null && isAlpha) {
+ jredisSort.ALPHA();
+ }
+ }
+
+ if (storeKey != null) {
+ jredisSort.STORE(decode(storeKey));
+ }
+
+
+ return jredisSort;
+ }
+
+ static Properties info(Map map) {
+ Properties info = new Properties();
+ info.putAll(map);
+ return info;
+ }
+}
\ No newline at end of file
diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/jredis/package-info.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/jredis/package-info.java
new file mode 100644
index 000000000..0affe42a0
--- /dev/null
+++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/jredis/package-info.java
@@ -0,0 +1,5 @@
+/**
+ * Connection package for JRedis library.
+ */
+package org.springframework.data.keyvalue.redis.connection.jredis;
+
diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/package-info.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/package-info.java
new file mode 100644
index 000000000..72c48c6b4
--- /dev/null
+++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/package-info.java
@@ -0,0 +1,8 @@
+/**
+ * Connection package providing low-level abstractions for interacting with
+ * the various Redis 'drivers'/libraries.
+ *
+ *
Performs exception translation between the underlying library exceptions to Spring's DAO hierarchy.
+ */
+package org.springframework.data.keyvalue.redis.connection;
+
diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/rjc/CloseSuppressingRjcConnection.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/rjc/CloseSuppressingRjcConnection.java
new file mode 100644
index 000000000..f5adba611
--- /dev/null
+++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/rjc/CloseSuppressingRjcConnection.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2011 the original author or authors.
+ *
+ * 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.redis.connection.rjc;
+
+import java.io.IOException;
+import java.net.UnknownHostException;
+import java.util.List;
+
+import org.idevlab.rjc.ds.RedisConnection;
+import org.idevlab.rjc.message.RedisNodeSubscriber;
+import org.idevlab.rjc.protocol.Protocol.Command;
+
+/**
+ * Basic decorator suppressing close() calls to the underlying connection.
+ * Used for reusing arbitrary connections with {@link RedisNodeSubscriber} without
+ * resorting to connection pooling.
+ *
+ * @author Costin Leau
+ */
+class CloseSuppressingRjcConnection implements RedisConnection {
+
+ private final RedisConnection delegate;
+
+ /**
+ * Constructs a new CloseSuppressingRjcConnection instance.
+ *
+ * @param delegate
+ */
+ CloseSuppressingRjcConnection(RedisConnection delegate) {
+ this.delegate = delegate;
+ }
+
+ public void close() {
+ // no-op
+ }
+
+ public void connect() throws UnknownHostException, IOException {
+ delegate.connect();
+ }
+
+ public List getAll() {
+ return delegate.getAll();
+ }
+
+ public String getBulkReply() {
+ return delegate.getBulkReply();
+ }
+
+ public String getHost() {
+ return delegate.getHost();
+ }
+
+ public Long getIntegerReply() {
+ return delegate.getIntegerReply();
+ }
+
+ public List getMultiBulkReply() {
+ return delegate.getMultiBulkReply();
+ }
+
+ public List getObjectMultiBulkReply() {
+ return delegate.getObjectMultiBulkReply();
+ }
+
+ public Object getOne() {
+ return delegate.getOne();
+ }
+
+ public int getPort() {
+ return delegate.getPort();
+ }
+
+ public String getStatusCodeReply() {
+ return delegate.getStatusCodeReply();
+ }
+
+ public int getTimeout() {
+ return delegate.getTimeout();
+ }
+
+ public boolean isConnected() {
+ return delegate.isConnected();
+ }
+
+ public void rollbackTimeout() {
+ delegate.rollbackTimeout();
+ }
+
+ public void sendCommand(Command arg0, byte[]... arg1) {
+ delegate.sendCommand(arg0, arg1);
+ }
+
+ public void sendCommand(Command arg0, String... arg1) {
+ delegate.sendCommand(arg0, arg1);
+ }
+
+ public void sendCommand(Command arg0) {
+ delegate.sendCommand(arg0);
+ }
+
+ public void setTimeoutInfinite() {
+ delegate.setTimeoutInfinite();
+ }
+}
\ No newline at end of file
diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/rjc/RjcConnection.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/rjc/RjcConnection.java
new file mode 100644
index 000000000..1176fc57d
--- /dev/null
+++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/connection/rjc/RjcConnection.java
@@ -0,0 +1,2144 @@
+/*
+ * Copyright 2011 the original author or authors.
+ *
+ * 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.redis.connection.rjc;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import org.idevlab.rjc.Client;
+import org.idevlab.rjc.RedisException;
+import org.idevlab.rjc.Session;
+import org.idevlab.rjc.SessionFactoryImpl;
+import org.idevlab.rjc.SortingParams;
+import org.idevlab.rjc.ZParams;
+import org.idevlab.rjc.message.RedisNodeSubscriber;
+import org.springframework.dao.DataAccessException;
+import org.springframework.data.keyvalue.UncategorizedKeyvalueStoreException;
+import org.springframework.data.keyvalue.redis.connection.DataType;
+import org.springframework.data.keyvalue.redis.connection.MessageListener;
+import org.springframework.data.keyvalue.redis.connection.RedisConnection;
+import org.springframework.data.keyvalue.redis.connection.RedisSubscribedConnectionException;
+import org.springframework.data.keyvalue.redis.connection.SortParameters;
+import org.springframework.data.keyvalue.redis.connection.Subscription;
+
+/**
+ * {@code RedisConnection} implementation on top of rjc library.
+ *
+ * @author Costin Leau
+ */
+public class RjcConnection implements RedisConnection {
+
+ private final int dbIndex;
+ private boolean isClosed = false;
+
+ private final Client client;
+ private final Session session;
+ private volatile Client pipeline;
+
+ private volatile RjcSubscription subscription;
+ private volatile RedisNodeSubscriber subscriber;
+
+ public RjcConnection(org.idevlab.rjc.ds.RedisConnection connection, int dbIndex) {
+ SingleDataSource connectionDataSource = new SingleDataSource(connection);
+ session = new SessionFactoryImpl(connectionDataSource).create();
+ subscriber = new RedisNodeSubscriber();
+ subscriber.setDataSource(new SingleDataSource(new CloseSuppressingRjcConnection(connection)));
+ client = new Client(connection);
+
+ this.dbIndex = dbIndex;
+
+ // select the db
+ if (dbIndex > 0) {
+ select(dbIndex);
+ }
+ }
+
+ protected DataAccessException convertRjcAccessException(Exception ex) {
+ if (ex instanceof RedisException) {
+ return RjcUtils.convertRjcAccessException((RedisException) ex);
+ }
+ return new UncategorizedKeyvalueStoreException("Unknown rjc exception", ex);
+ }
+
+ @Override
+ public void close() throws DataAccessException {
+ isClosed = true;
+
+ // reset the connection (in case a pool is being used)
+ if (dbIndex > 0) {
+ select(0);
+ }
+
+ try {
+ subscriber.close();
+ session.close();
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+
+ @Override
+ public boolean isClosed() {
+ return isClosed;
+ }
+
+ @Override
+ public Session getNativeConnection() {
+ return session;
+ }
+
+ @Override
+ public boolean isQueueing() {
+ return client.isInMulti();
+ }
+
+ @Override
+ public boolean isPipelined() {
+ return (pipeline != null);
+ }
+
+ @Override
+ public void openPipeline() {
+ if (pipeline == null) {
+ pipeline = client;
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public List closePipeline() {
+ if (pipeline != null) {
+ List execute = client.getAll();
+ if (execute != null && !execute.isEmpty()) {
+ return execute;
+ }
+ }
+ return Collections.emptyList();
+ }
+
+ @Override
+ public List sort(byte[] key, SortParameters params) {
+
+ SortingParams sortParams = RjcUtils.convertSortParams(params);
+ final String stringKey = RjcUtils.decode(key);
+
+ try {
+ if (isPipelined()) {
+ if (sortParams != null) {
+ pipeline.sort(stringKey, sortParams);
+ }
+ else {
+ pipeline.sort(stringKey);
+ }
+
+ return null;
+ }
+ return RjcUtils.convertToList((sortParams != null ? session.sort(stringKey, sortParams)
+ : session.sort(stringKey)));
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long sort(byte[] key, SortParameters params, byte[] sortKey) {
+
+ SortingParams sortParams = RjcUtils.convertSortParams(params);
+ final String stringKey = RjcUtils.decode(key);
+ final String stringSortKey = RjcUtils.decode(sortKey);
+
+ try {
+ if (isPipelined()) {
+ if (sortParams != null) {
+ pipeline.sort(stringKey, sortParams, stringSortKey);
+ }
+ else {
+ pipeline.sort(stringKey, stringSortKey);
+ }
+
+ return null;
+ }
+ return (sortParams != null ? session.sort(stringKey, sortParams, stringSortKey) : session.sort(stringKey,
+ stringSortKey));
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long dbSize() {
+ try {
+ if (isPipelined()) {
+ pipeline.dbSize();
+ return null;
+ }
+ return session.dbSize();
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+
+ @Override
+ public void flushDb() {
+ try {
+ if (isPipelined()) {
+ pipeline.flushDB();
+ return;
+ }
+ session.flushDB();
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public void flushAll() {
+ try {
+ if (isPipelined()) {
+ pipeline.flushAll();
+ return;
+ }
+ session.flushAll();
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public void bgSave() {
+ try {
+ if (isPipelined()) {
+ pipeline.bgsave();
+ return;
+ }
+ session.bgsave();
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public void bgWriteAof() {
+ try {
+ if (isPipelined()) {
+ pipeline.bgrewriteaof();
+ return;
+ }
+ session.bgrewriteaof();
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public void save() {
+ try {
+ if (isPipelined()) {
+ pipeline.save();
+ return;
+ }
+ session.save();
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public List getConfig(String param) {
+ try {
+ if (isPipelined()) {
+ pipeline.configGet(param);
+ return null;
+ }
+ return session.configGet(param);
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public Properties info() {
+ try {
+ if (isPipelined()) {
+ pipeline.info();
+ return null;
+ }
+ return RjcUtils.info(session.info());
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long lastSave() {
+ try {
+ if (isPipelined()) {
+ pipeline.lastsave();
+ return null;
+ }
+ return session.lastsave();
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public void setConfig(String param, String value) {
+ try {
+ if (isPipelined()) {
+ pipeline.configSet(param, value);
+ return;
+ }
+ session.configSet(param, value);
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+
+ @Override
+ public void resetConfigStats() {
+ try {
+ if (isPipelined()) {
+ pipeline.configResetStat();
+ return;
+ }
+ client.configResetStat();
+ client.getStatusCodeReply();
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public void shutdown() {
+ try {
+ if (isPipelined()) {
+ pipeline.shutdown();
+ return;
+ }
+ session.shutdown();
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public byte[] echo(byte[] message) {
+ String stringMsg = RjcUtils.decode(message);
+ try {
+ if (isPipelined()) {
+ pipeline.echo(stringMsg);
+ return null;
+ }
+ return RjcUtils.encode(session.echo(stringMsg));
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public String ping() {
+ try {
+ if (isPipelined()) {
+ pipeline.ping();
+ }
+ return session.ping();
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long del(byte[]... keys) {
+ String[] stringKeys = RjcUtils.decodeMultiple(keys);
+
+ try {
+ if (isPipelined()) {
+ pipeline.del(stringKeys);
+ return null;
+ }
+ return session.del(stringKeys);
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public void discard() {
+ try {
+ if (isPipelined()) {
+ pipeline.discard();
+ return;
+ }
+
+ session.discard();
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public List exec() {
+ try {
+ if (isPipelined()) {
+ pipeline.exec();
+ return null;
+ }
+ return session.exec();
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public Boolean exists(byte[] key) {
+ String stringKey = RjcUtils.decode(key);
+
+ try {
+ if (isPipelined()) {
+ pipeline.exists(stringKey);
+ return null;
+ }
+ return session.exists(stringKey);
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public Boolean expire(byte[] key, long seconds) {
+ String stringKey = RjcUtils.decode(key);
+
+ try {
+ if (isPipelined()) {
+ pipeline.expire(stringKey, (int) seconds);
+ return null;
+ }
+ return session.expire(stringKey, (int) seconds);
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public Boolean expireAt(byte[] key, long unixTime) {
+ String stringKey = RjcUtils.decode(key);
+
+ try {
+ if (isPipelined()) {
+ pipeline.expireAt(stringKey, unixTime);
+ return null;
+ }
+ return session.expireAt(stringKey, unixTime);
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public Set keys(byte[] pattern) {
+ String stringKey = RjcUtils.decode(pattern);
+
+ try {
+ if (isPipelined()) {
+ pipeline.keys(stringKey);
+ return null;
+ }
+ return RjcUtils.convertToSet(session.keys(stringKey));
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public void multi() {
+ if (isQueueing()) {
+ return;
+ }
+ try {
+ if (isPipelined()) {
+ pipeline.multi();
+ return;
+ }
+ session.multi();
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public Boolean persist(byte[] key) {
+ String stringKey = RjcUtils.decode(key);
+
+ try {
+ if (isPipelined()) {
+ pipeline.persist(stringKey);
+ return null;
+ }
+ return session.persist(stringKey);
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public Boolean move(byte[] key, int dbIndex) {
+ String stringKey = RjcUtils.decode(key);
+
+ try {
+ if (isPipelined()) {
+ pipeline.move(stringKey, dbIndex);
+ return null;
+ }
+ return session.move(stringKey, dbIndex);
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public byte[] randomKey() {
+ try {
+ if (isPipelined()) {
+ pipeline.randomKey();
+ return null;
+ }
+ return RjcUtils.encode(session.randomKey());
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public void rename(byte[] oldName, byte[] newName) {
+ String stringOldKey = RjcUtils.decode(oldName);
+ String stringNewKey = RjcUtils.decode(newName);
+
+ try {
+ if (isPipelined()) {
+ pipeline.rename(stringOldKey, stringNewKey);
+ return;
+ }
+ session.rename(stringOldKey, stringNewKey);
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public Boolean renameNX(byte[] oldName, byte[] newName) {
+ String stringOldKey = RjcUtils.decode(oldName);
+ String stringNewKey = RjcUtils.decode(newName);
+
+ try {
+ if (isPipelined()) {
+ pipeline.renamenx(stringOldKey, stringNewKey);
+ return null;
+ }
+ return session.renamenx(stringOldKey, stringNewKey);
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public void select(int dbIndex) {
+ try {
+ if (isPipelined()) {
+ pipeline.select(dbIndex);
+ return;
+ }
+ session.select(dbIndex);
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long ttl(byte[] key) {
+ String stringKey = RjcUtils.decode(key);
+
+ try {
+ if (isPipelined()) {
+ pipeline.ttl(stringKey);
+ return null;
+ }
+ return session.ttl(stringKey);
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public DataType type(byte[] key) {
+ String stringKey = RjcUtils.decode(key);
+
+ try {
+ if (isPipelined()) {
+ pipeline.type(stringKey);
+ return null;
+ }
+ return DataType.fromCode(session.type(stringKey));
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public void unwatch() {
+ try {
+ if (isPipelined()) {
+ pipeline.unwatch();
+ return;
+ }
+
+ session.unwatch();
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public void watch(byte[]... keys) {
+ String[] stringKeys = RjcUtils.decodeMultiple(keys);
+
+ if (isQueueing()) {
+ return;
+ }
+ try {
+ if (isPipelined()) {
+ pipeline.watch(stringKeys);
+ return;
+ }
+ else {
+ session.watch(stringKeys);
+ }
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ //
+ // String commands
+ //
+
+ @Override
+ public byte[] get(byte[] key) {
+ String stringKey = RjcUtils.decode(key);
+
+ try {
+ if (isPipelined()) {
+ pipeline.get(stringKey);
+ return null;
+ }
+
+ return RjcUtils.encode(session.get(stringKey));
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public void set(byte[] key, byte[] value) {
+ String stringKey = RjcUtils.decode(key);
+ String stringValue = RjcUtils.decode(value);
+
+ try {
+ if (isPipelined()) {
+ pipeline.set(stringKey, stringValue);
+ return;
+ }
+ session.set(stringKey, stringValue);
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+
+ @Override
+ public byte[] getSet(byte[] key, byte[] value) {
+ String stringKey = RjcUtils.decode(key);
+ String stringValue = RjcUtils.decode(value);
+
+ try {
+ if (isPipelined()) {
+ pipeline.getSet(stringKey, stringValue);
+ return null;
+ }
+ return RjcUtils.encode(session.getSet(stringKey, stringValue));
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long append(byte[] key, byte[] value) {
+ String stringKey = RjcUtils.decode(key);
+ String stringValue = RjcUtils.decode(value);
+
+ try {
+ if (isPipelined()) {
+ pipeline.append(stringKey, stringValue);
+ return null;
+ }
+ return session.append(stringKey, stringValue);
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public List mGet(byte[]... keys) {
+ String[] stringKeys = RjcUtils.decodeMultiple(keys);
+
+ try {
+ if (isPipelined()) {
+ pipeline.mget(stringKeys);
+ return null;
+ }
+ return RjcUtils.convertToList(session.mget(stringKeys));
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public void mSet(Map tuples) {
+ String[] decodeMap = RjcUtils.flatten(tuples);
+
+ try {
+ if (isPipelined()) {
+ pipeline.mset(decodeMap);
+ return;
+ }
+ session.mset(decodeMap);
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public void mSetNX(Map tuples) {
+ String[] decodeMap = RjcUtils.flatten(tuples);
+
+ try {
+
+ if (isPipelined()) {
+ pipeline.msetnx(decodeMap);
+ return;
+ }
+ session.msetnx(decodeMap);
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public void setEx(byte[] key, long time, byte[] value) {
+ String stringKey = RjcUtils.decode(key);
+ String stringValue = RjcUtils.decode(value);
+
+ try {
+ if (isPipelined()) {
+ pipeline.setex(stringKey, (int) time, stringValue);
+ return;
+ }
+ session.setex(stringKey, (int) time, stringValue);
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public Boolean setNX(byte[] key, byte[] value) {
+ String stringKey = RjcUtils.decode(key);
+ String stringValue = RjcUtils.decode(value);
+
+ try {
+ if (isPipelined()) {
+ pipeline.setnx(stringKey, stringValue);
+ return null;
+ }
+ return session.setnx(stringKey, stringValue);
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public byte[] getRange(byte[] key, long start, long end) {
+ String stringKey = RjcUtils.decode(key);
+
+ try {
+ if (isPipelined()) {
+ pipeline.getRange(stringKey, (int) start, (int) end);
+ return null;
+ }
+ return RjcUtils.encode(session.getRange(stringKey, (int) start, (int) end));
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long decr(byte[] key) {
+ String stringKey = RjcUtils.decode(key);
+ try {
+
+ if (isPipelined()) {
+ pipeline.decr(stringKey);
+ return null;
+ }
+ return session.decr(stringKey);
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long decrBy(byte[] key, long value) {
+ String stringKey = RjcUtils.decode(key);
+ try {
+
+ if (isPipelined()) {
+ pipeline.decrBy(stringKey, (int) value);
+ return null;
+ }
+ return session.decrBy(stringKey, (int) value);
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long incr(byte[] key) {
+ String stringKey = RjcUtils.decode(key);
+
+ try {
+
+ if (isPipelined()) {
+ pipeline.incr(stringKey);
+ return null;
+ }
+ return session.incr(stringKey);
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long incrBy(byte[] key, long value) {
+ String stringKey = RjcUtils.decode(key);
+
+
+ try {
+ if (isPipelined()) {
+ pipeline.incrBy(stringKey, (int) value);
+ return null;
+ }
+ return session.incrBy(stringKey, (int) value);
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public Boolean getBit(byte[] key, long offset) {
+ String stringKey = RjcUtils.decode(key);
+
+ try {
+ if (isPipelined()) {
+ pipeline.getbit(stringKey, (int) offset);
+ return null;
+ }
+ return (session.getBit(stringKey, (int) offset) == 0 ? Boolean.FALSE : Boolean.TRUE);
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public void setBit(byte[] key, long offset, boolean value) {
+ String stringKey = RjcUtils.decode(key);
+
+ try {
+ if (isPipelined()) {
+ pipeline.setbit(stringKey, (int) offset, RjcUtils.asBit(value));
+ return;
+ }
+ session.setBit(stringKey, (int) offset, RjcUtils.asBit(value));
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public void setRange(byte[] key, byte[] value, long offset) {
+ String stringKey = RjcUtils.decode(key);
+ String stringValue = RjcUtils.decode(value);
+
+ try {
+ if (isPipelined()) {
+ pipeline.setRange(stringKey, (int) offset, stringValue);
+ return;
+ }
+ session.setRange(stringKey, (int) offset, stringValue);
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long strLen(byte[] key) {
+ String stringKey = RjcUtils.decode(key);
+
+ try {
+ if (isPipelined()) {
+ pipeline.strlen(stringKey);
+ return null;
+ }
+ return session.strlen(stringKey);
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ //
+ // List commands
+ //
+
+ @Override
+ public Long lPush(byte[] key, byte[] value) {
+ String stringKey = RjcUtils.decode(key);
+ String stringValue = RjcUtils.decode(value);
+
+ try {
+ if (isPipelined()) {
+ pipeline.lpush(stringKey, stringValue);
+ return null;
+ }
+ return session.lpush(stringKey, stringValue);
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long rPush(byte[] key, byte[] value) {
+ String stringKey = RjcUtils.decode(key);
+ String stringValue = RjcUtils.decode(value);
+
+ try {
+
+ if (isPipelined()) {
+ pipeline.rpush(stringKey, stringValue);
+ return null;
+ }
+ return session.rpush(stringKey, stringValue);
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public List bLPop(int timeout, byte[]... keys) {
+ String[] stringKeys = RjcUtils.decodeMultiple(keys);
+
+ try {
+ if (isPipelined()) {
+ pipeline.blpop(stringKeys);
+ return null;
+ }
+ return RjcUtils.convertToList(session.blpop(timeout, stringKeys));
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public List bRPop(int timeout, byte[]... keys) {
+ String[] stringKeys = RjcUtils.decodeMultiple(keys);
+
+ try {
+ if (isPipelined()) {
+ pipeline.brpop(stringKeys);
+ return null;
+ }
+ return RjcUtils.convertToList(session.brpop(timeout, stringKeys));
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public byte[] lIndex(byte[] key, long index) {
+ String stringKey = RjcUtils.decode(key);
+
+
+ try {
+ if (isPipelined()) {
+ pipeline.lindex(stringKey, (int) index);
+ return null;
+ }
+ return RjcUtils.encode(session.lindex(stringKey, (int) index));
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long lInsert(byte[] key, Position where, byte[] pivot, byte[] value) {
+ String stringKey = RjcUtils.decode(key);
+ String stringValue = RjcUtils.decode(value);
+ String stringPivot = RjcUtils.decode(pivot);
+ Client.LIST_POSITION position = RjcUtils.convertPosition(where);
+
+ try {
+ if (isPipelined()) {
+ pipeline.linsert(stringKey, position, stringPivot, stringValue);
+ return null;
+ }
+ return session.linsert(stringKey, position, stringPivot, stringValue);
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long lLen(byte[] key) {
+ String stringKey = RjcUtils.decode(key);
+
+ try {
+
+ if (isPipelined()) {
+ pipeline.llen(stringKey);
+ return null;
+ }
+ return session.llen(stringKey);
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public byte[] lPop(byte[] key) {
+ String stringKey = RjcUtils.decode(key);
+
+ try {
+
+ if (isPipelined()) {
+ pipeline.lpop(stringKey);
+ return null;
+ }
+ return RjcUtils.encode(session.lpop(stringKey));
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public List lRange(byte[] key, long start, long end) {
+ String stringKey = RjcUtils.decode(key);
+
+ try {
+
+ if (isPipelined()) {
+ pipeline.lrange(stringKey, (int) start, (int) end);
+ return null;
+ }
+ return RjcUtils.convertToList(session.lrange(stringKey, (int) start, (int) end));
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long lRem(byte[] key, long count, byte[] value) {
+ String stringKey = RjcUtils.decode(key);
+ String stringValue = RjcUtils.decode(value);
+
+ try {
+
+ if (isPipelined()) {
+ pipeline.lrem(stringKey, (int) count, stringValue);
+ return null;
+ }
+ return session.lrem(stringKey, (int) count, stringValue);
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public void lSet(byte[] key, long index, byte[] value) {
+ String stringKey = RjcUtils.decode(key);
+ String stringValue = RjcUtils.decode(value);
+ try {
+
+ if (isPipelined()) {
+ pipeline.lset(stringKey, (int) index, stringValue);
+ return;
+ }
+ session.lset(stringKey, (int) index, stringValue);
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public void lTrim(byte[] key, long start, long end) {
+ String stringKey = RjcUtils.decode(key);
+
+ try {
+
+ if (isPipelined()) {
+ pipeline.ltrim(stringKey, (int) start, (int) end);
+ return;
+ }
+ session.ltrim(stringKey, (int) start, (int) end);
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public byte[] rPop(byte[] key) {
+ String stringKey = RjcUtils.decode(key);
+
+ try {
+
+ if (isPipelined()) {
+ pipeline.rpop(stringKey);
+ return null;
+ }
+ return RjcUtils.encode(session.rpop(stringKey));
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public byte[] rPopLPush(byte[] srcKey, byte[] dstKey) {
+ String stringKey = RjcUtils.decode(srcKey);
+ String stringDest = RjcUtils.decode(dstKey);
+
+ try {
+
+ if (isPipelined()) {
+ pipeline.rpoplpush(stringKey, stringDest);
+ return null;
+ }
+ return RjcUtils.encode(session.rpoplpush(stringKey, stringDest));
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public byte[] bRPopLPush(int timeout, byte[] srcKey, byte[] dstKey) {
+ String stringKey = RjcUtils.decode(srcKey);
+ String stringDest = RjcUtils.decode(dstKey);
+
+ try {
+ if (isPipelined()) {
+ pipeline.brpoplpush(stringKey, stringDest, timeout);
+ return null;
+ }
+ return RjcUtils.encode(session.brpoplpush(stringKey, stringDest, timeout));
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long lPushX(byte[] key, byte[] value) {
+ String stringKey = RjcUtils.decode(key);
+ String stringValue = RjcUtils.decode(value);
+ try {
+ if (isPipelined()) {
+ pipeline.lpushx(stringKey, stringValue);
+ return null;
+ }
+ return session.lpushx(stringKey, stringValue);
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long rPushX(byte[] key, byte[] value) {
+ String stringKey = RjcUtils.decode(key);
+ String stringValue = RjcUtils.decode(value);
+ try {
+ if (isPipelined()) {
+ pipeline.rpushx(stringKey, stringValue);
+ return null;
+ }
+ return session.rpushx(stringKey, stringValue);
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+
+ //
+ // Set commands
+ //
+
+ @Override
+ public Boolean sAdd(byte[] key, byte[] value) {
+ String stringKey = RjcUtils.decode(key);
+ String stringValue = RjcUtils.decode(value);
+
+ try {
+
+ if (isPipelined()) {
+ pipeline.sadd(stringKey, stringValue);
+ return null;
+ }
+ return session.sadd(stringKey, stringValue);
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public Long sCard(byte[] key) {
+ String stringKey = RjcUtils.decode(key);
+
+ try {
+
+ if (isPipelined()) {
+ pipeline.scard(stringKey);
+ return null;
+ }
+ return session.scard(stringKey);
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public Set sDiff(byte[]... keys) {
+ String[] stringKeys = RjcUtils.decodeMultiple(keys);
+
+ try {
+
+ if (isPipelined()) {
+ pipeline.sdiff(stringKeys);
+ return null;
+ }
+ return RjcUtils.convertToSet(session.sdiff(stringKeys));
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public void sDiffStore(byte[] destKey, byte[]... keys) {
+ String stringKey = RjcUtils.decode(destKey);
+ String[] stringKeys = RjcUtils.decodeMultiple(keys);
+
+ try {
+
+ if (isPipelined()) {
+ pipeline.sdiffstore(stringKey, stringKeys);
+ return;
+ }
+ session.sdiffstore(stringKey, stringKeys);
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public Set sInter(byte[]... keys) {
+ String[] stringKeys = RjcUtils.decodeMultiple(keys);
+ try {
+
+ if (isPipelined()) {
+ pipeline.sinter(stringKeys);
+ return null;
+ }
+ return RjcUtils.convertToSet(session.sinter(stringKeys));
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public void sInterStore(byte[] destKey, byte[]... keys) {
+ String stringKey = RjcUtils.decode(destKey);
+ String[] stringKeys = RjcUtils.decodeMultiple(keys);
+ try {
+
+ if (isPipelined()) {
+ pipeline.sinterstore(stringKey, stringKeys);
+ return;
+ }
+ session.sinterstore(stringKey, stringKeys);
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public Boolean sIsMember(byte[] key, byte[] value) {
+ String stringKey = RjcUtils.decode(key);
+ String stringValue = RjcUtils.decode(value);
+
+ try {
+
+ if (isPipelined()) {
+ pipeline.sismember(stringKey, stringValue);
+ return null;
+ }
+ return session.sismember(stringKey, stringValue);
+ } catch (Exception ex) {
+ throw convertRjcAccessException(ex);
+ }
+ }
+
+ @Override
+ public Set