├── trpc-registry ├── trpc-registry-consul │ └── build.gradle ├── trpc-registry-redis │ └── build.gradle ├── trpc-registry-etcd │ └── build.gradle └── trpc-registry-zookeeper │ ├── src │ ├── test │ │ ├── resources │ │ │ └── log4j.properties │ │ └── java │ │ │ └── com │ │ │ └── github │ │ │ └── sofn │ │ │ └── trpc │ │ │ └── registry │ │ │ └── zk │ │ │ └── test │ │ │ ├── ThriftServerPublisherTest.java │ │ │ ├── ZkMonitorTest.java │ │ │ └── ZkRegistryTest.java │ └── main │ │ └── java │ │ └── com │ │ └── github │ │ └── sofn │ │ └── trpc │ │ └── registry │ │ └── zk │ │ ├── ZkConstant.java │ │ ├── ZkMonitor.java │ │ └── ZkRegistry.java │ └── build.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── trpc-core ├── src │ ├── test │ │ ├── resources │ │ │ ├── thrift │ │ │ │ ├── gen.sh │ │ │ │ └── hello.thrift │ │ │ └── log4j.properties │ │ └── java │ │ │ └── com │ │ │ └── github │ │ │ └── sofn │ │ │ └── trpc │ │ │ ├── core │ │ │ └── test │ │ │ │ ├── utils │ │ │ │ ├── NetUtilsTest.java │ │ │ │ └── ClassNameUtilsTest.java │ │ │ │ ├── config │ │ │ │ ├── ThriftServerInfoTest.java │ │ │ │ └── ServiceArgsTest.java │ │ │ │ └── model │ │ │ │ └── RegistryConfigTest.java │ │ │ ├── direct │ │ │ ├── HelloServer.java │ │ │ ├── DemoServer.java │ │ │ └── DemoClient.java │ │ │ ├── utils │ │ │ └── NumUtil.java │ │ │ └── demo │ │ │ └── Hello.java │ └── main │ │ └── java │ │ └── com │ │ └── github │ │ └── sofn │ │ └── trpc │ │ └── core │ │ ├── exception │ │ ├── TRpcException.java │ │ └── TRpcRegistryException.java │ │ ├── utils │ │ ├── ClassNameUtils.java │ │ ├── Threads.java │ │ ├── JsonUtils.java │ │ ├── ValidationUtils.java │ │ └── NetUtils.java │ │ ├── IRegistry.java │ │ ├── AbstractMonitor.java │ │ ├── monitor │ │ ├── RegistryConfigListener.java │ │ └── StaticMonitor.java │ │ └── config │ │ ├── AbstractConfig.java │ │ ├── ServiceConfig.java │ │ ├── ServiceArgs.java │ │ ├── ThriftServerInfo.java │ │ └── RegistryConfig.java └── build.gradle ├── trpc-server ├── build.gradle └── src │ ├── main │ └── java │ │ └── com │ │ └── github │ │ └── sofn │ │ └── trpc │ │ └── server │ │ ├── netty │ │ ├── ThriftFramedEncoder.java │ │ ├── ThriftFramedDecoder.java │ │ ├── TNettyTransport.java │ │ ├── NettyServerArgs.java │ │ ├── ThriftHandler.java │ │ └── TNettyServer.java │ │ ├── TrpcRegistryEventHandler.java │ │ ├── config │ │ └── ServerArgs.java │ │ └── ThriftServerPublisher.java │ └── test │ └── java │ └── com │ └── github │ └── sofn │ └── trpc │ └── server │ └── test │ └── config │ ├── NettyClientTest.java │ ├── NettyServerTest.java │ └── ServerArgsTest.java ├── trpc-test ├── build.gradle └── src │ └── test │ └── java │ └── com │ └── github │ └── sofn │ └── trpc │ └── test │ ├── monitor │ ├── StaticMonitorTest.java │ └── ServiceFactoryTest.java │ └── TrpcClientProxyTest.java ├── trpc-client ├── build.gradle └── src │ ├── main │ └── java │ │ └── com │ │ └── github │ │ └── sofn │ │ └── trpc │ │ └── client │ │ ├── config │ │ ├── ServiceKey.java │ │ ├── TrpcServiceNode.java │ │ └── ClientArgs.java │ │ ├── pool │ │ ├── TrpcClientPoolProvider.java │ │ └── impl │ │ │ ├── TrpcClientFactory.java │ │ │ └── TrpcClientPoolImpl.java │ │ ├── loadbalance │ │ ├── AbstractLoadBalance.java │ │ ├── RandomLoadBalance.java │ │ └── RoundRobinLoadBalance.java │ │ ├── client │ │ ├── AbstractTrpcClient.java │ │ ├── BlockTrpcClient.java │ │ └── AsyncTrpcClient.java │ │ ├── factory │ │ └── ClientCluster.java │ │ ├── monitor │ │ └── ServiceFactory.java │ │ └── TrpcClientProxy.java │ └── test │ └── java │ └── com │ └── github │ └── sofn │ └── trpc │ └── client │ └── test │ └── pool │ └── TrpcClientPoolTest.java ├── .gitignore ├── README.md ├── gradle.properties ├── .travis.yml ├── settings.gradle ├── gradlew.bat ├── gradlew └── LICENSE /trpc-registry/trpc-registry-consul/build.gradle: -------------------------------------------------------------------------------- 1 | dependencies { 2 | compile project(":trpc-core") 3 | } -------------------------------------------------------------------------------- /trpc-registry/trpc-registry-redis/build.gradle: -------------------------------------------------------------------------------- 1 | dependencies { 2 | compile project(":trpc-core") 3 | } -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sofn/trpc/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /trpc-core/src/test/resources/thrift/gen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | SCRIPT_DIR=`dirname $0` 3 | thrift --gen java -out ${SCRIPT_DIR}/../../java hello.thrift -------------------------------------------------------------------------------- /trpc-core/src/test/resources/thrift/hello.thrift: -------------------------------------------------------------------------------- 1 | namespace java com.github.sofn.trpc.demo 2 | 3 | key Hello { 4 | string hi(1:string name); 5 | } -------------------------------------------------------------------------------- /trpc-registry/trpc-registry-etcd/build.gradle: -------------------------------------------------------------------------------- 1 | dependencies { 2 | compile project(":trpc-core") 3 | compile group: 'redis.clients', name: 'jedis', version: "${jedisVersion}" 4 | } -------------------------------------------------------------------------------- /trpc-server/build.gradle: -------------------------------------------------------------------------------- 1 | dependencies { 2 | compile project(":trpc-core") 3 | testCompile project(':trpc-core').sourceSets.test.output 4 | compile group: 'io.netty', name: 'netty-all', version: "${nettyVersion}" 5 | } 6 | -------------------------------------------------------------------------------- /trpc-test/build.gradle: -------------------------------------------------------------------------------- 1 | dependencies { 2 | testCompile project(":trpc-client") 3 | testCompile project(":trpc-server") 4 | testCompile project(":trpc-registry:trpc-registry-zookeeper") 5 | testCompile project(':trpc-core').sourceSets.test.output 6 | } 7 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sat Sep 17 23:24:17 CST 2016 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.0-bin.zip 7 | -------------------------------------------------------------------------------- /trpc-client/build.gradle: -------------------------------------------------------------------------------- 1 | dependencies { 2 | compile project(":trpc-core") 3 | testCompile project(':trpc-core').sourceSets.test.output 4 | compile group: 'org.apache.commons', name: 'commons-pool2', version: "${commonsPoolVersion}" 5 | compile group: 'org.javassist', name: 'javassist', version: "${javassistVersion}" 6 | } -------------------------------------------------------------------------------- /trpc-core/src/test/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | ### 设置### 2 | log4j.rootLogger=debug,stdout 3 | 4 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 5 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 6 | log4j.appender.stdout.layout.ConversionPattern=[QC] %p [%t] %C.%M(%L) | %m%n 7 | 8 | log4j.logger.org=debug 9 | log4j.logger.com=debug -------------------------------------------------------------------------------- /trpc-registry/trpc-registry-zookeeper/src/test/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | ### 设置### 2 | log4j.rootLogger=debug,stdout 3 | 4 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 5 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 6 | log4j.appender.stdout.layout.ConversionPattern=[QC] %p [%t] %C.%M(%L) | %m%n 7 | 8 | log4j.logger.org=debug 9 | log4j.logger.com=debug -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | .classpath 3 | .project 4 | .settings/ 5 | classes 6 | lib/ 7 | logs/ 8 | target/ 9 | .DS_Store 10 | .metadata 11 | *.log 12 | *.log.* 13 | .idea/ 14 | .clover/ 15 | *.iml 16 | .vagrant/ 17 | .#* 18 | .gitmessage.txt 19 | matrix.ipr 20 | matrix.iws 21 | .lein* 22 | .nrepl* 23 | out/ 24 | *.class 25 | build/ 26 | classes/* 27 | .gradle/ 28 | include/ 29 | *.o 30 | *.out 31 | rebel.xml -------------------------------------------------------------------------------- /trpc-registry/trpc-registry-zookeeper/build.gradle: -------------------------------------------------------------------------------- 1 | dependencies { 2 | compile project(":trpc-core") 3 | compile project(":trpc-server") 4 | testCompile project(':trpc-core').sourceSets.test.output 5 | compile group: 'org.apache.curator', name: 'curator-framework', version: "${curatorVersion}" 6 | compile group: 'org.apache.curator', name: 'curator-recipes', version: "${curatorVersion}" 7 | } -------------------------------------------------------------------------------- /trpc-client/src/main/java/com/github/sofn/trpc/client/config/ServiceKey.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.client.config; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | 6 | /** 7 | * @author sofn 8 | * @version 1.0 Created at: 2016-09-26 13:16 9 | */ 10 | @Data 11 | @AllArgsConstructor 12 | public class ServiceKey { 13 | private String remoteKey; 14 | private String service; 15 | } 16 | -------------------------------------------------------------------------------- /trpc-core/src/main/java/com/github/sofn/trpc/core/exception/TRpcException.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.core.exception; 2 | 3 | /** 4 | * @author sofn 5 | * @version 1.0 Created at: 2016-09-19 16:58 6 | */ 7 | public class TRpcException extends RuntimeException { 8 | 9 | public TRpcException(Exception e) { 10 | super(e); 11 | } 12 | 13 | public TRpcException(String s, Exception e) { 14 | super(s, e); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /trpc-core/src/test/java/com/github/sofn/trpc/core/test/utils/NetUtilsTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.core.test.utils; 2 | 3 | import com.github.sofn.trpc.core.utils.NetUtils; 4 | import org.junit.Test; 5 | 6 | /** 7 | * Authors: sofn 8 | * Version: 1.0 Created at 2016-09-19 00:13. 9 | */ 10 | public class NetUtilsTest { 11 | @Test 12 | public void testGetLocalHost() { 13 | System.out.println(NetUtils.getLocalAddress().getHostName()); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /trpc-server/src/main/java/com/github/sofn/trpc/server/netty/ThriftFramedEncoder.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.server.netty; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.handler.codec.MessageToByteEncoder; 6 | 7 | public class ThriftFramedEncoder extends MessageToByteEncoder { 8 | 9 | @Override 10 | protected void encode(ChannelHandlerContext ctx, ByteBuf msg, ByteBuf out) throws Exception { 11 | out.writeInt(msg.readableBytes()); 12 | out.writeBytes(msg); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #基于Thrift的RPC框架 2 | 3 | [![Build Status](https://api.travis-ci.org/sofn/trpc.svg)](https://travis-ci.org/sofn/trpc) 4 | [![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html) 5 | 6 | ####简介 7 | --------- 8 | Thrift是Facebook开源的优秀RPC框架,支持多语言,并且有很好的压缩比和压缩效率,是跨系统调用的利器。但是Thrift只提供了点对点的连接,在构建大规模微服务的时候,手动维护机器列表显然不可能。 9 | 10 | ######trpc扩展的Thrift功能: 11 | * 服务端Netty发布支持 12 | * 客户端连接池支持 13 | * 异步客户端支持 14 | * 重试机制 15 | 16 | ######trpc在Thrift的基础上提供的功能: 17 | * 服务发现 18 | * 服务治理 19 | * 负载均衡 20 | * 断路保护 21 | -------------------------------------------------------------------------------- /trpc-core/src/main/java/com/github/sofn/trpc/core/exception/TRpcRegistryException.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.core.exception; 2 | 3 | /** 4 | * @author sofn 5 | * @version 1.0 Created at: 2016-09-19 16:58 6 | */ 7 | public class TRpcRegistryException extends RuntimeException { 8 | 9 | public TRpcRegistryException(Exception e) { 10 | super(e); 11 | } 12 | 13 | public TRpcRegistryException(String s, Exception e) { 14 | super(s, e); 15 | } 16 | 17 | public TRpcRegistryException(String s) { 18 | super(s); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /trpc-registry/trpc-registry-zookeeper/src/main/java/com/github/sofn/trpc/registry/zk/ZkConstant.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.registry.zk; 2 | 3 | import java.util.concurrent.ExecutorService; 4 | import java.util.concurrent.Executors; 5 | 6 | /** 7 | * Authors: sofn 8 | * Version: 1.0 Created at 2016-09-27 21:43. 9 | */ 10 | public class ZkConstant { 11 | //执行节点变化listener的线程池 12 | static final ExecutorService zkPool = Executors.newFixedThreadPool(2); 13 | static final String NAMESPACE = "trpc"; 14 | static final String SERVICES_DIR = "/servers/"; 15 | } 16 | -------------------------------------------------------------------------------- /trpc-core/src/main/java/com/github/sofn/trpc/core/utils/ClassNameUtils.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.core.utils; 2 | 3 | /** 4 | * @author sofn 5 | * @version 1.0 Created at: 2016-09-23 16:06 6 | */ 7 | public class ClassNameUtils { 8 | 9 | public static String getClassName(Class clazz) { 10 | return clazz.getName(); 11 | } 12 | 13 | public static String getOuterClassName(Class clazz) { 14 | int spliterIndex = clazz.getName().lastIndexOf("$"); 15 | return spliterIndex > 0 ? clazz.getName().substring(0, spliterIndex) : clazz.getName(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx256m -XX:MaxMetaspaceSize=512m 2 | 3 | guavaVersion=19.0 4 | commonsLangVersion=3.4 5 | commonsCollectionsVersion=3.2.2 6 | commonsPoolVersion=2.4.2 7 | thriftVersion=0.9.3 8 | lombokVersion=1.16.10 9 | slf4jVersion=1.7.21 10 | log4jVersion=2.6.2 11 | javassistVersion=3.20.0-GA 12 | hibernateValidatorVersion=5.2.4.Final 13 | validationApiVersion=1.1.0.Final 14 | elApiVersion=3.0.0 15 | jacksonVersion=2.8.3 16 | nettyVersion=4.1.6.Final 17 | 18 | curatorVersion=2.11.0 19 | jedisVersion=2.9.0 20 | 21 | junitVersion=4.12 22 | assertjVersion=3.2.0 23 | mockitoVersion=1.10.19 -------------------------------------------------------------------------------- /trpc-core/src/main/java/com/github/sofn/trpc/core/IRegistry.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.core; 2 | 3 | import com.github.sofn.trpc.core.config.RegistryConfig; 4 | import com.github.sofn.trpc.core.config.ThriftServerInfo; 5 | 6 | /** 7 | * Authors: sofn 8 | * Version: 1.0 Created at 2016-09-17 23:56. 9 | */ 10 | public interface IRegistry { 11 | 12 | /** 13 | * 注册 14 | */ 15 | void registry(RegistryConfig registryConfig); 16 | 17 | void modify(RegistryConfig registryConfig); 18 | 19 | /** 20 | * 取消注册 21 | */ 22 | boolean unRegistry(String appKey, ThriftServerInfo serverInfo); 23 | } 24 | -------------------------------------------------------------------------------- /trpc-core/src/main/java/com/github/sofn/trpc/core/AbstractMonitor.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.core; 2 | 3 | import com.github.sofn.trpc.core.config.RegistryConfig; 4 | import com.github.sofn.trpc.core.monitor.RegistryConfigListener; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * Authors: sofn 10 | * Version: 1.0 Created at 2016-09-20 22:40. 11 | */ 12 | public abstract class AbstractMonitor { 13 | 14 | /** 15 | * 返回remoteKey下所有节点数据,并监控变化 16 | * 17 | * @param monitor 消息listener 18 | * @return 返回现在的数据 19 | */ 20 | public abstract List monitorRemoteKey(RegistryConfigListener monitor); 21 | 22 | } 23 | -------------------------------------------------------------------------------- /trpc-core/src/test/java/com/github/sofn/trpc/direct/HelloServer.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.direct; 2 | 3 | import com.github.sofn.trpc.demo.Hello; 4 | import org.apache.thrift.TException; 5 | 6 | import java.util.concurrent.TimeUnit; 7 | 8 | /** 9 | * @author sofn 10 | * @version 1.0 Created at: 2016-09-23 19:11 11 | */ 12 | public class HelloServer implements Hello.Iface { 13 | 14 | public String hi(String name) throws TException { 15 | try { 16 | TimeUnit.MILLISECONDS.sleep(10); 17 | } catch (InterruptedException e) { 18 | e.printStackTrace(); 19 | } 20 | return "hello " + name; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | jdk: 3 | - oraclejdk8 4 | before_install: 5 | # Add repository key 6 | - "curl -s http://archive.cloudera.com/cdh4/ubuntu/precise/amd64/cdh/archive.key | sudo apt-key add -" 7 | - "wget http://archive.cloudera.com/cdh4/one-click-install/precise/amd64/cdh4-repository_1.0_all.deb" 8 | # Add Cloudera repository 9 | - "sudo dpkg -i cdh4-repository_1.0_all.deb" 10 | - "sudo apt-get update -qq" 11 | # Install ZooKeeper 12 | - "sudo apt-get install -y zookeeper-server" 13 | before_script: 14 | - "sudo service zookeeper-server init" 15 | - "sudo service zookeeper-server start" 16 | after_script: 17 | - "sudo service zookeeper-server stop" -------------------------------------------------------------------------------- /trpc-core/src/test/java/com/github/sofn/trpc/utils/NumUtil.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.utils; 2 | 3 | import java.util.concurrent.atomic.AtomicInteger; 4 | import java.util.concurrent.atomic.AtomicLong; 5 | 6 | /** 7 | * Authors: sofn 8 | * Version: 1.0 Created at 2016-10-09 23:40. 9 | */ 10 | public class NumUtil { 11 | private static final AtomicLong NUM = new AtomicLong(); 12 | private static final AtomicInteger PORT = new AtomicInteger(10000); 13 | 14 | public static long nextNum() { 15 | return NUM.incrementAndGet(); 16 | } 17 | 18 | public static int nextPort() { 19 | return PORT.incrementAndGet(); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'trpc' 2 | 3 | include 'trpc-core' 4 | include 'trpc-server' 5 | include 'trpc-client' 6 | include 'trpc-test' 7 | include 'trpc-registry:trpc-registry-zookeeper' 8 | findProject(':trpc-registry:trpc-registry-zookeeper')?.name = 'trpc-registry-zookeeper' 9 | include 'trpc-registry:trpc-registry-etcd' 10 | findProject(':trpc-registry:trpc-registry-etcd')?.name = 'trpc-registry-etcd' 11 | include 'trpc-registry:trpc-registry-redis' 12 | findProject(':trpc-registry:trpc-registry-redis')?.name = 'trpc-registry-redis' 13 | include 'trpc-registry:trpc-registry-consul' 14 | findProject(':trpc-registry:trpc-registry-consul')?.name = 'trpc-registry-consul' 15 | 16 | -------------------------------------------------------------------------------- /trpc-core/src/main/java/com/github/sofn/trpc/core/monitor/RegistryConfigListener.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.core.monitor; 2 | 3 | import com.github.sofn.trpc.core.config.RegistryConfig; 4 | import com.github.sofn.trpc.core.config.ThriftServerInfo; 5 | import lombok.AllArgsConstructor; 6 | import lombok.Getter; 7 | 8 | /** 9 | * Authors: sofn 10 | * Version: 1.0 Created at 2016-09-27 21:50. 11 | */ 12 | @Getter 13 | @AllArgsConstructor 14 | public abstract class RegistryConfigListener { 15 | private String remoteKey; 16 | 17 | public abstract void addServer(RegistryConfig config); 18 | 19 | public abstract void removeServer(ThriftServerInfo serverInfo); 20 | 21 | public abstract void updateServer(RegistryConfig config); 22 | } 23 | -------------------------------------------------------------------------------- /trpc-core/src/test/java/com/github/sofn/trpc/core/test/config/ThriftServerInfoTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.core.test.config; 2 | 3 | import com.github.sofn.trpc.core.config.ThriftServerInfo; 4 | import org.junit.Test; 5 | 6 | import static org.assertj.core.api.Assertions.assertThat; 7 | 8 | /** 9 | * Authors: sofn 10 | * Version: 1.0 Created at 2016-09-27 23:59. 11 | */ 12 | public class ThriftServerInfoTest { 13 | 14 | @Test 15 | public void test() { 16 | ThriftServerInfo info = new ThriftServerInfo("127.0.0.1", 8888); 17 | assertThat(info.toString()).isEqualTo("127.0.0.1:8888"); 18 | ThriftServerInfo info2 = ThriftServerInfo.parse(info.toString()); 19 | assertThat(info2).isNotNull(); 20 | assertThat(info2.getIp()).isEqualTo("127.0.0.1"); 21 | assertThat(info2.getPort()).isEqualTo(8888); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /trpc-core/src/test/java/com/github/sofn/trpc/core/test/utils/ClassNameUtilsTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.core.test.utils; 2 | 3 | import com.github.sofn.trpc.core.utils.ClassNameUtils; 4 | import com.github.sofn.trpc.demo.Hello; 5 | import org.junit.Test; 6 | 7 | import static org.assertj.core.api.Assertions.assertThat; 8 | 9 | /** 10 | * @author sofn 11 | * @version 1.0 Created at: 2016-09-23 16:08 12 | */ 13 | public class ClassNameUtilsTest { 14 | 15 | @Test 16 | public void testClassName() { 17 | assertThat(ClassNameUtils.getClassName(Hello.class)).isEqualTo("com.github.sofn.trpc.demo.Hello"); 18 | assertThat(ClassNameUtils.getOuterClassName(Hello.class)).isEqualTo("com.github.sofn.trpc.demo.Hello"); 19 | assertThat(ClassNameUtils.getOuterClassName(Hello.Client.class)).isEqualTo("com.github.sofn.trpc.demo.Hello"); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /trpc-client/src/main/java/com/github/sofn/trpc/client/pool/TrpcClientPoolProvider.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.client.pool; 2 | 3 | import com.github.sofn.trpc.client.client.AbstractTrpcClient; 4 | import com.github.sofn.trpc.core.config.ThriftServerInfo; 5 | 6 | /** 7 | * Authors: sofn 8 | * Version: 1.0 Created at 2016-09-19 22:59. 9 | */ 10 | public interface TrpcClientPoolProvider { 11 | /** 12 | *

13 | * getConnection. 14 | *

15 | */ 16 | T getConnection(ThriftServerInfo thriftServerInfo); 17 | 18 | /** 19 | *

20 | * returnConnection. 21 | *

22 | */ 23 | void returnConnection(ThriftServerInfo thriftServerInfo, T transport); 24 | 25 | /** 26 | *

27 | * returnBrokenConnection. 28 | *

29 | */ 30 | void returnBrokenConnection(ThriftServerInfo thriftServerInfo, T transport); 31 | 32 | } 33 | -------------------------------------------------------------------------------- /trpc-client/src/main/java/com/github/sofn/trpc/client/loadbalance/AbstractLoadBalance.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.client.loadbalance; 2 | 3 | import com.github.sofn.trpc.client.config.ClientArgs; 4 | import com.github.sofn.trpc.client.config.ServiceKey; 5 | import com.github.sofn.trpc.client.config.TrpcServiceNode; 6 | import com.github.sofn.trpc.client.monitor.ServiceFactory; 7 | import com.google.common.collect.ImmutableList; 8 | 9 | import java.util.List; 10 | 11 | /** 12 | * @author sofn 13 | * @version 1.0 Created at: 2016-10-02 00:07 14 | */ 15 | public abstract class AbstractLoadBalance { 16 | 17 | /** 18 | * 从集群获取一个节点信息用于访问 19 | */ 20 | public abstract TrpcServiceNode getNode(ServiceKey key, ClientArgs args); 21 | 22 | /** 23 | * 有序集合 24 | */ 25 | protected List getAllNodes(ServiceKey key, ClientArgs args) { 26 | return ImmutableList.copyOf(ServiceFactory.getServiceKeys(key, args.getMonitors())); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /trpc-server/src/test/java/com/github/sofn/trpc/server/test/config/NettyClientTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.server.test.config; 2 | 3 | import com.github.sofn.trpc.direct.DemoClient; 4 | import com.github.sofn.trpc.utils.NumUtil; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.junit.Before; 7 | import org.junit.Test; 8 | 9 | import java.util.concurrent.TimeUnit; 10 | 11 | /** 12 | * Authors: sofn 13 | * Version: 1.0 Created at 2016-10-26 22:17. 14 | */ 15 | @Slf4j 16 | public class NettyClientTest { 17 | private DemoClient client = new DemoClient(); 18 | 19 | @Before 20 | public void init() throws InterruptedException { 21 | int port = NumUtil.nextPort(); 22 | this.client.setPort(port); 23 | new NettyServerTest().startDaemon(port); 24 | TimeUnit.SECONDS.sleep(1); 25 | } 26 | 27 | @Test 28 | public void nioCall() { 29 | this.client.nioCall(); 30 | } 31 | 32 | @Test 33 | public void bioCall() { 34 | this.client.bioCall(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /trpc-server/src/main/java/com/github/sofn/trpc/server/netty/ThriftFramedDecoder.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.server.netty; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.handler.codec.ByteToMessageDecoder; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * 因为Thrift固定前4位为Frame长度,更简洁直接的写法代替 LengthFieldBasedFrameDecoder 11 | */ 12 | public class ThriftFramedDecoder extends ByteToMessageDecoder { 13 | 14 | private static final int FRAME_LENGTH_FIELD_LENGTH = 4; 15 | 16 | @Override 17 | protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { 18 | if (in.readableBytes() < FRAME_LENGTH_FIELD_LENGTH) { 19 | return; 20 | } 21 | 22 | in.markReaderIndex(); 23 | int frameLength = in.readInt(); 24 | 25 | if (in.readableBytes() < frameLength) { 26 | in.resetReaderIndex(); 27 | return; 28 | } 29 | 30 | ByteBuf frame = in.readSlice(frameLength).retain(); 31 | out.add(frame); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /trpc-client/src/main/java/com/github/sofn/trpc/client/client/AbstractTrpcClient.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.client.client; 2 | 3 | import com.github.sofn.trpc.core.config.ThriftServerInfo; 4 | 5 | import java.util.Map; 6 | import java.util.concurrent.ConcurrentHashMap; 7 | 8 | /** 9 | * @author sofn 10 | * @version 1.0 Created at: 2016-09-23 14:13 11 | */ 12 | public abstract class AbstractTrpcClient { 13 | protected Map clients = new ConcurrentHashMap<>(); 14 | protected ThriftServerInfo serverInfo; 15 | 16 | public AbstractTrpcClient(ThriftServerInfo serverInfo) { 17 | this.serverInfo = serverInfo; 18 | } 19 | 20 | /** 21 | * 建立socket连接 22 | */ 23 | public abstract void open(); 24 | 25 | /** 26 | * @return 返回是否连接是否正常 27 | */ 28 | public abstract boolean isOpen(); 29 | 30 | /** 31 | * 销毁连接 32 | */ 33 | public abstract void close(); 34 | 35 | /** 36 | * 获取client 37 | * 38 | * @param clazz client类 39 | * @return client 40 | */ 41 | public abstract C getClient(Class clazz); 42 | } 43 | -------------------------------------------------------------------------------- /trpc-core/src/main/java/com/github/sofn/trpc/core/config/AbstractConfig.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.core.config; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | import java.util.Map; 7 | import java.util.concurrent.ConcurrentHashMap; 8 | import java.util.concurrent.atomic.AtomicLong; 9 | 10 | /** 11 | * Authors: sofn 12 | * Version: 1.0 Created at 2016-09-19 22:13. 13 | */ 14 | @Data 15 | public abstract class AbstractConfig implements Serializable { 16 | private static final long serialVersionUID = 4267533505537413570L; 17 | private static final Map counter = new ConcurrentHashMap<>(); 18 | 19 | protected final String configKey; 20 | protected long id = -1; 21 | 22 | protected AbstractConfig(String configKey) { 23 | this.configKey = configKey; 24 | } 25 | 26 | private static long nextId(String key) { 27 | return counter.computeIfAbsent(key, s -> new AtomicLong()).getAndIncrement(); 28 | } 29 | 30 | protected void fillId() { 31 | if (this.id < 0) { 32 | this.id = nextId(configKey); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /trpc-client/src/main/java/com/github/sofn/trpc/client/factory/ClientCluster.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.client.factory; 2 | 3 | import com.github.sofn.trpc.client.client.AbstractTrpcClient; 4 | import com.github.sofn.trpc.client.config.ClientArgs; 5 | import com.github.sofn.trpc.client.config.ServiceKey; 6 | import com.github.sofn.trpc.client.config.TrpcServiceNode; 7 | import com.github.sofn.trpc.core.config.ThriftServerInfo; 8 | import org.apache.commons.lang3.tuple.Pair; 9 | 10 | /** 11 | * @author sofn 12 | * @version 1.0 Created at: 2016-09-28 17:11 13 | */ 14 | public class ClientCluster { 15 | 16 | public static Pair getBlockClient(ClientArgs args) { 17 | //从负载均衡器里获取一个节点 18 | ServiceKey serviceKey = new ServiceKey(args.getRemoteAppKey(), args.getServiceInterface()); 19 | TrpcServiceNode node = args.getLoadBalance().getNode(serviceKey, args); 20 | ThriftServerInfo serverInfo = node.toThriftServerInfo(); 21 | AbstractTrpcClient trpcClient = args.getPoolProvider().getConnection(serverInfo); 22 | return Pair.of(serverInfo, trpcClient); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /trpc-core/src/main/java/com/github/sofn/trpc/core/config/ServiceConfig.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.core.config; 2 | 3 | import lombok.Getter; 4 | import org.hibernate.validator.constraints.NotBlank; 5 | 6 | import javax.validation.constraints.Max; 7 | import javax.validation.constraints.Min; 8 | import java.util.concurrent.TimeUnit; 9 | 10 | /** 11 | * Authors: sofn 12 | * Version: 1.0 Created at 2016-09-25 16:34. 13 | */ 14 | @Getter 15 | public class ServiceConfig extends AbstractConfig { 16 | @NotBlank 17 | private String service; 18 | @Min(0) 19 | @Max(100) 20 | private int weight = -1; 21 | @Min(0) 22 | private int timeout = (int) TimeUnit.SECONDS.toMillis(3); 23 | 24 | private ServiceConfig() { 25 | super("service"); 26 | } 27 | 28 | public ServiceConfig(String service, int weight) { 29 | this(); 30 | this.service = service; 31 | this.weight = weight; 32 | } 33 | 34 | public ServiceConfig(String service, int weight, int timeout) { 35 | this(); 36 | this.service = service; 37 | this.weight = weight; 38 | this.timeout = timeout; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /trpc-core/src/main/java/com/github/sofn/trpc/core/config/ServiceArgs.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.core.config; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnore; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Getter; 6 | import lombok.Setter; 7 | import org.apache.thrift.TBaseProcessor; 8 | import org.hibernate.validator.constraints.NotBlank; 9 | 10 | import javax.validation.constraints.Max; 11 | import javax.validation.constraints.Min; 12 | import javax.validation.constraints.NotNull; 13 | import java.util.concurrent.TimeUnit; 14 | 15 | /** 16 | * Authors: sofn 17 | * Version: 1.0 Created at 2016-09-25 16:34. 18 | */ 19 | @Setter 20 | @Getter 21 | @AllArgsConstructor 22 | public class ServiceArgs { 23 | @NotNull 24 | private TBaseProcessor processor; 25 | @NotBlank 26 | private String service; 27 | @Min(0) 28 | @Max(100) 29 | private int weight = -1; 30 | @Min(0) 31 | private int timeout = (int) TimeUnit.SECONDS.toMillis(3); 32 | 33 | @JsonIgnore 34 | public TBaseProcessor getProcessor() { 35 | return this.processor; 36 | } 37 | 38 | public ServiceConfig getServiceConfig() { 39 | return new ServiceConfig(this.service, this.weight, this.timeout); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /trpc-core/build.gradle: -------------------------------------------------------------------------------- 1 | dependencies { 2 | compile group: 'org.apache.thrift', name: 'libthrift', version: "${thriftVersion}" 3 | //common 4 | compile group: 'com.google.guava', name: 'guava', version: "${guavaVersion}" 5 | compile group: 'org.apache.commons', name: 'commons-lang3', version: "${commonsLangVersion}" 6 | compile group: 'commons-collections', name: 'commons-collections', version: "${commonsCollectionsVersion}" 7 | //util 8 | compile group: 'org.projectlombok', name: 'lombok', version: "${lombokVersion}" 9 | //json 10 | compile group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: "${jacksonVersion}" 11 | compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: "${jacksonVersion}" 12 | compile group: 'com.fasterxml.jackson.core', name: 'jackson-annotations', version: "${jacksonVersion}" 13 | //bean validator 14 | compile group: 'javax.validation', name: 'validation-api', version: "${validationApiVersion}" 15 | compile group: 'org.hibernate', name: 'hibernate-validator', version: "${hibernateValidatorVersion}" 16 | compile group: 'javax.el', name: 'javax.el-api', version: "${elApiVersion}" 17 | //log 18 | compile group: 'org.slf4j', name: 'slf4j-api', version: "${slf4jVersion}" 19 | } 20 | -------------------------------------------------------------------------------- /trpc-core/src/main/java/com/github/sofn/trpc/core/utils/Threads.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.core.utils; 2 | 3 | import java.util.concurrent.ExecutorService; 4 | import java.util.concurrent.TimeUnit; 5 | 6 | /** 7 | * 线程相关工具类. 8 | */ 9 | public class Threads { 10 | 11 | /** 12 | * 按照ExecutorService JavaDoc示例代码编写的Graceful Shutdown方法. 先使用shutdown, 停止接收新任务并尝试完成所有已存在任务. 如果超时, 则调用shutdownNow, 13 | * 取消在workQueue中Pending的任务,并中断所有阻塞函数. 如果仍然超時,則強制退出. 另对在shutdown时线程本身被调用中断做了处理. 14 | */ 15 | public static void gracefulShutdown(ExecutorService pool, int shutdownTimeout, int shutdownNowTimeout, 16 | TimeUnit timeUnit) { 17 | pool.shutdown(); // Disable new tasks from being submitted 18 | try { 19 | // Wait a while for existing tasks to terminate 20 | if (!pool.awaitTermination(shutdownTimeout, timeUnit)) { 21 | pool.shutdownNow(); // Cancel currently executing tasks 22 | // Wait a while for tasks to respond to being cancelled 23 | if (!pool.awaitTermination(shutdownNowTimeout, timeUnit)) { 24 | System.err.println("Pool did not terminated"); 25 | } 26 | } 27 | } catch (InterruptedException ie) { 28 | // (Re-)Cancel if current thread also interrupted 29 | pool.shutdownNow(); 30 | // Preserve interrupt status 31 | Thread.currentThread().interrupt(); 32 | } 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /trpc-server/src/main/java/com/github/sofn/trpc/server/TrpcRegistryEventHandler.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.server; 2 | 3 | import com.github.sofn.trpc.core.IRegistry; 4 | import com.github.sofn.trpc.server.config.ServerArgs; 5 | import org.apache.thrift.protocol.TProtocol; 6 | import org.apache.thrift.server.ServerContext; 7 | import org.apache.thrift.server.TServerEventHandler; 8 | import org.apache.thrift.transport.TTransport; 9 | 10 | /** 11 | * Authors: sofn 12 | * Version: 1.0 Created at 2016-09-25 21:36. 13 | */ 14 | public class TrpcRegistryEventHandler implements TServerEventHandler { 15 | private ServerArgs serverArgs; 16 | 17 | public TrpcRegistryEventHandler(ServerArgs serverArgs) { 18 | this.serverArgs = serverArgs; 19 | } 20 | 21 | @Override 22 | public void preServe() { 23 | for (IRegistry registry : serverArgs.getRegistrys()) { 24 | registry.registry(serverArgs.getRegistryConfig()); 25 | } 26 | } 27 | 28 | @Override 29 | public ServerContext createContext(TProtocol tProtocol, TProtocol tProtocol1) { 30 | return null; 31 | } 32 | 33 | @Override 34 | public void deleteContext(ServerContext serverContext, TProtocol tProtocol, TProtocol tProtocol1) { 35 | } 36 | 37 | @Override 38 | public void processContext(ServerContext serverContext, TTransport tTransport, TTransport tTransport1) { 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /trpc-core/src/main/java/com/github/sofn/trpc/core/config/ThriftServerInfo.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.core.config; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.EqualsAndHashCode; 6 | import org.apache.commons.lang3.StringUtils; 7 | import org.apache.commons.lang3.math.NumberUtils; 8 | 9 | import static com.google.common.base.Preconditions.checkArgument; 10 | import static com.google.common.base.Preconditions.checkNotNull; 11 | 12 | /** 13 | * Authors: sofn 14 | * Version: 1.0 Created at 2016-09-19 23:02. 15 | */ 16 | @Data 17 | @AllArgsConstructor 18 | @EqualsAndHashCode 19 | public class ThriftServerInfo { 20 | private String ip; 21 | private int port; 22 | 23 | public ThriftServerInfo(String ipPort) { 24 | checkNotNull(ipPort); 25 | String[] splits = ipPort.split(":"); 26 | checkArgument(splits.length == 2, "ipPort format error"); 27 | this.ip = splits[0]; 28 | this.port = NumberUtils.toInt(splits[1]); 29 | } 30 | 31 | @Override 32 | public String toString() { 33 | return ip + ":" + port; 34 | } 35 | 36 | public static ThriftServerInfo parse(String info) { 37 | String[] splits = StringUtils.split(info, ":"); 38 | if (splits == null || splits.length != 2) { 39 | return null; 40 | } 41 | return new ThriftServerInfo(splits[0], NumberUtils.toInt(splits[1])); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /trpc-core/src/main/java/com/github/sofn/trpc/core/monitor/StaticMonitor.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.core.monitor; 2 | 3 | import com.github.sofn.trpc.core.AbstractMonitor; 4 | import com.github.sofn.trpc.core.config.RegistryConfig; 5 | import com.github.sofn.trpc.core.config.ServiceConfig; 6 | import com.github.sofn.trpc.core.config.ThriftServerInfo; 7 | 8 | import java.util.List; 9 | import java.util.stream.Collectors; 10 | 11 | import static com.google.common.base.Preconditions.checkNotNull; 12 | 13 | /** 14 | * Authors: sofn 15 | * Version: 1.0 Created at 2016-10-09 22:35. 16 | */ 17 | public class StaticMonitor extends AbstractMonitor { 18 | 19 | private List servers; 20 | private List services; 21 | private String appKey; 22 | 23 | public StaticMonitor(List servers, List services, String appKey) { 24 | checkNotNull(servers); 25 | checkNotNull(services); 26 | this.servers = servers; 27 | this.services = services; 28 | this.appKey = appKey; 29 | } 30 | 31 | @Override 32 | public List monitorRemoteKey(RegistryConfigListener monitor) { 33 | List serviceConfigs = services.stream().map(s -> new ServiceConfig(s, 100)).collect(Collectors.toList()); 34 | return servers.stream() 35 | .map(s -> new RegistryConfig(serviceConfigs, s, appKey, "static", s.getIp(), 100)) 36 | .collect(Collectors.toList()); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /trpc-server/src/main/java/com/github/sofn/trpc/server/netty/TNettyTransport.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.server.netty; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.channel.Channel; 5 | import org.apache.thrift.transport.TTransport; 6 | import org.apache.thrift.transport.TTransportException; 7 | 8 | /** 9 | * Thrift in memory transport base on Netty's ByteBuf. 10 | */ 11 | public class TNettyTransport extends TTransport { 12 | 13 | public static final int DEFAULT_BUFFER_SIZE = 1024; 14 | 15 | private Channel channel; 16 | 17 | public ByteBuf in; 18 | public ByteBuf out; 19 | 20 | public TNettyTransport(Channel channel, ByteBuf in) { 21 | this.channel = channel; 22 | this.in = in; 23 | out = channel.alloc().buffer(DEFAULT_BUFFER_SIZE); 24 | } 25 | 26 | @Override 27 | public int read(byte[] bytes, int offset, int length) throws TTransportException { 28 | int _read = Math.min(in.readableBytes(), length); 29 | in.readBytes(bytes, offset, _read); 30 | return _read; 31 | } 32 | 33 | @Override 34 | public void write(byte[] bytes, int offset, int length) throws TTransportException { 35 | out.writeBytes(bytes, offset, length); 36 | } 37 | 38 | @Override 39 | public void open() throws TTransportException { 40 | // no-op 41 | } 42 | 43 | @Override 44 | public boolean isOpen() { 45 | return channel.isOpen(); 46 | } 47 | 48 | @Override 49 | public void close() { 50 | channel.close(); 51 | } 52 | 53 | @Override 54 | public void flush() throws TTransportException { 55 | // no-op 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /trpc-client/src/main/java/com/github/sofn/trpc/client/config/TrpcServiceNode.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.client.config; 2 | 3 | import com.github.sofn.trpc.core.config.RegistryConfig; 4 | import com.github.sofn.trpc.core.config.ThriftServerInfo; 5 | import lombok.AllArgsConstructor; 6 | import lombok.EqualsAndHashCode; 7 | import lombok.Getter; 8 | import lombok.ToString; 9 | 10 | import java.util.List; 11 | import java.util.stream.Collectors; 12 | 13 | /** 14 | * @author sofn 15 | * @version 1.0 Created at: 2016-09-26 13:27 16 | */ 17 | @Getter 18 | @ToString 19 | @AllArgsConstructor 20 | @EqualsAndHashCode(of = {"ip", "port"}) 21 | public class TrpcServiceNode implements Comparable { 22 | private String ip; 23 | private int port; 24 | private int weight; 25 | private int timeout; 26 | 27 | public static List fromRegistryConfig(RegistryConfig registryConfig) { 28 | ThriftServerInfo server = registryConfig.getServerInfo(); 29 | return registryConfig.getServers().stream() 30 | .map(s -> new TrpcServiceNode(server.getIp(), server.getPort(), s.getWeight(), s.getTimeout())) 31 | .collect(Collectors.toList()); 32 | } 33 | 34 | public ThriftServerInfo toThriftServerInfo() { 35 | return new ThriftServerInfo(this.ip, this.port); 36 | } 37 | 38 | @Override 39 | public int compareTo(TrpcServiceNode other) { 40 | int result = this.ip.compareTo(other.ip); 41 | return result != 0 ? result : this.port - other.port; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /trpc-core/src/main/java/com/github/sofn/trpc/core/config/RegistryConfig.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.core.config; 2 | 3 | import com.github.sofn.trpc.core.utils.JsonUtils; 4 | import lombok.*; 5 | 6 | import java.util.Collections; 7 | import java.util.List; 8 | 9 | /** 10 | * @author sofn 11 | * @version 1.0 Created at: 2016-09-19 16:53 12 | */ 13 | @Setter 14 | @Getter 15 | @Builder 16 | @EqualsAndHashCode(of = {"serverInfo", "appKey"}, callSuper = false) 17 | public class RegistryConfig extends AbstractConfig { 18 | @Singular 19 | private List servers = Collections.emptyList(); 20 | private ThriftServerInfo serverInfo; 21 | private String appKey; 22 | private String registry; 23 | private String hostName; 24 | private int weight; //权重 25 | 26 | public RegistryConfig() { 27 | super("registry"); 28 | } 29 | 30 | public RegistryConfig(List servers, ThriftServerInfo serverInfo, String appKey, String registry, String hostName, int weight) { 31 | this(); 32 | this.servers = servers; 33 | this.serverInfo = serverInfo; 34 | this.appKey = appKey; 35 | this.registry = registry; 36 | this.hostName = hostName; 37 | this.weight = weight; 38 | } 39 | 40 | public String toJsonString() { 41 | this.servers.stream().forEach(AbstractConfig::fillId); 42 | this.fillId(); 43 | return JsonUtils.toJson(this); 44 | } 45 | 46 | public static RegistryConfig parse(String json) { 47 | return JsonUtils.fromJson(json, RegistryConfig.class); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /trpc-server/src/test/java/com/github/sofn/trpc/server/test/config/NettyServerTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.server.test.config; 2 | 3 | import com.github.sofn.trpc.core.utils.ClassNameUtils; 4 | import com.github.sofn.trpc.demo.Hello; 5 | import com.github.sofn.trpc.direct.HelloServer; 6 | import com.github.sofn.trpc.server.netty.NettyServerArgs; 7 | import com.github.sofn.trpc.server.netty.TNettyServer; 8 | import org.apache.thrift.TMultiplexedProcessor; 9 | 10 | /** 11 | * Authors: sofn 12 | * Version: 1.0 Created at 2016-10-26 22:03. 13 | */ 14 | public class NettyServerTest { 15 | 16 | public void startNettyServer(int port) throws InterruptedException { 17 | TMultiplexedProcessor processor = new TMultiplexedProcessor(); 18 | processor.registerProcessor(ClassNameUtils.getClassName(Hello.class), new Hello.Processor<>(new HelloServer())); 19 | 20 | NettyServerArgs serverArgs = new NettyServerArgs() 21 | .port(port) 22 | .processor(processor); 23 | 24 | TNettyServer server = new TNettyServer(serverArgs); 25 | server.serve(); 26 | server.waitForClose(); 27 | } 28 | 29 | public void startDaemon(int port) { 30 | Thread thread = new Thread(new Runnable() { 31 | @Override 32 | public void run() { 33 | try { 34 | startNettyServer(port); 35 | } catch (InterruptedException e) { 36 | e.printStackTrace(); 37 | } 38 | } 39 | }); 40 | thread.setDaemon(true); 41 | thread.start(); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /trpc-client/src/main/java/com/github/sofn/trpc/client/loadbalance/RandomLoadBalance.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.client.loadbalance; 2 | 3 | import com.github.sofn.trpc.client.config.ClientArgs; 4 | import com.github.sofn.trpc.client.config.ServiceKey; 5 | import com.github.sofn.trpc.client.config.TrpcServiceNode; 6 | import org.apache.commons.lang3.RandomUtils; 7 | 8 | import java.util.List; 9 | 10 | 11 | /** 12 | * @author sofn 13 | * @version 1.0 Created at: 2016-10-02 00:20 14 | */ 15 | public class RandomLoadBalance extends AbstractLoadBalance { 16 | 17 | @Override 18 | public TrpcServiceNode getNode(ServiceKey key, ClientArgs args) { 19 | List allNodes = getAllNodes(key, args); 20 | 21 | int length = allNodes.size(); // 总个数 22 | int totalWeight = 0; // 总权重 23 | boolean sameWeight = true; // 权重是否都一样 24 | for (int i = 0; i < length; i++) { 25 | int weight = allNodes.get(i).getWeight(); 26 | totalWeight += weight; // 累计总权重 27 | if (sameWeight && i > 0 && weight != allNodes.get(i - 1).getWeight()) { 28 | sameWeight = false; // 计算所有权重是否一样 29 | } 30 | } 31 | if (totalWeight > 0 && !sameWeight) { 32 | // 如果权重不相同且权重大于0则按总权重数随机 33 | int offset = RandomUtils.nextInt(0, totalWeight); 34 | // 并确定随机值落在哪个片断上 35 | for (TrpcServiceNode node : allNodes) { 36 | offset -= node.getWeight(); 37 | if (offset < 0) { 38 | return node; 39 | } 40 | } 41 | } 42 | // 如果权重相同或权重为0则均等随机 43 | return allNodes.get(RandomUtils.nextInt(0, length)); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /trpc-core/src/main/java/com/github/sofn/trpc/core/utils/JsonUtils.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.core.utils; 2 | 3 | import com.fasterxml.jackson.databind.DeserializationFeature; 4 | import com.fasterxml.jackson.databind.ObjectMapper; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.apache.commons.lang3.StringUtils; 7 | 8 | import java.io.IOException; 9 | 10 | /** 11 | * 简单封装Jackson 12 | * Authors: sofn 13 | * Version: 1.0 Created at 2016-09-25 17:59. 14 | */ 15 | @Slf4j 16 | public class JsonUtils { 17 | private static ObjectMapper mapper; 18 | 19 | static { 20 | mapper = new ObjectMapper(); 21 | //设置输入时忽略在JSON字符串中存在但Java对象实际没有的属性 22 | mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); 23 | } 24 | 25 | /** 26 | * Object可以是POJO,也可以是Collection或数组。 27 | * 如果对象为Null, 返回"null". 28 | * 如果集合为空集合, 返回"[]". 29 | */ 30 | public static String toJson(Object object) { 31 | 32 | try { 33 | return mapper.writeValueAsString(object); 34 | } catch (IOException e) { 35 | log.warn("write to json string error:" + object, e); 36 | return null; 37 | } 38 | } 39 | 40 | /** 41 | * 反序列化POJO或简单Collection如List. 42 | *

43 | * 如果JSON字符串为Null或"null"字符串, 返回Null. 44 | * 如果JSON字符串为"[]", 返回空集合. 45 | *

46 | * 如需反序列化复杂Collection如List, 请使用fromJson(String, JavaType) 47 | */ 48 | public static T fromJson(String jsonString, Class clazz) { 49 | if (StringUtils.isEmpty(jsonString)) { 50 | return null; 51 | } 52 | 53 | try { 54 | return mapper.readValue(jsonString, clazz); 55 | } catch (IOException e) { 56 | log.warn("parse json string error:" + jsonString, e); 57 | return null; 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /trpc-registry/trpc-registry-zookeeper/src/test/java/com/github/sofn/trpc/registry/zk/test/ThriftServerPublisherTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.registry.zk.test; 2 | 3 | import com.github.sofn.trpc.core.config.ServiceArgs; 4 | import com.github.sofn.trpc.core.utils.ClassNameUtils; 5 | import com.github.sofn.trpc.demo.Hello; 6 | import com.github.sofn.trpc.direct.DemoClient; 7 | import com.github.sofn.trpc.direct.HelloServer; 8 | import com.github.sofn.trpc.registry.zk.ZkRegistry; 9 | import com.github.sofn.trpc.server.ThriftServerPublisher; 10 | import com.github.sofn.trpc.server.config.ServerArgs; 11 | import com.github.sofn.trpc.utils.NumUtil; 12 | import org.junit.Test; 13 | 14 | import java.net.UnknownHostException; 15 | import java.util.concurrent.TimeUnit; 16 | 17 | /** 18 | * Authors: sofn 19 | * Version: 1.0 Created at 2016-09-18 23:14. 20 | */ 21 | public class ThriftServerPublisherTest { 22 | 23 | @Test 24 | public void test() throws UnknownHostException, InterruptedException { 25 | ZkRegistry registry = new ZkRegistry(); 26 | registry.setConnectString("localhost:2181"); 27 | registry.setSessionTimeout(100); 28 | registry.setConnectionTimeout(1000); 29 | 30 | registry.initConnect(); 31 | 32 | ServerArgs arg = ServerArgs.builder() 33 | .appkey("test") 34 | .host("127.0.0.1") 35 | .port(NumUtil.nextPort()) 36 | .service(new ServiceArgs(new Hello.Processor<>(new HelloServer()), ClassNameUtils.getClassName(Hello.class), 80, 100)) 37 | .registry(registry) 38 | .build(); 39 | arg.afterPropertiesSet(); 40 | 41 | ThriftServerPublisher publisher = new ThriftServerPublisher(arg); 42 | Thread thread = new Thread(publisher::init); 43 | thread.setDaemon(true); 44 | thread.start(); 45 | 46 | TimeUnit.MILLISECONDS.sleep(20); 47 | DemoClient demoClient = new DemoClient(); 48 | demoClient.setPort(arg.getPort()); 49 | demoClient.bioCall(); 50 | demoClient.nioCall(); 51 | publisher.stop(); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /trpc-server/src/main/java/com/github/sofn/trpc/server/netty/NettyServerArgs.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.server.netty; 2 | 3 | import org.apache.thrift.server.TServer.AbstractServerArgs; 4 | 5 | /** 6 | * Arguments for Netty Server 7 | */ 8 | public class NettyServerArgs extends AbstractServerArgs { 9 | 10 | public String ip; 11 | public int port = -1; 12 | 13 | public int bossThreads = 2; 14 | public int workerThreads = 0; 15 | public int userThreads = Runtime.getRuntime().availableProcessors() * 2; 16 | 17 | public int socketTimeoutMills = -1; 18 | public int shutdownTimeoutMills = 10000; 19 | 20 | public int sendBuff = -1; 21 | public int recvBuff = -1; 22 | 23 | public NettyServerArgs() { 24 | super(null); 25 | } 26 | 27 | 28 | public NettyServerArgs ip(String ip) { 29 | this.ip = ip; 30 | return this; 31 | } 32 | 33 | public NettyServerArgs port(int port) { 34 | this.port = port; 35 | return this; 36 | } 37 | 38 | public NettyServerArgs bossThreads(int bossThreads) { 39 | this.bossThreads = bossThreads; 40 | return this; 41 | } 42 | 43 | public NettyServerArgs workerThreads(int workerThreads) { 44 | this.workerThreads = workerThreads; 45 | return this; 46 | } 47 | 48 | public NettyServerArgs userThreads(int userThreads) { 49 | this.userThreads = userThreads; 50 | return this; 51 | } 52 | 53 | public NettyServerArgs socketTimeoutMills(int socketTimeoutMills) { 54 | this.socketTimeoutMills = socketTimeoutMills; 55 | return this; 56 | } 57 | 58 | public NettyServerArgs shutdownTimeoutMills(int shutdownTimeoutMills) { 59 | this.shutdownTimeoutMills = shutdownTimeoutMills; 60 | return this; 61 | } 62 | 63 | public NettyServerArgs sendBuff(int sendBuff) { 64 | this.sendBuff = sendBuff; 65 | return this; 66 | } 67 | 68 | public NettyServerArgs recvBuff(int recvBuff) { 69 | this.recvBuff = recvBuff; 70 | return this; 71 | } 72 | 73 | public void validate() { 74 | if (port < 0) { 75 | throw new IllegalArgumentException("port " + port + " is wrong."); 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /trpc-core/src/test/java/com/github/sofn/trpc/core/test/model/RegistryConfigTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.core.test.model; 2 | 3 | import com.github.sofn.trpc.core.config.RegistryConfig; 4 | import com.github.sofn.trpc.core.config.ServiceConfig; 5 | import com.github.sofn.trpc.core.config.ThriftServerInfo; 6 | import com.google.common.collect.ImmutableList; 7 | import org.junit.Before; 8 | import org.junit.Test; 9 | 10 | import static org.assertj.core.api.Assertions.assertThat; 11 | 12 | /** 13 | * @author sofn 14 | * @version 1.0 Created at: 2016-09-19 17:07 15 | */ 16 | public class RegistryConfigTest { 17 | private RegistryConfig data; 18 | 19 | @Before 20 | public void init() { 21 | data = new RegistryConfig(); 22 | data.setRegistry("zookeeper"); 23 | data.setServerInfo(new ThriftServerInfo("127.0.0.1", 8080)); 24 | data.setAppKey("appKey"); 25 | data.setHostName("localhost"); 26 | data.setWeight(80); 27 | data.setServers(ImmutableList.of(new ServiceConfig("aaa", 100, 100), new ServiceConfig("bbb", 100, 100))); 28 | } 29 | 30 | @Test 31 | public void test() { 32 | assertThat(data.toJsonString()).isEqualTo("{\"configKey\":\"registry\",\"id\":0,\"servers\":[{\"configKey\":\"service\",\"id\":0,\"service\":\"aaa\",\"weight\":100,\"timeout\":100},{\"configKey\":\"service\",\"id\":1,\"service\":\"bbb\",\"weight\":100,\"timeout\":100}],\"serverInfo\":{\"ip\":\"127.0.0.1\",\"port\":8080},\"appKey\":\"appKey\",\"registry\":\"zookeeper\",\"hostName\":\"localhost\",\"weight\":80}"); 33 | 34 | RegistryConfig data2 = RegistryConfig.parse(data.toJsonString()); 35 | assertThat(data2).isNotNull(); 36 | assertThat(data2.getRegistry()).isEqualTo(data.getRegistry()); 37 | assertThat(data2.getServerInfo().getIp()).isEqualTo(data.getServerInfo().getIp()); 38 | assertThat(data2.getServerInfo().getPort()).isEqualTo(data.getServerInfo().getPort()); 39 | assertThat(data2.getWeight()).isEqualTo(data.getWeight()); 40 | assertThat(data2.getHostName()).isEqualTo(data.getHostName()); 41 | assertThat(data2.getId()).isEqualTo(0); 42 | assertThat(data2.getServers().size()).isEqualTo(2); 43 | assertThat(data2.getServers().get(0).getId()).isEqualTo(0L); 44 | assertThat(data2.getServers().get(1).getId()).isEqualTo(1L); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /trpc-client/src/main/java/com/github/sofn/trpc/client/pool/impl/TrpcClientFactory.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.client.pool.impl; 2 | 3 | import com.github.sofn.trpc.client.client.AbstractTrpcClient; 4 | import com.github.sofn.trpc.core.config.ThriftServerInfo; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.apache.commons.pool2.KeyedPooledObjectFactory; 7 | import org.apache.commons.pool2.PooledObject; 8 | import org.apache.commons.pool2.impl.DefaultPooledObject; 9 | 10 | import java.util.function.Function; 11 | 12 | /** 13 | * AbstractTrpcClient 构建工程类 14 | * 15 | * @author sofn 16 | * @version 1.0 Created at: 2016-09-20 11:55 17 | */ 18 | @Slf4j 19 | public class TrpcClientFactory implements KeyedPooledObjectFactory { 20 | 21 | private final Function transportProvider; 22 | 23 | public TrpcClientFactory(Function transportProvider) { 24 | this.transportProvider = transportProvider; 25 | } 26 | 27 | @Override 28 | public PooledObject makeObject(ThriftServerInfo info) throws Exception { 29 | T client = transportProvider.apply(info); 30 | client.open(); 31 | DefaultPooledObject result = new DefaultPooledObject<>(client); 32 | log.debug("make new ThriftClient:{}", info); 33 | return result; 34 | } 35 | 36 | @Override 37 | public void destroyObject(ThriftServerInfo info, PooledObject p) throws Exception { 38 | T client = p.getObject(); 39 | if (client != null && client.isOpen()) { 40 | client.close(); 41 | log.trace("unRegistry thrift connection:{}", info); 42 | } 43 | } 44 | 45 | @Override 46 | public boolean validateObject(ThriftServerInfo info, PooledObject p) { 47 | try { 48 | return p.getObject().isOpen(); 49 | } catch (Throwable e) { 50 | log.error("fail to validate tsocket:{}", info, e); 51 | return false; 52 | } 53 | } 54 | 55 | @Override 56 | public void activateObject(ThriftServerInfo info, PooledObject p) 57 | throws Exception { 58 | // do nothing 59 | } 60 | 61 | @Override 62 | public void passivateObject(ThriftServerInfo info, PooledObject p) 63 | throws Exception { 64 | // do nothing 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /trpc-client/src/main/java/com/github/sofn/trpc/client/pool/impl/TrpcClientPoolImpl.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.client.pool.impl; 2 | 3 | import com.github.sofn.trpc.client.client.AbstractTrpcClient; 4 | import com.github.sofn.trpc.client.client.AsyncTrpcClient; 5 | import com.github.sofn.trpc.client.client.BlockTrpcClient; 6 | import com.github.sofn.trpc.client.pool.TrpcClientPoolProvider; 7 | import com.github.sofn.trpc.core.config.ThriftServerInfo; 8 | import lombok.extern.slf4j.Slf4j; 9 | import org.apache.commons.pool2.impl.GenericKeyedObjectPool; 10 | import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig; 11 | 12 | import java.util.function.Function; 13 | 14 | /** 15 | *

16 | * TrpcClientPoolImpl class. 17 | *

18 | * 19 | * @author sofn 20 | * @version 1.0 Created at: 2016-09-22 14:13 21 | */ 22 | @Slf4j 23 | public final class TrpcClientPoolImpl implements TrpcClientPoolProvider { 24 | 25 | private final GenericKeyedObjectPool connections; 26 | 27 | public TrpcClientPoolImpl(GenericKeyedObjectPoolConfig config) { 28 | this(config, false); 29 | } 30 | 31 | @SuppressWarnings("unchecked") 32 | public TrpcClientPoolImpl(GenericKeyedObjectPoolConfig config, boolean async) { 33 | Function creater; 34 | if (async) { 35 | creater = AsyncTrpcClient::new; 36 | } else { 37 | creater = BlockTrpcClient::new; 38 | } 39 | connections = new GenericKeyedObjectPool(new TrpcClientFactory<>(creater), config); 40 | } 41 | 42 | @Override 43 | public T getConnection(ThriftServerInfo thriftServerInfo) { 44 | try { 45 | return connections.borrowObject(thriftServerInfo); 46 | } catch (Exception e) { 47 | log.error("fail to get connection for {}", thriftServerInfo, e); 48 | throw new RuntimeException(e); 49 | } 50 | } 51 | 52 | @Override 53 | public void returnConnection(ThriftServerInfo thriftServerInfo, T transport) { 54 | connections.returnObject(thriftServerInfo, transport); 55 | } 56 | 57 | @Override 58 | public void returnBrokenConnection(ThriftServerInfo thriftServerInfo, T transport) { 59 | try { 60 | connections.invalidateObject(thriftServerInfo, transport); 61 | } catch (Exception e) { 62 | log.error("fail to invalid object:{},{}", thriftServerInfo, transport, e); 63 | } 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /trpc-client/src/main/java/com/github/sofn/trpc/client/client/BlockTrpcClient.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.client.client; 2 | 3 | import com.github.sofn.trpc.core.config.ThriftServerInfo; 4 | import com.github.sofn.trpc.core.exception.TRpcException; 5 | import com.github.sofn.trpc.core.utils.ClassNameUtils; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.apache.thrift.TServiceClient; 8 | import org.apache.thrift.protocol.TBinaryProtocol; 9 | import org.apache.thrift.protocol.TMultiplexedProtocol; 10 | import org.apache.thrift.protocol.TProtocol; 11 | import org.apache.thrift.transport.TFramedTransport; 12 | import org.apache.thrift.transport.TSocket; 13 | import org.apache.thrift.transport.TTransport; 14 | import org.apache.thrift.transport.TTransportException; 15 | 16 | /** 17 | * @author sofn 18 | * @version 1.0 Created at: 2016-09-23 14:29 19 | */ 20 | @Slf4j 21 | public class BlockTrpcClient extends AbstractTrpcClient { 22 | private TProtocol protocol; 23 | 24 | public BlockTrpcClient(ThriftServerInfo serverInfo) { 25 | super(serverInfo); 26 | } 27 | 28 | @Override 29 | public void open() { 30 | TTransport transport; 31 | 32 | transport = new TSocket(serverInfo.getIp(), serverInfo.getPort()); 33 | transport = new TFramedTransport(transport); 34 | try { 35 | transport.open(); 36 | } catch (TTransportException e) { 37 | log.error("connect thrift key error", e); 38 | throw new TRpcException(e); 39 | } 40 | 41 | this.protocol = new TBinaryProtocol(transport); 42 | } 43 | 44 | @Override 45 | public boolean isOpen() { 46 | return this.protocol != null && this.protocol.getTransport().isOpen(); 47 | } 48 | 49 | @Override 50 | public void close() { 51 | if (this.protocol != null) { 52 | this.protocol.getTransport().close(); 53 | } 54 | } 55 | 56 | @Override 57 | @SuppressWarnings("unchecked") 58 | public C getClient(final Class clazz) { 59 | return (C) super.clients.computeIfAbsent(ClassNameUtils.getOuterClassName(clazz), className -> { 60 | TMultiplexedProtocol tmp = new TMultiplexedProtocol(this.protocol, className); 61 | try { 62 | return clazz.getConstructor(TProtocol.class).newInstance(tmp); 63 | } catch (Exception e) { 64 | log.error("never execute"); 65 | return null; 66 | } 67 | }); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /trpc-core/src/test/java/com/github/sofn/trpc/direct/DemoServer.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.direct; 2 | 3 | import com.github.sofn.trpc.core.utils.ClassNameUtils; 4 | import com.github.sofn.trpc.demo.Hello; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.apache.thrift.TMultiplexedProcessor; 7 | import org.apache.thrift.protocol.TBinaryProtocol; 8 | import org.apache.thrift.protocol.TProtocolFactory; 9 | import org.apache.thrift.server.TServer; 10 | import org.apache.thrift.server.TThreadedSelectorServer; 11 | import org.apache.thrift.transport.TFramedTransport; 12 | import org.apache.thrift.transport.TNonblockingServerSocket; 13 | import org.apache.thrift.transport.TTransportFactory; 14 | 15 | import java.util.concurrent.CountDownLatch; 16 | 17 | /** 18 | * @author sofn 19 | * @version 1.0 Created at: 2016-09-23 19:09 20 | */ 21 | @Slf4j 22 | public class DemoServer { 23 | private Thread thread; 24 | 25 | public void start(CountDownLatch latch, int port) { 26 | try { 27 | TNonblockingServerSocket serverTransport = new TNonblockingServerSocket(port); 28 | //异步IO,需要使用TFramedTransport,它将分块缓存读取。 29 | TTransportFactory transportFactory = new TFramedTransport.Factory(); 30 | //使用高密度二进制协议 31 | TProtocolFactory proFactory = new TBinaryProtocol.Factory(); 32 | //发布多个服务 33 | TMultiplexedProcessor processor = new TMultiplexedProcessor(); 34 | processor.registerProcessor(ClassNameUtils.getClassName(Hello.class), new Hello.Processor<>(new HelloServer())); 35 | 36 | TServer server = new TThreadedSelectorServer(new 37 | TThreadedSelectorServer.Args(serverTransport) 38 | .transportFactory(transportFactory) 39 | .protocolFactory(proFactory) 40 | .processor(processor) 41 | ); 42 | System.out.println("Starting the hello server..."); 43 | latch.countDown(); 44 | server.serve(); 45 | } catch (Exception e) { 46 | e.printStackTrace(); 47 | } 48 | } 49 | 50 | public void startDaemon() { 51 | startDaemon(8888); 52 | } 53 | 54 | public void startDaemon(int port) { 55 | CountDownLatch latch = new CountDownLatch(1); 56 | thread = new Thread(() -> start(latch, port)); 57 | thread.setDaemon(true); 58 | thread.start(); 59 | try { 60 | latch.await(); 61 | } catch (InterruptedException e) { 62 | e.printStackTrace(); 63 | } 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /trpc-client/src/main/java/com/github/sofn/trpc/client/loadbalance/RoundRobinLoadBalance.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.client.loadbalance; 2 | 3 | import com.github.sofn.trpc.client.config.ClientArgs; 4 | import com.github.sofn.trpc.client.config.ServiceKey; 5 | import com.github.sofn.trpc.client.config.TrpcServiceNode; 6 | 7 | import java.util.LinkedHashMap; 8 | import java.util.List; 9 | import java.util.Map; 10 | import java.util.concurrent.ConcurrentHashMap; 11 | import java.util.concurrent.atomic.AtomicInteger; 12 | 13 | 14 | /** 15 | * @author sofn 16 | * @version 1.0 Created at: 2016-10-03 10:20 17 | */ 18 | public class RoundRobinLoadBalance extends AbstractLoadBalance { 19 | 20 | private final Map callCounts = new ConcurrentHashMap<>(); 21 | 22 | @Override 23 | public TrpcServiceNode getNode(ServiceKey serviceKey, ClientArgs args) { 24 | List allNodes = getAllNodes(serviceKey, args); 25 | int length = allNodes.size(); // 总个数 26 | int maxWeight = 0; // 最大权重 27 | int minWeight = Integer.MAX_VALUE; // 最小权重 28 | int weightSum = 0; 29 | Map weightMap = new LinkedHashMap<>(); 30 | for (int i = 0; i < length; i++) { 31 | TrpcServiceNode node = allNodes.get(i); 32 | weightMap.put(node, new AtomicInteger(node.getWeight())); 33 | int weight = node.getWeight(); 34 | maxWeight = Math.max(maxWeight, weight); // 累计最大权重 35 | minWeight = Math.min(minWeight, weight); // 累计最小权重 36 | if (weight > 0) { 37 | weightSum += weight; 38 | } 39 | } 40 | AtomicInteger count = callCounts.computeIfAbsent(serviceKey, key -> new AtomicInteger()); 41 | int currentSequence = count.getAndIncrement(); 42 | if (maxWeight > 0 && minWeight < maxWeight) { // 权重不一样 43 | int mod = currentSequence % weightSum; 44 | for (int i = 0; i < maxWeight; i++) { 45 | 46 | for (Map.Entry entry : weightMap.entrySet()) { 47 | if (mod == 0 && entry.getValue().get() > 0) { 48 | return entry.getKey(); 49 | } 50 | if (entry.getValue().get() > 0) { 51 | entry.getValue().decrementAndGet(); 52 | mod--; 53 | } 54 | } 55 | } 56 | } 57 | // 取模轮循 58 | return allNodes.get(currentSequence % length); 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /trpc-core/src/main/java/com/github/sofn/trpc/core/utils/ValidationUtils.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.core.utils; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | 5 | import javax.validation.ConstraintViolation; 6 | import javax.validation.ConstraintViolationException; 7 | import javax.validation.Validation; 8 | import javax.validation.Validator; 9 | import java.util.List; 10 | import java.util.Set; 11 | import java.util.stream.Collectors; 12 | 13 | /** 14 | * Authors: sofn 15 | * Version: 1.0 Created at 2016-09-25 16:43. 16 | */ 17 | @Slf4j 18 | public class ValidationUtils { 19 | private static Validator validator = Validation.buildDefaultValidatorFactory().getValidator(); 20 | 21 | /** 22 | * 调用JSR303的validate方法, 验证失败时抛出ConstraintViolationException, 而不是返回constraintViolations. 23 | */ 24 | public static void validateWithException(Object object, Class... groups) 25 | throws ConstraintViolationException { 26 | Set> constraintViolations = validator.validate(object, groups); 27 | if (!constraintViolations.isEmpty()) { 28 | log.error(extractMessageAsString(constraintViolations)); 29 | throw new ConstraintViolationException(constraintViolations); 30 | } 31 | } 32 | 33 | /** 34 | * 辅助方法, 转换ConstraintViolationException中的Set中为List. 35 | */ 36 | public static List extractMessage(ConstraintViolationException e) { 37 | return extractMessage(e.getConstraintViolations()); 38 | } 39 | 40 | /** 41 | * 辅助方法, 转换Set为List 42 | */ 43 | public static List extractMessage(Set constraintViolations) { 44 | return constraintViolations.stream() 45 | .map(c -> c.getRootBeanClass().getSimpleName() + "." + c.getPropertyPath() + " " + c.getMessage() + " invalidValue: " + c.getInvalidValue()) 46 | .collect(Collectors.toList()); 47 | } 48 | 49 | /** 50 | * 辅助方法, 转换ConstraintViolationException中的Set中为String. 51 | */ 52 | public static String extractMessageAsString(ConstraintViolationException e) { 53 | return extractMessageAsString(e.getConstraintViolations()); 54 | } 55 | 56 | /** 57 | * 辅助方法, 转换Set为List 58 | */ 59 | public static String extractMessageAsString(Set constraintViolations) { 60 | return constraintViolations.stream() 61 | .map(c -> c.getRootBeanClass().getSimpleName() + "." + c.getPropertyPath() + " " + c.getMessage() + " invalidValue: " + c.getInvalidValue()) 62 | .collect(Collectors.joining(",")); 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /trpc-registry/trpc-registry-zookeeper/src/test/java/com/github/sofn/trpc/registry/zk/test/ZkMonitorTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.registry.zk.test; 2 | 3 | import com.github.sofn.trpc.core.config.RegistryConfig; 4 | import com.github.sofn.trpc.core.config.ThriftServerInfo; 5 | import com.github.sofn.trpc.core.monitor.RegistryConfigListener; 6 | import com.github.sofn.trpc.registry.zk.ZkMonitor; 7 | import com.github.sofn.trpc.registry.zk.ZkRegistry; 8 | import com.github.sofn.trpc.server.config.ServerArgs; 9 | import lombok.extern.slf4j.Slf4j; 10 | import org.junit.Test; 11 | 12 | import java.util.List; 13 | import java.util.concurrent.TimeUnit; 14 | 15 | /** 16 | * Authors: sofn 17 | * Version: 1.0 Created at 2016-09-27 22:15. 18 | */ 19 | @Slf4j 20 | public class ZkMonitorTest { 21 | private String zkconnStr = "localhost:2181"; 22 | private String appKey = "test"; 23 | 24 | @Test 25 | public void test01() throws InterruptedException { 26 | ZkRegistryTest registryTest = new ZkRegistryTest(); 27 | registryTest.startZkRegistry(zkconnStr, appKey, "127.0.0.1", 8000); 28 | 29 | TimeUnit.MILLISECONDS.sleep(20); 30 | 31 | ZkMonitor monitor = new ZkMonitor(); 32 | monitor.setConnectString(zkconnStr); 33 | monitor.setSessionTimeout(100); 34 | monitor.setConnectionTimeout(1000); 35 | List registryConfigs = monitor.monitorRemoteKey(new RegistryConfigListener(appKey) { 36 | @Override 37 | public void addServer(RegistryConfig config) { 38 | log.info("monitorRemoteKey addServer value: " + config.toJsonString()); 39 | } 40 | 41 | @Override 42 | public void removeServer(ThriftServerInfo serverInfo) { 43 | log.info("monitorRemoteKey removeServer receive: " + serverInfo); 44 | } 45 | 46 | @Override 47 | public void updateServer(RegistryConfig config) { 48 | log.info("monitorRemoteKey updateServer value: " + config.toJsonString()); 49 | } 50 | }); 51 | TimeUnit.MILLISECONDS.sleep(10); 52 | ZkRegistry zkRegistry = registryTest.startZkRegistry(zkconnStr, appKey, "127.0.0.1", 8001); 53 | TimeUnit.MILLISECONDS.sleep(10); 54 | ServerArgs oldArgs = registryTest.getServerArgs(appKey, "127.0.0.1", 8001); 55 | oldArgs.setWeight(60); 56 | zkRegistry.modify(oldArgs.getRegistryConfig()); 57 | TimeUnit.MILLISECONDS.sleep(10); 58 | zkRegistry.unRegistry(appKey, new ThriftServerInfo("127.0.0.1", 8001)); 59 | 60 | System.out.println(registryConfigs.size()); 61 | registryConfigs.stream().map(RegistryConfig::toJsonString).forEach(System.out::println); 62 | 63 | TimeUnit.MILLISECONDS.sleep(20); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /trpc-server/src/main/java/com/github/sofn/trpc/server/config/ServerArgs.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.server.config; 2 | 3 | import com.github.sofn.trpc.core.IRegistry; 4 | import com.github.sofn.trpc.core.config.RegistryConfig; 5 | import com.github.sofn.trpc.core.config.ServiceArgs; 6 | import com.github.sofn.trpc.core.config.ThriftServerInfo; 7 | import com.github.sofn.trpc.core.utils.NetUtils; 8 | import com.github.sofn.trpc.core.utils.ValidationUtils; 9 | import com.github.sofn.trpc.server.netty.NettyServerArgs; 10 | import lombok.Builder; 11 | import lombok.Data; 12 | import lombok.Singular; 13 | import org.apache.commons.lang3.StringUtils; 14 | import org.hibernate.validator.constraints.NotBlank; 15 | 16 | import javax.validation.constraints.Max; 17 | import javax.validation.constraints.Min; 18 | import javax.validation.constraints.Size; 19 | import java.net.InetAddress; 20 | import java.util.Collections; 21 | import java.util.List; 22 | import java.util.stream.Collectors; 23 | 24 | /** 25 | * 封装所有server端的配置信息 26 | * Authors: sofn 27 | * Version: 1.0 Created at 2016-09-25 16:28. 28 | */ 29 | @Data 30 | @Builder 31 | public class ServerArgs { 32 | @Singular 33 | private List registrys = Collections.emptyList(); 34 | @Size(min = 1, max = 100) 35 | @Singular 36 | private List services = Collections.emptyList(); 37 | private NettyServerArgs nettyServerArgs; 38 | @NotBlank 39 | private String appkey; //localAppKey 40 | @NotBlank 41 | private String host; 42 | @NotBlank 43 | private String hostName; 44 | @Min(1) 45 | private int port; 46 | @Min(0) 47 | @Max(100) 48 | private int weight = 100; 49 | 50 | public void setWeight(int weight) { 51 | services.stream().filter(s -> s.getWeight() == this.weight).forEach(s -> s.setWeight(weight)); 52 | this.weight = weight; 53 | } 54 | 55 | //对象创建完成后执行此方法 56 | public void afterPropertiesSet() { 57 | InetAddress localAddress = NetUtils.getLocalAddress(); 58 | if (StringUtils.isBlank(host)) { 59 | this.host = localAddress.getHostAddress(); 60 | } 61 | services.stream().filter(s -> s.getWeight() < 0).forEach(s -> s.setWeight(weight)); 62 | this.hostName = localAddress.getHostName(); 63 | ValidationUtils.validateWithException(this); 64 | } 65 | 66 | public RegistryConfig getRegistryConfig() { 67 | return RegistryConfig.builder() 68 | .serverInfo(new ThriftServerInfo(this.host, this.port)) 69 | .servers(this.services.stream().map(ServiceArgs::getServiceConfig).collect(Collectors.toList())) 70 | .appKey(this.appkey) 71 | .hostName(this.hostName) 72 | .weight(this.weight) 73 | .build(); 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /trpc-server/src/main/java/com/github/sofn/trpc/server/netty/ThriftHandler.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.server.netty; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.channel.ChannelHandler; 5 | import io.netty.channel.ChannelHandlerContext; 6 | import io.netty.channel.ChannelInboundHandlerAdapter; 7 | import lombok.extern.slf4j.Slf4j; 8 | import org.apache.thrift.TException; 9 | import org.apache.thrift.TProcessorFactory; 10 | import org.apache.thrift.protocol.TProtocol; 11 | import org.apache.thrift.protocol.TProtocolFactory; 12 | 13 | import java.util.concurrent.Executor; 14 | 15 | /** 16 | * Netty Channel Handler for thrift message. 17 | */ 18 | @Slf4j 19 | @ChannelHandler.Sharable 20 | public class ThriftHandler extends ChannelInboundHandlerAdapter { 21 | 22 | private TProcessorFactory processorFactory; 23 | private TProtocolFactory inProtocolFactory; 24 | private TProtocolFactory outProtocolFactory; 25 | 26 | private Executor userExecutor; 27 | 28 | public ThriftHandler(TProcessorFactory processorFactory, TProtocolFactory inProtocolFactory, 29 | TProtocolFactory outProtocolFactory, Executor executor) { 30 | this.processorFactory = processorFactory; 31 | this.inProtocolFactory = inProtocolFactory; 32 | this.outProtocolFactory = outProtocolFactory; 33 | this.userExecutor = executor; 34 | } 35 | 36 | @Override 37 | public void channelRead(ChannelHandlerContext ctx, Object msg) { 38 | TNettyTransport transport = new TNettyTransport(ctx.channel(), (ByteBuf) msg); 39 | userExecutor.execute(new ProcessorTask(ctx, transport)); 40 | } 41 | 42 | /** 43 | * Execute the thrift processor and user code in user threads. 44 | */ 45 | class ProcessorTask implements Runnable { 46 | private ChannelHandlerContext ctx; 47 | private TNettyTransport transport; 48 | 49 | ProcessorTask(ChannelHandlerContext ctx, TNettyTransport transport) { 50 | this.ctx = ctx; 51 | this.transport = transport; 52 | } 53 | 54 | @Override 55 | public void run() { 56 | TProtocol inProtocol = inProtocolFactory.getProtocol(transport); 57 | TProtocol outProtocol = outProtocolFactory.getProtocol(transport); 58 | try { 59 | processorFactory.getProcessor(transport).process(inProtocol, outProtocol); 60 | ctx.writeAndFlush(transport.out); 61 | } catch (TException e) { 62 | log.error("Thrift exception happen when call processor", e); 63 | // TODO: response thrift wrong exception, 64 | } catch (Exception e) { 65 | log.error("User exception happen when call processor", e); 66 | // TODO: response user wrong exception, 67 | } finally { 68 | transport.in.release(); 69 | } 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /trpc-test/src/test/java/com/github/sofn/trpc/test/monitor/StaticMonitorTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.test.monitor; 2 | 3 | import com.github.sofn.trpc.client.TrpcClientProxy; 4 | import com.github.sofn.trpc.client.config.ClientArgs; 5 | import com.github.sofn.trpc.core.utils.ClassNameUtils; 6 | import com.github.sofn.trpc.demo.Hello; 7 | import com.github.sofn.trpc.server.ThriftServerPublisher; 8 | import com.github.sofn.trpc.server.config.ServerArgs; 9 | import com.github.sofn.trpc.utils.NumUtil; 10 | import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig; 11 | import org.apache.thrift.TException; 12 | import org.junit.Before; 13 | import org.junit.Test; 14 | 15 | import java.util.concurrent.TimeUnit; 16 | 17 | import static java.util.concurrent.TimeUnit.MINUTES; 18 | import static org.junit.Assert.*; 19 | 20 | /** 21 | * Authors: sofn 22 | * Version: 1.0 Created at 2016-10-09 22:46. 23 | */ 24 | public class StaticMonitorTest { 25 | private static final int MIN_CONN = 1; 26 | private static final int MAX_CONN = 1000; 27 | private static final String appKey = "statictest"; 28 | private static final String localAppKey = "clientkey"; 29 | 30 | private GenericKeyedObjectPoolConfig poolConfig; 31 | private int port = NumUtil.nextPort(); 32 | 33 | @Before 34 | public void init() throws InterruptedException { 35 | ServiceFactoryTest serviceFactoryTest = new ServiceFactoryTest(); 36 | ServerArgs serverArgs = serviceFactoryTest.getServerArgs(appKey, "127.0.0.1", port); 37 | 38 | ThriftServerPublisher publisher = new ThriftServerPublisher(serverArgs); 39 | Thread thread = new Thread(publisher::init); 40 | thread.setDaemon(true); 41 | thread.start(); 42 | TimeUnit.MILLISECONDS.sleep(400); 43 | 44 | poolConfig = new GenericKeyedObjectPoolConfig(); 45 | poolConfig.setMaxTotal(MAX_CONN); 46 | poolConfig.setMaxTotalPerKey(MAX_CONN); 47 | poolConfig.setMaxIdlePerKey(MAX_CONN); 48 | poolConfig.setMinIdlePerKey(MIN_CONN); 49 | poolConfig.setTestOnBorrow(true); 50 | poolConfig.setMinEvictableIdleTimeMillis(MINUTES.toMillis(1)); 51 | poolConfig.setSoftMinEvictableIdleTimeMillis(MINUTES.toMillis(1)); 52 | poolConfig.setJmxEnabled(false); 53 | } 54 | 55 | @Test 56 | public void testStaticMonitor() { 57 | ClientArgs args = ClientArgs.builder() 58 | .poolConfig(poolConfig) 59 | .localAppKey(localAppKey) 60 | .remoteAppKey(appKey) 61 | .ipPorts("127.0.0.1:" + port) 62 | .serviceInterface(ClassNameUtils.getClassName(Hello.class)) 63 | .timeout(100) 64 | .build(); 65 | 66 | TrpcClientProxy proxy = new TrpcClientProxy(); 67 | proxy.setClientArgs(args); 68 | Hello.Client client = proxy.client(); 69 | try { 70 | String response = client.hi("world"); 71 | System.out.println("response: " + response); 72 | } catch (TException e) { 73 | fail(); 74 | } 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /trpc-client/src/main/java/com/github/sofn/trpc/client/client/AsyncTrpcClient.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.client.client; 2 | 3 | import com.github.sofn.trpc.core.config.ThriftServerInfo; 4 | import com.github.sofn.trpc.core.exception.TRpcException; 5 | import com.github.sofn.trpc.core.utils.ClassNameUtils; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.apache.thrift.async.TAsyncClient; 8 | import org.apache.thrift.async.TAsyncClientManager; 9 | import org.apache.thrift.protocol.TBinaryProtocol; 10 | import org.apache.thrift.protocol.TMultiplexedProtocol; 11 | import org.apache.thrift.protocol.TProtocol; 12 | import org.apache.thrift.protocol.TProtocolFactory; 13 | import org.apache.thrift.transport.TNonblockingSocket; 14 | import org.apache.thrift.transport.TNonblockingTransport; 15 | 16 | import java.nio.channels.UnresolvedAddressException; 17 | 18 | /** 19 | * @author sofn 20 | * @version 1.0 Created at: 2016-09-24 19:32 21 | */ 22 | @Slf4j 23 | public class AsyncTrpcClient extends AbstractTrpcClient { 24 | private TNonblockingTransport transport; 25 | private TAsyncClientManager clientManager; 26 | private volatile boolean isOpen = true; 27 | 28 | public AsyncTrpcClient(ThriftServerInfo serverInfo) { 29 | super(serverInfo); 30 | } 31 | 32 | @Override 33 | public void open() { 34 | try { 35 | //异步调用管理器 36 | this.clientManager = new TAsyncClientManager(); 37 | //设置传输通道,调用非阻塞IO。 38 | this.transport = new TNonblockingSocket(this.serverInfo.getIp(), this.serverInfo.getPort(), 1000); 39 | } catch (Exception e) { 40 | log.error("create AsyncTrpcClient:" + this.serverInfo + " error", e); 41 | throw new TRpcException("create AsyncTrpcClient:" + this.serverInfo + " error", e); 42 | } 43 | } 44 | 45 | @Override 46 | public boolean isOpen() { 47 | return this.isOpen; 48 | } 49 | 50 | @Override 51 | public void close() { 52 | if (this.transport != null && this.transport.isOpen()) { 53 | log.info("unRegistry client: " + serverInfo); 54 | this.transport.close(); 55 | } else { 56 | log.warn("try to unRegistry not open client: " + serverInfo); 57 | } 58 | } 59 | 60 | @Override 61 | @SuppressWarnings("unchecked") 62 | public X getClient(final Class clazz) { 63 | return (X) super.clients.computeIfAbsent(ClassNameUtils.getOuterClassName(clazz), (className) -> { 64 | TProtocolFactory protocolFactory = (TProtocolFactory) tTransport -> { 65 | TProtocol protocol = new TBinaryProtocol(tTransport); 66 | return new TMultiplexedProtocol(protocol, className); 67 | }; 68 | try { 69 | return clazz.getConstructor(TProtocolFactory.class, TAsyncClientManager.class, TNonblockingTransport.class) 70 | .newInstance(protocolFactory, this.clientManager, this.transport); 71 | } catch (Throwable e) { 72 | if (e instanceof UnresolvedAddressException) { 73 | this.isOpen = false; 74 | } 75 | return null; 76 | } 77 | }); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /trpc-registry/trpc-registry-zookeeper/src/test/java/com/github/sofn/trpc/registry/zk/test/ZkRegistryTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.registry.zk.test; 2 | 3 | import com.github.sofn.trpc.core.config.ServiceArgs; 4 | import com.github.sofn.trpc.core.exception.TRpcRegistryException; 5 | import com.github.sofn.trpc.core.utils.ClassNameUtils; 6 | import com.github.sofn.trpc.demo.Hello; 7 | import com.github.sofn.trpc.direct.HelloServer; 8 | import com.github.sofn.trpc.registry.zk.ZkRegistry; 9 | import com.github.sofn.trpc.server.config.ServerArgs; 10 | import org.junit.Test; 11 | 12 | import java.net.UnknownHostException; 13 | import java.util.concurrent.TimeUnit; 14 | 15 | /** 16 | * Authors: sofn 17 | * Version: 1.0 Created at 2016-09-18 23:14. 18 | */ 19 | public class ZkRegistryTest { 20 | 21 | public ServerArgs getServerArgs(String appKey, String host, int port) { 22 | ServerArgs arg = ServerArgs.builder() 23 | .appkey(appKey) 24 | .port(port) 25 | .host(host) 26 | .weight(80) 27 | .service(new ServiceArgs(new Hello.Processor<>(new HelloServer()), ClassNameUtils.getClassName(Hello.class), 80, 100)) 28 | .build(); 29 | arg.afterPropertiesSet(); 30 | return arg; 31 | } 32 | 33 | public ZkRegistry startZkRegistry(String zkConn, String appKey, String host, int port) { 34 | ZkRegistry registry = new ZkRegistry(); 35 | registry.setConnectString(zkConn); 36 | registry.setSessionTimeout(100); 37 | registry.setConnectionTimeout(1000); 38 | registry.initConnect(); 39 | ServerArgs arg = getServerArgs(appKey, host, port); 40 | registry.registry(arg.getRegistryConfig()); 41 | return registry; 42 | } 43 | 44 | @Test 45 | public void testRegistry() throws UnknownHostException, InterruptedException { 46 | startZkRegistry("localhost:2181", "test", "127.0.0.1", 8080); 47 | TimeUnit.MILLISECONDS.sleep(10); 48 | } 49 | 50 | @Test(expected = TRpcRegistryException.class) 51 | public void testRepeatRegistry() throws UnknownHostException, InterruptedException { 52 | startZkRegistry("localhost:2181", "test", "127.0.0.1", 8080); 53 | startZkRegistry("localhost:2181", "test", "127.0.0.1", 8080); 54 | TimeUnit.MILLISECONDS.sleep(10); 55 | } 56 | 57 | @Test 58 | public void testModify() throws UnknownHostException, InterruptedException { 59 | ZkRegistry registry = startZkRegistry("localhost:2181", "test", "127.0.0.1", 8081); 60 | ServerArgs oldArgs = getServerArgs("test", "127.0.0.1", 8081); 61 | oldArgs.setWeight(60); 62 | registry.modify(oldArgs.getRegistryConfig()); 63 | TimeUnit.MILLISECONDS.sleep(10); 64 | } 65 | 66 | @Test 67 | public void testModifyDirect() throws UnknownHostException, InterruptedException { 68 | ZkRegistry registry = new ZkRegistry(); 69 | registry.setConnectString("localhost:2181"); 70 | registry.setSessionTimeout(100); 71 | registry.setConnectionTimeout(1000); 72 | registry.initConnect(); 73 | ServerArgs args = getServerArgs("test", "127.0.0.1", 8082); 74 | registry.modify(args.getRegistryConfig()); 75 | TimeUnit.MILLISECONDS.sleep(10); 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /trpc-core/src/test/java/com/github/sofn/trpc/core/test/config/ServiceArgsTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.core.test.config; 2 | 3 | import com.github.sofn.trpc.core.config.ServiceArgs; 4 | import com.github.sofn.trpc.core.utils.ValidationUtils; 5 | import com.github.sofn.trpc.demo.Hello; 6 | import com.github.sofn.trpc.direct.HelloServer; 7 | import lombok.extern.slf4j.Slf4j; 8 | import org.junit.Test; 9 | 10 | import javax.validation.ConstraintViolationException; 11 | import java.util.List; 12 | 13 | import static org.assertj.core.api.Assertions.assertThat; 14 | 15 | /** 16 | * Authors: sofn 17 | * Version: 1.0 Created at 2016-09-25 16:51. 18 | */ 19 | @Slf4j 20 | public class ServiceArgsTest { 21 | 22 | @Test 23 | public void testNormal() { 24 | ServiceArgs service = new ServiceArgs(new Hello.Processor<>(new HelloServer()), "service", 100, 1); 25 | ValidationUtils.validateWithException(service); 26 | } 27 | 28 | @Test(expected = ConstraintViolationException.class) 29 | public void testNull() { 30 | ServiceArgs service = new ServiceArgs(null, "service", 100, 1); 31 | ValidationUtils.validateWithException(service); 32 | } 33 | 34 | @Test(expected = ConstraintViolationException.class) 35 | public void testEmpty() { 36 | ServiceArgs service = new ServiceArgs(new Hello.Processor<>(new HelloServer()), "", 100, 1); 37 | ValidationUtils.validateWithException(service); 38 | } 39 | 40 | @Test(expected = ConstraintViolationException.class) 41 | public void testMinMax1() { 42 | ServiceArgs service = new ServiceArgs(new Hello.Processor<>(new HelloServer()), "service", 101, 0); 43 | ValidationUtils.validateWithException(service); 44 | } 45 | 46 | @Test(expected = ConstraintViolationException.class) 47 | public void testMinMax2() { 48 | ServiceArgs service = new ServiceArgs(new Hello.Processor<>(new HelloServer()), "service", -1, 0); 49 | ValidationUtils.validateWithException(service); 50 | } 51 | 52 | @Test(expected = ConstraintViolationException.class) 53 | public void testMinMax3() { 54 | ServiceArgs service = new ServiceArgs(new Hello.Processor<>(new HelloServer()), "service", 100, -1); 55 | ValidationUtils.validateWithException(service); 56 | } 57 | 58 | @Test 59 | public void testValidateInfo() { 60 | ServiceArgs service = new ServiceArgs(new Hello.Processor<>(new HelloServer()), "service", 100, -1); 61 | try { 62 | ValidationUtils.validateWithException(service); 63 | } catch (ConstraintViolationException e) { 64 | List message = ValidationUtils.extractMessage(e); 65 | assertThat(message.size()).isEqualTo(1); 66 | log.info("ServiceArgs.timeout 最小不能小于0 invalidValue: -1"); 67 | } 68 | } 69 | 70 | @Test 71 | public void testValidateInfo2() { 72 | ServiceArgs service = new ServiceArgs(new Hello.Processor<>(new HelloServer()), "service", 100, -1); 73 | try { 74 | ValidationUtils.validateWithException(service); 75 | } catch (ConstraintViolationException e) { 76 | String message = ValidationUtils.extractMessageAsString(e); 77 | assertThat(message).isNotEmpty(); 78 | log.info("ServiceArgs.timeout 最小不能小于0 invalidValue: -1"); 79 | } 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /trpc-server/src/main/java/com/github/sofn/trpc/server/ThriftServerPublisher.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.server; 2 | 3 | import com.github.sofn.trpc.core.config.ServiceArgs; 4 | import com.github.sofn.trpc.server.config.ServerArgs; 5 | import com.github.sofn.trpc.server.netty.TNettyServer; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.apache.thrift.TMultiplexedProcessor; 8 | import org.apache.thrift.protocol.TBinaryProtocol; 9 | import org.apache.thrift.protocol.TProtocolFactory; 10 | import org.apache.thrift.server.TServer; 11 | import org.apache.thrift.server.TThreadedSelectorServer; 12 | import org.apache.thrift.transport.TFramedTransport; 13 | import org.apache.thrift.transport.TNonblockingServerSocket; 14 | import org.apache.thrift.transport.TTransportFactory; 15 | 16 | import java.net.InetSocketAddress; 17 | 18 | /** 19 | * Authors: sofn 20 | * Version: 1.0 Created at 2016-09-17 23:44. 21 | */ 22 | @Slf4j 23 | public class ThriftServerPublisher { 24 | private ServerArgs serverArgs; 25 | private TServer server; 26 | 27 | public ThriftServerPublisher(ServerArgs serverArgs) { 28 | serverArgs.afterPropertiesSet(); 29 | this.serverArgs = serverArgs; 30 | } 31 | 32 | public void init() { 33 | try { 34 | TMultiplexedProcessor processor = new TMultiplexedProcessor(); 35 | for (ServiceArgs service : serverArgs.getServices()) { 36 | String className = service.getService(); 37 | if (className.endsWith("$Processor")) { 38 | className = className.substring(0, className.indexOf("$Processor")); 39 | } 40 | processor.registerProcessor(className, service.getProcessor()); 41 | } 42 | if (serverArgs.getNettyServerArgs() != null) { 43 | this.server = new TNettyServer(serverArgs.getNettyServerArgs().ip(serverArgs.getHost()).port(serverArgs.getPort())); 44 | } else { 45 | TNonblockingServerSocket serverTransport = new TNonblockingServerSocket(new InetSocketAddress(serverArgs.getHost(), serverArgs.getPort())); 46 | //异步IO,需要使用TFramedTransport,它将分块缓存读取。 47 | TTransportFactory transportFactory = new TFramedTransport.Factory(); 48 | //使用高密度二进制协议 49 | TProtocolFactory proFactory = new TBinaryProtocol.Factory(); 50 | // Use this for a multithreaded key 51 | this.server = new TThreadedSelectorServer(new 52 | TThreadedSelectorServer.Args(serverTransport) 53 | .transportFactory(transportFactory) 54 | .protocolFactory(proFactory) 55 | .processor(processor) 56 | ); 57 | } 58 | log.info("Starting the Thrift key..."); 59 | this.server.setServerEventHandler(new TrpcRegistryEventHandler(serverArgs)); 60 | this.server.serve(); 61 | if (this.serverArgs.getNettyServerArgs() != null) { 62 | ((TNettyServer) this.server).waitForClose(); 63 | } 64 | } catch (Exception e) { 65 | log.error("publish thrift key error", e); 66 | } 67 | } 68 | 69 | public void stop() { 70 | if (this.server != null && this.server.isServing()) { 71 | this.server.stop(); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /trpc-server/src/test/java/com/github/sofn/trpc/server/test/config/ServerArgsTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.server.test.config; 2 | 3 | import com.github.sofn.trpc.core.config.ServiceArgs; 4 | import com.github.sofn.trpc.demo.Hello; 5 | import com.github.sofn.trpc.direct.HelloServer; 6 | import com.github.sofn.trpc.server.config.ServerArgs; 7 | import lombok.extern.slf4j.Slf4j; 8 | import org.junit.Test; 9 | 10 | import javax.validation.ConstraintViolationException; 11 | 12 | import static org.assertj.core.api.Assertions.assertThat; 13 | 14 | /** 15 | * Authors: sofn 16 | * Version: 1.0 Created at 2016-09-25 18:12. 17 | */ 18 | @Slf4j 19 | public class ServerArgsTest { 20 | 21 | @Test 22 | public void testNormal() { 23 | ServerArgs arg = ServerArgs.builder() 24 | .appkey("test") 25 | .port(8080) 26 | .host("127.0.0.1") 27 | .hostName("localhost") 28 | .weight(80) 29 | .service(new ServiceArgs(new Hello.Processor<>(new HelloServer()), "helloService", 80, 100)) 30 | .service(new ServiceArgs(new Hello.Processor<>(new HelloServer()), "helloService2", 80, 100)) 31 | .build(); 32 | arg.afterPropertiesSet(); 33 | } 34 | 35 | @Test(expected = ConstraintViolationException.class) 36 | public void testEmpty() { 37 | ServerArgs arg = ServerArgs.builder() 38 | .appkey("") 39 | .port(8080) 40 | .host("") 41 | .weight(80) 42 | .service(new ServiceArgs(new Hello.Processor<>(new HelloServer()), "helloService", 80, 100)) 43 | .service(new ServiceArgs(new Hello.Processor<>(new HelloServer()), "helloService2", 80, 100)) 44 | .build(); 45 | arg.afterPropertiesSet(); 46 | } 47 | 48 | @Test(expected = ConstraintViolationException.class) 49 | public void testEmptyList() { 50 | ServerArgs arg = ServerArgs.builder() 51 | .appkey("test") 52 | .port(8080) 53 | .host("127.0.0.1") 54 | .hostName("localhost") 55 | .weight(80) 56 | .build(); 57 | arg.afterPropertiesSet(); 58 | } 59 | 60 | @Test 61 | public void testAfterPropertiesSet() { 62 | ServerArgs arg = ServerArgs.builder() 63 | .appkey("test") 64 | .port(8080) 65 | .host("127.0.0.1") 66 | .weight(80) 67 | .service(new ServiceArgs(new Hello.Processor<>(new HelloServer()), "helloService", 80, 100)) 68 | .service(new ServiceArgs(new Hello.Processor<>(new HelloServer()), "helloService2", 80, 100)) 69 | .build(); 70 | arg.afterPropertiesSet(); 71 | assertThat(arg.getPort()).isEqualTo(8080); 72 | assertThat(arg.getHost()).isEqualTo("127.0.0.1"); 73 | 74 | arg = ServerArgs.builder() 75 | .appkey("test") 76 | .port(8080) 77 | .weight(80) 78 | .service(new ServiceArgs(new Hello.Processor<>(new HelloServer()), "helloService", 80, 100)) 79 | .service(new ServiceArgs(new Hello.Processor<>(new HelloServer()), "helloService2", 80, 100)) 80 | .build(); 81 | arg.afterPropertiesSet(); 82 | assertThat(arg.getPort()).isEqualTo(8080); 83 | assertThat(arg.getHost()).isNotEqualTo("127.0.0.1"); 84 | log.info("hostName: " + arg.getHostName()); 85 | log.info("hostAddress: " + arg.getHost()); 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /trpc-client/src/main/java/com/github/sofn/trpc/client/config/ClientArgs.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.client.config; 2 | 3 | import com.github.sofn.trpc.client.loadbalance.AbstractLoadBalance; 4 | import com.github.sofn.trpc.client.loadbalance.RandomLoadBalance; 5 | import com.github.sofn.trpc.client.pool.TrpcClientPoolProvider; 6 | import com.github.sofn.trpc.client.pool.impl.TrpcClientPoolImpl; 7 | import com.github.sofn.trpc.core.AbstractMonitor; 8 | import com.github.sofn.trpc.core.config.ThriftServerInfo; 9 | import com.github.sofn.trpc.core.monitor.StaticMonitor; 10 | import lombok.Builder; 11 | import lombok.Getter; 12 | import org.apache.commons.lang3.StringUtils; 13 | import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig; 14 | 15 | import java.util.ArrayList; 16 | import java.util.Arrays; 17 | import java.util.List; 18 | import java.util.stream.Collectors; 19 | 20 | /** 21 | * @author sofn 22 | * @version 1.0 Created at: 2016-09-28 16:55 23 | */ 24 | @Getter 25 | public class ClientArgs { 26 | private volatile TrpcClientPoolProvider poolProvider; 27 | private volatile AbstractLoadBalance loadBalance; 28 | private GenericKeyedObjectPoolConfig poolConfig; 29 | private List monitors; 30 | private List serviceInterfaces; 31 | private String serviceInterface; 32 | private String localAppKey; 33 | private String remoteAppKey; 34 | private String ipPorts; 35 | private int timeout; 36 | private boolean async; 37 | 38 | @Builder 39 | public ClientArgs(GenericKeyedObjectPoolConfig poolConfig, List monitors, List serviceInterfaces, String serviceInterface, String localAppKey, String remoteAppKey, String ipPorts, int timeout, boolean async) { 40 | this.poolConfig = poolConfig; 41 | this.monitors = monitors; 42 | this.serviceInterfaces = serviceInterfaces; 43 | this.serviceInterface = serviceInterface; 44 | this.localAppKey = localAppKey; 45 | this.remoteAppKey = remoteAppKey; 46 | this.ipPorts = ipPorts; 47 | this.timeout = timeout; 48 | this.async = async; 49 | afterPropertiesSet(); 50 | } 51 | 52 | private void afterPropertiesSet() { 53 | if (StringUtils.isNoneEmpty(serviceInterface)) { 54 | if (serviceInterfaces == null) { 55 | serviceInterfaces = new ArrayList<>(); 56 | } 57 | serviceInterfaces.add(serviceInterface); 58 | } 59 | if (StringUtils.isNotEmpty(ipPorts)) { 60 | List serverInfos = Arrays.stream(ipPorts.split(",")).map(ThriftServerInfo::new).collect(Collectors.toList()); 61 | if (monitors == null) { 62 | monitors = new ArrayList<>(); 63 | } 64 | monitors.add(new StaticMonitor(serverInfos, serviceInterfaces, remoteAppKey)); 65 | } 66 | } 67 | 68 | public AbstractLoadBalance getLoadBalance() { 69 | if (this.loadBalance == null) { 70 | synchronized (this) { 71 | if (this.loadBalance == null) { 72 | this.loadBalance = new RandomLoadBalance(); 73 | } 74 | } 75 | } 76 | return this.loadBalance; 77 | } 78 | 79 | public TrpcClientPoolProvider getPoolProvider() { 80 | if (this.poolProvider == null) { 81 | synchronized (this) { 82 | if (this.poolProvider == null) { 83 | this.poolProvider = new TrpcClientPoolImpl(this.poolConfig, this.async); 84 | } 85 | } 86 | } 87 | return this.poolProvider; 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /trpc-client/src/test/java/com/github/sofn/trpc/client/test/pool/TrpcClientPoolTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.client.test.pool; 2 | 3 | import com.github.sofn.trpc.client.client.AsyncTrpcClient; 4 | import com.github.sofn.trpc.client.client.BlockTrpcClient; 5 | import com.github.sofn.trpc.client.pool.impl.TrpcClientPoolImpl; 6 | import com.github.sofn.trpc.core.config.ThriftServerInfo; 7 | import com.github.sofn.trpc.demo.Hello; 8 | import com.github.sofn.trpc.direct.DemoServer; 9 | import org.apache.commons.lang3.RandomUtils; 10 | import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig; 11 | import org.apache.thrift.TException; 12 | import org.apache.thrift.async.AsyncMethodCallback; 13 | import org.junit.Before; 14 | import org.junit.Test; 15 | 16 | import java.util.concurrent.CountDownLatch; 17 | 18 | import static java.util.concurrent.TimeUnit.MINUTES; 19 | import static org.assertj.core.api.Assertions.assertThat; 20 | import static org.junit.Assert.fail; 21 | 22 | /** 23 | * @author sofn 24 | * @version 1.0 Created at: 2016-09-23 23:12 25 | */ 26 | public class TrpcClientPoolTest { 27 | private static final int MIN_CONN = 1; 28 | private static final int MAX_CONN = 1000; 29 | 30 | private int port = 8888; 31 | private GenericKeyedObjectPoolConfig config; 32 | 33 | @Before 34 | public void init() { 35 | this.port = RandomUtils.nextInt(10000, 20000); 36 | new DemoServer().startDaemon(this.port); 37 | 38 | config = new GenericKeyedObjectPoolConfig(); 39 | config.setMaxTotal(MAX_CONN); 40 | config.setMaxTotalPerKey(MAX_CONN); 41 | config.setMaxIdlePerKey(MAX_CONN); 42 | config.setMinIdlePerKey(MIN_CONN); 43 | config.setTestOnBorrow(true); 44 | config.setMinEvictableIdleTimeMillis(MINUTES.toMillis(1)); 45 | config.setSoftMinEvictableIdleTimeMillis(MINUTES.toMillis(1)); 46 | config.setJmxEnabled(false); 47 | } 48 | 49 | @Test 50 | public void testBlockPool() throws TException { 51 | TrpcClientPoolImpl clientPool = new TrpcClientPoolImpl(config); 52 | 53 | ThriftServerInfo serverInfo = new ThriftServerInfo("localhost", this.port); 54 | BlockTrpcClient trpcClient = (BlockTrpcClient) clientPool.getConnection(serverInfo); 55 | assertThat(trpcClient.isOpen()).isTrue(); 56 | 57 | Hello.Client client = trpcClient.getClient(Hello.Client.class); 58 | assertThat(client.hi("world")).isEqualTo("hello world"); 59 | } 60 | 61 | @Test 62 | public void testAysncPool() throws TException, InterruptedException { 63 | ThriftServerInfo serverInfo = new ThriftServerInfo("localhost", this.port); 64 | TrpcClientPoolImpl clientPool = new TrpcClientPoolImpl(config, true); 65 | AsyncTrpcClient trpcClient = (AsyncTrpcClient) clientPool.getConnection(serverInfo); 66 | Hello.AsyncClient client = trpcClient.getClient(Hello.AsyncClient.class); 67 | 68 | CountDownLatch downLatch = new CountDownLatch(1); 69 | client.hi("world", new AsyncMethodCallback() { 70 | @Override 71 | public void onComplete(Hello.AsyncClient.hi_call hi_call) { 72 | try { 73 | System.out.println(hi_call.getResult()); 74 | assertThat(hi_call.getResult()).isEqualTo("hello world"); 75 | downLatch.countDown(); 76 | } catch (TException e) { 77 | fail(); 78 | } 79 | } 80 | 81 | @Override 82 | public void onError(Exception e) { 83 | fail(); 84 | } 85 | }); 86 | downLatch.await(); 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /trpc-core/src/test/java/com/github/sofn/trpc/direct/DemoClient.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.direct; 2 | 3 | import com.github.sofn.trpc.demo.Hello; 4 | import com.github.sofn.trpc.utils.NumUtil; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.apache.thrift.TException; 7 | import org.apache.thrift.async.AsyncMethodCallback; 8 | import org.apache.thrift.async.TAsyncClientManager; 9 | import org.apache.thrift.protocol.*; 10 | import org.apache.thrift.transport.*; 11 | import org.junit.Before; 12 | import org.junit.Test; 13 | 14 | import java.util.concurrent.TimeUnit; 15 | 16 | import static org.junit.Assert.*; 17 | 18 | /** 19 | * @author sofn 20 | * @version 1.0 Created at: 2016-09-23 19:09 21 | */ 22 | @Slf4j 23 | public class DemoClient { 24 | private int port; 25 | 26 | public void setPort(int port) { 27 | this.port = port; 28 | } 29 | 30 | @Before 31 | public void init() { 32 | this.port = NumUtil.nextPort(); 33 | new DemoServer().startDaemon(this.port); 34 | } 35 | 36 | @Test 37 | public void nioCall() { 38 | try { 39 | //异步调用管理器 40 | TAsyncClientManager clientManager = new TAsyncClientManager(); 41 | //设置传输通道,调用非阻塞IO。 42 | final TNonblockingTransport transport = new TNonblockingSocket("127.0.0.1", this.port, 1000); 43 | //设置协议 44 | TProtocolFactory protocolFactory = (TProtocolFactory) tTransport -> { 45 | TProtocol protocol = new TBinaryProtocol(tTransport); 46 | return new TMultiplexedProtocol(protocol, Hello.class.getName()); 47 | }; 48 | 49 | //创建Client 50 | final Hello.AsyncClient client = new Hello.AsyncClient(protocolFactory, clientManager, transport); 51 | //调用服务 52 | log.info("开始:" + System.currentTimeMillis()); 53 | client.hi("world", new AsyncMethodCallback() { 54 | @Override 55 | public void onError(Exception exception) { 56 | log.info("error: " + System.currentTimeMillis()); 57 | exception.printStackTrace(); 58 | fail(); 59 | } 60 | 61 | @Override 62 | public void onComplete(Hello.AsyncClient.hi_call hi_call) { 63 | log.info("complete: " + System.currentTimeMillis()); 64 | try { 65 | log.info(hi_call.getResult()); 66 | } catch (Exception e) { 67 | fail(); 68 | } 69 | } 70 | }); 71 | log.info("结束:" + System.currentTimeMillis()); 72 | TimeUnit.MILLISECONDS.sleep(100); 73 | } catch (Exception e) { 74 | log.error("error", e); 75 | fail(); 76 | } 77 | 78 | } 79 | 80 | @Test 81 | public void bioCall() { 82 | try { 83 | log.info("开始:" + System.currentTimeMillis()); 84 | TTransport transport = new TFramedTransport(new TSocket("localhost", this.port)); 85 | transport.open(); 86 | 87 | //使用二进制协议 88 | TProtocol protocol = new TBinaryProtocol(transport); 89 | 90 | TMultiplexedProtocol mp2 = new TMultiplexedProtocol(protocol, Hello.class.getName()); 91 | Hello.Client helloClient2 = new Hello.Client(mp2); 92 | log.info(helloClient2.hi("tom")); 93 | log.info(helloClient2.hi("tom")); 94 | log.info(helloClient2.hi("tom")); 95 | log.info("结束:" + System.currentTimeMillis()); 96 | transport.close(); 97 | } catch (TException x) { 98 | x.printStackTrace(); 99 | fail(); 100 | } 101 | } 102 | 103 | } 104 | -------------------------------------------------------------------------------- /trpc-test/src/test/java/com/github/sofn/trpc/test/monitor/ServiceFactoryTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.test.monitor; 2 | 3 | import com.github.sofn.trpc.client.config.ServiceKey; 4 | import com.github.sofn.trpc.client.config.TrpcServiceNode; 5 | import com.github.sofn.trpc.client.monitor.ServiceFactory; 6 | import com.github.sofn.trpc.core.config.ServiceArgs; 7 | import com.github.sofn.trpc.core.utils.ClassNameUtils; 8 | import com.github.sofn.trpc.demo.Hello; 9 | import com.github.sofn.trpc.direct.HelloServer; 10 | import com.github.sofn.trpc.registry.zk.ZkMonitor; 11 | import com.github.sofn.trpc.registry.zk.ZkRegistry; 12 | import com.github.sofn.trpc.server.config.ServerArgs; 13 | import com.google.common.collect.Lists; 14 | import org.junit.Test; 15 | 16 | import java.util.Set; 17 | import java.util.concurrent.TimeUnit; 18 | 19 | import static org.assertj.core.api.Assertions.assertThat; 20 | 21 | /** 22 | * @author sofn 23 | * @version 1.0 Created at: 2016-10-02 11:48 24 | */ 25 | public class ServiceFactoryTest { 26 | private String zkconnStr = "localhost:2181"; 27 | private String appKey = "serviceFactoryTest"; 28 | 29 | public ServerArgs getServerArgs(String appKey, String host, int port) { 30 | ServerArgs arg = ServerArgs.builder() 31 | .appkey(appKey) 32 | .port(port) 33 | .host(host) 34 | .weight(80) 35 | .service(new ServiceArgs(new Hello.Processor<>(new HelloServer()), ClassNameUtils.getClassName(Hello.class), 80, 100)) 36 | .build(); 37 | arg.afterPropertiesSet(); 38 | return arg; 39 | } 40 | 41 | public ZkRegistry getZkRegistry() { 42 | ZkRegistry registry = new ZkRegistry(); 43 | registry.setConnectString(zkconnStr); 44 | registry.setSessionTimeout(100); 45 | registry.setConnectionTimeout(1000); 46 | registry.initConnect(); 47 | return registry; 48 | } 49 | 50 | @Test 51 | public void test() throws InterruptedException { 52 | ZkRegistry registry = getZkRegistry(); 53 | ServerArgs arg = getServerArgs(appKey, "127.0.0.1", 8000); 54 | registry.registry(arg.getRegistryConfig()); 55 | TimeUnit.MILLISECONDS.sleep(5); 56 | 57 | ZkMonitor zkMonitor = new ZkMonitor(); 58 | zkMonitor.setConnectString(zkconnStr); 59 | Set nodes = ServiceFactory.getServiceKeys(new ServiceKey(appKey, ClassNameUtils.getClassName(Hello.class)), zkMonitor); 60 | assertThat(nodes.size()).isEqualTo(1); 61 | nodes.forEach(System.out::println); 62 | 63 | //test add one 64 | ServerArgs arg2 = getServerArgs(appKey, "127.0.0.1", 8001); 65 | registry.registry(arg2.getRegistryConfig()); 66 | TimeUnit.MILLISECONDS.sleep(10); 67 | 68 | nodes = ServiceFactory.getServiceKeys(new ServiceKey(appKey, ClassNameUtils.getClassName(Hello.class)), zkMonitor); 69 | assertThat(nodes.size()).isEqualTo(2); 70 | nodes.forEach(System.out::println); 71 | 72 | //test update 73 | arg2.setWeight(70); 74 | registry.modify(arg2.getRegistryConfig()); 75 | TimeUnit.MILLISECONDS.sleep(20); 76 | nodes = ServiceFactory.getServiceKeys(new ServiceKey(appKey, ClassNameUtils.getClassName(Hello.class)), zkMonitor); 77 | assertThat(nodes.size()).isEqualTo(2); 78 | nodes.forEach(System.out::println); 79 | assertThat(Lists.newArrayList(nodes).get(1).getWeight()).isEqualTo(70); 80 | 81 | //test delete 82 | registry.unRegistry(appKey, arg2.getRegistryConfig().getServerInfo()); 83 | TimeUnit.MILLISECONDS.sleep(10); 84 | nodes = ServiceFactory.getServiceKeys(new ServiceKey(appKey, ClassNameUtils.getClassName(Hello.class)), zkMonitor); 85 | assertThat(nodes.size()).isEqualTo(1); 86 | nodes.forEach(System.out::println); 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /trpc-client/src/main/java/com/github/sofn/trpc/client/monitor/ServiceFactory.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.client.monitor; 2 | 3 | import com.github.sofn.trpc.client.config.ServiceKey; 4 | import com.github.sofn.trpc.client.config.TrpcServiceNode; 5 | import com.github.sofn.trpc.core.AbstractMonitor; 6 | import com.github.sofn.trpc.core.config.RegistryConfig; 7 | import com.github.sofn.trpc.core.config.ThriftServerInfo; 8 | import com.github.sofn.trpc.core.monitor.RegistryConfigListener; 9 | import com.google.common.collect.ImmutableList; 10 | import lombok.extern.slf4j.Slf4j; 11 | import org.apache.commons.lang3.StringUtils; 12 | 13 | import java.util.*; 14 | import java.util.concurrent.ConcurrentHashMap; 15 | import java.util.concurrent.ConcurrentSkipListSet; 16 | 17 | /** 18 | * 根据服务信息,获取节点信息,有监控机制保证数据实时同步 19 | * Authors: sofn 20 | * Version: 1.0 Created at 2016-09-28 23:02. 21 | */ 22 | @Slf4j 23 | public class ServiceFactory { 24 | private static Map> servicesMap = new ConcurrentHashMap<>(); 25 | 26 | /** 27 | * 获取节点信息 28 | */ 29 | public static Set getServiceKeys(ServiceKey serviceKey, AbstractMonitor monitor) { 30 | return getServiceKeys(serviceKey, ImmutableList.of(monitor)); 31 | } 32 | 33 | public static Set getServiceKeys(ServiceKey serviceKey, List monitors) { 34 | if (servicesMap.get(serviceKey) == null) { 35 | synchronized (ServiceFactory.class) { 36 | if (servicesMap.get(serviceKey) == null) { 37 | startMonitor(serviceKey.getRemoteKey(), monitors); 38 | } 39 | } 40 | } 41 | return servicesMap.computeIfAbsent(serviceKey, key -> new ConcurrentSkipListSet<>()); 42 | } 43 | 44 | /** 45 | * 开始监控 46 | */ 47 | private static void startMonitor(final String remoteKey, List monitors) { 48 | final Set result = new HashSet<>(); 49 | monitors.forEach(monitor -> { 50 | List registryConfigs = monitor.monitorRemoteKey(new RegistryConfigListenerImpl(remoteKey)); 51 | result.addAll(new HashSet<>(registryConfigs)); 52 | }); 53 | registry2ServiceMap(result); 54 | } 55 | 56 | private static void registry2ServiceMap(RegistryConfig config) { 57 | log.info("registry2ServiceMap" + config); 58 | config.getServers().forEach(service -> { 59 | //取出现有元素 60 | Set nodes = servicesMap.computeIfAbsent( 61 | new ServiceKey(config.getAppKey(), service.getService()), 62 | serviceKey -> new ConcurrentSkipListSet<>() 63 | ); 64 | //拼接 65 | nodes.addAll(new HashSet<>(TrpcServiceNode.fromRegistryConfig(config))); 66 | }); 67 | } 68 | 69 | private static void registry2ServiceMap(Set registryConfigs) { 70 | registryConfigs.forEach(ServiceFactory::registry2ServiceMap); 71 | } 72 | 73 | private static class RegistryConfigListenerImpl extends RegistryConfigListener { 74 | 75 | RegistryConfigListenerImpl(String remoteKey) { 76 | super(remoteKey); 77 | } 78 | 79 | @Override 80 | public void addServer(RegistryConfig config) { 81 | registry2ServiceMap(config); 82 | } 83 | 84 | @Override 85 | public void removeServer(ThriftServerInfo serverInfo) { 86 | Map> deleteNodes = new HashMap<>(); 87 | servicesMap.forEach((k, set) -> set.forEach(v -> { 88 | if (StringUtils.equals(v.getIp(), serverInfo.getIp()) && v.getPort() == serverInfo.getPort()) { 89 | deleteNodes.computeIfAbsent(k, key -> new HashSet<>()).add(v); 90 | } 91 | })); 92 | 93 | deleteNodes.forEach((k, set) -> servicesMap.get(k).removeAll(set)); 94 | } 95 | 96 | @Override 97 | public void updateServer(RegistryConfig config) { 98 | removeServer(config.getServerInfo()); 99 | addServer(config); 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /trpc-registry/trpc-registry-zookeeper/src/main/java/com/github/sofn/trpc/registry/zk/ZkMonitor.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.registry.zk; 2 | 3 | import com.github.sofn.trpc.core.AbstractMonitor; 4 | import com.github.sofn.trpc.core.config.RegistryConfig; 5 | import com.github.sofn.trpc.core.config.ThriftServerInfo; 6 | import com.github.sofn.trpc.core.monitor.RegistryConfigListener; 7 | import lombok.Setter; 8 | import lombok.extern.slf4j.Slf4j; 9 | import org.apache.curator.framework.CuratorFramework; 10 | import org.apache.curator.framework.CuratorFrameworkFactory; 11 | import org.apache.curator.framework.recipes.cache.PathChildrenCache; 12 | import org.apache.curator.retry.ExponentialBackoffRetry; 13 | 14 | import java.util.List; 15 | import java.util.stream.Collectors; 16 | 17 | /** 18 | * @author sofn 19 | * @version 1.0 Created at: 2016-09-26 14:38 20 | */ 21 | @Slf4j 22 | @Setter 23 | public class ZkMonitor extends AbstractMonitor { 24 | 25 | private String connectString; 26 | private int sessionTimeout = 3000; 27 | private int connectionTimeout = 100; 28 | private int retrySleepTime = 100; 29 | private int maxRetries = 3; 30 | 31 | private CuratorFramework client = null; 32 | 33 | private void initMonitor() { 34 | client = CuratorFrameworkFactory.builder() 35 | .connectString(connectString) 36 | .sessionTimeoutMs(sessionTimeout) 37 | .connectionTimeoutMs(connectionTimeout) 38 | .canBeReadOnly(false) 39 | .retryPolicy(new ExponentialBackoffRetry(retrySleepTime, maxRetries)) 40 | .namespace(ZkConstant.NAMESPACE) 41 | .build(); 42 | client.start(); 43 | client.getConnectionStateListenable().addListener((client1, newState) 44 | -> log.info("zookeeper client " + connectString + " change status: " + newState.name())); 45 | log.info("init zookeeper connect: " + connectString); 46 | } 47 | 48 | public CuratorFramework getClient() { 49 | if (this.client == null) { 50 | initMonitor(); 51 | } 52 | return client; 53 | } 54 | 55 | @Override 56 | public List monitorRemoteKey(RegistryConfigListener listener) { 57 | try { 58 | final PathChildrenCache childrenCache = new PathChildrenCache(getClient(), ZkConstant.SERVICES_DIR + listener.getRemoteKey(), true); 59 | childrenCache.getListenable().addListener( 60 | (client1, event) -> { 61 | switch (event.getType()) { 62 | case CHILD_ADDED: 63 | listener.addServer(RegistryConfig.parse(new String(event.getData().getData()))); 64 | log.info("CHILD_ADDED: " + event.getData().getPath()); 65 | break; 66 | case CHILD_REMOVED: 67 | listener.removeServer(nodeName2ServerInfo(event.getData().getPath())); 68 | log.info("CHILD_REMOVED: " + event.getData().getPath()); 69 | break; 70 | case CHILD_UPDATED: 71 | String newData = new String(event.getData().getData()); 72 | listener.updateServer(RegistryConfig.parse(newData)); 73 | log.info("CHILD_UPDATED: " + event.getData().getPath()); 74 | break; 75 | default: 76 | break; 77 | } 78 | }, ZkConstant.zkPool); 79 | childrenCache.start(PathChildrenCache.StartMode.BUILD_INITIAL_CACHE); 80 | return childrenCache.getCurrentData().stream().map(d -> RegistryConfig.parse(new String(d.getData()))).collect(Collectors.toList()); 81 | } catch (Exception e) { 82 | log.error("startMonitor error", e); 83 | } 84 | return null; 85 | } 86 | 87 | private ThriftServerInfo nodeName2ServerInfo(String path) { 88 | if (path.lastIndexOf("-") > 0) { 89 | return ThriftServerInfo.parse(path.substring(path.lastIndexOf("-") + 1)); 90 | } 91 | return null; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /trpc-server/src/main/java/com/github/sofn/trpc/server/netty/TNettyServer.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.server.netty; 2 | 3 | import com.github.sofn.trpc.core.exception.TRpcException; 4 | import com.github.sofn.trpc.core.utils.Threads; 5 | import io.netty.bootstrap.ServerBootstrap; 6 | import io.netty.buffer.PooledByteBufAllocator; 7 | import io.netty.channel.*; 8 | import io.netty.channel.nio.NioEventLoopGroup; 9 | import io.netty.channel.socket.SocketChannel; 10 | import io.netty.channel.socket.nio.NioServerSocketChannel; 11 | import io.netty.util.concurrent.DefaultThreadFactory; 12 | import org.apache.thrift.server.TServer; 13 | import org.slf4j.Logger; 14 | import org.slf4j.LoggerFactory; 15 | 16 | import java.util.concurrent.ExecutorService; 17 | import java.util.concurrent.Executors; 18 | import java.util.concurrent.TimeUnit; 19 | 20 | /** 21 | * Thrift NIO Server base on Netty. 22 | */ 23 | public class TNettyServer extends TServer { 24 | 25 | private static Logger logger = LoggerFactory.getLogger(TNettyServer.class); 26 | 27 | private NettyServerArgs args; 28 | private EventLoopGroup bossGroup; 29 | private EventLoopGroup workerGroup; 30 | private ExecutorService userThreadPool; 31 | private ChannelFuture f; 32 | 33 | public TNettyServer(NettyServerArgs args) { 34 | super(args); 35 | this.args = args; 36 | } 37 | 38 | @Override 39 | public void serve() { 40 | logger.info("Netty Server is starting"); 41 | 42 | args.validate(); 43 | 44 | ServerBootstrap b = configServer(); 45 | 46 | try { 47 | // start server 48 | if (args.ip != null && args.ip.length() > 0) { 49 | f = b.bind(args.ip, args.port).sync(); 50 | } else { 51 | f = b.bind(args.port).sync(); 52 | } 53 | logger.info("Netty Server started and listening on " + args.port); 54 | setServing(true); 55 | 56 | // register shutown hook 57 | Runtime.getRuntime().addShutdownHook(new ShutdownThread()); 58 | 59 | } catch (Exception e) { 60 | logger.error("Exception happen when start server", e); 61 | throw new TRpcException(e); 62 | } 63 | } 64 | 65 | /** 66 | * blocking to wait for close. 67 | */ 68 | public void waitForClose() throws InterruptedException { 69 | f.channel().closeFuture().sync(); 70 | } 71 | 72 | @Override 73 | public void stop() { 74 | logger.info("Netty server is stopping"); 75 | 76 | bossGroup.shutdownGracefully(); 77 | Threads.gracefulShutdown(userThreadPool, args.shutdownTimeoutMills, args.shutdownTimeoutMills, TimeUnit.SECONDS); 78 | workerGroup.shutdownGracefully(); 79 | 80 | logger.info("Netty server stoped"); 81 | } 82 | 83 | private ServerBootstrap configServer() { 84 | bossGroup = new NioEventLoopGroup(args.bossThreads, new DefaultThreadFactory("NettyBossGroup", true)); 85 | workerGroup = new NioEventLoopGroup(args.workerThreads, new DefaultThreadFactory("NettyWorkerGroup", true)); 86 | userThreadPool = Executors.newFixedThreadPool(args.userThreads, new DefaultThreadFactory("UserThreads", true)); 87 | 88 | final ThriftHandler thriftHandler = new ThriftHandler(this.processorFactory_, this.inputProtocolFactory_, 89 | this.outputProtocolFactory_, userThreadPool); 90 | 91 | ServerBootstrap b = new ServerBootstrap(); 92 | b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class) 93 | .childOption(ChannelOption.SO_REUSEADDR, true).childOption(ChannelOption.SO_KEEPALIVE, true) 94 | .childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT); 95 | 96 | if (args.socketTimeoutMills > 0) { 97 | b.childOption(ChannelOption.SO_TIMEOUT, args.socketTimeoutMills); 98 | } 99 | 100 | if (args.recvBuff > 0) { 101 | b.childOption(ChannelOption.SO_RCVBUF, args.recvBuff); 102 | } 103 | 104 | if (args.sendBuff > 0) { 105 | b.childOption(ChannelOption.SO_SNDBUF, args.sendBuff); 106 | } 107 | 108 | b.childHandler(new ChannelInitializer() { 109 | @Override 110 | public void initChannel(SocketChannel ch) throws Exception { 111 | ch.pipeline().addLast(createThriftFramedDecoder(), createThriftFramedEncoder(), thriftHandler); 112 | } 113 | }); 114 | 115 | return b; 116 | } 117 | 118 | private ChannelHandler createThriftFramedDecoder() { 119 | return new ThriftFramedDecoder(); 120 | } 121 | 122 | private ChannelHandler createThriftFramedEncoder() { 123 | return new ThriftFramedEncoder(); 124 | } 125 | 126 | class ShutdownThread extends Thread { 127 | @Override 128 | public void run() { 129 | TNettyServer.this.stop(); 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /trpc-registry/trpc-registry-zookeeper/src/main/java/com/github/sofn/trpc/registry/zk/ZkRegistry.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.registry.zk; 2 | 3 | import com.github.sofn.trpc.core.IRegistry; 4 | import com.github.sofn.trpc.core.config.RegistryConfig; 5 | import com.github.sofn.trpc.core.config.ThriftServerInfo; 6 | import com.github.sofn.trpc.core.exception.TRpcRegistryException; 7 | import lombok.Setter; 8 | import lombok.extern.slf4j.Slf4j; 9 | import org.apache.commons.lang3.StringUtils; 10 | import org.apache.curator.framework.CuratorFramework; 11 | import org.apache.curator.framework.CuratorFrameworkFactory; 12 | import org.apache.curator.framework.recipes.nodes.PersistentNode; 13 | import org.apache.curator.retry.ExponentialBackoffRetry; 14 | import org.apache.zookeeper.CreateMode; 15 | 16 | import java.util.Map; 17 | import java.util.concurrent.ConcurrentHashMap; 18 | import java.util.concurrent.TimeUnit; 19 | 20 | /** 21 | * Authors: sofn 22 | * Version: 1.0 Created at 2016-09-18 22:37. 23 | */ 24 | @Slf4j 25 | @Setter 26 | public class ZkRegistry implements IRegistry { 27 | public static final String registry = "zookeeper"; 28 | private static final Map> nodeNames = new ConcurrentHashMap<>(); 29 | private String connectString; 30 | private int sessionTimeout; 31 | private int connectionTimeout; 32 | private int retrySleepTime = 100; 33 | private int maxRetries = 3; 34 | 35 | private CuratorFramework client; 36 | 37 | public void initConnect() { 38 | client = CuratorFrameworkFactory.builder() 39 | .connectString(connectString) 40 | .sessionTimeoutMs(sessionTimeout) 41 | .connectionTimeoutMs(connectionTimeout) 42 | .canBeReadOnly(false) 43 | .retryPolicy(new ExponentialBackoffRetry(retrySleepTime, maxRetries)) 44 | .namespace(ZkConstant.NAMESPACE) 45 | .build(); 46 | client.start(); 47 | log.info("init zookeeper connect: " + connectString); 48 | } 49 | 50 | @Override 51 | public void registry(RegistryConfig registryConfig) { 52 | registryConfig.setRegistry(registry); 53 | try { 54 | String nodeName = registryConfig.getServerInfo().toString(); 55 | Map appKeyServers = nodeNames.computeIfAbsent(registryConfig.getAppKey(), (key) -> new ConcurrentHashMap<>()); 56 | if (appKeyServers.get(nodeName) != null) { 57 | log.error("server registry exists: " + nodeName); 58 | throw new TRpcRegistryException("server registry exists for key:" + nodeName); 59 | } 60 | String nodeValue = registryConfig.toJsonString(); 61 | PersistentNode node = new PersistentNode(client, CreateMode.EPHEMERAL, true, ZkConstant.SERVICES_DIR + registryConfig.getAppKey() + "/" + nodeName, nodeValue.getBytes()); 62 | node.start(); 63 | node.waitForInitialCreate(3, TimeUnit.SECONDS); 64 | appKeyServers.put(nodeName, node); 65 | String actualPath = node.getActualPath(); 66 | log.info("registry to zookeeper, node: " + actualPath + " value: " + nodeValue); 67 | } catch (Exception e) { 68 | if (e instanceof RuntimeException) { 69 | throw (RuntimeException) e; 70 | } else { 71 | log.error("registry error", e); 72 | } 73 | } 74 | } 75 | 76 | @Override 77 | public void modify(RegistryConfig registryConfig) { 78 | registryConfig.setRegistry(registry); 79 | try { 80 | String nodeName = registryConfig.getServerInfo().toString(); 81 | Map appKeyServers = nodeNames.computeIfAbsent(registryConfig.getAppKey(), (key) -> new ConcurrentHashMap<>()); 82 | PersistentNode node = appKeyServers.get(nodeName); 83 | if (node == null) { 84 | log.warn("server registry not exists " + nodeName + " try to registry"); 85 | registry(registryConfig); 86 | return; 87 | } 88 | String nodeValue = registryConfig.toJsonString(); 89 | node.setData(nodeValue.getBytes()); 90 | String actualPath = node.getActualPath(); 91 | log.info("zookeeper modify, node: " + actualPath + " value: " + nodeValue); 92 | } catch (Exception e) { 93 | log.error("modify error", e); 94 | } 95 | } 96 | 97 | @Override 98 | public boolean unRegistry(String appKey, ThriftServerInfo serverInfo) { 99 | try { 100 | Map appKeyServers = nodeNames.computeIfAbsent(appKey, (key) -> new ConcurrentHashMap<>()); 101 | PersistentNode node = appKeyServers.get(serverInfo.toString()); 102 | if (node != null) { 103 | log.info("unRegistry " + serverInfo + " actualPath: " + node.getActualPath()); 104 | node.close(); 105 | appKeyServers.remove(serverInfo.toString()); 106 | return true; 107 | } else { 108 | log.warn("unRegistry " + serverInfo + " node not found"); 109 | } 110 | } catch (Exception e) { 111 | log.error("unRegistry error, serverInfo: " + serverInfo, e); 112 | } 113 | return false; 114 | } 115 | 116 | } 117 | -------------------------------------------------------------------------------- /trpc-test/src/test/java/com/github/sofn/trpc/test/TrpcClientProxyTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.test; 2 | 3 | import com.github.sofn.trpc.client.TrpcClientProxy; 4 | import com.github.sofn.trpc.client.config.ClientArgs; 5 | import com.github.sofn.trpc.core.utils.ClassNameUtils; 6 | import com.github.sofn.trpc.demo.Hello; 7 | import com.github.sofn.trpc.registry.zk.ZkMonitor; 8 | import com.github.sofn.trpc.registry.zk.ZkRegistry; 9 | import com.github.sofn.trpc.server.ThriftServerPublisher; 10 | import com.github.sofn.trpc.server.config.ServerArgs; 11 | import com.github.sofn.trpc.test.monitor.ServiceFactoryTest; 12 | import com.github.sofn.trpc.utils.NumUtil; 13 | import com.google.common.collect.ImmutableList; 14 | import lombok.extern.slf4j.Slf4j; 15 | import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig; 16 | import org.apache.thrift.TException; 17 | import org.apache.thrift.async.AsyncMethodCallback; 18 | import org.junit.Before; 19 | import org.junit.Test; 20 | 21 | import java.util.concurrent.CountDownLatch; 22 | import java.util.concurrent.TimeUnit; 23 | 24 | import static java.util.concurrent.TimeUnit.MINUTES; 25 | import static org.junit.Assert.*; 26 | 27 | /** 28 | * @author sofn 29 | * @version 1.0 Created at: 2016-10-03 22:59 30 | */ 31 | @Slf4j 32 | public class TrpcClientProxyTest { 33 | private static final int MIN_CONN = 1; 34 | private static final int MAX_CONN = 1000; 35 | private static final String localAppKey = "clientkey"; 36 | private String appKey; 37 | 38 | private GenericKeyedObjectPoolConfig poolConfig; 39 | 40 | @Before 41 | public void init() throws InterruptedException { 42 | this.appKey = "proxytest" + NumUtil.nextNum(); 43 | ServiceFactoryTest serviceFactoryTest = new ServiceFactoryTest(); 44 | ServerArgs serverArgs = serviceFactoryTest.getServerArgs(this.appKey, "127.0.0.1", NumUtil.nextPort()); 45 | ZkRegistry zkRegistry = serviceFactoryTest.getZkRegistry(); 46 | serverArgs.setRegistrys(ImmutableList.of(zkRegistry)); 47 | 48 | ThriftServerPublisher publisher = new ThriftServerPublisher(serverArgs); 49 | Thread thread = new Thread(publisher::init); 50 | thread.setDaemon(true); 51 | thread.start(); 52 | TimeUnit.MILLISECONDS.sleep(400); 53 | 54 | poolConfig = new GenericKeyedObjectPoolConfig(); 55 | poolConfig.setMaxTotal(MAX_CONN); 56 | poolConfig.setMaxTotalPerKey(MAX_CONN); 57 | poolConfig.setMaxIdlePerKey(MAX_CONN); 58 | poolConfig.setMinIdlePerKey(MIN_CONN); 59 | poolConfig.setTestOnBorrow(true); 60 | poolConfig.setMinEvictableIdleTimeMillis(MINUTES.toMillis(1)); 61 | poolConfig.setSoftMinEvictableIdleTimeMillis(MINUTES.toMillis(1)); 62 | poolConfig.setJmxEnabled(false); 63 | } 64 | 65 | @Test 66 | public void testBlock() { 67 | ZkMonitor zkMonitor = new ZkMonitor(); 68 | zkMonitor.setConnectString("localhost:2181"); 69 | ClientArgs args = ClientArgs.builder() 70 | .poolConfig(poolConfig) 71 | .localAppKey(localAppKey) 72 | .remoteAppKey(appKey) 73 | .monitors(ImmutableList.of(zkMonitor)) 74 | .serviceInterface(ClassNameUtils.getClassName(Hello.class)) 75 | .timeout(100) 76 | .build(); 77 | 78 | TrpcClientProxy proxy = new TrpcClientProxy(); 79 | proxy.setClientArgs(args); 80 | Hello.Client client = proxy.client(); 81 | try { 82 | String response = client.hi("world"); 83 | System.out.println("response: " + response); 84 | } catch (TException e) { 85 | log.error("call error", e); 86 | } 87 | } 88 | 89 | 90 | @Test 91 | public void testAysnc() throws InterruptedException { 92 | ZkMonitor zkMonitor = new ZkMonitor(); 93 | zkMonitor.setConnectString("localhost:2181"); 94 | ClientArgs args = ClientArgs.builder() 95 | .poolConfig(poolConfig) 96 | .localAppKey(localAppKey) 97 | .remoteAppKey(appKey) 98 | .monitors(ImmutableList.of(zkMonitor)) 99 | .serviceInterface(ClassNameUtils.getClassName(Hello.class)) 100 | .timeout(100) 101 | .async(true) 102 | .build(); 103 | 104 | TrpcClientProxy proxy = new TrpcClientProxy(); 105 | proxy.setClientArgs(args); 106 | Hello.AsyncClient client = proxy.client(); 107 | CountDownLatch latch = new CountDownLatch(3); 108 | try { 109 | client.hi("world", new ProxyTestCallBack(latch)); 110 | client.hi("world2", new ProxyTestCallBack(latch)); 111 | client.hi("world3", new ProxyTestCallBack(latch)); 112 | } catch (TException e) { 113 | fail(); 114 | } 115 | latch.await(); 116 | } 117 | 118 | private class ProxyTestCallBack implements AsyncMethodCallback { 119 | private CountDownLatch latch; 120 | 121 | ProxyTestCallBack(CountDownLatch latch) { 122 | this.latch = latch; 123 | } 124 | 125 | @Override 126 | public void onComplete(Hello.AsyncClient.hi_call hi) { 127 | try { 128 | System.out.println("async response: " + hi.getResult()); 129 | latch.countDown(); 130 | } catch (TException e) { 131 | fail(); 132 | } 133 | } 134 | 135 | @Override 136 | public void onError(Exception e) { 137 | fail(); 138 | } 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn ( ) { 37 | echo "$*" 38 | } 39 | 40 | die ( ) { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 165 | if [[ "$(uname)" == "Darwin" ]] && [[ "$HOME" == "$PWD" ]]; then 166 | cd "$(dirname "$0")" 167 | fi 168 | 169 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 170 | -------------------------------------------------------------------------------- /trpc-client/src/main/java/com/github/sofn/trpc/client/TrpcClientProxy.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.client; 2 | 3 | import com.github.sofn.trpc.client.client.AbstractTrpcClient; 4 | import com.github.sofn.trpc.client.config.ClientArgs; 5 | import com.github.sofn.trpc.client.factory.ClientCluster; 6 | import com.github.sofn.trpc.core.config.ThriftServerInfo; 7 | import com.github.sofn.trpc.core.exception.TRpcException; 8 | import javassist.util.proxy.MethodHandler; 9 | import javassist.util.proxy.Proxy; 10 | import javassist.util.proxy.ProxyFactory; 11 | import lombok.Setter; 12 | import lombok.extern.slf4j.Slf4j; 13 | import org.apache.commons.lang3.tuple.Pair; 14 | import org.apache.thrift.async.AsyncMethodCallback; 15 | import org.apache.thrift.async.TAsyncClientManager; 16 | import org.apache.thrift.protocol.TProtocol; 17 | import org.apache.thrift.protocol.TProtocolFactory; 18 | import org.apache.thrift.transport.TNonblockingTransport; 19 | 20 | import java.lang.reflect.InvocationHandler; 21 | import java.lang.reflect.Method; 22 | 23 | /** 24 | * @author sofn 25 | * @version 1.0 Created at: 2016-09-19 16:05 26 | */ 27 | @Setter 28 | @Slf4j 29 | public class TrpcClientProxy { 30 | private ClientArgs clientArgs; 31 | 32 | @SuppressWarnings("unchecked") 33 | public T client() { 34 | Class clazz; 35 | String className = clientArgs.getServiceInterface() + (clientArgs.isAsync() ? "$AsyncClient" : "$Client"); 36 | try { 37 | clazz = Class.forName(className); 38 | } catch (ClassNotFoundException e) { 39 | log.error("class not found: " + className); 40 | throw new TRpcException(e); 41 | } 42 | 43 | ProxyFactory factory = new ProxyFactory(); 44 | factory.setSuperclass(clazz); 45 | 46 | try { 47 | T t; 48 | if (clientArgs.isAsync()) { 49 | t = (T) factory.create(new Class[]{TProtocolFactory.class, TAsyncClientManager.class, TNonblockingTransport.class}, new Object[]{null, null, null}); 50 | } else { 51 | t = (T) factory.create(new Class[]{TProtocol.class}, new Object[]{null}); 52 | } 53 | if (this.clientArgs.isAsync()) { 54 | ((Proxy) t).setHandler(asyncHandler(clazz)); 55 | } else { 56 | ((Proxy) t).setHandler(blockHandler(clazz)); 57 | } 58 | return t; 59 | } catch (Exception e) { 60 | log.error("proxy error", e); 61 | } 62 | return null; 63 | } 64 | 65 | @SuppressWarnings("unchecked") 66 | private MethodHandler blockHandler(final Class clazz) { 67 | return (o, method, method1, args) -> { 68 | Pair borrowClient = ClientCluster.getBlockClient(clientArgs); 69 | Object client = borrowClient.getValue().getClient(clazz); 70 | boolean success = false; 71 | long startTime = System.currentTimeMillis(); 72 | try { 73 | Object result = method.invoke(client, args); 74 | success = true; 75 | //将连接归还对象池 76 | clientArgs.getPoolProvider().returnConnection(borrowClient.getKey(), borrowClient.getValue()); 77 | return result; 78 | } catch (Exception e) { 79 | log.error("call rpc error", e); 80 | clientArgs.getPoolProvider().returnBrokenConnection(borrowClient.getKey(), borrowClient.getValue()); 81 | throw e; 82 | } finally { 83 | log.info("call " + method.getName() + " " + success + " time: " + (System.currentTimeMillis() - startTime)); 84 | } 85 | }; 86 | } 87 | 88 | @SuppressWarnings("unchecked") 89 | private MethodHandler asyncHandler(final Class clazz) { 90 | return (o, method, method1, args) -> { 91 | Pair borrowClient = ClientCluster.getBlockClient(clientArgs); 92 | Object client = borrowClient.getValue().getClient(clazz); 93 | try { 94 | if (args.length > 0 && args[args.length - 1] instanceof AsyncMethodCallback) { 95 | //代理AsyncMethodCallback 96 | args[args.length - 1] = java.lang.reflect.Proxy.newProxyInstance(AsyncMethodCallback.class.getClassLoader(), 97 | new Class[]{AsyncMethodCallback.class}, 98 | new AsyncMethodCallbackProxy(args[args.length - 1], clientArgs, borrowClient)); 99 | } 100 | return method.invoke(client, args); 101 | } catch (Exception e) { 102 | log.error("call rpc error", e); 103 | throw e; 104 | } 105 | }; 106 | } 107 | 108 | @SuppressWarnings("unchecked") 109 | private class AsyncMethodCallbackProxy implements InvocationHandler { 110 | private Object proxied; 111 | private long startTime = System.currentTimeMillis(); 112 | private ClientArgs clientArgs; 113 | private Pair borrowClient; 114 | 115 | private AsyncMethodCallbackProxy(Object proxied, ClientArgs clientArgs, Pair borrowClient) { 116 | this.proxied = proxied; 117 | this.clientArgs = clientArgs; 118 | this.borrowClient = borrowClient; 119 | } 120 | 121 | public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 122 | Object result; 123 | try { 124 | result = method.invoke(proxied, args); 125 | this.clientArgs.getPoolProvider().returnConnection(this.borrowClient.getKey(), this.borrowClient.getValue()); 126 | } catch (Exception e) { 127 | this.clientArgs.getPoolProvider().returnBrokenConnection(this.borrowClient.getKey(), this.borrowClient.getValue()); 128 | log.error("async rpc error", e); 129 | throw e; 130 | } 131 | log.info("call " + method.getName() + " time: " + (System.currentTimeMillis() - startTime)); 132 | return result; 133 | } 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /trpc-core/src/main/java/com/github/sofn/trpc/core/utils/NetUtils.java: -------------------------------------------------------------------------------- 1 | package com.github.sofn.trpc.core.utils; 2 | 3 | import org.apache.commons.lang3.math.NumberUtils; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import java.io.IOException; 8 | import java.net.InetAddress; 9 | import java.net.InetSocketAddress; 10 | import java.net.NetworkInterface; 11 | import java.net.ServerSocket; 12 | import java.util.Enumeration; 13 | import java.util.Random; 14 | import java.util.regex.Pattern; 15 | 16 | /** 17 | * IP and Port Helper for RPC 18 | */ 19 | 20 | public class NetUtils { 21 | 22 | private static final Logger logger = LoggerFactory.getLogger(NetUtils.class); 23 | 24 | public static final String LOCALHOST = "127.0.0.1"; 25 | 26 | public static final String ANYHOST = "0.0.0.0"; 27 | 28 | private static final int RND_PORT_START = 30000; 29 | 30 | private static final int RND_PORT_RANGE = 10000; 31 | 32 | private static final Random RANDOM = new Random(System.currentTimeMillis()); 33 | 34 | public static int getRandomPort() { 35 | return RND_PORT_START + RANDOM.nextInt(RND_PORT_RANGE); 36 | } 37 | 38 | public static int getAvailablePort() { 39 | ServerSocket ss = null; 40 | try { 41 | ss = new ServerSocket(); 42 | ss.bind(null); 43 | return ss.getLocalPort(); 44 | } catch (IOException e) { 45 | return getRandomPort(); 46 | } finally { 47 | if (ss != null) { 48 | try { 49 | ss.close(); 50 | } catch (IOException e) { 51 | } 52 | } 53 | } 54 | } 55 | 56 | public static int getAvailablePort(int port) { 57 | if (port <= 0) { 58 | return getAvailablePort(); 59 | } 60 | for (int i = port; i < MAX_PORT; i++) { 61 | ServerSocket ss = null; 62 | try { 63 | ss = new ServerSocket(i); 64 | return i; 65 | } catch (IOException e) { 66 | // continue 67 | } finally { 68 | if (ss != null) { 69 | try { 70 | ss.close(); 71 | } catch (IOException e) { 72 | } 73 | } 74 | } 75 | } 76 | return port; 77 | } 78 | 79 | private static final int MIN_PORT = 0; 80 | 81 | private static final int MAX_PORT = 65535; 82 | 83 | public static boolean isInvalidPort(int port) { 84 | return port > MIN_PORT || port <= MAX_PORT; 85 | } 86 | 87 | private static final Pattern ADDRESS_PATTERN = Pattern.compile("^\\d{1,3}(\\.\\d{1,3}){3}\\:\\d{1,5}$"); 88 | 89 | public static boolean isValidAddress(String address) { 90 | return ADDRESS_PATTERN.matcher(address).matches(); 91 | } 92 | 93 | private static final Pattern LOCAL_IP_PATTERN = Pattern.compile("127(\\.\\d{1,3}){3}$"); 94 | 95 | public static boolean isLocalHost(String host) { 96 | return host != null 97 | && (LOCAL_IP_PATTERN.matcher(host).matches() 98 | || host.equalsIgnoreCase("localhost")); 99 | } 100 | 101 | public static boolean isAnyHost(String host) { 102 | return "0.0.0.0".equals(host); 103 | } 104 | 105 | public static boolean isInvalidLocalHost(String host) { 106 | return host == null 107 | || host.length() == 0 108 | || host.equalsIgnoreCase("localhost") 109 | || host.equals("0.0.0.0") 110 | || (LOCAL_IP_PATTERN.matcher(host).matches()); 111 | } 112 | 113 | public static boolean isValidLocalHost(String host) { 114 | return !isInvalidLocalHost(host); 115 | } 116 | 117 | public static InetSocketAddress getLocalSocketAddress(String host, int port) { 118 | return isInvalidLocalHost(host) ? new InetSocketAddress(port) : new InetSocketAddress(host, port); 119 | } 120 | 121 | private static final Pattern IP_PATTERN = Pattern.compile("\\d{1,3}(\\.\\d{1,3}){3,5}$"); 122 | 123 | private static boolean isValidAddress(InetAddress address) { 124 | if (address == null || address.isLoopbackAddress()) 125 | return false; 126 | String name = address.getHostAddress(); 127 | return (name != null 128 | && !ANYHOST.equals(name) 129 | && !LOCALHOST.equals(name) 130 | && IP_PATTERN.matcher(name).matches() 131 | && !name.startsWith("172.17")); 132 | } 133 | 134 | public static String getLocalHost() { 135 | InetAddress address = getLocalAddress(); 136 | return address == null ? LOCALHOST : address.getHostAddress(); 137 | } 138 | 139 | private static volatile InetAddress LOCAL_ADDRESS = null; 140 | 141 | /** 142 | * 遍历本地网卡,返回第一个合理的IP。 143 | * 144 | * @return 本地网卡IP 145 | */ 146 | public static InetAddress getLocalAddress() { 147 | if (LOCAL_ADDRESS != null) { 148 | return LOCAL_ADDRESS; 149 | } 150 | InetAddress localAddress = getLocalAddress0(); 151 | LOCAL_ADDRESS = localAddress; 152 | return localAddress; 153 | } 154 | 155 | private static InetAddress getLocalAddress0() { 156 | InetAddress localAddress = null; 157 | try { 158 | localAddress = InetAddress.getLocalHost(); 159 | if (isValidAddress(localAddress)) { 160 | return localAddress; 161 | } 162 | } catch (Throwable e) { 163 | logger.warn("Failed to retriving ip address, " + e.getMessage(), e); 164 | } 165 | try { 166 | Enumeration interfaces = NetworkInterface.getNetworkInterfaces(); 167 | if (interfaces != null) { 168 | while (interfaces.hasMoreElements()) { 169 | try { 170 | NetworkInterface network = interfaces.nextElement(); 171 | Enumeration addresses = network.getInetAddresses(); 172 | while (addresses.hasMoreElements()) { 173 | try { 174 | InetAddress address = addresses.nextElement(); 175 | if (isValidAddress(address)) { 176 | if (localAddress != null) { 177 | String[] split = address.getHostAddress().split("\\."); 178 | byte[] bytes = new byte[split.length]; 179 | for (int i = 0; i < split.length; i++) { 180 | bytes[i] = (byte) NumberUtils.toInt(split[i]); 181 | } 182 | return InetAddress.getByAddress(localAddress.getHostName(), bytes); 183 | } else { 184 | return address; 185 | } 186 | } 187 | } catch (Throwable e) { 188 | logger.warn("Failed to retriving ip address, " + e.getMessage(), e); 189 | } 190 | } 191 | } catch (Throwable e) { 192 | logger.warn("Failed to retriving ip address, " + e.getMessage(), e); 193 | } 194 | } 195 | } 196 | } catch (Throwable e) { 197 | logger.warn("Failed to retriving ip address, " + e.getMessage(), e); 198 | } 199 | logger.error("Could not get local host ip address, will use 127.0.0.1 instead."); 200 | return localAddress; 201 | } 202 | 203 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, and 10 | distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by the copyright 13 | owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all other entities 16 | that control, are controlled by, or are under common control with that entity. 17 | For the purposes of this definition, "control" means (i) the power, direct or 18 | indirect, to cause the direction or management of such entity, whether by 19 | contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the 20 | outstanding shares, or (iii) beneficial ownership of such entity. 21 | 22 | "You" (or "Your") shall mean an individual or Legal Entity exercising 23 | permissions granted by this License. 24 | 25 | "Source" form shall mean the preferred form for making modifications, including 26 | but not limited to software source code, documentation source, and configuration 27 | files. 28 | 29 | "Object" form shall mean any form resulting from mechanical transformation or 30 | translation of a Source form, including but not limited to compiled object code, 31 | generated documentation, and conversions to other media types. 32 | 33 | "Work" shall mean the work of authorship, whether in Source or Object form, made 34 | available under the License, as indicated by a copyright notice that is included 35 | in or attached to the work (an example is provided in the Appendix below). 36 | 37 | "Derivative Works" shall mean any work, whether in Source or Object form, that 38 | is based on (or derived from) the Work and for which the editorial revisions, 39 | annotations, elaborations, or other modifications represent, as a whole, an 40 | original work of authorship. For the purposes of this License, Derivative Works 41 | shall not include works that remain separable from, or merely link (or bind by 42 | name) to the interfaces of, the Work and Derivative Works thereof. 43 | 44 | "Contribution" shall mean any work of authorship, including the original version 45 | of the Work and any modifications or additions to that Work or Derivative Works 46 | thereof, that is intentionally submitted to Licensor for inclusion in the Work 47 | by the copyright owner or by an individual or Legal Entity authorized to submit 48 | on behalf of the copyright owner. For the purposes of this definition, 49 | "submitted" means any form of electronic, verbal, or written communication sent 50 | to the Licensor or its representatives, including but not limited to 51 | communication on electronic mailing lists, source code control systems, and 52 | issue tracking systems that are managed by, or on behalf of, the Licensor for 53 | the purpose of discussing and improving the Work, but excluding communication 54 | that is conspicuously marked or otherwise designated in writing by the copyright 55 | owner as "Not a Contribution." 56 | 57 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf 58 | of whom a Contribution has been received by Licensor and subsequently 59 | incorporated within the Work. 60 | 61 | 2. Grant of Copyright License. 62 | 63 | Subject to the terms and conditions of this License, each Contributor hereby 64 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, 65 | irrevocable copyright license to reproduce, prepare Derivative Works of, 66 | publicly display, publicly perform, sublicense, and distribute the Work and such 67 | Derivative Works in Source or Object form. 68 | 69 | 3. Grant of Patent License. 70 | 71 | Subject to the terms and conditions of this License, each Contributor hereby 72 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, 73 | irrevocable (except as stated in this section) patent license to make, have 74 | made, use, offer to sell, sell, import, and otherwise transfer the Work, where 75 | such license applies only to those patent claims licensable by such Contributor 76 | that are necessarily infringed by their Contribution(s) alone or by combination 77 | of their Contribution(s) with the Work to which such Contribution(s) was 78 | submitted. If You institute patent litigation against any entity (including a 79 | cross-claim or counterclaim in a lawsuit) alleging that the Work or a 80 | Contribution incorporated within the Work constitutes direct or contributory 81 | patent infringement, then any patent licenses granted to You under this License 82 | for that Work shall terminate as of the date such litigation is filed. 83 | 84 | 4. Redistribution. 85 | 86 | You may reproduce and distribute copies of the Work or Derivative Works thereof 87 | in any medium, with or without modifications, and in Source or Object form, 88 | provided that You meet the following conditions: 89 | 90 | You must give any other recipients of the Work or Derivative Works a copy of 91 | this License; and 92 | You must cause any modified files to carry prominent notices stating that You 93 | changed the files; and 94 | You must retain, in the Source form of any Derivative Works that You distribute, 95 | all copyright, patent, trademark, and attribution notices from the Source form 96 | of the Work, excluding those notices that do not pertain to any part of the 97 | Derivative Works; and 98 | If the Work includes a "NOTICE" text file as part of its distribution, then any 99 | Derivative Works that You distribute must include a readable copy of the 100 | attribution notices contained within such NOTICE file, excluding those notices 101 | that do not pertain to any part of the Derivative Works, in at least one of the 102 | following places: within a NOTICE text file distributed as part of the 103 | Derivative Works; within the Source form or documentation, if provided along 104 | with the Derivative Works; or, within a display generated by the Derivative 105 | Works, if and wherever such third-party notices normally appear. The contents of 106 | the NOTICE file are for informational purposes only and do not modify the 107 | License. You may add Your own attribution notices within Derivative Works that 108 | You distribute, alongside or as an addendum to the NOTICE text from the Work, 109 | provided that such additional attribution notices cannot be construed as 110 | modifying the License. 111 | You may add Your own copyright statement to Your modifications and may provide 112 | additional or different license terms and conditions for use, reproduction, or 113 | distribution of Your modifications, or for any such Derivative Works as a whole, 114 | provided Your use, reproduction, and distribution of the Work otherwise complies 115 | with the conditions stated in this License. 116 | 117 | 5. Submission of Contributions. 118 | 119 | Unless You explicitly state otherwise, any Contribution intentionally submitted 120 | for inclusion in the Work by You to the Licensor shall be under the terms and 121 | conditions of this License, without any additional terms or conditions. 122 | Notwithstanding the above, nothing herein shall supersede or modify the terms of 123 | any separate license agreement you may have executed with Licensor regarding 124 | such Contributions. 125 | 126 | 6. Trademarks. 127 | 128 | This License does not grant permission to use the trade names, trademarks, 129 | service marks, or product names of the Licensor, except as required for 130 | reasonable and customary use in describing the origin of the Work and 131 | reproducing the content of the NOTICE file. 132 | 133 | 7. Disclaimer of Warranty. 134 | 135 | Unless required by applicable law or agreed to in writing, Licensor provides the 136 | Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, 137 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, 138 | including, without limitation, any warranties or conditions of TITLE, 139 | NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are 140 | solely responsible for determining the appropriateness of using or 141 | redistributing the Work and assume any risks associated with Your exercise of 142 | permissions under this License. 143 | 144 | 8. Limitation of Liability. 145 | 146 | In no event and under no legal theory, whether in tort (including negligence), 147 | contract, or otherwise, unless required by applicable law (such as deliberate 148 | and grossly negligent acts) or agreed to in writing, shall any Contributor be 149 | liable to You for damages, including any direct, indirect, special, incidental, 150 | or consequential damages of any character arising as a result of this License or 151 | out of the use or inability to use the Work (including but not limited to 152 | damages for loss of goodwill, work stoppage, computer failure or malfunction, or 153 | any and all other commercial damages or losses), even if such Contributor has 154 | been advised of the possibility of such damages. 155 | 156 | 9. Accepting Warranty or Additional Liability. 157 | 158 | While redistributing the Work or Derivative Works thereof, You may choose to 159 | offer, and charge a fee for, acceptance of support, warranty, indemnity, or 160 | other liability obligations and/or rights consistent with this License. However, 161 | in accepting such obligations, You may act only on Your own behalf and on Your 162 | sole responsibility, not on behalf of any other Contributor, and only if You 163 | agree to indemnify, defend, and hold each Contributor harmless for any liability 164 | incurred by, or claims asserted against, such Contributor by reason of your 165 | accepting any such warranty or additional liability. 166 | 167 | END OF TERMS AND CONDITIONS 168 | 169 | APPENDIX: How to apply the Apache License to your work 170 | 171 | To apply the Apache License to your work, attach the following boilerplate 172 | notice, with the fields enclosed by brackets "{}" replaced with your own 173 | identifying information. (Don't include the brackets!) The text should be 174 | enclosed in the appropriate comment syntax for the file format. We also 175 | recommend that a file or class name and description of purpose be included on 176 | the same "printed page" as the copyright notice for easier identification within 177 | third-party archives. 178 | 179 | Copyright 2016 sofn 180 | 181 | Licensed under the Apache License, Version 2.0 (the "License"); 182 | you may not use this file except in compliance with the License. 183 | You may obtain a copy of the License at 184 | 185 | http://www.apache.org/licenses/LICENSE-2.0 186 | 187 | Unless required by applicable law or agreed to in writing, software 188 | distributed under the License is distributed on an "AS IS" BASIS, 189 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 190 | See the License for the specific language governing permissions and 191 | limitations under the License. -------------------------------------------------------------------------------- /trpc-core/src/test/java/com/github/sofn/trpc/demo/Hello.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Autogenerated by Thrift Compiler (0.9.3) 3 | * 4 | * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING 5 | * @generated 6 | */ 7 | package com.github.sofn.trpc.demo; 8 | 9 | import org.apache.thrift.scheme.IScheme; 10 | import org.apache.thrift.scheme.SchemeFactory; 11 | import org.apache.thrift.scheme.StandardScheme; 12 | 13 | import org.apache.thrift.scheme.TupleScheme; 14 | import org.apache.thrift.protocol.TTupleProtocol; 15 | import org.apache.thrift.protocol.TProtocolException; 16 | import org.apache.thrift.EncodingUtils; 17 | import org.apache.thrift.TException; 18 | import org.apache.thrift.async.AsyncMethodCallback; 19 | import org.apache.thrift.server.AbstractNonblockingServer.*; 20 | import java.util.List; 21 | import java.util.ArrayList; 22 | import java.util.Map; 23 | import java.util.HashMap; 24 | import java.util.EnumMap; 25 | import java.util.Set; 26 | import java.util.HashSet; 27 | import java.util.EnumSet; 28 | import java.util.Collections; 29 | import java.util.BitSet; 30 | import java.nio.ByteBuffer; 31 | import java.util.Arrays; 32 | import javax.annotation.Generated; 33 | import org.slf4j.Logger; 34 | import org.slf4j.LoggerFactory; 35 | 36 | @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked"}) 37 | @Generated(value = "Autogenerated by Thrift Compiler (0.9.3)", date = "2016-09-23") 38 | public class Hello { 39 | 40 | public interface Iface { 41 | 42 | public String hi(String name) throws org.apache.thrift.TException; 43 | 44 | } 45 | 46 | public interface AsyncIface { 47 | 48 | public void hi(String name, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException; 49 | 50 | } 51 | 52 | public static class Client extends org.apache.thrift.TServiceClient implements Iface { 53 | public static class Factory implements org.apache.thrift.TServiceClientFactory { 54 | public Factory() {} 55 | public Client getClient(org.apache.thrift.protocol.TProtocol prot) { 56 | return new Client(prot); 57 | } 58 | public Client getClient(org.apache.thrift.protocol.TProtocol iprot, org.apache.thrift.protocol.TProtocol oprot) { 59 | return new Client(iprot, oprot); 60 | } 61 | } 62 | 63 | public Client(org.apache.thrift.protocol.TProtocol prot) 64 | { 65 | super(prot, prot); 66 | } 67 | 68 | public Client(org.apache.thrift.protocol.TProtocol iprot, org.apache.thrift.protocol.TProtocol oprot) { 69 | super(iprot, oprot); 70 | } 71 | 72 | public String hi(String name) throws org.apache.thrift.TException 73 | { 74 | send_hi(name); 75 | return recv_hi(); 76 | } 77 | 78 | public void send_hi(String name) throws org.apache.thrift.TException 79 | { 80 | hi_args args = new hi_args(); 81 | args.setName(name); 82 | sendBase("hi", args); 83 | } 84 | 85 | public String recv_hi() throws org.apache.thrift.TException 86 | { 87 | hi_result result = new hi_result(); 88 | receiveBase(result, "hi"); 89 | if (result.isSetSuccess()) { 90 | return result.success; 91 | } 92 | throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "hi failed: unknown result"); 93 | } 94 | 95 | } 96 | public static class AsyncClient extends org.apache.thrift.async.TAsyncClient implements AsyncIface { 97 | public static class Factory implements org.apache.thrift.async.TAsyncClientFactory { 98 | private org.apache.thrift.async.TAsyncClientManager clientManager; 99 | private org.apache.thrift.protocol.TProtocolFactory protocolFactory; 100 | public Factory(org.apache.thrift.async.TAsyncClientManager clientManager, org.apache.thrift.protocol.TProtocolFactory protocolFactory) { 101 | this.clientManager = clientManager; 102 | this.protocolFactory = protocolFactory; 103 | } 104 | public AsyncClient getAsyncClient(org.apache.thrift.transport.TNonblockingTransport transport) { 105 | return new AsyncClient(protocolFactory, clientManager, transport); 106 | } 107 | } 108 | 109 | public AsyncClient(org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.async.TAsyncClientManager clientManager, org.apache.thrift.transport.TNonblockingTransport transport) { 110 | super(protocolFactory, clientManager, transport); 111 | } 112 | 113 | public void hi(String name, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException { 114 | checkReady(); 115 | hi_call method_call = new hi_call(name, resultHandler, this, ___protocolFactory, ___transport); 116 | this.___currentMethod = method_call; 117 | ___manager.call(method_call); 118 | } 119 | 120 | public static class hi_call extends org.apache.thrift.async.TAsyncMethodCall { 121 | private String name; 122 | public hi_call(String name, org.apache.thrift.async.AsyncMethodCallback resultHandler, org.apache.thrift.async.TAsyncClient client, org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.transport.TNonblockingTransport transport) throws org.apache.thrift.TException { 123 | super(client, protocolFactory, transport, resultHandler, false); 124 | this.name = name; 125 | } 126 | 127 | public void write_args(org.apache.thrift.protocol.TProtocol prot) throws org.apache.thrift.TException { 128 | prot.writeMessageBegin(new org.apache.thrift.protocol.TMessage("hi", org.apache.thrift.protocol.TMessageType.CALL, 0)); 129 | hi_args args = new hi_args(); 130 | args.setName(name); 131 | args.write(prot); 132 | prot.writeMessageEnd(); 133 | } 134 | 135 | public String getResult() throws org.apache.thrift.TException { 136 | if (getState() != org.apache.thrift.async.TAsyncMethodCall.State.RESPONSE_READ) { 137 | throw new IllegalStateException("Method call not finished!"); 138 | } 139 | org.apache.thrift.transport.TMemoryInputTransport memoryTransport = new org.apache.thrift.transport.TMemoryInputTransport(getFrameBuffer().array()); 140 | org.apache.thrift.protocol.TProtocol prot = client.getProtocolFactory().getProtocol(memoryTransport); 141 | return (new Client(prot)).recv_hi(); 142 | } 143 | } 144 | 145 | } 146 | 147 | public static class Processor extends org.apache.thrift.TBaseProcessor implements org.apache.thrift.TProcessor { 148 | private static final Logger LOGGER = LoggerFactory.getLogger(Processor.class.getName()); 149 | public Processor(I iface) { 150 | super(iface, getProcessMap(new HashMap>())); 151 | } 152 | 153 | protected Processor(I iface, Map> processMap) { 154 | super(iface, getProcessMap(processMap)); 155 | } 156 | 157 | private static Map> getProcessMap(Map> processMap) { 158 | processMap.put("hi", new hi()); 159 | return processMap; 160 | } 161 | 162 | public static class hi extends org.apache.thrift.ProcessFunction { 163 | public hi() { 164 | super("hi"); 165 | } 166 | 167 | public hi_args getEmptyArgsInstance() { 168 | return new hi_args(); 169 | } 170 | 171 | protected boolean isOneway() { 172 | return false; 173 | } 174 | 175 | public hi_result getResult(I iface, hi_args args) throws org.apache.thrift.TException { 176 | hi_result result = new hi_result(); 177 | result.success = iface.hi(args.name); 178 | return result; 179 | } 180 | } 181 | 182 | } 183 | 184 | public static class AsyncProcessor extends org.apache.thrift.TBaseAsyncProcessor { 185 | private static final Logger LOGGER = LoggerFactory.getLogger(AsyncProcessor.class.getName()); 186 | public AsyncProcessor(I iface) { 187 | super(iface, getProcessMap(new HashMap>())); 188 | } 189 | 190 | protected AsyncProcessor(I iface, Map> processMap) { 191 | super(iface, getProcessMap(processMap)); 192 | } 193 | 194 | private static Map> getProcessMap(Map> processMap) { 195 | processMap.put("hi", new hi()); 196 | return processMap; 197 | } 198 | 199 | public static class hi extends org.apache.thrift.AsyncProcessFunction { 200 | public hi() { 201 | super("hi"); 202 | } 203 | 204 | public hi_args getEmptyArgsInstance() { 205 | return new hi_args(); 206 | } 207 | 208 | public AsyncMethodCallback getResultHandler(final AsyncFrameBuffer fb, final int seqid) { 209 | final org.apache.thrift.AsyncProcessFunction fcall = this; 210 | return new AsyncMethodCallback() { 211 | public void onComplete(String o) { 212 | hi_result result = new hi_result(); 213 | result.success = o; 214 | try { 215 | fcall.sendResponse(fb,result, org.apache.thrift.protocol.TMessageType.REPLY,seqid); 216 | return; 217 | } catch (Exception e) { 218 | LOGGER.error("Exception writing to internal frame buffer", e); 219 | } 220 | fb.close(); 221 | } 222 | public void onError(Exception e) { 223 | byte msgType = org.apache.thrift.protocol.TMessageType.REPLY; 224 | org.apache.thrift.TBase msg; 225 | hi_result result = new hi_result(); 226 | { 227 | msgType = org.apache.thrift.protocol.TMessageType.EXCEPTION; 228 | msg = (org.apache.thrift.TBase)new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.INTERNAL_ERROR, e.getMessage()); 229 | } 230 | try { 231 | fcall.sendResponse(fb,msg,msgType,seqid); 232 | return; 233 | } catch (Exception ex) { 234 | LOGGER.error("Exception writing to internal frame buffer", ex); 235 | } 236 | fb.close(); 237 | } 238 | }; 239 | } 240 | 241 | protected boolean isOneway() { 242 | return false; 243 | } 244 | 245 | public void start(I iface, hi_args args, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws TException { 246 | iface.hi(args.name,resultHandler); 247 | } 248 | } 249 | 250 | } 251 | 252 | public static class hi_args implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { 253 | private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("hi_args"); 254 | 255 | private static final org.apache.thrift.protocol.TField NAME_FIELD_DESC = new org.apache.thrift.protocol.TField("name", org.apache.thrift.protocol.TType.STRING, (short)1); 256 | 257 | private static final Map, SchemeFactory> schemes = new HashMap, SchemeFactory>(); 258 | static { 259 | schemes.put(StandardScheme.class, new hi_argsStandardSchemeFactory()); 260 | schemes.put(TupleScheme.class, new hi_argsTupleSchemeFactory()); 261 | } 262 | 263 | public String name; // required 264 | 265 | /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */ 266 | public enum _Fields implements org.apache.thrift.TFieldIdEnum { 267 | NAME((short)1, "name"); 268 | 269 | private static final Map byName = new HashMap(); 270 | 271 | static { 272 | for (_Fields field : EnumSet.allOf(_Fields.class)) { 273 | byName.put(field.getFieldName(), field); 274 | } 275 | } 276 | 277 | /** 278 | * Find the _Fields constant that matches fieldId, or null if its not found. 279 | */ 280 | public static _Fields findByThriftId(int fieldId) { 281 | switch(fieldId) { 282 | case 1: // NAME 283 | return NAME; 284 | default: 285 | return null; 286 | } 287 | } 288 | 289 | /** 290 | * Find the _Fields constant that matches fieldId, throwing an exception 291 | * if it is not found. 292 | */ 293 | public static _Fields findByThriftIdOrThrow(int fieldId) { 294 | _Fields fields = findByThriftId(fieldId); 295 | if (fields == null) throw new IllegalArgumentException("Field " + fieldId + " doesn't exist!"); 296 | return fields; 297 | } 298 | 299 | /** 300 | * Find the _Fields constant that matches name, or null if its not found. 301 | */ 302 | public static _Fields findByName(String name) { 303 | return byName.get(name); 304 | } 305 | 306 | private final short _thriftId; 307 | private final String _fieldName; 308 | 309 | _Fields(short thriftId, String fieldName) { 310 | _thriftId = thriftId; 311 | _fieldName = fieldName; 312 | } 313 | 314 | public short getThriftFieldId() { 315 | return _thriftId; 316 | } 317 | 318 | public String getFieldName() { 319 | return _fieldName; 320 | } 321 | } 322 | 323 | // isset id assignments 324 | public static final Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap; 325 | static { 326 | Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class); 327 | tmpMap.put(_Fields.NAME, new org.apache.thrift.meta_data.FieldMetaData("name", org.apache.thrift.TFieldRequirementType.DEFAULT, 328 | new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING))); 329 | metaDataMap = Collections.unmodifiableMap(tmpMap); 330 | org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(hi_args.class, metaDataMap); 331 | } 332 | 333 | public hi_args() { 334 | } 335 | 336 | public hi_args( 337 | String name) 338 | { 339 | this(); 340 | this.name = name; 341 | } 342 | 343 | /** 344 | * Performs a deep copy on other. 345 | */ 346 | public hi_args(hi_args other) { 347 | if (other.isSetName()) { 348 | this.name = other.name; 349 | } 350 | } 351 | 352 | public hi_args deepCopy() { 353 | return new hi_args(this); 354 | } 355 | 356 | @Override 357 | public void clear() { 358 | this.name = null; 359 | } 360 | 361 | public String getName() { 362 | return this.name; 363 | } 364 | 365 | public hi_args setName(String name) { 366 | this.name = name; 367 | return this; 368 | } 369 | 370 | public void unsetName() { 371 | this.name = null; 372 | } 373 | 374 | /** Returns true if field name is set (has been assigned a value) and false otherwise */ 375 | public boolean isSetName() { 376 | return this.name != null; 377 | } 378 | 379 | public void setNameIsSet(boolean value) { 380 | if (!value) { 381 | this.name = null; 382 | } 383 | } 384 | 385 | public void setFieldValue(_Fields field, Object value) { 386 | switch (field) { 387 | case NAME: 388 | if (value == null) { 389 | unsetName(); 390 | } else { 391 | setName((String)value); 392 | } 393 | break; 394 | 395 | } 396 | } 397 | 398 | public Object getFieldValue(_Fields field) { 399 | switch (field) { 400 | case NAME: 401 | return getName(); 402 | 403 | } 404 | throw new IllegalStateException(); 405 | } 406 | 407 | /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */ 408 | public boolean isSet(_Fields field) { 409 | if (field == null) { 410 | throw new IllegalArgumentException(); 411 | } 412 | 413 | switch (field) { 414 | case NAME: 415 | return isSetName(); 416 | } 417 | throw new IllegalStateException(); 418 | } 419 | 420 | @Override 421 | public boolean equals(Object that) { 422 | if (that == null) 423 | return false; 424 | if (that instanceof hi_args) 425 | return this.equals((hi_args)that); 426 | return false; 427 | } 428 | 429 | public boolean equals(hi_args that) { 430 | if (that == null) 431 | return false; 432 | 433 | boolean this_present_name = true && this.isSetName(); 434 | boolean that_present_name = true && that.isSetName(); 435 | if (this_present_name || that_present_name) { 436 | if (!(this_present_name && that_present_name)) 437 | return false; 438 | if (!this.name.equals(that.name)) 439 | return false; 440 | } 441 | 442 | return true; 443 | } 444 | 445 | @Override 446 | public int hashCode() { 447 | List list = new ArrayList(); 448 | 449 | boolean present_name = true && (isSetName()); 450 | list.add(present_name); 451 | if (present_name) 452 | list.add(name); 453 | 454 | return list.hashCode(); 455 | } 456 | 457 | @Override 458 | public int compareTo(hi_args other) { 459 | if (!getClass().equals(other.getClass())) { 460 | return getClass().getName().compareTo(other.getClass().getName()); 461 | } 462 | 463 | int lastComparison = 0; 464 | 465 | lastComparison = Boolean.valueOf(isSetName()).compareTo(other.isSetName()); 466 | if (lastComparison != 0) { 467 | return lastComparison; 468 | } 469 | if (isSetName()) { 470 | lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.name, other.name); 471 | if (lastComparison != 0) { 472 | return lastComparison; 473 | } 474 | } 475 | return 0; 476 | } 477 | 478 | public _Fields fieldForId(int fieldId) { 479 | return _Fields.findByThriftId(fieldId); 480 | } 481 | 482 | public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException { 483 | schemes.get(iprot.getScheme()).getScheme().read(iprot, this); 484 | } 485 | 486 | public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException { 487 | schemes.get(oprot.getScheme()).getScheme().write(oprot, this); 488 | } 489 | 490 | @Override 491 | public String toString() { 492 | StringBuilder sb = new StringBuilder("hi_args("); 493 | boolean first = true; 494 | 495 | sb.append("name:"); 496 | if (this.name == null) { 497 | sb.append("null"); 498 | } else { 499 | sb.append(this.name); 500 | } 501 | first = false; 502 | sb.append(")"); 503 | return sb.toString(); 504 | } 505 | 506 | public void validate() throws org.apache.thrift.TException { 507 | // check for required fields 508 | // check for sub-struct validity 509 | } 510 | 511 | private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException { 512 | try { 513 | write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out))); 514 | } catch (org.apache.thrift.TException te) { 515 | throw new java.io.IOException(te); 516 | } 517 | } 518 | 519 | private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, ClassNotFoundException { 520 | try { 521 | read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in))); 522 | } catch (org.apache.thrift.TException te) { 523 | throw new java.io.IOException(te); 524 | } 525 | } 526 | 527 | private static class hi_argsStandardSchemeFactory implements SchemeFactory { 528 | public hi_argsStandardScheme getScheme() { 529 | return new hi_argsStandardScheme(); 530 | } 531 | } 532 | 533 | private static class hi_argsStandardScheme extends StandardScheme { 534 | 535 | public void read(org.apache.thrift.protocol.TProtocol iprot, hi_args struct) throws org.apache.thrift.TException { 536 | org.apache.thrift.protocol.TField schemeField; 537 | iprot.readStructBegin(); 538 | while (true) 539 | { 540 | schemeField = iprot.readFieldBegin(); 541 | if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { 542 | break; 543 | } 544 | switch (schemeField.id) { 545 | case 1: // NAME 546 | if (schemeField.type == org.apache.thrift.protocol.TType.STRING) { 547 | struct.name = iprot.readString(); 548 | struct.setNameIsSet(true); 549 | } else { 550 | org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); 551 | } 552 | break; 553 | default: 554 | org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); 555 | } 556 | iprot.readFieldEnd(); 557 | } 558 | iprot.readStructEnd(); 559 | 560 | // check for required fields of primitive type, which can't be checked in the validate method 561 | struct.validate(); 562 | } 563 | 564 | public void write(org.apache.thrift.protocol.TProtocol oprot, hi_args struct) throws org.apache.thrift.TException { 565 | struct.validate(); 566 | 567 | oprot.writeStructBegin(STRUCT_DESC); 568 | if (struct.name != null) { 569 | oprot.writeFieldBegin(NAME_FIELD_DESC); 570 | oprot.writeString(struct.name); 571 | oprot.writeFieldEnd(); 572 | } 573 | oprot.writeFieldStop(); 574 | oprot.writeStructEnd(); 575 | } 576 | 577 | } 578 | 579 | private static class hi_argsTupleSchemeFactory implements SchemeFactory { 580 | public hi_argsTupleScheme getScheme() { 581 | return new hi_argsTupleScheme(); 582 | } 583 | } 584 | 585 | private static class hi_argsTupleScheme extends TupleScheme { 586 | 587 | @Override 588 | public void write(org.apache.thrift.protocol.TProtocol prot, hi_args struct) throws org.apache.thrift.TException { 589 | TTupleProtocol oprot = (TTupleProtocol) prot; 590 | BitSet optionals = new BitSet(); 591 | if (struct.isSetName()) { 592 | optionals.set(0); 593 | } 594 | oprot.writeBitSet(optionals, 1); 595 | if (struct.isSetName()) { 596 | oprot.writeString(struct.name); 597 | } 598 | } 599 | 600 | @Override 601 | public void read(org.apache.thrift.protocol.TProtocol prot, hi_args struct) throws org.apache.thrift.TException { 602 | TTupleProtocol iprot = (TTupleProtocol) prot; 603 | BitSet incoming = iprot.readBitSet(1); 604 | if (incoming.get(0)) { 605 | struct.name = iprot.readString(); 606 | struct.setNameIsSet(true); 607 | } 608 | } 609 | } 610 | 611 | } 612 | 613 | public static class hi_result implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { 614 | private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("hi_result"); 615 | 616 | private static final org.apache.thrift.protocol.TField SUCCESS_FIELD_DESC = new org.apache.thrift.protocol.TField("success", org.apache.thrift.protocol.TType.STRING, (short)0); 617 | 618 | private static final Map, SchemeFactory> schemes = new HashMap, SchemeFactory>(); 619 | static { 620 | schemes.put(StandardScheme.class, new hi_resultStandardSchemeFactory()); 621 | schemes.put(TupleScheme.class, new hi_resultTupleSchemeFactory()); 622 | } 623 | 624 | public String success; // required 625 | 626 | /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */ 627 | public enum _Fields implements org.apache.thrift.TFieldIdEnum { 628 | SUCCESS((short)0, "success"); 629 | 630 | private static final Map byName = new HashMap(); 631 | 632 | static { 633 | for (_Fields field : EnumSet.allOf(_Fields.class)) { 634 | byName.put(field.getFieldName(), field); 635 | } 636 | } 637 | 638 | /** 639 | * Find the _Fields constant that matches fieldId, or null if its not found. 640 | */ 641 | public static _Fields findByThriftId(int fieldId) { 642 | switch(fieldId) { 643 | case 0: // SUCCESS 644 | return SUCCESS; 645 | default: 646 | return null; 647 | } 648 | } 649 | 650 | /** 651 | * Find the _Fields constant that matches fieldId, throwing an exception 652 | * if it is not found. 653 | */ 654 | public static _Fields findByThriftIdOrThrow(int fieldId) { 655 | _Fields fields = findByThriftId(fieldId); 656 | if (fields == null) throw new IllegalArgumentException("Field " + fieldId + " doesn't exist!"); 657 | return fields; 658 | } 659 | 660 | /** 661 | * Find the _Fields constant that matches name, or null if its not found. 662 | */ 663 | public static _Fields findByName(String name) { 664 | return byName.get(name); 665 | } 666 | 667 | private final short _thriftId; 668 | private final String _fieldName; 669 | 670 | _Fields(short thriftId, String fieldName) { 671 | _thriftId = thriftId; 672 | _fieldName = fieldName; 673 | } 674 | 675 | public short getThriftFieldId() { 676 | return _thriftId; 677 | } 678 | 679 | public String getFieldName() { 680 | return _fieldName; 681 | } 682 | } 683 | 684 | // isset id assignments 685 | public static final Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap; 686 | static { 687 | Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class); 688 | tmpMap.put(_Fields.SUCCESS, new org.apache.thrift.meta_data.FieldMetaData("success", org.apache.thrift.TFieldRequirementType.DEFAULT, 689 | new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING))); 690 | metaDataMap = Collections.unmodifiableMap(tmpMap); 691 | org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(hi_result.class, metaDataMap); 692 | } 693 | 694 | public hi_result() { 695 | } 696 | 697 | public hi_result( 698 | String success) 699 | { 700 | this(); 701 | this.success = success; 702 | } 703 | 704 | /** 705 | * Performs a deep copy on other. 706 | */ 707 | public hi_result(hi_result other) { 708 | if (other.isSetSuccess()) { 709 | this.success = other.success; 710 | } 711 | } 712 | 713 | public hi_result deepCopy() { 714 | return new hi_result(this); 715 | } 716 | 717 | @Override 718 | public void clear() { 719 | this.success = null; 720 | } 721 | 722 | public String getSuccess() { 723 | return this.success; 724 | } 725 | 726 | public hi_result setSuccess(String success) { 727 | this.success = success; 728 | return this; 729 | } 730 | 731 | public void unsetSuccess() { 732 | this.success = null; 733 | } 734 | 735 | /** Returns true if field success is set (has been assigned a value) and false otherwise */ 736 | public boolean isSetSuccess() { 737 | return this.success != null; 738 | } 739 | 740 | public void setSuccessIsSet(boolean value) { 741 | if (!value) { 742 | this.success = null; 743 | } 744 | } 745 | 746 | public void setFieldValue(_Fields field, Object value) { 747 | switch (field) { 748 | case SUCCESS: 749 | if (value == null) { 750 | unsetSuccess(); 751 | } else { 752 | setSuccess((String)value); 753 | } 754 | break; 755 | 756 | } 757 | } 758 | 759 | public Object getFieldValue(_Fields field) { 760 | switch (field) { 761 | case SUCCESS: 762 | return getSuccess(); 763 | 764 | } 765 | throw new IllegalStateException(); 766 | } 767 | 768 | /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */ 769 | public boolean isSet(_Fields field) { 770 | if (field == null) { 771 | throw new IllegalArgumentException(); 772 | } 773 | 774 | switch (field) { 775 | case SUCCESS: 776 | return isSetSuccess(); 777 | } 778 | throw new IllegalStateException(); 779 | } 780 | 781 | @Override 782 | public boolean equals(Object that) { 783 | if (that == null) 784 | return false; 785 | if (that instanceof hi_result) 786 | return this.equals((hi_result)that); 787 | return false; 788 | } 789 | 790 | public boolean equals(hi_result that) { 791 | if (that == null) 792 | return false; 793 | 794 | boolean this_present_success = true && this.isSetSuccess(); 795 | boolean that_present_success = true && that.isSetSuccess(); 796 | if (this_present_success || that_present_success) { 797 | if (!(this_present_success && that_present_success)) 798 | return false; 799 | if (!this.success.equals(that.success)) 800 | return false; 801 | } 802 | 803 | return true; 804 | } 805 | 806 | @Override 807 | public int hashCode() { 808 | List list = new ArrayList(); 809 | 810 | boolean present_success = true && (isSetSuccess()); 811 | list.add(present_success); 812 | if (present_success) 813 | list.add(success); 814 | 815 | return list.hashCode(); 816 | } 817 | 818 | @Override 819 | public int compareTo(hi_result other) { 820 | if (!getClass().equals(other.getClass())) { 821 | return getClass().getName().compareTo(other.getClass().getName()); 822 | } 823 | 824 | int lastComparison = 0; 825 | 826 | lastComparison = Boolean.valueOf(isSetSuccess()).compareTo(other.isSetSuccess()); 827 | if (lastComparison != 0) { 828 | return lastComparison; 829 | } 830 | if (isSetSuccess()) { 831 | lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.success, other.success); 832 | if (lastComparison != 0) { 833 | return lastComparison; 834 | } 835 | } 836 | return 0; 837 | } 838 | 839 | public _Fields fieldForId(int fieldId) { 840 | return _Fields.findByThriftId(fieldId); 841 | } 842 | 843 | public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException { 844 | schemes.get(iprot.getScheme()).getScheme().read(iprot, this); 845 | } 846 | 847 | public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException { 848 | schemes.get(oprot.getScheme()).getScheme().write(oprot, this); 849 | } 850 | 851 | @Override 852 | public String toString() { 853 | StringBuilder sb = new StringBuilder("hi_result("); 854 | boolean first = true; 855 | 856 | sb.append("success:"); 857 | if (this.success == null) { 858 | sb.append("null"); 859 | } else { 860 | sb.append(this.success); 861 | } 862 | first = false; 863 | sb.append(")"); 864 | return sb.toString(); 865 | } 866 | 867 | public void validate() throws org.apache.thrift.TException { 868 | // check for required fields 869 | // check for sub-struct validity 870 | } 871 | 872 | private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException { 873 | try { 874 | write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out))); 875 | } catch (org.apache.thrift.TException te) { 876 | throw new java.io.IOException(te); 877 | } 878 | } 879 | 880 | private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, ClassNotFoundException { 881 | try { 882 | read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in))); 883 | } catch (org.apache.thrift.TException te) { 884 | throw new java.io.IOException(te); 885 | } 886 | } 887 | 888 | private static class hi_resultStandardSchemeFactory implements SchemeFactory { 889 | public hi_resultStandardScheme getScheme() { 890 | return new hi_resultStandardScheme(); 891 | } 892 | } 893 | 894 | private static class hi_resultStandardScheme extends StandardScheme { 895 | 896 | public void read(org.apache.thrift.protocol.TProtocol iprot, hi_result struct) throws org.apache.thrift.TException { 897 | org.apache.thrift.protocol.TField schemeField; 898 | iprot.readStructBegin(); 899 | while (true) 900 | { 901 | schemeField = iprot.readFieldBegin(); 902 | if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { 903 | break; 904 | } 905 | switch (schemeField.id) { 906 | case 0: // SUCCESS 907 | if (schemeField.type == org.apache.thrift.protocol.TType.STRING) { 908 | struct.success = iprot.readString(); 909 | struct.setSuccessIsSet(true); 910 | } else { 911 | org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); 912 | } 913 | break; 914 | default: 915 | org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); 916 | } 917 | iprot.readFieldEnd(); 918 | } 919 | iprot.readStructEnd(); 920 | 921 | // check for required fields of primitive type, which can't be checked in the validate method 922 | struct.validate(); 923 | } 924 | 925 | public void write(org.apache.thrift.protocol.TProtocol oprot, hi_result struct) throws org.apache.thrift.TException { 926 | struct.validate(); 927 | 928 | oprot.writeStructBegin(STRUCT_DESC); 929 | if (struct.success != null) { 930 | oprot.writeFieldBegin(SUCCESS_FIELD_DESC); 931 | oprot.writeString(struct.success); 932 | oprot.writeFieldEnd(); 933 | } 934 | oprot.writeFieldStop(); 935 | oprot.writeStructEnd(); 936 | } 937 | 938 | } 939 | 940 | private static class hi_resultTupleSchemeFactory implements SchemeFactory { 941 | public hi_resultTupleScheme getScheme() { 942 | return new hi_resultTupleScheme(); 943 | } 944 | } 945 | 946 | private static class hi_resultTupleScheme extends TupleScheme { 947 | 948 | @Override 949 | public void write(org.apache.thrift.protocol.TProtocol prot, hi_result struct) throws org.apache.thrift.TException { 950 | TTupleProtocol oprot = (TTupleProtocol) prot; 951 | BitSet optionals = new BitSet(); 952 | if (struct.isSetSuccess()) { 953 | optionals.set(0); 954 | } 955 | oprot.writeBitSet(optionals, 1); 956 | if (struct.isSetSuccess()) { 957 | oprot.writeString(struct.success); 958 | } 959 | } 960 | 961 | @Override 962 | public void read(org.apache.thrift.protocol.TProtocol prot, hi_result struct) throws org.apache.thrift.TException { 963 | TTupleProtocol iprot = (TTupleProtocol) prot; 964 | BitSet incoming = iprot.readBitSet(1); 965 | if (incoming.get(0)) { 966 | struct.success = iprot.readString(); 967 | struct.setSuccessIsSet(true); 968 | } 969 | } 970 | } 971 | 972 | } 973 | 974 | } 975 | --------------------------------------------------------------------------------