Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
as.leap.vertx.rpc.impl.VertxRPCServer Maven / Gradle / Ivy
Go to download
Wrap eventBus of vert.x 3 as transport layer for RPC invoking
package as.leap.vertx.rpc.impl;
import as.leap.vertx.rpc.RPCHook;
import as.leap.vertx.rpc.RPCServer;
import as.leap.vertx.rpc.VertxRPCException;
import io.vertx.core.*;
import io.vertx.core.eventbus.Message;
import io.vertx.core.eventbus.MessageConsumer;
import io.vertx.core.json.JsonObject;
import io.vertx.core.logging.Logger;
import io.vertx.core.logging.LoggerFactory;
import io.vertx.core.shareddata.LocalMap;
import rx.Observable;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Stream;
/**
* Stream
*/
public class VertxRPCServer extends RPCBase implements RPCServer {
private static final Logger log = LoggerFactory.getLogger(VertxRPCServer.class);
private final LocalMap serviceMapping;
private final MessageConsumer consumer;
private RPCServerOptions options;
private RPCHook rpcHook;
private Vertx vertx;
public VertxRPCServer(RPCServerOptions options) {
vertx = options.getVertx();
checkBusAddress(options.getBusAddress());
this.options = options;
if (options.getServiceMapping().size() == 0)
throw new VertxRPCException("please add service implementation to RPCServerOptions.");
this.serviceMapping = options.getServiceMapping();
this.rpcHook = options.getRpcHook();
this.consumer = options.getVertx().eventBus().consumer(options.getBusAddress());
this.consumer.setMaxBufferedMessages(options.getMaxBufferedMessages());
registryService();
}
private void registryService() {
consumer.handler(message -> {
try {
RPCRequest request = asObject(message.body(), RPCRequest.class);
VertxRPCServer.this.call(request, message);
} catch (Exception e) {
replyFail(e, message);
}
});
}
private void call(RPCRequest request, Message message) {
try {
Object service = serviceMapping.get(request.getServiceName()).getValue();
Class>[] argClasses = {};
Object[] args = {};
//args
if (request.getArgs() != null && request.getArgs().size() > 0) {
List argList = request.getArgs();
int argCount = argList.size() >>> 1;
args = new Object[argCount];
argClasses = new Class[argCount];
for (int i = 0; i < argList.size(); i += 2) {
int index = i >>> 1;
String argClassName = (String) argList.get(i);
byte[] argBytes = (byte[]) argList.get(i + 1);
Class> argClass = Class.forName(argClassName);
Object arg = asObject(argBytes, argClass);
//check type for get real class and real value
if (arg instanceof WrapperType) {
argClasses[index] = ((WrapperType) arg).getClazz();
args[index] = ((WrapperType) arg).getValue();
} else {
argClasses[index] = arg.getClass();
args[index] = arg;
}
}
}
CallbackType callbackType = CallbackType.valueOf(message.headers().get(CALLBACK_TYPE));
final Object[] finalArgs = args;
final Class>[] finalArgClasses = argClasses;
//hook
if (rpcHook != null) {
if (options.isHookOnEventLoop()) {
rpcHook.beforeHandler(request.getServiceName(), request.getMethodName(), finalArgs, message.headers().remove(CALLBACK_TYPE));
executeInvoke(callbackType, request, message, service, finalArgClasses, finalArgs);
} else {
vertx.executeBlocking(future -> {
rpcHook.beforeHandler(request.getServiceName(), request.getMethodName(), finalArgs, message.headers().remove(CALLBACK_TYPE));
future.complete();
}, false, event -> executeInvoke(callbackType, request, message, service, finalArgClasses, finalArgs));
}
} else {
executeInvoke(callbackType, request, message, service, finalArgClasses, finalArgs);
}
} catch (Exception e) {
replyFail(e, message);
}
}
private void executeInvoke(CallbackType callbackType, RPCRequest request, Message message, Object service, Class>[] argClasses, Object[] args) {
try {
switch (callbackType) {
case FUTURE:
Future> vertxFuture = (Future) service.getClass().getMethod(request.getMethodName(), argClasses).invoke(service, args);
vertxFuture.setHandler(asyncResult -> {
if (asyncResult.failed()) {
replyFail(asyncResult.cause(), message);
} else {
replySuccess(asyncResult.result(), message);
}
});
break;
case ASYNC_HANDLER:
argClasses = Arrays.copyOf(argClasses, argClasses.length + 1);
argClasses[argClasses.length - 1] = Handler.class;
args = Arrays.copyOf(args, args.length + 1);
args[args.length - 1] = (Handler>) event -> {
if (event.succeeded()) replySuccess(event.result(), message);
else replyFail(event.cause(), message);
};
service.getClass().getMethod(request.getMethodName(), argClasses).invoke(service, args);
break;
case REACTIVE:
Observable> observable = (Observable) service.getClass().getMethod(request.getMethodName(), argClasses).invoke(service, args);
observable.subscribe(result -> replySuccess(result, message), ex -> replyFail(ex, message));
break;
case COMPLETABLE_FUTURE:
CompletableFuture> future = (CompletableFuture) service.getClass().getMethod(request.getMethodName(), argClasses).invoke(service, args);
future.whenComplete((result, ex) -> {
if (ex != null) replyFail(ex, message);
else replySuccess(result, message);
});
break;
}
} catch (Exception e) {
replyFail(e, message);
}
}
private void replySuccess(T result, Message message) {
try {
String resultClassName;
byte[] resultBytes = {};
if (Optional.ofNullable(result).isPresent()) {
Class> resultClass = result.getClass();
resultClassName = isWrapType(resultClass) ? WrapperType.class.getName() : resultClass.getName();
resultBytes = asBytes(result);
} else {
// result is null, so we have wrap it.
resultClassName = WrapperType.class.getName();
}
RPCResponse response = new RPCResponse(resultClassName, resultBytes);
byte[] responseBytes = asBytes(response);
message.reply(responseBytes);
//hook
if (rpcHook != null) {
if (options.isHookOnEventLoop()) {
rpcHook.afterHandler(result, message.headers());
} else {
vertx.executeBlocking(future -> {
rpcHook.afterHandler(result, message.headers());
future.complete();
}, false, null);
}
}
} catch (Exception e) {
replyFail(e, message);
}
}
private void replyFail(Throwable ex, Message message) {
Throwable realEx = ex.getCause() != null && !ex.getCause().equals(ex) ? ex.getCause() : ex;
JsonObject exJson = new JsonObject().put("message", realEx.getMessage());
exJson.put("exClass", ex.getClass().getName());
Stream.of(realEx.getClass().getDeclaredFields()).forEach(field -> {
field.setAccessible(true);
try {
exJson.put(field.getName(), field.get(realEx));
} catch (Exception e) {
if (e instanceof VertxException) {
try {
Optional.ofNullable(field.get(realEx)).ifPresent(value -> exJson.put(field.getName(), value.toString()));
} catch (IllegalAccessException illegalEx) {
log.error(illegalEx.getMessage(), illegalEx);
}
}
log.error(e.getMessage(), e);
}
});
message.fail(500, exJson.encode());
//hook
if (rpcHook != null) {
if (options.isHookOnEventLoop()) {
rpcHook.afterHandler(ex, message.headers());
} else {
vertx.executeBlocking(future -> {
rpcHook.afterHandler(ex, message.headers());
future.complete();
}, false, null);
}
}
}
@Override
public void shutdown(Handler> handler) {
if (Optional.ofNullable(handler).isPresent()) {
consumer.unregister(handler);
} else {
consumer.unregister();
}
}
}