com.github.lontime.shaded.org.redisson.remote.BaseRemoteService Maven / Gradle / Ivy
The newest version!
/**
* Copyright (c) 2013-2021 Nikita Koksharov
*
* 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 com.github.lontime.shaded.org.redisson.remote;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.util.CharsetUtil;
import io.netty.util.Timeout;
import io.netty.util.TimerTask;
import com.github.lontime.shaded.org.redisson.RedissonMap;
import com.github.lontime.shaded.org.redisson.api.RFuture;
import com.github.lontime.shaded.org.redisson.api.RMap;
import com.github.lontime.shaded.org.redisson.api.RemoteInvocationOptions;
import com.github.lontime.shaded.org.redisson.api.annotation.RRemoteAsync;
import com.github.lontime.shaded.org.redisson.api.annotation.RRemoteReactive;
import com.github.lontime.shaded.org.redisson.api.annotation.RRemoteRx;
import com.github.lontime.shaded.org.redisson.client.codec.Codec;
import com.github.lontime.shaded.org.redisson.client.codec.StringCodec;
import com.github.lontime.shaded.org.redisson.codec.CompositeCodec;
import com.github.lontime.shaded.org.redisson.command.CommandAsyncExecutor;
import com.github.lontime.shaded.org.redisson.executor.RemotePromise;
import com.github.lontime.shaded.org.redisson.misc.Hash;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.*;
import java.util.stream.Collectors;
/**
*
* @author Nikita Koksharov
*
*/
public abstract class BaseRemoteService {
private final Map, String> requestQueueNameCache = new ConcurrentHashMap<>();
private final ConcurrentMap methodSignaturesCache = new ConcurrentHashMap<>();
protected final Codec codec;
protected final String name;
protected final CommandAsyncExecutor commandExecutor;
protected final String executorId;
protected final String cancelRequestMapName;
protected final String cancelResponseMapName;
protected final String responseQueueName;
private final ConcurrentMap responses;
public BaseRemoteService(Codec codec, String name, CommandAsyncExecutor commandExecutor, String executorId, ConcurrentMap responses) {
this.codec = codec;
this.name = commandExecutor.getConnectionManager().getConfig().getNameMapper().map(name);
this.commandExecutor = commandExecutor;
this.executorId = executorId;
this.responses = responses;
this.cancelRequestMapName = "{" + name + ":remote" + "}:cancel-request";
this.cancelResponseMapName = "{" + name + ":remote" + "}:cancel-response";
this.responseQueueName = getResponseQueueName(executorId);
}
public String getResponseQueueName(String executorId) {
return "{remote_response}:" + executorId;
}
protected String getAckName(String requestId) {
return "{" + name + ":remote" + "}:" + requestId + ":ack";
}
public String getRequestQueueName(Class> remoteInterface) {
return requestQueueNameCache.computeIfAbsent(remoteInterface, k -> "{" + name + ":" + k.getName() + "}");
}
protected ByteBuf encode(Object obj) {
try {
return codec.getValueEncoder().encode(obj);
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
}
public T get(Class remoteInterface) {
return get(remoteInterface, RemoteInvocationOptions.defaults());
}
public T get(Class remoteInterface, long executionTimeout, TimeUnit executionTimeUnit) {
return get(remoteInterface,
RemoteInvocationOptions.defaults().expectResultWithin(executionTimeout, executionTimeUnit));
}
public T get(Class remoteInterface, long executionTimeout, TimeUnit executionTimeUnit, long ackTimeout,
TimeUnit ackTimeUnit) {
return get(remoteInterface, RemoteInvocationOptions.defaults().expectAckWithin(ackTimeout, ackTimeUnit)
.expectResultWithin(executionTimeout, executionTimeUnit));
}
public T get(Class remoteInterface, RemoteInvocationOptions options) {
for (Annotation annotation : remoteInterface.getAnnotations()) {
if (annotation.annotationType() == RRemoteAsync.class) {
Class syncInterface = (Class) ((RRemoteAsync) annotation).value();
AsyncRemoteProxy proxy = new AsyncRemoteProxy(commandExecutor, name, responseQueueName, responses, codec, executorId, cancelRequestMapName, this);
return proxy.create(remoteInterface, options, syncInterface);
}
if (annotation.annotationType() == RRemoteReactive.class) {
Class syncInterface = (Class) ((RRemoteReactive) annotation).value();
ReactiveRemoteProxy proxy = new ReactiveRemoteProxy(commandExecutor, name, responseQueueName, responses, codec, executorId, cancelRequestMapName, this);
return proxy.create(remoteInterface, options, syncInterface);
}
if (annotation.annotationType() == RRemoteRx.class) {
Class syncInterface = (Class) ((RRemoteRx) annotation).value();
RxRemoteProxy proxy = new RxRemoteProxy(commandExecutor, name, responseQueueName, responses, codec, executorId, cancelRequestMapName, this);
return proxy.create(remoteInterface, options, syncInterface);
}
}
SyncRemoteProxy proxy = new SyncRemoteProxy(commandExecutor, name, responseQueueName, responses, codec, executorId, this);
return proxy.create(remoteInterface, options);
}
protected long getTimeout(Long executionTimeoutInMillis, RemoteServiceRequest request) {
return executionTimeoutInMillis;
}
protected RMap getMap(String name) {
return new RedissonMap<>(new CompositeCodec(StringCodec.INSTANCE, codec, codec), commandExecutor, name);
}
protected void scheduleCheck(String mapName, String requestId, CompletableFuture cancelRequest) {
commandExecutor.getConnectionManager().newTimeout(new TimerTask() {
@Override
public void run(Timeout timeout) throws Exception {
if (cancelRequest.isDone()) {
return;
}
RMap canceledRequests = getMap(mapName);
RFuture future = canceledRequests.removeAsync(requestId);
future.whenComplete((request, ex) -> {
if (cancelRequest.isDone()) {
return;
}
if (ex != null) {
scheduleCheck(mapName, requestId, cancelRequest);
return;
}
if (request == null) {
scheduleCheck(mapName, requestId, cancelRequest);
} else {
cancelRequest.complete(request);
}
});
}
}, 3000, TimeUnit.MILLISECONDS);
}
protected String generateRequestId(Object[] args) {
byte[] id = new byte[16];
ThreadLocalRandom.current().nextBytes(id);
return ByteBufUtil.hexDump(id);
}
protected abstract CompletableFuture addAsync(String requestQueueName, RemoteServiceRequest request,
RemotePromise