hu.akarnokd.reactiverpc.RpcServiceMapper Maven / Gradle / Ivy
package hu.akarnokd.reactiverpc;
import java.io.IOException;
import java.lang.reflect.*;
import java.util.*;
import java.util.concurrent.atomic.*;
import java.util.function.Function;
import org.reactivestreams.*;
import rsc.publisher.Px;
import rsc.subscriber.BlockingLastSubscriber;
import rsc.util.*;
enum RpcServiceMapper {
;
public static void invokeInit(Object api, RpcStreamContext> ctx) {
for (Method m : api.getClass().getMethods()) {
if (m.isAnnotationPresent(RsRpcInit.class)) {
if (m.getReturnType() == Void.TYPE) {
if (m.getParameterCount() == 1 &&
RpcStreamContext.class.isAssignableFrom(m.getParameterTypes()[0])) {
try {
m.invoke(api, ctx);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
UnsignalledExceptions.onErrorDropped(e);
throw new IllegalStateException(e);
}
return;
}
}
throw new IllegalStateException("RsRpcInit method has to be void and accepting only a single RpcStreamContext parameter");
}
}
}
public static void invokeDone(Object api, RpcStreamContext> ctx) {
for (Method m : api.getClass().getMethods()) {
if (m.isAnnotationPresent(RsRpcDone.class)) {
if (m.getReturnType() == Void.TYPE) {
if (m.getParameterCount() == 1 &&
RpcStreamContext.class.isAssignableFrom(m.getParameterTypes()[0])) {
try {
m.invoke(api, ctx);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
UnsignalledExceptions.onErrorDropped(e);
throw new IllegalStateException(e);
}
return;
}
}
throw new IllegalStateException("RsRpcInit method has to be void and accepting only a single RpcStreamContext parameter");
}
}
}
public static Map serverServiceMap(Object api) {
Map result = new HashMap<>();
for (Method m : api.getClass().getMethods()) {
if (m.isAnnotationPresent(RsRpc.class)) {
RsRpc a = m.getAnnotation(RsRpc.class);
String name = m.getName();
String aname = a.name();
if (!aname.isEmpty()) {
name = aname;
}
Class> rt = m.getReturnType();
if (rt == Void.TYPE) {
int pc = m.getParameterCount();
if (pc == 2) {
if (RpcStreamContext.class.isAssignableFrom(m.getParameterTypes()[0])) {
if (Publisher.class.isAssignableFrom(m.getParameterTypes()[1])) {
result.put(name, new RpcServerReceive(m, api));
} else {
throw new IllegalStateException("RsRpc annotated methods require a second Publisher as a parameter: " + m);
}
} else {
throw new IllegalStateException("RsRpc annotated methods require a first RpcStreamContext as a parameter: " + m);
}
} else
if (pc > 2) {
if (RpcStreamContext.class.isAssignableFrom(m.getParameterTypes()[0])) {
result.put(name, new RpcServerSyncReceive(m, api));
} else {
throw new IllegalStateException("RsRpc annotated methods require a first RpcStreamContext as a parameter: " + m);
}
} else {
throw new IllegalStateException("RsRpc annotated methods require one RpcStreamContext and one Publisher as a parameter: " + m);
}
} else
if (Publisher.class.isAssignableFrom(rt)) {
int pc = m.getParameterCount();
if (pc == 1) {
if (RpcStreamContext.class.isAssignableFrom(m.getParameterTypes()[0])) {
result.put(name, new RpcServerSend(m, api));
} else {
throw new IllegalStateException("RsRpc annotated methods require at one RpcStreamContext as a parameter: " + m);
}
} else
if (pc == 2) {
if (RpcStreamContext.class.isAssignableFrom(m.getParameterTypes()[0])) {
if (Publisher.class.isAssignableFrom(m.getParameterTypes()[1])) {
result.put(name, new RpcServerMap(m, api));
} else {
throw new IllegalStateException("RsRpc annotated methods require the second parameter to be Publisher.");
}
} else {
throw new IllegalStateException("RsRpc annotated methods require the first parameter to be RpcStreamContext.");
}
} else {
throw new IllegalStateException("RsRpc annotated methods require one RpcStreamContext and one Publisher as a parameter: " + m);
}
} else {
int pc = m.getParameterCount();
if (pc > 0 && RpcStreamContext.class.isAssignableFrom(m.getParameterTypes()[0])) {
if (pc == 1) {
result.put(name, new RpcServerSyncSend(m, api));
} else {
result.put(name, new RpcServerSyncMap(m, api));
}
} else {
throw new IllegalStateException("RsRpc annotated methods require at one RpcStreamContext as a parameter: " + m);
}
}
}
}
return result;
}
public static Map clientServiceMap(Class> api) {
Map result = new HashMap<>();
for (Method m : api.getMethods()) {
if (m.isAnnotationPresent(RsRpc.class)) {
RsRpc a = m.getAnnotation(RsRpc.class);
String name = m.getName();
String aname = a.name();
if (!aname.isEmpty()) {
name = aname;
}
if (result.containsKey(name)) {
throw new IllegalStateException("Overloads with the same target name are not supported");
}
Class> rt = m.getReturnType();
if (rt == Void.TYPE) {
int pc = m.getParameterCount();
if (pc == 0) {
throw new IllegalStateException("RsRpc annotated void methods require at least one parameter");
} else
if (pc == 1) {
if (Function.class.isAssignableFrom(m.getParameterTypes()[0])) {
result.put(name, new RpcClientUmap());
continue;
} else
if (Publisher.class.isAssignableFrom(m.getParameterTypes()[0])) {
result.put(name, new RpcClientSend());
continue;
}
}
result.put(name, new RpcClientSyncSend());
} else
if (Publisher.class.isAssignableFrom(rt)) {
int pc = m.getParameterCount();
if (pc > 1) {
throw new IllegalStateException("RsRpc annotated methods returning a Publisher require 0 or 1 parameter: " + m);
}
if (pc == 0) {
result.put(name, new RpcClientReceive());
} else {
if (Publisher.class.isAssignableFrom(m.getParameterTypes()[0])) {
result.put(name, new RpcClientMap());
} else {
throw new IllegalStateException("RsRpc annotated methods returning a Publisher allows only Publisher as parameter: " + m);
}
}
} else {
if (m.getParameterCount() == 0) {
result.put(name, new RpcClientSyncReceive());
} else {
result.put(name, new RpcClientSyncMap());
}
}
}
}
return result;
}
public static boolean dispatchServer(long streamId, Object action, RpcIOManager io, RpcStreamContext> ctx) {
if (action instanceof RpcServerSend) {
RpcServerSend rpcServerSend = (RpcServerSend) action;
return rpcServerSend.send(streamId, ctx, io);
} else
if (action instanceof RpcServerReceive) {
RpcServerReceive rpcServerReceive = (RpcServerReceive) action;
return rpcServerReceive.receive(streamId, ctx, io);
} else
if (action instanceof RpcServerMap) {
RpcServerMap rpcServerMap = (RpcServerMap) action;
return rpcServerMap.map(streamId, ctx, io);
} else
if (action instanceof RpcServerSyncSend) {
RpcServerSyncSend rpcServerSyncSend = (RpcServerSyncSend) action;
return rpcServerSyncSend.send(streamId, ctx, io);
} else
if (action instanceof RpcServerSyncReceive) {
RpcServerSyncReceive rpcServerSyncReceive = (RpcServerSyncReceive) action;
return rpcServerSyncReceive.receive(streamId, ctx, io);
} else
if (action instanceof RpcServerSyncMap) {
RpcServerSyncMap rpcServerSyncMap = (RpcServerSyncMap) action;
return rpcServerSyncMap.map(streamId, ctx, io);
}
UnsignalledExceptions.onErrorDropped(new IllegalStateException("Unsupported action: " + action.getClass()));
return false;
}
public static Object dispatchClient(String name, Object action, Object[] args, RpcIOManager io) {
if (action instanceof RpcClientSend) {
if (args[0] == null) {
throw new NullPointerException("The source Publisher is null");
}
RpcClientSend rpcSend = (RpcClientSend) action;
rpcSend.send(name, (Publisher>)args[0], io);
return null;
} else
if (action instanceof RpcClientReceive) {
RpcClientReceive rpcReceive = (RpcClientReceive) action;
return rpcReceive.receive(name, io);
} else
if (action instanceof RpcClientMap) {
if (args[0] == null) {
throw new NullPointerException("The source Publisher is null");
}
RpcClientMap rpcMap = (RpcClientMap) action;
return rpcMap.map(name, (Publisher>)args[0], io);
} else
if (action instanceof RpcClientUmap) {
if (args[0] == null) {
throw new NullPointerException("The umapper function is null");
}
RpcClientUmap rpcUmap = (RpcClientUmap) action;
@SuppressWarnings("unchecked")
Function, Publisher>> f = (Function, Publisher>>)args[0];
rpcUmap.umap(name, f, io);
return null;
} else
if (action instanceof RpcClientSyncSend) {
RpcClientSyncSend rpcClientSyncSend = (RpcClientSyncSend) action;
rpcClientSyncSend.send(name, args, io);
return null;
} else
if (action instanceof RpcClientSyncReceive) {
RpcClientSyncReceive rpcClientSyncReceive = (RpcClientSyncReceive) action;
return rpcClientSyncReceive.receive(name, io);
} else
if (action instanceof RpcClientSyncMap) {
RpcClientSyncMap rpcClientSyncMap = (RpcClientSyncMap) action;
return rpcClientSyncMap.map(name, args, io);
}
throw new IllegalStateException("Unsupported action class: " + action.getClass());
}
static final class RpcClientSyncSend {
public void send(String function, Object[] args, RpcIOManager io) {
if (args.length == 1) {
RpcClientSend.sendStatic(function, Px.just(args[0]), io);
} else {
RpcClientSend.sendStatic(function, Px.just(args), io);
}
}
}
static final class RpcClientSend {
public static void sendStatic(String function, Publisher> values, RpcIOManager io) {
long streamId = io.newStreamId();
SendSubscriber s = new SendSubscriber(io, streamId);
io.registerSubscription(streamId, s);
io.sendNew(streamId, function);
values.subscribe(s);
}
public void send(String function, Publisher> values, RpcIOManager io) {
sendStatic(function, values, io);
}
static final class SendSubscriber
extends DeferredSubscription
implements Subscriber
© 2015 - 2025 Weber Informatics LLC | Privacy Policy