All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.swingfrog.summer.server.RemoteProtobufDispatchMgr Maven / Gradle / Ivy

package com.swingfrog.summer.server;

import com.google.common.collect.Maps;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.Message;
import com.swingfrog.summer.annotation.Optional;
import com.swingfrog.summer.annotation.Remote;
import com.swingfrog.summer.ioc.ContainerMgr;
import com.swingfrog.summer.ioc.MethodParameterName;
import com.swingfrog.summer.protocol.protobuf.Protobuf;
import com.swingfrog.summer.protocol.protobuf.ReqProtobufMgr;
import com.swingfrog.summer.protocol.protobuf.ProtobufRequest;
import com.swingfrog.summer.server.async.AsyncResponse;
import com.swingfrog.summer.server.async.ProcessResult;
import com.swingfrog.summer.server.exception.CodeException;
import com.swingfrog.summer.server.exception.RemoteRuntimeException;
import com.swingfrog.summer.server.exception.SessionException;
import com.swingfrog.summer.struct.AutowireParam;
import com.swingfrog.summer.util.ProtobufUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.*;
import java.util.Iterator;
import java.util.Map;

public class RemoteProtobufDispatchMgr {

    private static final Logger log = LoggerFactory.getLogger(RemoteProtobufDispatchMgr.class);

    private final Map remoteMethodMap;


    private static class SingleCase {
        public static final RemoteProtobufDispatchMgr INSTANCE = new RemoteProtobufDispatchMgr();
    }

    private RemoteProtobufDispatchMgr() {
        remoteMethodMap = Maps.newHashMap();
    }

    public static RemoteProtobufDispatchMgr get() {
        return RemoteProtobufDispatchMgr.SingleCase.INSTANCE;
    }

    public void init() throws Exception {
        Iterator> ite = ContainerMgr.get().iteratorRemoteList();
        while (ite.hasNext()) {
            Class clazz = ite.next();
            log.info("server try register remote protobuf {}", clazz.getSimpleName());
            RemoteClass remoteClass = new RemoteClass(clazz);
            Method[] methods = clazz.getDeclaredMethods();
            MethodParameterName mpn = new MethodParameterName(clazz);
            for (Method method : methods) {
                if (method.getModifiers() != Modifier.PUBLIC || !ProtobufUtil.hasProtobufParam(method)) {
                    continue;
                }
                RemoteMethod remoteMethod = new RemoteMethod(remoteClass, method, mpn);
                int messageId = remoteMethod.getMessageId();
                if (remoteMethodMap.putIfAbsent(messageId, remoteMethod) == null) {
                    log.info("remote protobuf register {}.{} {}", clazz.getSimpleName(), method.getName(), ReqProtobufMgr.get().getProtoName(messageId));
                } else {
                    throw new RemoteRuntimeException("protobuf message repeat %s.%s messageId[%s] protoName[%s]",  clazz.getSimpleName(), method.getName(), messageId, ReqProtobufMgr.get().getProtoName(messageId));
                }
            }
        }
    }

    private Object invoke(ServerContext serverContext, ProtobufRequest req, Message reqMessage, AutowireParam autowireParam) throws Throwable {
        Map, Object> objForTypes = autowireParam.getTypes();
        Map objForNames = autowireParam.getNames();
        int messageId = req.getId();
        RemoteMethod remoteMethod = remoteMethodMap.get(messageId);
        if (remoteMethod == null) {
            throw new CodeException(SessionException.METHOD_NOT_EXIST);
        }
        RemoteClass remoteClass = remoteMethod.getRemoteClass();
        if (remoteClass.isFilter() && !remoteClass.getServerName().equals(serverContext.getConfig().getServerName())) {
            throw new CodeException(SessionException.REMOTE_WAS_PROTECTED);
        }

        int messageIndex = remoteMethod.getMessageIndex();
        Object remoteObj = ContainerMgr.get().getDeclaredComponent(remoteClass.getClazz());
        Method remoteMod = remoteMethod.getMethod();
        String[] params = remoteMethod.getParams();
        Parameter[] parameters = remoteMethod.getParameters();
        boolean auto = ContainerMgr.get().isAutowiredParameter(remoteClass.getClazz());
        Object[] obj = new Object[params.length];
        try {
            for (int i = 0; i < parameters.length; i++) {
                String param = params[i];
                Parameter parameter = parameters[i];
                Type type = parameter.getParameterizedType();
                if (i == messageIndex) {
                    obj[i] = reqMessage;
                } else {
                    if (auto) {
                        Class typeClazz = parameter.getType();
                        if (objForTypes != null && objForTypes.containsKey(typeClazz)) {
                            obj[i] = objForTypes.get(typeClazz);
                        } else if (objForNames != null && objForNames.containsKey(param)) {
                            obj[i] = objForNames.get(param);
                        } else {
                            obj[i] = ContainerMgr.get().getComponent(typeClazz);
                            if (obj[i] == null) {
                                try {
                                    obj[i] = ((Class) type).newInstance();
                                } catch (Exception e) {
                                    log.error(e.getMessage(), e);
                                }
                            }
                        }
                    }
                }
                if (obj[i] == null) {
                    if (!parameter.isAnnotationPresent(Optional.class)) {
                        throw new CodeException(SessionException.PARAMETER_ERROR);
                    }
                }
            }
        } catch (Exception e) {
            throw new CodeException(SessionException.PARAMETER_ERROR);
        }
        try {
            return remoteMod.invoke(remoteObj, obj);
        } catch (InvocationTargetException e) {
            throw e.getTargetException();
        }
    }

    public ProcessResult process(ServerContext serverContext, ProtobufRequest req, Message reqMessage, SessionContext sctx,
                                                   AutowireParam autowireParam) throws Throwable {
        Map, Object> objForTypes = autowireParam.getTypes();
        objForTypes.putIfAbsent(SessionContext.class, sctx);
        objForTypes.putIfAbsent(ProtobufRequest.class, req);
        Object result = invoke(serverContext, req, reqMessage, autowireParam);
        if (result instanceof AsyncResponse) {
            return new ProcessResult<>(true, null);
        }
        if (result instanceof Message) {
            return new ProcessResult<>(false, (Message) result);
        }
        return null;
    }

    public Message parse(Protobuf data) throws InvalidProtocolBufferException {
        int messageId = data.getId();
        Message messageTemplate = ReqProtobufMgr.get().getMessageTemplate(messageId);
        if (messageTemplate == null) {
            throw new CodeException(SessionException.PROTOBUF_NOT_EXIST);
        }
        return ProtobufUtil.parseMessage(messageTemplate, data.getBytes());
    }

    private static class RemoteMethod {
        private final RemoteClass remoteClass;
        private final Method method;
        private final String[] params;
        private final Parameter[] parameters;
        private int messageIndex = -1;
        private final int messageId;
        public RemoteMethod(RemoteClass remoteClass, Method method, MethodParameterName mpn) throws Exception {
            this.remoteClass = remoteClass;
            this.method = method;
            params = mpn.getParameterNameByMethod(method);
            parameters = method.getParameters();
            Message messageTemplate = null;
            for (int i = 0; i < parameters.length; i++) {
                Class typeClazz = parameters[i].getType();
                if (Message.class.isAssignableFrom(typeClazz)) {
                    messageTemplate = ProtobufUtil.getDefaultInstance(typeClazz);
                    messageIndex = i;
                    break;
                }
            }
            if (messageTemplate == null)
                throw new RuntimeException("not found protobuf message in remote method");
            messageId = ProtobufUtil.getMessageId(messageTemplate);
            ReqProtobufMgr.get().registerMessage(messageId, messageTemplate);
        }
        public RemoteClass getRemoteClass() {
            return remoteClass;
        }
        public Method getMethod() {
            return method;
        }
        public String[] getParams() {
            return params;
        }
        public Parameter[] getParameters() {
            return parameters;
        }
        public int getMessageIndex() {
            return messageIndex;
        }
        public int getMessageId() {
            return messageId;
        }
    }

    private static class RemoteClass {
        private final boolean filter;
        private final String serverName;
        private final Class clazz;
        public RemoteClass(Class clazz) {
            this.clazz = clazz;
            filter = clazz.getAnnotation(Remote.class).filter();
            serverName = clazz.getAnnotation(Remote.class).serverName();
        }
        public boolean isFilter() {
            return filter;
        }
        public String getServerName() {
            return serverName;
        }
        public Class getClazz() {
            return clazz;
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy