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

net.dongliu.prettypb.rpc.server.RpcServiceRegistry Maven / Gradle / Ivy

There is a newer version: 0.3.5
Show newest version
/**
 *   Copyright 2010-2014 Peter Klauser
 *
 *   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 net.dongliu.prettypb.rpc.server;

import net.dongliu.prettypb.rpc.info.MethodInfo;
import net.dongliu.prettypb.rpc.info.ServiceInfo;
import net.dongliu.prettypb.runtime.include.ProtoService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Method;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
 * The RpcServiceRegistry holds a reference to each RPC service
 * implementation that can service calls. Optionally a message
 * ExtensionRegistry can be associated with the Service calls in
 * order for the RPC layer to transparently handle
 * protobuf messages with extensions.
 *
 * @author Peter Klauser
 */
public class RpcServiceRegistry {

    private static Logger logger = LoggerFactory.getLogger(RpcServiceRegistry.class);

    /**
     * service register without proto packageName
     * proto-rpc-pro has a issue do not consider the package of proto file. we add it here and
     * keep compatible with the origin proto-rpc-pro
     */
    private final Map simpleServiceMap = new HashMap<>();

    /**
     * service register with proto packageName
     */
    private final Map serviceMap = new HashMap<>();

    public RpcServiceRegistry() {
    }

    /**
     * Registers a Service implementation at an RPC server.
     *
     * @param impl
     */
    public void registerService(Object impl) {
        addService(impl, true);
    }

    /**
     * Return a map of service names to their descriptors.
     *
     * @return
     */
    public Map getServices() {
        return Collections.unmodifiableMap(serviceMap);
    }

    /**
     * Clears all registered services.
     */
    public void clear() {
        simpleServiceMap.clear();
        serviceMap.clear();
    }

    /**
     * Registers a Service implementation at an RPC server.
     *
     * @param allowTimeout whether to allow client timeouts to cause service cancellation.
     * @param impl
     */
    public void registerService(Object impl, boolean allowTimeout) {
        addService(impl, allowTimeout);
    }

    /**
     * Removes a Service and it's corresponding ExtensionRegistry if
     * one exists.
     *
     * @param impl
     */
    public void removeService(Object impl) {
        String serviceName = getServiceInfo(impl, true).getName();
        if (simpleServiceMap.remove(serviceName) != null) {
            logger.info("Removed " + serviceName);
        }
        if (serviceMap.remove(serviceName) != null) {
            logger.info("Removed " + serviceName);
        }
    }

    /**
     * service resolve without proto packageName
     * proto-rpc-pro has a issue do not consider the package of proto file. we add it here and
     * keep compatible with the origin proto-rpc-pro
     */
    public ServiceInfo simpleResolveService(String serviceName) {
        ServiceInfo s = simpleServiceMap.get(serviceName);
        if (s != null) {
            logger.debug("Resolved {}", serviceName);
        } else {
            logger.debug("Unable to resolve {}", serviceName);
        }
        return s;
    }

    /**
     * service resolve without proto packageName
     */
    public ServiceInfo resolveService(String packageName, String name) {
        String fullName;
        if (packageName == null || packageName.isEmpty()) {
            fullName = name;
        } else {
            fullName = packageName + "." + name;
        }
        return resolveService(fullName);
    }

    /**
     * service resolve without proto packageName
     */
    public ServiceInfo resolveService(String fullServiceName) {
        ServiceInfo s = serviceMap.get(fullServiceName);
        if (s != null) {
            logger.debug("Resolved {}", fullServiceName);
        } else {
            logger.debug("Unable to resolve {}", fullServiceName);
        }
        return s;
    }

    private String addService(Object impl, boolean allowTimeout) {
        ServiceInfo serviceInfo = getServiceInfo(impl, allowTimeout);
        String serviceName = serviceInfo.getName();
        String fullServiceName = serviceInfo.getFullName();
        if (serviceMap.containsKey(fullServiceName)) {
            throw new IllegalStateException("Duplicate serviceName: " + fullServiceName);
        }
        if (simpleServiceMap.containsKey(serviceName)) {
            logger.warn("duplicated service name in different package, " +
                    "may have issue if use old buggy proto-rpc-pro client, name:{}", serviceName);
        }
        simpleServiceMap.put(serviceName, serviceInfo);
        serviceMap.put(fullServiceName, serviceInfo);
        logger.info("Registered service:{}, async:{}, allowTimeout={}", fullServiceName,
                serviceInfo.isAsync(), allowTimeout);

        return serviceName;
    }

    private ServiceInfo getServiceInfo(Object impl, boolean allowTimeout) {
        Class[] interfaces = impl.getClass().getInterfaces();
        Class interfaceClass = null;
        ProtoService protoService = null;
        for (Class ic : interfaces) {
            protoService = ic.getAnnotation(ProtoService.class);
            if (protoService != null) {
                interfaceClass = ic;
                break;
            }
        }
        if (protoService == null) {
            throw new IllegalArgumentException("Not a valid proto service impl");
        }

        ServiceInfo serviceInfo = ServiceInfo.inspect(interfaceClass);
        serviceInfo.setImpl(impl);
        serviceInfo.setAllowTimeout(allowTimeout);

        // add impl method
        Map methodMap = serviceInfo.getMethodMap();
        for (MethodInfo methodInfo : methodMap.values()) {
            try {
                Method implMethod = impl.getClass().getMethod(methodInfo.getName(),
                        methodInfo.getRequestType());
                methodInfo.setImplMethod(implMethod);
            } catch (NoSuchMethodException e) {
                //should not happen
                throw new RuntimeException("method not found");
            }
        }
        return serviceInfo;
    }

    private String getFullName(String packageName, String name) {
        if (packageName == null || packageName.isEmpty()) {
            return name;
        } else {
            return packageName + "." + name;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy