diff --git a/gradle.properties b/gradle.properties index f09fb8eb53..d58d56c8cb 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,7 +4,7 @@ jredisVersion=06052013 jedisVersion=2.4.1 springVersion=3.2.8.RELEASE log4jVersion=1.2.17 -version=1.3.0.BUILD-SNAPSHOT +version=1.3.0.DATAREDIS-293-SNAPSHOT srpVersion=0.7 jacksonVersion=1.8.8 fasterXmlJacksonVersion=2.2.0 diff --git a/src/test/java/org/springframework/data/redis/Version.java b/src/main/java/org/springframework/data/redis/Version.java similarity index 53% rename from src/test/java/org/springframework/data/redis/Version.java rename to src/main/java/org/springframework/data/redis/Version.java index c8e7666077..77bca1a2e9 100644 --- a/src/test/java/org/springframework/data/redis/Version.java +++ b/src/main/java/org/springframework/data/redis/Version.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2013 the original author or authors. + * Copyright 2011-2014 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. @@ -19,8 +19,12 @@ * A {@link Comparable} software version * * @author Jennifer Hickey + * @author Christoph Strobl */ public class Version implements Comparable { + + public static final Version UNKNOWN = new Version(0, 0, 0); + Integer major; Integer minor; Integer patch; @@ -48,4 +52,51 @@ public int compareTo(Version o) { public String toString() { return "" + major + "." + minor + "." + patch; } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((major == null) ? 0 : major.hashCode()); + result = prime * result + ((minor == null) ? 0 : minor.hashCode()); + result = prime * result + ((patch == null) ? 0 : patch.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (!(obj instanceof Version)) { + return false; + } + Version other = (Version) obj; + if (major == null) { + if (other.major != null) { + return false; + } + } else if (!major.equals(other.major)) { + return false; + } + if (minor == null) { + if (other.minor != null) { + return false; + } + } else if (!minor.equals(other.minor)) { + return false; + } + if (patch == null) { + if (other.patch != null) { + return false; + } + } else if (!patch.equals(other.patch)) { + return false; + } + return true; + } + } diff --git a/src/main/java/org/springframework/data/redis/VersionParser.java b/src/main/java/org/springframework/data/redis/VersionParser.java new file mode 100644 index 0000000000..f06c02683b --- /dev/null +++ b/src/main/java/org/springframework/data/redis/VersionParser.java @@ -0,0 +1,53 @@ +/* + * Copyright 2014 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.redis; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Central class for reading version string (eg. {@literal 1.3.1}) into {@link Version}. + * + * @author Christoph Strobl + * @since 1.3 + */ +public class VersionParser { + + private static final Pattern VERSION_MATCHER = Pattern.compile("([0-9]+)\\.([0-9]+)(\\.([0-9]+))?(.*)"); + + /** + * Parse version string {@literal eg. 1.1.1} to {@link Version}. + * + * @param version + * @return + */ + public static Version parseVersion(String version) { + if (version == null) { + return Version.UNKNOWN; + } + + Matcher matcher = VERSION_MATCHER.matcher(version); + if (matcher.matches()) { + String major = matcher.group(1); + String minor = matcher.group(2); + String patch = matcher.group(4); + return new Version(Integer.parseInt(major), minor != null ? Integer.parseInt(minor) : 0, + patch != null ? Integer.parseInt(patch) : 0); + } + return Version.UNKNOWN; + } + +} diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnection.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnection.java index a69f0daeb2..44f22a4e34 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnection.java @@ -2923,7 +2923,7 @@ private Map zAddArgs(Set tuples) { Map args = new HashMap(); for (Tuple tuple : tuples) { - if (args.containsValue(tuple.getScore())) { + if (args.containsValue(tuple.getScore()) && !JedisVersionUtil.atLeastJedis24()) { throw new UnsupportedOperationException( "Bulk add of multiple elements with the same score is not supported. Add the elements individually."); } diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisVersionUtil.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisVersionUtil.java new file mode 100644 index 0000000000..ad771e1149 --- /dev/null +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisVersionUtil.java @@ -0,0 +1,97 @@ +/* + * Copyright 2014 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.redis.connection.jedis; + +import java.io.IOException; +import java.util.Properties; + +import org.springframework.core.io.support.PropertiesLoaderUtils; +import org.springframework.data.redis.Version; +import org.springframework.data.redis.VersionParser; +import org.springframework.util.StringUtils; + +import redis.clients.jedis.Jedis; + +/** + * @author Christoph Strobl + * @since 1.3 + */ +public class JedisVersionUtil { + + private static Version jedisVersion = parseVersion(resolveJedisVersion()); + + /** + * @return current {@link redis.clients.jedis.Jedis} version. + */ + public static Version jedisVersion() { + return jedisVersion; + } + + /** + * Parse version string {@literal eg. 1.1.1} to {@link Version}. + * + * @param version + * @return + */ + static Version parseVersion(String version) { + return VersionParser.parseVersion(version); + } + + /** + * @return true if used jedis version is at minimum {@literal 2.4}. + */ + public static boolean atLeastJedis24() { + return atLeast("2.4"); + } + + private static String resolveJedisVersion() { + + String version = Jedis.class.getPackage().getImplementationVersion(); + + if (!StringUtils.hasText(version)) { + try { + Properties props = PropertiesLoaderUtils.loadAllProperties("META-INF/maven/redis.clients/jedis/pom.properties"); + if (props.containsKey("version")) { + version = props.getProperty("version"); + } + } catch (IOException e) { + // ignore this one + } + } + return version; + } + + /** + * Compares given version string against current jedis version. + * + * @param version + * @return true in case given version is greater than equal to current one. + */ + public static boolean atLeast(String version) { + return jedisVersion.compareTo(parseVersion(version)) >= 0; + } + + /** + * Compares given version string against current jedis version. + * + * @param version + * @return true in case given version is less than equal to current one. + */ + public static boolean atMost(String version) { + return jedisVersion.compareTo(parseVersion(version)) <= 0; + } + +} diff --git a/src/test/java/org/springframework/data/redis/RedisVersionUtils.java b/src/test/java/org/springframework/data/redis/RedisVersionUtils.java index d3503db05b..4a755ac96c 100644 --- a/src/test/java/org/springframework/data/redis/RedisVersionUtils.java +++ b/src/test/java/org/springframework/data/redis/RedisVersionUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2013 the original author or authors. + * Copyright 2011-2014 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. @@ -15,20 +15,16 @@ */ package org.springframework.data.redis; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - import org.springframework.data.redis.connection.RedisConnection; /** * Utilities for examining the Redis version * * @author Jennifer Hickey + * @author Christoph Strobl */ public abstract class RedisVersionUtils { - private static final Pattern VERSION_MATCHER = Pattern.compile("([0-9]+)\\.([0-9]+)(\\.([0-9]+))?"); - public static Version getRedisVersion(RedisConnection connection) { return parseVersion((String) connection.info().get("redis_version")); } @@ -42,14 +38,11 @@ public static boolean atMost(String version, RedisConnection connection) { } public static Version parseVersion(String version) { - Matcher matcher = VERSION_MATCHER.matcher(version); - if (matcher.matches()) { - String major = matcher.group(1); - String minor = matcher.group(2); - String patch = matcher.group(4); - return new Version(Integer.parseInt(major), minor != null ? Integer.parseInt(minor) : 0, - patch != null ? Integer.parseInt(patch) : 0); + + Version resolvedVersion = VersionParser.parseVersion(version); + if (Version.UNKNOWN.equals(resolvedVersion)) { + throw new IllegalArgumentException("Specified version cannot be parsed"); } - throw new IllegalArgumentException("Specified version cannot be parsed"); + return resolvedVersion; } } diff --git a/src/test/java/org/springframework/data/redis/VersionParserUnitTests.java b/src/test/java/org/springframework/data/redis/VersionParserUnitTests.java new file mode 100644 index 0000000000..6e3e783f56 --- /dev/null +++ b/src/test/java/org/springframework/data/redis/VersionParserUnitTests.java @@ -0,0 +1,57 @@ +/* + * Copyright 2014 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.redis; + +import static org.hamcrest.core.IsEqual.*; +import static org.junit.Assert.*; + +import org.junit.Test; + +/** + * @author Christoph Strobl + */ +public class VersionParserUnitTests { + + @Test + public void shouldParseNullToUnknown() { + assertThat(VersionParser.parseVersion(null), equalTo(Version.UNKNOWN)); + } + + @Test + public void shouldParseEmptyVersionStringToUnknown() { + assertThat(VersionParser.parseVersion(""), equalTo(Version.UNKNOWN)); + } + + @Test + public void shouldParseInvalidVersionStringToUnknown() { + assertThat(VersionParser.parseVersion("ThisIsNoValidVersion"), equalTo(Version.UNKNOWN)); + } + + @Test + public void shouldParseMajorMinorWithoutPatchCorrectly() { + assertThat(VersionParser.parseVersion("1.2"), equalTo(new Version(1, 2, 0))); + } + + @Test + public void shouldParseMajorMinorPatchCorrectly() { + assertThat(VersionParser.parseVersion("1.2.3"), equalTo(new Version(1, 2, 3))); + } + + @Test + public void shouldParseMajorWithoutMinorPatchCorrectly() { + assertThat(VersionParser.parseVersion("1.2.3.a"), equalTo(new Version(1, 2, 3))); + } +} diff --git a/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionIntegrationTests.java index 026a9a6d82..81971162fc 100644 --- a/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionIntegrationTests.java @@ -117,12 +117,13 @@ public void testClosePool() { factory2.destroy(); } - @Test(expected = UnsupportedOperationException.class) + @Test public void testZAddSameScores() { Set strTuples = new HashSet(); strTuples.add(new DefaultStringTuple("Bob".getBytes(), "Bob", 2.0)); strTuples.add(new DefaultStringTuple("James".getBytes(), "James", 2.0)); - connection.zAdd("myset", strTuples); + Long added = connection.zAdd("myset", strTuples); + assertEquals(2L, added.longValue()); } @Test(expected = InvalidDataAccessApiUsageException.class)