Add RedisTemplate methods for executing Redis scripts
DATAREDIS-199
This commit is contained in:
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package org.springframework.data.redis.connection;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents a data type returned from Redis, currently used to denote the
|
||||
* expected return type of Redis scripting commands
|
||||
@@ -37,5 +39,21 @@ public enum ReturnType {
|
||||
STATUS,
|
||||
|
||||
/** Returned as byte[] **/
|
||||
VALUE
|
||||
VALUE;
|
||||
|
||||
public static ReturnType fromJavaType(Class<?> javaType) {
|
||||
if(javaType == null) {
|
||||
return ReturnType.STATUS;
|
||||
}
|
||||
if(javaType.isAssignableFrom(List.class)) {
|
||||
return ReturnType.MULTI;
|
||||
}
|
||||
if(javaType.isAssignableFrom(Boolean.class)) {
|
||||
return ReturnType.BOOLEAN;
|
||||
}
|
||||
if(javaType.isAssignableFrom(Long.class)) {
|
||||
return ReturnType.INTEGER;
|
||||
}
|
||||
return ReturnType.VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.springframework.data.redis.connection.DataType;
|
||||
import org.springframework.data.redis.core.query.SortQuery;
|
||||
import org.springframework.data.redis.core.script.RedisScript;
|
||||
import org.springframework.data.redis.serializer.RedisSerializer;
|
||||
|
||||
|
||||
@@ -104,6 +105,40 @@ public interface RedisOperations<K, V> {
|
||||
*/
|
||||
List<Object> executePipelined(final SessionCallback<?> session, final RedisSerializer<?> resultSerializer);
|
||||
|
||||
/**
|
||||
* Executes the given {@link RedisScript}
|
||||
*
|
||||
* @param script
|
||||
* The script to execute
|
||||
* @param keys
|
||||
* Any keys that need to be passed to the script
|
||||
* @param args
|
||||
* Any args that need to be passed to the script
|
||||
* @return The return value of the script or null if {@link RedisScript#getResultType()} is
|
||||
* null, likely indicating a throw-away status reply (i.e. "OK")
|
||||
*/
|
||||
<T> T execute(RedisScript<T> script, List<K> keys, Object... args);
|
||||
|
||||
/**
|
||||
* Executes the given {@link RedisScript}, using the provided {@link RedisSerializer}s to
|
||||
* serialize the script arguments and result.
|
||||
*
|
||||
* @param script
|
||||
* The script to execute
|
||||
* @param argsSerializer
|
||||
* The {@link RedisSerializer} to use for serializing args
|
||||
* @param resultSerializer
|
||||
* The {@link RedisSerializer} to use for serializing the script return value
|
||||
* @param keys
|
||||
* Any keys that need to be passed to the script
|
||||
* @param args
|
||||
* Any args that need to be passed to the script
|
||||
* @return The return value of the script or null if {@link RedisScript#getResultType()} is
|
||||
* null, likely indicating a throw-away status reply (i.e. "OK")
|
||||
*/
|
||||
<T> T execute(RedisScript<T> script, RedisSerializer<?> argsSerializer, RedisSerializer<T> resultSerializer,
|
||||
List<K> keys, Object... args);
|
||||
|
||||
Boolean hasKey(K key);
|
||||
|
||||
void delete(K key);
|
||||
|
||||
@@ -37,6 +37,9 @@ import org.springframework.data.redis.connection.SortParameters;
|
||||
import org.springframework.data.redis.core.ZSetOperations.TypedTuple;
|
||||
import org.springframework.data.redis.core.query.QueryUtils;
|
||||
import org.springframework.data.redis.core.query.SortQuery;
|
||||
import org.springframework.data.redis.core.script.DefaultScriptExecutor;
|
||||
import org.springframework.data.redis.core.script.RedisScript;
|
||||
import org.springframework.data.redis.core.script.ScriptExecutor;
|
||||
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
|
||||
import org.springframework.data.redis.serializer.RedisSerializer;
|
||||
import org.springframework.data.redis.serializer.SerializationUtils;
|
||||
@@ -83,6 +86,8 @@ public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperation
|
||||
private RedisSerializer hashValueSerializer = null;
|
||||
private RedisSerializer<String> stringSerializer = new StringRedisSerializer();
|
||||
|
||||
private ScriptExecutor<K> scriptExecutor;
|
||||
|
||||
// cache singleton objects (where possible)
|
||||
private ValueOperations<K, V> valueOps;
|
||||
private ListOperations<K, V> listOps;
|
||||
@@ -124,6 +129,10 @@ public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperation
|
||||
Assert.notNull(defaultSerializer, "default serializer null and not all serializers initialized");
|
||||
}
|
||||
|
||||
if(scriptExecutor == null) {
|
||||
this.scriptExecutor = new DefaultScriptExecutor<K>(this);
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
@@ -269,6 +278,15 @@ public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperation
|
||||
});
|
||||
}
|
||||
|
||||
public <T> T execute(RedisScript<T> script, List<K> keys, Object... args) {
|
||||
return scriptExecutor.execute(script, keys, args);
|
||||
}
|
||||
|
||||
public <T> T execute(RedisScript<T> script, RedisSerializer<?> argsSerializer, RedisSerializer<T> resultSerializer,
|
||||
List<K> keys, Object... args) {
|
||||
return scriptExecutor.execute(script, argsSerializer, resultSerializer, keys, args);
|
||||
}
|
||||
|
||||
private Object executeSession(SessionCallback<?> session) {
|
||||
return session.execute(this);
|
||||
}
|
||||
@@ -441,6 +459,14 @@ public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperation
|
||||
this.stringSerializer = stringSerializer;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param scriptExecutor The {@link ScriptExecutor} to use for executing Redis scripts
|
||||
*/
|
||||
public void setScriptExecutor(ScriptExecutor<K> scriptExecutor) {
|
||||
this.scriptExecutor = scriptExecutor;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private byte[] rawKey(Object key) {
|
||||
Assert.notNull(key, "non null key required");
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright 2013 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.core.script;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.scripting.ScriptSource;
|
||||
import org.springframework.scripting.support.ResourceScriptSource;
|
||||
import org.springframework.scripting.support.StaticScriptSource;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link RedisScript}. Delegates to an underlying {@link ScriptSource} to
|
||||
* retrieve script text and detect if script has been modified (and thus should have SHA1
|
||||
* re-calculated). This class is best used as a Singleton to avoid re-calculation of SHA1 on every
|
||||
* script execution.
|
||||
*
|
||||
* @author Jennifer Hickey
|
||||
*
|
||||
* @param <T>
|
||||
* The script result type. Should be one of Long, Boolean, List, or deserialized value
|
||||
* type. Can be null if the script returns a throw-away status (i.e "OK")
|
||||
*/
|
||||
public class DefaultRedisScript<T> implements RedisScript<T> {
|
||||
|
||||
private ScriptSource scriptSource;
|
||||
|
||||
private String sha1;
|
||||
|
||||
private Class<T> resultType;
|
||||
|
||||
private final Object shaModifiedMonitor = new Object();
|
||||
|
||||
/**
|
||||
*
|
||||
* @param scriptLocation
|
||||
* The location of the script
|
||||
* @param resultType
|
||||
* The Script result type
|
||||
*/
|
||||
public DefaultRedisScript(Resource scriptLocation, Class<T> resultType) {
|
||||
this(new ResourceScriptSource(scriptLocation), resultType);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param script
|
||||
* The script
|
||||
* @param resultType
|
||||
* The Script result type
|
||||
*/
|
||||
public DefaultRedisScript(String script, Class<T> resultType) {
|
||||
this(new StaticScriptSource(script), resultType);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param scriptSource
|
||||
* The {@link ScriptSource} of the script
|
||||
* @param resultType
|
||||
* The Script result type
|
||||
*/
|
||||
public DefaultRedisScript(ScriptSource scriptSource, Class<T> resultType) {
|
||||
this.scriptSource = scriptSource;
|
||||
this.resultType = resultType;
|
||||
}
|
||||
|
||||
public String getSha1() {
|
||||
synchronized (shaModifiedMonitor) {
|
||||
if (sha1 == null || scriptSource.isModified()) {
|
||||
this.sha1 = DigestUtils.sha1DigestAsHex(getScriptAsString());
|
||||
}
|
||||
return sha1;
|
||||
}
|
||||
}
|
||||
|
||||
public Class<T> getResultType() {
|
||||
return this.resultType;
|
||||
}
|
||||
|
||||
public String getScriptAsString() {
|
||||
try {
|
||||
return scriptSource.getScriptAsString();
|
||||
} catch (IOException e) {
|
||||
throw new ScriptingException("Error reading script text", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright 2013 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.core.script;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.data.redis.connection.RedisConnection;
|
||||
import org.springframework.data.redis.connection.ReturnType;
|
||||
import org.springframework.data.redis.core.RedisCallback;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.serializer.RedisSerializer;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link ScriptExecutor}. Optimizes performance by attempting to execute
|
||||
* script first using evalsha, then falling back to eval if Redis has not yet cached the script.
|
||||
* Evalsha is not attempted if the script is executed in a pipeline or transaction.
|
||||
*
|
||||
* @author Jennifer Hickey
|
||||
*
|
||||
* @param <K>
|
||||
* The type of keys that may be passed during script execution
|
||||
*/
|
||||
public class DefaultScriptExecutor<K> implements ScriptExecutor<K> {
|
||||
|
||||
private RedisTemplate<K, ?> template;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param template The {@link RedisTemplate} to use
|
||||
*/
|
||||
public DefaultScriptExecutor(RedisTemplate<K, ?> template) {
|
||||
this.template = template;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T execute(final RedisScript<T> script, final List<K> keys, final Object... args) {
|
||||
// use the Template's value serializer for args and result
|
||||
return execute(script, template.getValueSerializer(),
|
||||
(RedisSerializer<T>) template.getValueSerializer(), keys, args);
|
||||
}
|
||||
|
||||
public <T> T execute(final RedisScript<T> script, final RedisSerializer<?> argsSerializer, final RedisSerializer<T> resultSerializer,
|
||||
final List<K> keys, final Object... args) {
|
||||
return template.execute(new RedisCallback<T>() {
|
||||
public T doInRedis(RedisConnection connection) throws DataAccessException {
|
||||
final ReturnType returnType = ReturnType.fromJavaType(script.getResultType());
|
||||
final byte[][] keysAndArgs = keysAndArgs(argsSerializer, keys, args);
|
||||
final int keySize = keys != null ? keys.size() : 0;
|
||||
if (connection.isPipelined() || connection.isQueueing()) {
|
||||
// We could script load first and then do evalsha to ensure sha is present,
|
||||
// but this adds a sha1 to exec/closePipeline results. Instead, just eval
|
||||
connection.eval(scriptBytes(script), returnType, keySize, keysAndArgs);
|
||||
return null;
|
||||
}
|
||||
return eval(connection, script, returnType, keySize, keysAndArgs,
|
||||
resultSerializer);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected <T> T eval(RedisConnection connection, RedisScript<T> script, ReturnType returnType,
|
||||
int numKeys, byte[][] keysAndArgs, RedisSerializer<T> resultSerializer) {
|
||||
Object result;
|
||||
try {
|
||||
result = connection.evalSha(script.getSha1(), returnType, numKeys, keysAndArgs);
|
||||
} catch (Exception e) {
|
||||
result = connection.eval(scriptBytes(script), returnType, numKeys, keysAndArgs);
|
||||
}
|
||||
if (script.getResultType() == null) {
|
||||
return null;
|
||||
}
|
||||
return deserializeResult(resultSerializer, result);
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
protected byte[][] keysAndArgs(RedisSerializer argsSerializer, List<K> keys, Object[] args) {
|
||||
final int keySize = keys != null ? keys.size() : 0;
|
||||
byte[][] keysAndArgs = new byte[args.length + keySize][];
|
||||
int i = 0;
|
||||
if(keys != null) {
|
||||
for (K key : keys) {
|
||||
if (keySerializer() == null && key instanceof byte[]) {
|
||||
keysAndArgs[i++] = (byte[]) key;
|
||||
} else {
|
||||
keysAndArgs[i++] = keySerializer().serialize(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Object arg : args) {
|
||||
if (argsSerializer == null && arg instanceof byte[]) {
|
||||
keysAndArgs[i++] = (byte[]) arg;
|
||||
} else {
|
||||
keysAndArgs[i++] = argsSerializer.serialize(arg);
|
||||
}
|
||||
}
|
||||
return keysAndArgs;
|
||||
}
|
||||
|
||||
protected byte[] scriptBytes(RedisScript<?> script) {
|
||||
return template.getStringSerializer().serialize(script.getScriptAsString());
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
protected <T> T deserializeResult(RedisSerializer<T> resultSerializer, Object result) {
|
||||
if (result instanceof byte[]) {
|
||||
if (resultSerializer == null) {
|
||||
return (T) result;
|
||||
}
|
||||
return resultSerializer.deserialize((byte[]) result);
|
||||
}
|
||||
if (result instanceof List) {
|
||||
List results = new ArrayList();
|
||||
for (Object obj : (List) result) {
|
||||
results.add(deserializeResult(resultSerializer, obj));
|
||||
}
|
||||
return (T) results;
|
||||
}
|
||||
return (T) result;
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
protected RedisSerializer keySerializer() {
|
||||
return template.getKeySerializer();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2013 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.core.script;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
/**
|
||||
* Utilties for working with {@link MessageDigest}
|
||||
*
|
||||
* @author Jennifer Hickey
|
||||
*
|
||||
*/
|
||||
abstract public class DigestUtils {
|
||||
|
||||
private static final char[] HEX_CHARS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'a', 'b', 'c', 'd', 'e', 'f' };
|
||||
|
||||
private static final Charset UTF8_CHARSET = Charset.forName("UTF8");
|
||||
|
||||
/**
|
||||
* Returns the SHA1 of the provided data
|
||||
*
|
||||
* @param data
|
||||
* The data to calculate, such as the contents of a file
|
||||
* @return The human-readable SHA1
|
||||
*/
|
||||
public static String sha1DigestAsHex(String data) {
|
||||
byte[] dataBytes = getDigest("SHA").digest(data.getBytes(UTF8_CHARSET));
|
||||
return new String(encodeHex(dataBytes));
|
||||
}
|
||||
|
||||
private static char[] encodeHex(byte[] data) {
|
||||
int l = data.length;
|
||||
char[] out = new char[l << 1];
|
||||
for (int i = 0, j = 0; i < l; i++) {
|
||||
out[j++] = HEX_CHARS[(0xF0 & data[i]) >>> 4];
|
||||
out[j++] = HEX_CHARS[0x0F & data[i]];
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link MessageDigest} with the given algorithm. Necessary because
|
||||
* {@code MessageDigest} is not thread-safe.
|
||||
*/
|
||||
private static MessageDigest getDigest(String algorithm) {
|
||||
try {
|
||||
return MessageDigest.getInstance(algorithm);
|
||||
} catch (NoSuchAlgorithmException ex) {
|
||||
throw new IllegalStateException("Could not find MessageDigest with algorithm \""
|
||||
+ algorithm + "\"", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2013 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.core.script;
|
||||
|
||||
/**
|
||||
* A script to be executed using the <a href="http://redis.io/commands/eval">Redis scripting
|
||||
* support</a> available as of version 2.6
|
||||
*
|
||||
* @author Jennifer Hickey
|
||||
*
|
||||
* @param <T>
|
||||
* The script result type. Should be one of Long, Boolean, List, or deserialized value
|
||||
* type. Can be null if the script returns a throw-away status (i.e "OK")
|
||||
*/
|
||||
public interface RedisScript<T> {
|
||||
|
||||
/**
|
||||
*
|
||||
* @return The SHA1 of the script, used for executing Redis evalsha command
|
||||
*/
|
||||
String getSha1();
|
||||
|
||||
/**
|
||||
*
|
||||
* @return The script result type. Should be one of Long, Boolean, List, or deserialized value
|
||||
* type. Can be null if the script returns a throw-away status (i.e "OK")
|
||||
*/
|
||||
Class<T> getResultType();
|
||||
|
||||
/**
|
||||
*
|
||||
* @return The script contents
|
||||
*/
|
||||
String getScriptAsString();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2013 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.core.script;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.redis.serializer.RedisSerializer;
|
||||
|
||||
/**
|
||||
* Executes {@link RedisScript}s
|
||||
*
|
||||
* @author Jennifer Hickey
|
||||
*
|
||||
* @param <K>
|
||||
* The type of keys that may be passed during script execution
|
||||
*/
|
||||
public interface ScriptExecutor<K> {
|
||||
|
||||
/**
|
||||
* Executes the given {@link RedisScript}
|
||||
*
|
||||
* @param script
|
||||
* The script to execute
|
||||
* @param keys
|
||||
* Any keys that need to be passed to the script
|
||||
* @param args
|
||||
* Any args that need to be passed to the script
|
||||
* @return The return value of the script or null if {@link RedisScript#getResultType()} is
|
||||
* null, likely indicating a throw-away status reply (i.e. "OK")
|
||||
*/
|
||||
<T> T execute(RedisScript<T> script, List<K> keys, Object... args);
|
||||
|
||||
/**
|
||||
* Executes the given {@link RedisScript}, using the provided {@link RedisSerializer}s to
|
||||
* serialize the script arguments and result.
|
||||
*
|
||||
* @param script
|
||||
* The script to execute
|
||||
* @param argsSerializer
|
||||
* The {@link RedisSerializer} to use for serializing args
|
||||
* @param resultSerializer
|
||||
* The {@link RedisSerializer} to use for serializing the script return value
|
||||
* @param keys
|
||||
* Any keys that need to be passed to the script
|
||||
* @param args
|
||||
* Any args that need to be passed to the script
|
||||
* @return The return value of the script or null if {@link RedisScript#getResultType()} is
|
||||
* null, likely indicating a throw-away status reply (i.e. "OK")
|
||||
*/
|
||||
<T> T execute(RedisScript<T> script, RedisSerializer<?> argsSerializer, RedisSerializer<T> resultSerializer,
|
||||
List<K> keys, Object... args);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2013 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.core.script;
|
||||
|
||||
import org.springframework.core.NestedRuntimeException;
|
||||
|
||||
/**
|
||||
* {@link RuntimeException} thrown when issues occur with {@link RedisScript}s
|
||||
*
|
||||
* @author Jennifer Hickey
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class ScriptingException extends NestedRuntimeException {
|
||||
|
||||
/**
|
||||
* Constructs a new <code>ScriptingException</code> instance.
|
||||
*
|
||||
* @param msg
|
||||
* @param cause
|
||||
*/
|
||||
public ScriptingException(String msg, Throwable cause) {
|
||||
super(msg, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new <code>ScriptingException</code> instance.
|
||||
*
|
||||
* @param msg
|
||||
*/
|
||||
public ScriptingException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user