Search in sources :

Example 1 with MethodParam

use of rpc.turbo.param.MethodParam in project turbo-rpc by hank-whu.

the class RemoteServiceFactory method generateRemoteObject.

private Object generateRemoteObject(App app, Class<?> clazz, Collection<MethodConfig> configs) throws Exception {
    if (app == null) {
        throw new RuntimeException("app must not be null");
    }
    if (clazz == null) {
        throw new RuntimeException("clazz must not be null");
    }
    if (configs == null || configs.isEmpty()) {
        throw new RuntimeException("configs must not be empty");
    }
    for (MethodConfig config : configs) {
        if (config == null) {
            throw new RuntimeException("config must not be null");
        }
        if (config.method == null) {
            throw new RuntimeException("config.method must not be null");
        }
        if (config.timeout < 1) {
            throw new RuntimeException("config.timeout must > 0");
        }
        if (config.timeout > 5 * 60 * 1000) {
            throw new RuntimeException("config.timeout must < 5 * 60 * 1000 (5 mintues)");
        }
    }
    Method[] allMethods = clazz.getMethods();
    List<Method> allPublicMethods = // 
    Stream.of(// 
    allMethods).filter(// 
    m -> Modifier.isPublic(m.getModifiers())).filter(// 
    m -> !Modifier.isStatic(m.getModifiers())).peek(m -> {
        if (!CompletableFuture.class.equals(m.getReturnType())) {
            throw new RuntimeException("method return-type must be CompletableFuture, " + InvokerUtils.getServiceMethodName("", "", m));
        }
    }).collect(Collectors.toList());
    if (configs.size() != allPublicMethods.size()) {
        throw new RuntimeException("configs must contains all the interface's methods");
    }
    for (Method method : allMethods) {
        if (!CompletableFuture.class.equals(method.getReturnType())) {
            throw new RuntimeException("method return-type must be CompletableFuture, " + method);
        }
        if (!configs.stream().anyMatch(config -> config.method.equals(method))) {
            throw new RuntimeException("configs must contains the method: " + method);
        }
    }
    final String remoteClassName = // 
    clazz.getName() + "_RemoteService_" + UUID.randomUUID().toString().replace("-", "");
    // 创建类
    ClassPool pool = ClassPool.getDefault();
    CtClass remoteCtClass = pool.makeClass(remoteClassName);
    CtClass[] interfaces = { pool.getCtClass(clazz.getName()), pool.getCtClass(RemoteInterface.class.getName()) };
    remoteCtClass.setInterfaces(interfaces);
    // 添加私有成员app
    CtField appField = new CtField(pool.get(App.class.getName()), "app", remoteCtClass);
    appField.setModifiers(Modifier.PRIVATE | Modifier.FINAL);
    remoteCtClass.addField(appField);
    // 添加get方法
    remoteCtClass.addMethod(CtNewMethod.getter("getApp", appField));
    // 添加有参的构造函数
    CtConstructor constructor1 = new CtConstructor(new CtClass[] { pool.get(App.class.getName()) }, remoteCtClass);
    constructor1.setBody("{$0.app = $1;}");
    remoteCtClass.addConstructor(constructor1);
    for (MethodConfig config : configs) {
        Method method = config.method;
        Class<? extends MethodParam> methodParamClass = MethodParamClassFactory.createClass(method);
        long timeout = config.timeout;
        // 添加私有成员failoverInvoker
        String failoverFieldName = getFailoverInvokerFieldName(app, method);
        CtField failoverField = new CtField(pool.get(Invoker.class.getName()), failoverFieldName, remoteCtClass);
        appField.setModifiers(Modifier.PRIVATE);
        remoteCtClass.addField(failoverField);
        StringBuilder methodBuilder = new StringBuilder();
        methodBuilder.append("public ");
        methodBuilder.append(method.getReturnType().getName());
        methodBuilder.append(" ");
        methodBuilder.append(method.getName());
        methodBuilder.append("(");
        Class<?>[] parameterTypes = method.getParameterTypes();
        for (int i = 0; i < parameterTypes.length; i++) {
            Class<?> parameterType = parameterTypes[i];
            methodBuilder.append(parameterType.getName());
            methodBuilder.append(" param");
            methodBuilder.append(i);
            if (i != parameterTypes.length - 1) {
                methodBuilder.append(", ");
            }
        }
        methodBuilder.append("){\r\n");
        methodBuilder.append("  return ");
        if (config.ignore) {
            if (logger.isInfoEnabled()) {
                logger.info(InvokerUtils.getServiceMethodName(app.group, app.app, config.method) + " ignore");
            }
            methodBuilder.append("$remote_ignore()");
        } else {
            if (logger.isInfoEnabled()) {
                logger.info(// 
                InvokerUtils.getServiceMethodName(app.group, app.app, config.method) + " register, config:" + config);
            }
            methodBuilder.append("$remote_execute(");
            methodBuilder.append(app.getMethodId(method));
            methodBuilder.append(", ");
            methodBuilder.append(timeout);
            methodBuilder.append("L, ");
            methodBuilder.append("new ");
            methodBuilder.append(methodParamClass.getName());
            methodBuilder.append("(");
            for (int i = 0; i < parameterTypes.length; i++) {
                methodBuilder.append("param");
                methodBuilder.append(i);
                if (i != parameterTypes.length - 1) {
                    methodBuilder.append(",");
                }
            }
            methodBuilder.append("), ");
            methodBuilder.append(failoverFieldName);
            methodBuilder.append(")");
        }
        methodBuilder.append(";\r\n}");
        CtMethod m = CtNewMethod.make(methodBuilder.toString(), remoteCtClass);
        remoteCtClass.addMethod(m);
    }
    Class<?> invokerClass = remoteCtClass.toClass();
    return invokerClass.getConstructor(App.class).newInstance(app);
}
Also used : CtMethod(javassist.CtMethod) CompletableFuture(java.util.concurrent.CompletableFuture) CtClass(javassist.CtClass) CtNewMethod(javassist.CtNewMethod) App(rpc.turbo.transport.client.App) CtConstructor(javassist.CtConstructor) MethodConfig(rpc.turbo.config.MethodConfig) Method(java.lang.reflect.Method) Invoker(rpc.turbo.invoke.Invoker) TurboService(rpc.turbo.annotation.TurboService) Collection(java.util.Collection) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) MethodParam(rpc.turbo.param.MethodParam) IOException(java.io.IOException) UUID(java.util.UUID) Field(java.lang.reflect.Field) Collectors(java.util.stream.Collectors) CtField(javassist.CtField) MethodParamClassFactory(rpc.turbo.param.MethodParamClassFactory) List(java.util.List) InvokerUtils(rpc.turbo.invoke.InvokerUtils) Stream(java.util.stream.Stream) Closeable(java.io.Closeable) Modifier(java.lang.reflect.Modifier) Log(org.apache.commons.logging.Log) LogFactory(org.apache.commons.logging.LogFactory) ClassPool(javassist.ClassPool) FailoverInvokerFactory(rpc.turbo.invoke.FailoverInvokerFactory) App(rpc.turbo.transport.client.App) ClassPool(javassist.ClassPool) CtMethod(javassist.CtMethod) CtNewMethod(javassist.CtNewMethod) Method(java.lang.reflect.Method) CtConstructor(javassist.CtConstructor) MethodConfig(rpc.turbo.config.MethodConfig) CtClass(javassist.CtClass) CompletableFuture(java.util.concurrent.CompletableFuture) CtField(javassist.CtField) CtClass(javassist.CtClass) CtMethod(javassist.CtMethod)

Example 2 with MethodParam

use of rpc.turbo.param.MethodParam in project turbo-rpc by hank-whu.

the class JavassistInvoker method generateRealInvoker.

private Invoker<T> generateRealInvoker() throws Exception {
    final String invokerClassName = // 
    "rpc.turbo.invoke.generate.Invoker_" + serviceId + // 
    "_" + UUID.randomUUID().toString().replace("-", "");
    // 创建类
    ClassPool pool = ClassPool.getDefault();
    CtClass invokerCtClass = pool.makeClass(invokerClassName);
    invokerCtClass.setInterfaces(new CtClass[] { pool.getCtClass(Invoker.class.getName()) });
    // 添加私有成员service
    CtField serviceField = new CtField(pool.get(service.getClass().getName()), "service", invokerCtClass);
    serviceField.setModifiers(Modifier.PRIVATE | Modifier.FINAL);
    invokerCtClass.addField(serviceField);
    // 添加有参的构造函数
    CtConstructor constructor = new CtConstructor(new CtClass[] { pool.get(service.getClass().getName()) }, invokerCtClass);
    constructor.setBody("{$0.service = $1;}");
    invokerCtClass.addConstructor(constructor);
    {
        // 添加MethodParam方法
        StringBuilder methodBuilder = new StringBuilder();
        StringBuilder resultBuilder = new StringBuilder();
        methodBuilder.append("public Object invoke(rpc.turbo.param.MethodParam methodParam) {\r\n");
        if (parameterTypes.length > 0) {
            // 强制类型转换
            methodBuilder.append(methodParamClass.getName());
            methodBuilder.append("  params = (");
            methodBuilder.append(methodParamClass.getName());
            methodBuilder.append(")methodParam;");
        }
        methodBuilder.append("  return ");
        resultBuilder.append("service.");
        resultBuilder.append(method.getName());
        resultBuilder.append("(");
        for (int i = 0; i < parameterTypes.length; i++) {
            resultBuilder.append("params.$param");
            resultBuilder.append(i);
            resultBuilder.append("()");
            if (i != parameterTypes.length - 1) {
                methodBuilder.append(", ");
            }
        }
        resultBuilder.append(")");
        String resultStr = box(method.getReturnType(), resultBuilder.toString());
        methodBuilder.append(resultStr);
        methodBuilder.append(";\r\n}");
        CtMethod m = CtNewMethod.make(methodBuilder.toString(), invokerCtClass);
        invokerCtClass.addMethod(m);
    }
    {
        // 添加通用方法
        StringBuilder methodBuilder = new StringBuilder();
        StringBuilder resultBuilder = new StringBuilder();
        methodBuilder.append("public Object invoke(Object[] params) {\r\n");
        methodBuilder.append("  return ");
        resultBuilder.append("service.");
        resultBuilder.append(method.getName());
        resultBuilder.append("(");
        for (int i = 0; i < parameterTypes.length; i++) {
            Class<?> paramType = parameterTypes[i];
            resultBuilder.append("((");
            resultBuilder.append(forceCast(paramType));
            resultBuilder.append(")params[");
            resultBuilder.append(i);
            resultBuilder.append("])");
            resultBuilder.append(unbox(paramType));
        }
        resultBuilder.append(")");
        String resultStr = box(method.getReturnType(), resultBuilder.toString());
        methodBuilder.append(resultStr);
        methodBuilder.append(";\r\n}");
        CtMethod m = CtNewMethod.make(methodBuilder.toString(), invokerCtClass);
        invokerCtClass.addMethod(m);
    }
    if (parameterCount <= 6) {
        // just for benchmark
        StringBuilder methodBuilder = new StringBuilder();
        StringBuilder resultBuilder = new StringBuilder();
        methodBuilder.append("public Object invoke(");
        String params = // 
        IntStream.range(0, // 
        parameterCount).mapToObj(// 
        i -> "Object param" + i).collect(Collectors.joining(","));
        methodBuilder.append(params);
        methodBuilder.append(") {\r\n");
        methodBuilder.append("  return ");
        resultBuilder.append("service.");
        resultBuilder.append(method.getName());
        resultBuilder.append("(");
        for (int i = 0; i < parameterCount; i++) {
            Class<?> paramType = parameterTypes[i];
            resultBuilder.append("((");
            resultBuilder.append(forceCast(paramType));
            resultBuilder.append(")param");
            resultBuilder.append(i);
            resultBuilder.append(")");
            resultBuilder.append(unbox(paramType));
            if (i != parameterCount - 1) {
                resultBuilder.append(",");
            }
        }
        resultBuilder.append(")");
        String resultStr = box(method.getReturnType(), resultBuilder.toString());
        methodBuilder.append(resultStr);
        methodBuilder.append(";\r\n}");
        CtMethod m = CtNewMethod.make(methodBuilder.toString(), invokerCtClass);
        invokerCtClass.addMethod(m);
    }
    Class<?> invokerClass = invokerCtClass.toClass();
    // 通过反射创建有参的实例
    @SuppressWarnings("unchecked") Invoker<T> invoker = (Invoker<T>) invokerClass.getConstructor(service.getClass()).newInstance(service);
    return invoker;
}
Also used : IntStream(java.util.stream.IntStream) Arrays(java.util.Arrays) CtMethod(javassist.CtMethod) Modifier(javassist.Modifier) MethodParam(rpc.turbo.param.MethodParam) SourceCodeUtils.forceCast(rpc.turbo.util.SourceCodeUtils.forceCast) UUID(java.util.UUID) CtClass(javassist.CtClass) Collectors(java.util.stream.Collectors) EmptyMethodParam(rpc.turbo.param.EmptyMethodParam) CtField(javassist.CtField) CtNewMethod(javassist.CtNewMethod) MethodParamClassFactory(rpc.turbo.param.MethodParamClassFactory) TypeUtils(rpc.turbo.util.TypeUtils) SourceCodeUtils.unbox(rpc.turbo.util.SourceCodeUtils.unbox) Parameter(java.lang.reflect.Parameter) CtConstructor(javassist.CtConstructor) SourceCodeUtils.box(rpc.turbo.util.SourceCodeUtils.box) Method(java.lang.reflect.Method) ClassPool(javassist.ClassPool) ClassPool(javassist.ClassPool) CtConstructor(javassist.CtConstructor) CtClass(javassist.CtClass) CtField(javassist.CtField) CtClass(javassist.CtClass) CtMethod(javassist.CtMethod)

Example 3 with MethodParam

use of rpc.turbo.param.MethodParam in project turbo-rpc by hank-whu.

the class KryoSerializer method readRequest.

public Request readRequest(ByteBuf byteBuf) throws IOException {
    int requestId = byteBuf.readInt();
    int serviceId = ByteBufUtils.readVarInt(byteBuf);
    Tracer tracer = tracerSerializer.read(byteBuf);
    MethodParam methodParam = null;
    if (byteBuf.readBoolean()) {
        Class<?> clazz = getClass(serviceId);
        methodParam = (MethodParam) kryoContext().readObject(byteBuf, clazz);
    }
    Request request = RecycleRequest.newInstance(requestId, serviceId, tracer, methodParam);
    return request;
}
Also used : MethodParam(rpc.turbo.param.MethodParam) Tracer(rpc.turbo.trace.Tracer) Request(rpc.turbo.protocol.Request) RecycleRequest(rpc.turbo.protocol.recycle.RecycleRequest)

Example 4 with MethodParam

use of rpc.turbo.param.MethodParam in project turbo-rpc by hank-whu.

the class NettyRestHandler method channelRead0.

@Override
protected void channelRead0(ChannelHandlerContext ctx, final FullHttpRequest httpRequest) throws Exception {
    boolean keepAlive = HttpUtil.isKeepAlive(httpRequest);
    String uri = httpRequest.uri();
    HttpMethod httpMethod = httpRequest.method();
    int index = uri.indexOf('&', invokerFactory.restPrefix.length());
    if (index < 0) {
        index = uri.length();
    }
    if (invokerFactory.restPrefix.length() >= index) {
        if (logger.isInfoEnabled()) {
            logger.info("not support this method " + toString(httpRequest));
        }
        doRequestFilter(httpRequest, null);
        ctx.write(new RestHttpResponse(null, httpRequest, NOT_FOUND, NOT_SUPPORT_THIS_METHOD, keepAlive), ctx.voidPromise());
        return;
    }
    String restPath = uri.substring(invokerFactory.restPrefix.length(), index);
    final Invoker<CompletableFuture<?>> invoker = invokerFactory.get(restPath);
    CompletableFuture<?> future = null;
    try {
        if (invoker == null) {
            if (logger.isInfoEnabled()) {
                logger.info("not support this method " + toString(httpRequest));
            }
            doRequestFilter(httpRequest, null);
            ctx.write(new RestHttpResponse(null, httpRequest, NOT_FOUND, NOT_SUPPORT_THIS_METHOD, keepAlive), ctx.voidPromise());
            return;
        }
        boolean allowHandle = doRequestFilter(httpRequest, invoker);
        if (!allowHandle) {
            ctx.write(new RestHttpResponse(invoker, httpRequest, SERVICE_UNAVAILABLE, RestServerFilter.SERVER_FILTER_DENY, keepAlive), ctx.voidPromise());
            return;
        }
        Object params = null;
        if (httpMethod == HttpMethod.GET) {
            params = HttpParamExtractor.extractFromQueryPath(invoker, uri, index);
        } else if (httpMethod == HttpMethod.POST) {
            params = HttpParamExtractor.extractFromBody(invoker, jsonMapper, httpRequest.content());
        } else {
            if (logger.isInfoEnabled()) {
                logger.info("only support get and post " + toString(httpRequest));
            }
            ctx.write(new RestHttpResponse(invoker, httpRequest, INTERNAL_SERVER_ERROR, ONLY_SUPPORT_GET_POST, keepAlive), ctx.voidPromise());
            return;
        }
        if (params == null) {
            future = invoker.invoke();
        } else if (params instanceof MethodParam) {
            future = invoker.invoke((MethodParam) params);
        } else if (params instanceof Object[]) {
            future = invoker.invoke((Object[]) params);
        } else {
            future = invoker.invoke((Object) params);
        }
    } catch (Throwable e) {
        if (logger.isWarnEnabled()) {
            logger.warn(uri + " error ", e);
        }
        ctx.write(new RestHttpResponse(invoker, httpRequest, INTERNAL_SERVER_ERROR, e, keepAlive), ctx.voidPromise());
        return;
    }
    if (future == null) {
        if (logger.isWarnEnabled()) {
            logger.warn("unknown error " + toString(httpRequest));
        }
        ctx.write(new RestHttpResponse(invoker, httpRequest, INTERNAL_SERVER_ERROR, UNKNOWN, keepAlive), ctx.voidPromise());
        return;
    }
    future.whenComplete((result, throwable) -> {
        if (result != null) {
            ctx.write(new RestHttpResponse(invoker, httpRequest, OK, result, keepAlive), ctx.voidPromise());
        } else if (throwable != null) {
            ctx.write(new RestHttpResponse(invoker, httpRequest, INTERNAL_SERVER_ERROR, throwable, keepAlive), ctx.voidPromise());
        } else {
            ctx.write(new RestHttpResponse(invoker, httpRequest, INTERNAL_SERVER_ERROR, UNKNOWN, keepAlive), ctx.voidPromise());
        }
    });
}
Also used : MethodParam(rpc.turbo.param.MethodParam) CompletableFuture(java.util.concurrent.CompletableFuture) RestHttpResponse(rpc.turbo.transport.server.rest.protocol.RestHttpResponse) HttpMethod(io.netty.handler.codec.http.HttpMethod)

Example 5 with MethodParam

use of rpc.turbo.param.MethodParam in project turbo-rpc by hank-whu.

the class ProtostuffSerializer method readRequest.

public Request readRequest(ByteBuf byteBuf) throws IOException {
    int requestId = byteBuf.readInt();
    int serviceId = ByteBufUtils.readVarInt(byteBuf);
    Tracer tracer = tracerSerializer.read(byteBuf);
    Schema<MethodParam> schema = schema(serviceId);
    MethodParam methodParam = null;
    if (EmptyMethodParam.class.equals(schema.typeClass())) {
        methodParam = EmptyMethodParam.empty();
    } else {
        ByteBufInput input = getOrUpdate(INPUT_ATTACHMENT_INDEX, INPUT_SUPPLIER);
        input.setByteBuf(byteBuf, true);
        methodParam = schema.newMessage();
        schema.mergeFrom(input, methodParam);
    }
    Request request = RecycleRequest.newInstance(requestId, serviceId, tracer, methodParam);
    return request;
}
Also used : EmptyMethodParam(rpc.turbo.param.EmptyMethodParam) MethodParam(rpc.turbo.param.MethodParam) Tracer(rpc.turbo.trace.Tracer) RecycleRequest(rpc.turbo.protocol.recycle.RecycleRequest) Request(rpc.turbo.protocol.Request)

Aggregations

MethodParam (rpc.turbo.param.MethodParam)5 Method (java.lang.reflect.Method)2 UUID (java.util.UUID)2 CompletableFuture (java.util.concurrent.CompletableFuture)2 Collectors (java.util.stream.Collectors)2 ClassPool (javassist.ClassPool)2 CtClass (javassist.CtClass)2 CtConstructor (javassist.CtConstructor)2 CtField (javassist.CtField)2 CtMethod (javassist.CtMethod)2 CtNewMethod (javassist.CtNewMethod)2 EmptyMethodParam (rpc.turbo.param.EmptyMethodParam)2 MethodParamClassFactory (rpc.turbo.param.MethodParamClassFactory)2 Request (rpc.turbo.protocol.Request)2 RecycleRequest (rpc.turbo.protocol.recycle.RecycleRequest)2 Tracer (rpc.turbo.trace.Tracer)2 HttpMethod (io.netty.handler.codec.http.HttpMethod)1 Closeable (java.io.Closeable)1 IOException (java.io.IOException)1 Field (java.lang.reflect.Field)1