net.dongliu.prettypb.rpc.server.RpcServiceRegistry Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of prettypb-rpc Show documentation
Show all versions of prettypb-rpc Show documentation
proto rpc libs, compatible with proto-rpc-pro
/**
* 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.common.MethodInfo;
import net.dongliu.prettypb.rpc.common.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;
}
}
}