Merge branch 'mrniko/master' into feature/travis-ci
commit
4b87837111
@ -0,0 +1,129 @@
|
||||
/**
|
||||
* Copyright 2014 Nikita Koksharov, Nickolay Borbit
|
||||
*
|
||||
* 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.redisson;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.redisson.client.codec.Codec;
|
||||
import org.redisson.client.codec.LongCodec;
|
||||
import org.redisson.client.protocol.RedisCommand;
|
||||
import org.redisson.client.protocol.RedisCommands;
|
||||
import org.redisson.client.protocol.RedisCommand.ValueType;
|
||||
import org.redisson.client.protocol.convertor.BooleanReplayConvertor;
|
||||
import org.redisson.command.CommandAsyncExecutor;
|
||||
|
||||
import io.netty.util.concurrent.Future;
|
||||
|
||||
public class RedissonMultimapCache<K> {
|
||||
|
||||
private static final RedisCommand<Boolean> EVAL_EXPIRE_KEY = new RedisCommand<Boolean>("EVAL", new BooleanReplayConvertor(), 6, ValueType.MAP_KEY);
|
||||
|
||||
private final CommandAsyncExecutor commandExecutor;
|
||||
private final String name;
|
||||
private final Codec codec;
|
||||
private final String timeoutSetName;
|
||||
|
||||
public RedissonMultimapCache(CommandAsyncExecutor commandExecutor, String name, Codec codec, String timeoutSetName) {
|
||||
this.commandExecutor = commandExecutor;
|
||||
this.name = name;
|
||||
this.codec = codec;
|
||||
this.timeoutSetName = timeoutSetName;
|
||||
}
|
||||
|
||||
public Future<Boolean> expireKeyAsync(K key, long timeToLive, TimeUnit timeUnit) {
|
||||
long ttlTimeout = System.currentTimeMillis() + timeUnit.toMillis(timeToLive);
|
||||
|
||||
return commandExecutor.evalWriteAsync(name, codec, EVAL_EXPIRE_KEY,
|
||||
"if redis.call('hexists', KEYS[1], ARGV[2]) == 1 then "
|
||||
+ "if tonumber(ARGV[1]) > 0 then "
|
||||
+ "redis.call('zadd', KEYS[2], ARGV[1], ARGV[2]); " +
|
||||
"else " +
|
||||
"redis.call('zrem', KEYS[2], ARGV[2]); "
|
||||
+ "end; "
|
||||
+ "return 1; "
|
||||
+ "else "
|
||||
+ "return 0; "
|
||||
+ "end",
|
||||
Arrays.<Object>asList(name, timeoutSetName), ttlTimeout, key);
|
||||
}
|
||||
|
||||
public Future<Boolean> deleteAsync() {
|
||||
return commandExecutor.evalWriteAsync(name, LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN_AMOUNT,
|
||||
"local entries = redis.call('hgetall', KEYS[1]); " +
|
||||
"local keys = {KEYS[1], KEYS[2]}; " +
|
||||
"for i, v in ipairs(entries) do " +
|
||||
"if i % 2 == 0 then " +
|
||||
"local name = '{' .. KEYS[1] .. '}:' .. v; " +
|
||||
"table.insert(keys, name); " +
|
||||
"end;" +
|
||||
"end; " +
|
||||
|
||||
"local n = 0 "
|
||||
+ "for i=1, #keys,5000 do "
|
||||
+ "n = n + redis.call('del', unpack(keys, i, math.min(i+4999, table.getn(keys)))) "
|
||||
+ "end; "
|
||||
+ "return n;",
|
||||
Arrays.<Object>asList(name, timeoutSetName));
|
||||
}
|
||||
|
||||
public Future<Boolean> expireAsync(long timeToLive, TimeUnit timeUnit) {
|
||||
return commandExecutor.evalWriteAsync(name, LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,
|
||||
"redis.call('zadd', KEYS[2], 92233720368547758, 'redisson__expiretag'); " +
|
||||
"local entries = redis.call('hgetall', KEYS[1]); " +
|
||||
"for i, v in ipairs(entries) do " +
|
||||
"if i % 2 == 0 then " +
|
||||
"local name = '{' .. KEYS[1] .. '}:' .. v; " +
|
||||
"redis.call('pexpire', name, ARGV[1]); " +
|
||||
"end;" +
|
||||
"end; " +
|
||||
"redis.call('pexpire', KEYS[2], ARGV[1]); " +
|
||||
"return redis.call('pexpire', KEYS[1], ARGV[1]); ",
|
||||
Arrays.<Object>asList(name, timeoutSetName), timeUnit.toMillis(timeToLive));
|
||||
}
|
||||
|
||||
public Future<Boolean> expireAtAsync(long timestamp) {
|
||||
return commandExecutor.evalWriteAsync(name, LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,
|
||||
"redis.call('zadd', KEYS[2], 92233720368547758, 'redisson__expiretag');" +
|
||||
"local entries = redis.call('hgetall', KEYS[1]); " +
|
||||
"for i, v in ipairs(entries) do " +
|
||||
"if i % 2 == 0 then " +
|
||||
"local name = '{' .. KEYS[1] .. '}:' .. v; " +
|
||||
"redis.call('pexpireat', name, ARGV[1]); " +
|
||||
"end;" +
|
||||
"end; " +
|
||||
"redis.call('pexpireat', KEYS[2], ARGV[1]); " +
|
||||
"return redis.call('pexpireat', KEYS[1], ARGV[1]); ",
|
||||
Arrays.<Object>asList(name, timeoutSetName), timestamp);
|
||||
}
|
||||
|
||||
public Future<Boolean> clearExpireAsync() {
|
||||
return commandExecutor.evalWriteAsync(name, LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,
|
||||
"redis.call('zrem', KEYS[2], 'redisson__expiretag'); " +
|
||||
"local entries = redis.call('hgetall', KEYS[1]); " +
|
||||
"for i, v in ipairs(entries) do " +
|
||||
"if i % 2 == 0 then " +
|
||||
"local name = '{' .. KEYS[1] .. '}:' .. v; " +
|
||||
"redis.call('persist', name); " +
|
||||
"end;" +
|
||||
"end; " +
|
||||
"redis.call('persist', KEYS[2]); " +
|
||||
"return redis.call('persist', KEYS[1]); ",
|
||||
Arrays.<Object>asList(name, timeoutSetName));
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,165 @@
|
||||
/**
|
||||
* Copyright 2014 Nikita Koksharov, Nickolay Borbit
|
||||
*
|
||||
* 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.redisson;
|
||||
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.redisson.client.RedisException;
|
||||
import org.redisson.client.RedisTimeoutException;
|
||||
import org.redisson.core.MessageListener;
|
||||
import org.redisson.core.RBlockingQueue;
|
||||
import org.redisson.core.RRemoteService;
|
||||
import org.redisson.core.RTopic;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import io.netty.buffer.ByteBufUtil;
|
||||
import io.netty.util.concurrent.Future;
|
||||
import io.netty.util.concurrent.FutureListener;
|
||||
import io.netty.util.internal.PlatformDependent;
|
||||
import io.netty.util.internal.ThreadLocalRandom;
|
||||
|
||||
public class RedissonRemoteService implements RRemoteService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(RedissonRemoteService.class);
|
||||
|
||||
private final Map<RemoteServiceKey, RemoteServiceMethod> beans = PlatformDependent.newConcurrentHashMap();
|
||||
|
||||
private final Redisson redisson;
|
||||
|
||||
public RedissonRemoteService(Redisson redisson) {
|
||||
this.redisson = redisson;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void register(Class<T> remoteInterface, T object) {
|
||||
register(remoteInterface, object, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void register(Class<T> remoteInterface, T object, int executorsAmount) {
|
||||
if (executorsAmount < 1) {
|
||||
throw new IllegalArgumentException("executorsAmount can't be lower than 1");
|
||||
}
|
||||
for (Method method : remoteInterface.getMethods()) {
|
||||
RemoteServiceMethod value = new RemoteServiceMethod(method, object);
|
||||
RemoteServiceKey key = new RemoteServiceKey(remoteInterface, method.getName());
|
||||
if (beans.put(key, value) != null) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < executorsAmount; i++) {
|
||||
String requestQueueName = "redisson_remote_service:{" + remoteInterface.getName() + "}";
|
||||
RBlockingQueue<RemoteServiceRequest> requestQueue = redisson.getBlockingQueue(requestQueueName);
|
||||
subscribe(remoteInterface, requestQueue);
|
||||
}
|
||||
}
|
||||
|
||||
private <T> void subscribe(final Class<T> remoteInterface, final RBlockingQueue<RemoteServiceRequest> requestQueue) {
|
||||
Future<RemoteServiceRequest> take = requestQueue.takeAsync();
|
||||
take.addListener(new FutureListener<RemoteServiceRequest>() {
|
||||
@Override
|
||||
public void operationComplete(Future<RemoteServiceRequest> future) throws Exception {
|
||||
if (!future.isSuccess()) {
|
||||
return;
|
||||
}
|
||||
|
||||
RemoteServiceRequest request = future.getNow();
|
||||
RemoteServiceMethod method = beans.get(new RemoteServiceKey(remoteInterface, request.getMethodName()));
|
||||
String responseName = "redisson_remote_service:{" + remoteInterface.getName() + "}:" + request.getRequestId();
|
||||
RTopic<RemoteServiceResponse> topic = redisson.getTopic(responseName);
|
||||
RemoteServiceResponse response;
|
||||
try {
|
||||
Object result = method.getMethod().invoke(method.getBean(), request.getArgs());
|
||||
response = new RemoteServiceResponse(result);
|
||||
} catch (Exception e) {
|
||||
response = new RemoteServiceResponse(e.getCause());
|
||||
log.error("Can't execute: " + request, e);
|
||||
}
|
||||
|
||||
long clients = topic.publish(response);
|
||||
if (clients == 0) {
|
||||
log.error("None of clients has not received a response: {} for request: {}", response, request);
|
||||
}
|
||||
|
||||
subscribe(remoteInterface, requestQueue);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T get(Class<T> remoteInterface) {
|
||||
return get(remoteInterface, -1, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T get(final Class<T> remoteInterface, final int timeout, final TimeUnit timeUnit) {
|
||||
InvocationHandler handler = new InvocationHandler() {
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
String requestId = generateRequestId();
|
||||
|
||||
String requestQueueName = "redisson_remote_service:{" + remoteInterface.getName() + "}";
|
||||
RBlockingQueue<RemoteServiceRequest> requestQueue = redisson.getBlockingQueue(requestQueueName);
|
||||
RemoteServiceRequest request = new RemoteServiceRequest(requestId, method.getName(), args);
|
||||
requestQueue.add(request);
|
||||
|
||||
String responseName = "redisson_remote_service:{" + remoteInterface.getName() + "}:" + requestId;
|
||||
final RTopic<RemoteServiceResponse> topic = redisson.getTopic(responseName);
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
final AtomicReference<RemoteServiceResponse> response = new AtomicReference<RemoteServiceResponse>();
|
||||
int listenerId = topic.addListener(new MessageListener<RemoteServiceResponse>() {
|
||||
@Override
|
||||
public void onMessage(String channel, RemoteServiceResponse msg) {
|
||||
response.set(msg);
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
|
||||
if (timeout == -1) {
|
||||
latch.await();
|
||||
} else {
|
||||
if (!latch.await(timeout, timeUnit)) {
|
||||
topic.removeListener(listenerId);
|
||||
throw new RedisTimeoutException("No response after " + timeUnit.toMillis(timeout) + "ms for request: " + request);
|
||||
}
|
||||
}
|
||||
topic.removeListener(listenerId);
|
||||
RemoteServiceResponse msg = response.get();
|
||||
if (msg.getError() != null) {
|
||||
throw msg.getError();
|
||||
}
|
||||
return msg.getResult();
|
||||
}
|
||||
};
|
||||
return (T) Proxy.newProxyInstance(remoteInterface.getClassLoader(), new Class[] {remoteInterface}, handler);
|
||||
}
|
||||
|
||||
private String generateRequestId() {
|
||||
byte[] id = new byte[16];
|
||||
// TODO JDK UPGRADE replace to native ThreadLocalRandom
|
||||
ThreadLocalRandom.current().nextBytes(id);
|
||||
return ByteBufUtil.hexDump(id);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
/**
|
||||
* Copyright 2014 Nikita Koksharov, Nickolay Borbit
|
||||
*
|
||||
* 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.redisson;
|
||||
|
||||
public class RemoteServiceKey {
|
||||
|
||||
private final Class<?> serviceInterface;
|
||||
private final String methodName;
|
||||
|
||||
public RemoteServiceKey(Class<?> serviceInterface, String methodName) {
|
||||
super();
|
||||
this.serviceInterface = serviceInterface;
|
||||
this.methodName = methodName;
|
||||
}
|
||||
|
||||
public String getMethodName() {
|
||||
return methodName;
|
||||
}
|
||||
|
||||
public Class<?> getServiceInterface() {
|
||||
return serviceInterface;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((methodName == null) ? 0 : methodName.hashCode());
|
||||
result = prime * result + ((serviceInterface == null) ? 0 : serviceInterface.getName().hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
RemoteServiceKey other = (RemoteServiceKey) obj;
|
||||
if (methodName == null) {
|
||||
if (other.methodName != null)
|
||||
return false;
|
||||
} else if (!methodName.equals(other.methodName))
|
||||
return false;
|
||||
if (serviceInterface == null) {
|
||||
if (other.serviceInterface != null)
|
||||
return false;
|
||||
} else if (!serviceInterface.equals(other.serviceInterface))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Copyright 2014 Nikita Koksharov, Nickolay Borbit
|
||||
*
|
||||
* 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.redisson;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class RemoteServiceMethod {
|
||||
|
||||
private final Object bean;
|
||||
private final Method method;
|
||||
|
||||
public RemoteServiceMethod(Method method, Object bean) {
|
||||
super();
|
||||
this.method = method;
|
||||
this.bean = bean;
|
||||
}
|
||||
|
||||
public Object getBean() {
|
||||
return bean;
|
||||
}
|
||||
|
||||
public Method getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
/**
|
||||
* Copyright 2014 Nikita Koksharov, Nickolay Borbit
|
||||
*
|
||||
* 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.redisson;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class RemoteServiceRequest {
|
||||
|
||||
private String requestId;
|
||||
private String methodName;
|
||||
private Object[] args;
|
||||
|
||||
public RemoteServiceRequest() {
|
||||
}
|
||||
|
||||
public RemoteServiceRequest(String requestId, String methodName, Object[] args) {
|
||||
super();
|
||||
this.requestId = requestId;
|
||||
this.methodName = methodName;
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
public String getRequestId() {
|
||||
return requestId;
|
||||
}
|
||||
|
||||
public Object[] getArgs() {
|
||||
return args;
|
||||
}
|
||||
|
||||
public String getMethodName() {
|
||||
return methodName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RemoteServiceRequest[requestId=" + requestId + ", methodName=" + methodName + ", args="
|
||||
+ Arrays.toString(args) + "]";
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
/**
|
||||
* Copyright 2014 Nikita Koksharov, Nickolay Borbit
|
||||
*
|
||||
* 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.redisson;
|
||||
|
||||
public class RemoteServiceResponse {
|
||||
|
||||
private Object result;
|
||||
private Throwable error;
|
||||
|
||||
public RemoteServiceResponse() {
|
||||
}
|
||||
|
||||
public RemoteServiceResponse(Object result) {
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
public RemoteServiceResponse(Throwable error) {
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
public Throwable getError() {
|
||||
return error;
|
||||
}
|
||||
|
||||
public Object getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RemoteServiceResponse [result=" + result + ", error=" + error + "]";
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
/**
|
||||
* Copyright 2014 Nikita Koksharov, Nickolay Borbit
|
||||
*
|
||||
* 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.redisson.core;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public interface RRemoteService {
|
||||
|
||||
/**
|
||||
* Register remote service with single executor
|
||||
*
|
||||
* @param remoteInterface
|
||||
* @param object
|
||||
*/
|
||||
<T> void register(Class<T> remoteInterface, T object);
|
||||
|
||||
/**
|
||||
* Register remote service with custom executors amount
|
||||
*
|
||||
* @param remoteInterface
|
||||
* @param object
|
||||
* @param executorsAmount
|
||||
*/
|
||||
<T> void register(Class<T> remoteInterface, T object, int executorsAmount);
|
||||
|
||||
/**
|
||||
* Get remote service object for remote invocations
|
||||
*
|
||||
* @param remoteInterface
|
||||
* @return
|
||||
*/
|
||||
<T> T get(Class<T> remoteInterface);
|
||||
|
||||
/**
|
||||
* Get remote service object for remote invocations
|
||||
* with specified invocation timeout
|
||||
*
|
||||
* @param remoteInterface
|
||||
* @param timeout - invocation timeout
|
||||
* @param timeUnit
|
||||
* @return
|
||||
*/
|
||||
<T> T get(Class<T> remoteInterface, int timeout, TimeUnit timeUnit);
|
||||
|
||||
}
|
@ -0,0 +1,108 @@
|
||||
package org.redisson;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.redisson.client.RedisTimeoutException;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class RedissonRemoteServiceTest extends BaseTest {
|
||||
|
||||
public interface RemoteInterface {
|
||||
|
||||
void voidMethod(String name, Long param);
|
||||
|
||||
Long resultMethod(Long value);
|
||||
|
||||
void errorMethod() throws IOException;
|
||||
|
||||
void errorMethodWithCause();
|
||||
|
||||
void timeoutMethod() throws InterruptedException;
|
||||
|
||||
}
|
||||
|
||||
public class RemoteImpl implements RemoteInterface {
|
||||
|
||||
@Override
|
||||
public void voidMethod(String name, Long param) {
|
||||
System.out.println(name + " " + param);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long resultMethod(Long value) {
|
||||
return value*2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void errorMethod() throws IOException {
|
||||
throw new IOException("Checking error throw");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void errorMethodWithCause() {
|
||||
try {
|
||||
int s = 2 / 0;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Checking error throw", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void timeoutMethod() throws InterruptedException {
|
||||
Thread.sleep(2000);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Test(expected = RedisTimeoutException.class)
|
||||
public void testTimeout() throws InterruptedException {
|
||||
RedissonClient r1 = Redisson.create();
|
||||
r1.getRemoteSerivce().register(RemoteInterface.class, new RemoteImpl());
|
||||
|
||||
RedissonClient r2 = Redisson.create();
|
||||
RemoteInterface ri = r2.getRemoteSerivce().get(RemoteInterface.class, 1, TimeUnit.SECONDS);
|
||||
|
||||
try {
|
||||
ri.timeoutMethod();
|
||||
} finally {
|
||||
r1.shutdown();
|
||||
r2.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvocations() {
|
||||
RedissonClient r1 = Redisson.create();
|
||||
r1.getRemoteSerivce().register(RemoteInterface.class, new RemoteImpl());
|
||||
|
||||
RedissonClient r2 = Redisson.create();
|
||||
RemoteInterface ri = r2.getRemoteSerivce().get(RemoteInterface.class);
|
||||
|
||||
ri.voidMethod("someName", 100L);
|
||||
assertThat(ri.resultMethod(100L)).isEqualTo(200);
|
||||
|
||||
try {
|
||||
ri.errorMethod();
|
||||
Assert.fail();
|
||||
} catch (IOException e) {
|
||||
assertThat(e.getMessage()).isEqualTo("Checking error throw");
|
||||
}
|
||||
|
||||
try {
|
||||
ri.errorMethodWithCause();
|
||||
Assert.fail();
|
||||
} catch (Exception e) {
|
||||
assertThat(e.getCause()).isInstanceOf(ArithmeticException.class);
|
||||
assertThat(e.getCause().getMessage()).isEqualTo("/ by zero");
|
||||
}
|
||||
|
||||
r1.shutdown();
|
||||
r2.shutdown();
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue