├── .gitignore ├── .travis.yml ├── README.md ├── pom.xml ├── samples ├── python │ └── proxy_client.py └── ruby │ └── proxy_client.rb └── src ├── main └── scala │ └── com │ └── github.sstone │ └── amqp │ └── proxy │ ├── AmqpProxy.scala │ ├── App.scala │ ├── Serializers.scala │ └── serializers │ ├── JsonSerializer.scala │ ├── ProtobufSerializer.scala │ ├── SnappySerializer.scala │ └── ThriftSerializer.scala └── test ├── java └── com │ └── github.sstone │ └── amqp │ └── proxy │ ├── calculator │ └── Calculator.java │ ├── gpbtest │ └── Gpbtest.java │ └── thrifttest │ └── Person.java ├── resource ├── calculator.proto ├── gpbtest.proto └── reference.conf └── scala └── com └── github.sstone └── amqp └── proxy ├── ErrorTest.scala ├── RemoteGpbCallTest.scala ├── RemoteJsonCallTest.scala └── SerializationTest.scala /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | *.log 3 | 4 | # sbt specific 5 | dist/* 6 | target/ 7 | lib_managed/ 8 | src_managed/ 9 | project/boot/ 10 | project/plugins/project/ 11 | 12 | # Scala-IDE specific 13 | .scala_dependencies 14 | /.idea 15 | /*.iml 16 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: scala 2 | scala: 3 | - 2.10.0 4 | jdk: 5 | - oraclejdk7 6 | - openjdk7 7 | services: 8 | - rabbitmq -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Akka AMQP Proxies 2 | 3 | ## Overview 4 | 5 | “AMQP proxies” is a simple way of integrating AMQP with Akka to distribute jobs across a network of computing nodes. 6 | You still write “local” code, have very little to configure, and end up with a distributed, elastic, 7 | fault-tolerant grid where computing nodes can be written in nearly every programming language. 8 | 9 | This project started as a demo for [http://letitcrash.com/post/29988753572/akka-amqp-proxies](http://letitcrash.com/post/29988753572/akka-amqp-proxies) and 10 | is now used in a few "real" projects. 11 | 12 | The original code has been improved, with the addition of: 13 | * on-the-fly compression with snappy 14 | * a protobuf serializer (thanks to PM47!) 15 | * a thrift serializer 16 | 17 | [![Build Status](https://travis-ci.org/sstone/akka-amqp-proxies.png)](https://travis-ci.org/sstone/akka-amqp-proxies) 18 | 19 | ## Configuring maven/sbt 20 | 21 | ```xml 22 | 23 | 24 | sonatype snapshots 25 | https://oss.sonatype.org/content/repositories/snapshots/ 26 | 27 | 28 | 29 | 30 | 31 | com.github.sstone 32 | akka-amqp-proxies_SCALA-VERSION 33 | 1.3 34 | 35 | 36 | com.typesafe.akka 37 | akka-actor_SCALA-VERSION 38 | AKKA-VERSION 39 | 40 | 41 | ``` 42 | 43 | From version 1.1X on, snapshots are published to https://oss.sonatype.org/content/repositories/snapshots/ and releases 44 | are synced to Maven Central 45 | 46 | * version 1.1 (master branch) is compatible with Scala 2.9.2 and Akka 2.0.5 47 | * version 1.1 (scala2.10 branch) is compatible with Scala 2.10 and Akka 2.1.0 48 | * version 1.3 (scala2.10 branch) is compatible with Scala 2.10.X and Akka 2.1.X 49 | * version 1.4 (scala2.10 branch) targets Scala 2.10.X and Akka 2.2.X 50 | 51 | ## Calculator demo 52 | 53 | The demo is simple: 54 | 55 | * start with write a basic local calculator actor that can add numbers 56 | * "proxify" it over AMQP, using JSON serialization 57 | * you can now start as many calculator servers as you want, and you get an elastic, fault-tolerant, load-balanced calculator grid 58 | 59 | To start the demo with local actors: 60 | 61 | * mvn exec:java -Dexec.mainClass=com.github.sstone.amqp.proxy.Local 62 | 63 | To start the demo with a client proxy and remote server actors: 64 | 65 | * mvn exec:java -Dexec.classpathScope=compile -Dexec.mainClass=com.github.sstone.amqp.proxy.Server (as many times as you want) 66 | * mvn exec:java -Dexec.classpathScope=compile -Dexec.mainClass=com.github.sstone.amqp.proxy.Client 67 | 68 | ## Using Protobuf/Thrift serialization 69 | 70 | Please check [https://github.com/sstone/akka-amqp-proxies/blob/scala2.10/src/test/scala/com/github.sstone/amqp/proxy/RemoteGpbCallTest.scala] for an example 71 | of how to use Protobuf: I've defined a simple protobuf command language, generated java sources and added them to the project: 72 | 73 | ``` protobuf 74 | package com.github.sstone.amqp.proxy.calculator; 75 | 76 | // simple calculator API 77 | 78 | // add request 79 | // 80 | message AddRequest { 81 | required int32 x = 1; 82 | required int32 y = 2; 83 | } 84 | 85 | // Add response 86 | // 87 | message AddResponse { 88 | required int32 x = 1; 89 | required int32 y = 2; 90 | required int32 sum = 3; 91 | } 92 | ``` 93 | 94 | Now I can exchange AddRequest and AddResponse messages transparently: 95 | 96 | ```scala 97 | proxy ? AddRequest.newBuilder.setX(x).setY(y).build()).mapTo[AddResponse] 98 | ``` 99 | 100 | You would follow the same steps to use Thrift instead of Protobuf. 101 | Of course, in a real project, you would generate java sources at compilation time (using either one the of protobuf maven plugins or just the ant plugin). 102 | It should be fairly simple to write compatible sample clients and servers with Python or Ruby to demonstrate interroperrability 103 | 104 | ## Calling actors from other languages (python, ruby, ...) 105 | 106 | AMQP defines a binary protocol, and there are many AMQP clients available (PHP, python, ruby, java, scala, C#, haskell, ....) 107 | If you choose a standard message format, you can easily call Akka actors though AMQP proxies. 108 | So, let's see how we would call our "calculator" actor from other languages. The pattern is very simple and based on "standard" AMQP RPC: 109 | * create an exclusive, auto-delete reply queue (usually with a random broker-generated name) 110 | * publish serialized AddRequest messages with the following properties 111 | * reply-to = name of the reply queue 112 | * content-type = message type (the name of the class of the message we're sending, com.github.sstone.amqp.proxy.Demo$AddRequest in our case) 113 | * content-encoding = message format (json in our case) 114 | * wait for a response, which should be an AddResponse(x, y, sum) message in JSON format 115 | 116 | To run the client samples, don't forget to start the server with mvn exec:java -Dexec.classpathScope=compile -Dexec.mainClass=com.github.sstone.amqp.proxy.Server 117 | 118 | ### From python (using [pika](https://github.com/pika/pika)) 119 | 120 | ```python 121 | import pika 122 | import uuid 123 | import json 124 | 125 | class CalculatorRpcClient(object): 126 | def __init__(self): 127 | self.connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost')) 128 | 129 | self.channel = self.connection.channel() 130 | 131 | result = self.channel.queue_declare(exclusive=True) 132 | self.callback_queue = result.method.queue 133 | 134 | self.channel.basic_consume(self.on_response, no_ack=True, queue=self.callback_queue) 135 | 136 | def on_response(self, ch, method, props, body): 137 | if self.corr_id == props.correlation_id: 138 | self.response = body 139 | 140 | def add(self, x, y): 141 | self.response = None 142 | self.corr_id = str(uuid.uuid4()) 143 | msg = json.dumps({ "x":x, "y":y }) 144 | self.channel.basic_publish(exchange='', 145 | routing_key='calculator', 146 | properties=pika.BasicProperties( 147 | reply_to = self.callback_queue, 148 | correlation_id = self.corr_id, 149 | content_type = 'com.github.sstone.amqp.proxy.Demo$AddRequest', 150 | content_encoding = 'json' 151 | ), 152 | body=msg) 153 | while self.response is None: 154 | self.connection.process_data_events() 155 | raw = self.response 156 | decoded = json.loads(raw) 157 | return decoded['sum'] 158 | 159 | calculator_rpc = CalculatorRpcClient() 160 | 161 | x = 1 162 | y = 2 163 | print " [x] Requesting ", x, " + ", y 164 | response = calculator_rpc.add(x, y) 165 | print " [.] Got %r" % (response,) 166 | ``` 167 | 168 | ### From ruby (using [ruby-amqp](https://github.com/ruby-amqp/amqp)) 169 | 170 | ```ruby 171 | require 'amqp' 172 | require 'json' 173 | require 'securerandom' 174 | 175 | x = 1 176 | y = 2 177 | 178 | EventMachine.run do 179 | connection = AMQP.connect(:host => '127.0.0.1') 180 | puts "Connecting to AMQP broker. Running #{AMQP::VERSION} version of the gem..." 181 | 182 | channel = AMQP::Channel.new(connection) 183 | exchange = channel.default_exchange 184 | 185 | # create a JSON AddRequest message 186 | request = JSON.generate({:x => x, :y => y}) 187 | 188 | # "standard" RPC pattern: create an exclusive private queue with a unique, randomized, broker-generated name 189 | # and publish message with the 'reply-to' property set to the name of this reply queue 190 | reply_queue = channel.queue("", :exclusive => true, :auto_delete => true) do |queue| 191 | exchange.publish request, { 192 | :routing_key => "calculator", 193 | :correlation_id => SecureRandom.uuid, 194 | :reply_to => queue.name, 195 | :content_encoding => "json", 196 | :content_type => "com.github.sstone.amqp.proxy.Demo$AddRequest" 197 | } 198 | end 199 | reply_queue.subscribe do |metadata, payload| 200 | puts "raw esponse for #{metadata.correlation_id}: #{metadata.content_encoding} #{metadata.content_type} #{payload.inspect}" 201 | 202 | # payload shoud look like { "x" : x, "y" : y, "sum" : sum } 203 | response = JSON.parse(payload) 204 | puts "#{x} + #{y} = #{response['sum']}" 205 | 206 | connection.close { 207 | EventMachine.stop { exit } 208 | } 209 | end 210 | 211 | end 212 | ``` 213 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | org.sonatype.oss 5 | oss-parent 6 | 7 7 | 8 | com.github.sstone 9 | akka-amqp-proxies_2.10 10 | 1.4-SNAPSHOT 11 | jar 12 | ${project.artifactId} 13 | AMQP "proxies" for Akka 14 | https://github.com/sstone/akka-amqp-proxies 15 | 16 | 17 | 1.7 18 | 1.7 19 | UTF-8 20 | 2.10.3 21 | 2.2.3 22 | 23 | 24 | 25 | 26 | https://raw.github.com/sstone/akka-amqp-proxies/master/LICENCE.txt 27 | The MIT License 28 | repo 29 | 30 | 31 | 32 | 33 | scm:git:git@github.com:sstone/akka-amqp-proxies.git 34 | scm:git:git@github.com:sstone/akka-amqp-proxies.git 35 | git@github.com:sstone/akka-amqp-proxies.git 36 | 37 | 38 | 39 | 40 | sstone 41 | samuel.stone@hotmail.co.za 42 | 43 | 44 | pm47 45 | 46 | 47 | 48 | 49 | src/main/scala 50 | 51 | 52 | org.apache.maven.plugins 53 | maven-compiler-plugin 54 | 2.3.2 55 | 56 | 1.7 57 | 1.7 58 | 59 | 60 | 61 | compile 62 | 63 | compile 64 | 65 | 66 | 67 | 68 | 69 | org.apache.maven.plugins 70 | maven-source-plugin 71 | 2.1.2 72 | 73 | 74 | attach-sources 75 | 76 | jar 77 | 78 | 79 | 80 | 81 | 82 | net.alchim31.maven 83 | scala-maven-plugin 84 | 3.1.6 85 | 86 | 87 | process-resources 88 | process-resources 89 | 90 | compile 91 | 92 | 93 | 94 | 95 | compile 96 | testCompile 97 | 98 | 99 | 100 | attach-javadocs 101 | 102 | doc-jar 103 | 104 | 105 | 106 | 107 | 108 | org.apache.maven.plugins 109 | maven-surefire-plugin 110 | 2.10 111 | 112 | false 113 | true 114 | 115 | 116 | 117 | **/*Spec.* 118 | **/*Test.* 119 | **/*Suite.* 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | sonatype snapshots 129 | https://oss.sonatype.org/content/repositories/snapshots/ 130 | 131 | 132 | 133 | 134 | 135 | com.github.sstone 136 | amqp-client_2.10 137 | 1.3-ML4 138 | 139 | 140 | com.typesafe.akka 141 | akka-actor_2.10 142 | ${akka.version} 143 | provided 144 | 145 | 146 | ch.qos.logback 147 | logback-classic 148 | 1.0.9 149 | runtime 150 | 151 | 152 | org.json4s 153 | json4s-jackson_2.10 154 | 3.2.6 155 | 156 | 157 | com.google.protobuf 158 | protobuf-java 159 | 2.4.1 160 | 161 | 162 | org.apache.thrift 163 | libthrift 164 | 0.9.0 165 | 166 | 167 | org.xerial.snappy 168 | snappy-java 169 | 1.0.5-M3 170 | 171 | 172 | 173 | com.typesafe.akka 174 | akka-testkit_2.10 175 | ${akka.version} 176 | test 177 | 178 | 179 | org.scalatest 180 | scalatest_2.10 181 | 1.9 182 | test 183 | 184 | 185 | junit 186 | junit 187 | 4.8.2 188 | test 189 | 190 | 191 | 192 | 193 | 194 | release-sign-artifacts 195 | 196 | 197 | performRelease 198 | true 199 | 200 | 201 | 202 | 203 | 204 | org.apache.maven.plugins 205 | maven-gpg-plugin 206 | 207 | 208 | sign-artifacts 209 | verify 210 | 211 | sign 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | -------------------------------------------------------------------------------- /samples/python/proxy_client.py: -------------------------------------------------------------------------------- 1 | import pika 2 | import uuid 3 | import json 4 | 5 | class CalculatorRpcClient(object): 6 | def __init__(self): 7 | self.connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost')) 8 | 9 | self.channel = self.connection.channel() 10 | 11 | result = self.channel.queue_declare(exclusive=True) 12 | self.callback_queue = result.method.queue 13 | 14 | self.channel.basic_consume(self.on_response, no_ack=True, queue=self.callback_queue) 15 | 16 | def on_response(self, ch, method, props, body): 17 | if self.corr_id == props.correlation_id: 18 | self.response = body 19 | 20 | def add(self, x, y): 21 | self.response = None 22 | self.corr_id = str(uuid.uuid4()) 23 | msg = json.dumps({ "x":x, "y":y }) 24 | self.channel.basic_publish(exchange='', 25 | routing_key='calculator', 26 | properties=pika.BasicProperties( 27 | reply_to = self.callback_queue, 28 | correlation_id = self.corr_id, 29 | content_type = 'com.github.sstone.amqp.proxy.Demo$AddRequest', 30 | content_encoding = 'json' 31 | ), 32 | body=msg) 33 | while self.response is None: 34 | self.connection.process_data_events() 35 | raw = self.response 36 | decoded = json.loads(raw) 37 | return decoded['sum'] 38 | 39 | calculator_rpc = CalculatorRpcClient() 40 | 41 | x = 1 42 | y = 2 43 | print " [x] Requesting ", x, " + ", y 44 | response = calculator_rpc.add(x, y) 45 | print " [.] Got %r" % (response,) -------------------------------------------------------------------------------- /samples/ruby/proxy_client.rb: -------------------------------------------------------------------------------- 1 | require 'amqp' 2 | require 'json' 3 | require 'securerandom' 4 | 5 | x = 1 6 | y = 2 7 | 8 | EventMachine.run do 9 | connection = AMQP.connect(:host => '127.0.0.1') 10 | puts "Connecting to AMQP broker. Running #{AMQP::VERSION} version of the gem..." 11 | 12 | channel = AMQP::Channel.new(connection) 13 | exchange = channel.default_exchange 14 | 15 | # create a JSON AddRequest message 16 | request = JSON.generate({:x => x, :y => y}) 17 | 18 | # "standard" RPC pattern: create an exclusive private queue with a unique, randomized, broker-generated name 19 | # and publish message with the 'reply-to' property set to the name of this reply queue 20 | reply_queue = channel.queue("", :exclusive => true, :auto_delete => true) do |queue| 21 | exchange.publish request, { 22 | :routing_key => "calculator", 23 | :correlation_id => SecureRandom.uuid, 24 | :reply_to => queue.name, 25 | :content_encoding => "json", 26 | :content_type => "com.github.sstone.amqp.proxy.Demo$AddRequest" 27 | } 28 | end 29 | reply_queue.subscribe do |metadata, payload| 30 | puts "raw esponse for #{metadata.correlation_id}: #{metadata.content_encoding} #{metadata.content_type} #{payload.inspect}" 31 | 32 | # payload shoud look like { "x" : x, "y" : y, "sum" : sum } 33 | response = JSON.parse(payload) 34 | puts "#{x} + #{y} = #{response['sum']}" 35 | 36 | connection.close { 37 | EventMachine.stop { exit } 38 | } 39 | end 40 | 41 | end -------------------------------------------------------------------------------- /src/main/scala/com/github.sstone/amqp/proxy/AmqpProxy.scala: -------------------------------------------------------------------------------- 1 | package com.github.sstone.amqp.proxy 2 | 3 | import akka.actor.{Props, ActorLogging, Actor, ActorRef} 4 | import akka.serialization.Serializer 5 | import akka.pattern.{ask, pipe} 6 | import akka.util.Timeout 7 | import concurrent.{ExecutionContext, Future, Await} 8 | import concurrent.duration._ 9 | import util.{Try, Failure, Success} 10 | import com.rabbitmq.client.AMQP.BasicProperties 11 | import com.rabbitmq.client.AMQP 12 | import org.slf4j.LoggerFactory 13 | import serializers.JsonSerializer 14 | import com.github.sstone.amqp.{Amqp, RpcClient, RpcServer} 15 | import com.github.sstone.amqp.RpcServer.ProcessResult 16 | import com.github.sstone.amqp.Amqp.{Publish, Delivery} 17 | 18 | /** 19 | * Thrown when an error occurred on the "server" side and was sent back to the client 20 | * If you have a server Actor and create an AMQP proxy for it, then: 21 | * {{{ 22 | * proxy ? message 23 | * }}} 24 | * will behave as if you had written; 25 | * {{{ 26 | * server ? message 27 | * }}} 28 | * and server had sent back an `akka.actor.Status.ServerFailure(new AmqpProxyException(message)))` 29 | * @param message error message 30 | */ 31 | class AmqpProxyException(message: String, throwableAsString: String) extends RuntimeException(message) 32 | 33 | object AmqpProxy { 34 | 35 | /** 36 | * "server" side failure, that will be serialized and sent back to the client proxy 37 | * @param message error message 38 | */ 39 | private case class ServerFailure(message: String, throwableAsString: String) 40 | 41 | /** 42 | * serialize a message and return a (blob, AMQP properties) tuple. The following convention is used for the AMQP properties 43 | * the message will be sent with: 44 | * 48 | * @param msg input message 49 | * @param serializer serializer 50 | * @param deliveryMode AMQP delivery mode that will be included in the returned AMQP properties 51 | * @return a (blob, properties) tuple where blob is the serialized message and properties the AMQP properties the message 52 | * should be sent with. 53 | */ 54 | def serialize(msg: AnyRef, serializer: Serializer, deliveryMode: Int = 1) = { 55 | val body = serializer.toBinary(msg) 56 | val props = new BasicProperties.Builder().contentEncoding(Serializers.serializerToName(serializer)).contentType(msg.getClass.getName).deliveryMode(deliveryMode).build 57 | (body, props) 58 | } 59 | 60 | /** 61 | * deserialize a message 62 | * @param body serialized message 63 | * @param props AMQP properties, which contain meta-data for the serialized message 64 | * @return a (deserialized message, serializer) tuple 65 | * @see [[com.github.sstone.amqp.proxy.AmqpProxy.serialize( )]] 66 | */ 67 | def deserialize(body: Array[Byte], props: AMQP.BasicProperties) = { 68 | require(props.getContentType != null && props.getContentType != "", "content type is not specified") 69 | val serializer = props.getContentEncoding match { 70 | case "" | null => JsonSerializer // use JSON if not serialization format was specified 71 | case encoding => Serializers.nameToSerializer(encoding) 72 | } 73 | (serializer.fromBinary(body, Some(Class.forName(props.getContentType))), serializer) 74 | } 75 | 76 | class ProxyServer(server: ActorRef, timeout: Timeout = 30 seconds) extends RpcServer.IProcessor { 77 | 78 | import ExecutionContext.Implicits.global 79 | 80 | lazy val logger = LoggerFactory.getLogger(classOf[ProxyServer]) 81 | 82 | def process(delivery: Delivery) = { 83 | logger.trace("consumer %s received %s with properties %s".format(delivery.consumerTag, delivery.envelope, delivery.properties)) 84 | 85 | Try(deserialize(delivery.body, delivery.properties)) match { 86 | case Success((request, serializer)) => { 87 | logger.debug("handling delivery of type %s".format(request.getClass.getName)) 88 | 89 | val future = for { 90 | response <- (server ? request)(timeout).mapTo[AnyRef] 91 | _ = logger.debug("sending response of type %s".format(response.getClass.getName)) 92 | (body, props) = serialize(response, serializer) 93 | } yield ProcessResult(Some(body), Some(props)) 94 | 95 | future.onFailure { 96 | case cause => logger.error(s"inner call to server actor $server failed", cause) 97 | } 98 | future 99 | } 100 | case Failure(cause) => { 101 | logger.error("deserialization failed", cause) 102 | Future.failed(cause) 103 | } 104 | } 105 | } 106 | 107 | def onFailure(delivery: Delivery, e: Throwable) = { 108 | val (body, props) = serialize(ServerFailure(e.getMessage, e.toString), JsonSerializer) 109 | ProcessResult(Some(body), Some(props)) 110 | } 111 | } 112 | 113 | object ProxyClient { 114 | def props(client: ActorRef, exchange: String, routingKey: String, serializer: Serializer, timeout: Timeout = 30 seconds, mandatory: Boolean = true, immediate: Boolean = false, deliveryMode: Int = 1): Props = 115 | Props(new ProxyClient(client, exchange, routingKey, serializer, timeout, mandatory, immediate, deliveryMode)) 116 | } 117 | 118 | /** 119 | * standard one-request/one response proxy, which allows to write (myActor ? MyRequest).mapTo[MyResponse] 120 | * @param client AMQP RPC Client 121 | * @param exchange exchange to which requests will be sent 122 | * @param routingKey routing key with which requests will be sent 123 | * @param serializer message serializer 124 | * @param timeout response time-out 125 | * @param mandatory AMQP mandatory flag used to sent requests with; default to true 126 | * @param immediate AMQP immediate flag used to sent requests with; default to false; use with caution !! 127 | * @param deliveryMode AMQP delivery mode to sent request with; defaults to 1 ( 128 | */ 129 | class ProxyClient(client: ActorRef, exchange: String, routingKey: String, serializer: Serializer, timeout: Timeout = 30 seconds, mandatory: Boolean = true, immediate: Boolean = false, deliveryMode: Int = 1) extends Actor { 130 | 131 | import ExecutionContext.Implicits.global 132 | 133 | def receive = { 134 | case msg: AnyRef => { 135 | Try(serialize(msg, serializer, deliveryMode = deliveryMode)) match { 136 | case Success((body, props)) => { 137 | // publish the serialized message (and tell the RPC client that we expect one response) 138 | val publish = Publish(exchange, routingKey, body, Some(props), mandatory = mandatory, immediate = immediate) 139 | val future = (client ? RpcClient.Request(publish :: Nil, 1))(timeout).mapTo[RpcClient.Response].map(result => { 140 | val delivery = result.deliveries(0) 141 | val (response, serializer) = deserialize(delivery.body, delivery.properties) 142 | response match { 143 | case ServerFailure(message, throwableAsString) => akka.actor.Status.Failure(new AmqpProxyException(message, throwableAsString)) 144 | case _ => response 145 | } 146 | }) 147 | future.pipeTo(sender) 148 | } 149 | case Failure(cause) => sender ! akka.actor.Status.Failure(new AmqpProxyException("Serialization error", cause.getMessage)) 150 | } 151 | } 152 | } 153 | } 154 | 155 | /** 156 | * "fire-and-forget" proxy, which allows to write myActor ! MyRequest 157 | * @param client AMQP RPC Client 158 | * @param exchange exchange to which requests will be sent 159 | * @param routingKey routing key with which requests will be sent 160 | * @param serializer message serializer 161 | * @param mandatory AMQP mandatory flag used to sent requests with; default to true 162 | * @param immediate AMQP immediate flag used to sent requests with; default to false; use with caution !! 163 | * @param deliveryMode AMQP delivery mode to sent request with; defaults to 1 164 | */ 165 | class ProxySender(client: ActorRef, exchange: String, routingKey: String, serializer: Serializer, mandatory: Boolean = true, immediate: Boolean = false, deliveryMode: Int = 1) extends Actor with ActorLogging { 166 | 167 | def receive = { 168 | case Amqp.Ok(request, _) => log.debug("successfully processed request %s".format(request)) 169 | case Amqp.Error(request, error) => log.error("error while processing %s : %s".format(request, error)) 170 | case msg: AnyRef => { 171 | val (body, props) = serialize(msg, serializer, deliveryMode = deliveryMode) 172 | val publish = Publish(exchange, routingKey, body, Some(props), mandatory = mandatory, immediate = immediate) 173 | log.debug("sending %s to %s".format(publish, client)) 174 | client ! publish 175 | } 176 | } 177 | } 178 | 179 | } 180 | -------------------------------------------------------------------------------- /src/main/scala/com/github.sstone/amqp/proxy/App.scala: -------------------------------------------------------------------------------- 1 | package com.github.sstone.amqp.proxy 2 | 3 | import akka.actor._ 4 | import akka.pattern.ask 5 | import akka.util.Timeout 6 | import scala.concurrent.duration._ 7 | import com.rabbitmq.client.ConnectionFactory 8 | import akka.routing.SmallestMailboxRouter 9 | import com.github.sstone.amqp.{Amqp, RpcClient, RpcServer, ConnectionOwner} 10 | import com.github.sstone.amqp.Amqp.{ChannelParameters, QueueParameters, ExchangeParameters} 11 | import serializers.JsonSerializer 12 | import util.{Failure, Success} 13 | import concurrent.ExecutionContext 14 | 15 | object Demo { 16 | 17 | case class AddRequest(x: Int, y: Int) 18 | 19 | case class AddResponse(x: Int, y: Int, sum: Int) 20 | 21 | class Calculator extends Actor { 22 | def receive = { 23 | case AddRequest(x, y) => sender ! AddResponse(x, y, x + y) 24 | } 25 | } 26 | } 27 | 28 | import Demo._ 29 | 30 | object Server { 31 | def main(args: Array[String]) { 32 | val system = ActorSystem("MySystem") 33 | val calc = system.actorOf(Props[Calculator]) 34 | val connFactory = new ConnectionFactory() 35 | connFactory.setHost("localhost") 36 | val conn = system.actorOf(Props(new ConnectionOwner(connFactory)), name = "conn") 37 | val exchange = ExchangeParameters(name = "amq.direct", exchangeType = "", passive = true) 38 | val queue = QueueParameters(name = "calculator", passive = false, autodelete = true) 39 | val channelParams = ChannelParameters(qos = 1) 40 | // create an AMQP RPC server which consumes messages from queue "calculator" and passes 41 | // them to our Calculator actor 42 | val server = ConnectionOwner.createChildActor( 43 | conn, 44 | RpcServer.props(queue, exchange, "calculator", new AmqpProxy.ProxyServer(calc), channelParams), 45 | name = Some("server")) 46 | 47 | Amqp.waitForConnection(system, server).await() 48 | } 49 | } 50 | 51 | object Client { 52 | def compute(calc: ActorRef) { 53 | import ExecutionContext.Implicits.global 54 | implicit val timeout: Timeout = 5 second 55 | 56 | for (x <- 0 to 5) { 57 | for (y <- 0 to 5) { 58 | (calc ? AddRequest(x, y)).onComplete { 59 | case Success(AddResponse(x1, y1, sum)) => println("%d + %d = %d".format(x1, y1, sum)) 60 | case Failure(error) => println(error) 61 | } 62 | } 63 | } 64 | } 65 | 66 | def main(args: Array[String]) { 67 | val system = ActorSystem("MySystem") 68 | val connFactory = new ConnectionFactory() 69 | connFactory.setHost("localhost") 70 | // create a "connection owner" actor, which will try and reconnect automatically if the connection ins lost 71 | val conn = system.actorOf(Props(new ConnectionOwner(connFactory)), name = "conn") 72 | val client = ConnectionOwner.createChildActor(conn, RpcClient.props()) 73 | Amqp.waitForConnection(system, client).await() 74 | val proxy = system.actorOf( 75 | AmqpProxy.ProxyClient.props(client, "amq.direct", "calculator", JsonSerializer), 76 | name = "proxy") 77 | Client.compute(proxy) 78 | } 79 | } 80 | 81 | object Local { 82 | def main(args: Array[String]) { 83 | val system = ActorSystem("MySystem") 84 | val calc = system.actorOf(Props[Calculator].withRouter(SmallestMailboxRouter(nrOfInstances = 8))) 85 | Client.compute(calc) 86 | } 87 | } -------------------------------------------------------------------------------- /src/main/scala/com/github.sstone/amqp/proxy/Serializers.scala: -------------------------------------------------------------------------------- 1 | package com.github.sstone.amqp.proxy 2 | 3 | import serializers._ 4 | import akka.serialization.Serializer 5 | 6 | object Serializers { 7 | 8 | private val map = Map( 9 | "json" -> JsonSerializer, 10 | "protobuf" -> ProtobufSerializer, 11 | "thrift" -> ThriftSerializer, 12 | "snappy-json" -> SnappyJsonSerializer, 13 | "snappy-protobuf" -> SnappyProtobufSerializer, 14 | "snappy-thrift" -> SnappyThriftSerializer) 15 | 16 | def nameToSerializer(name: String) = map.get(name).get 17 | 18 | def serializerToName(serializer: Serializer) = map.map(_.swap).get(serializer).get 19 | } 20 | -------------------------------------------------------------------------------- /src/main/scala/com/github.sstone/amqp/proxy/serializers/JsonSerializer.scala: -------------------------------------------------------------------------------- 1 | package com.github.sstone.amqp.proxy.serializers 2 | 3 | import akka.serialization.Serializer 4 | import org.json4s._ 5 | import org.json4s.jackson.JsonMethods._ 6 | import org.json4s.jackson.Serialization 7 | 8 | object JsonSerializer extends Serializer { 9 | implicit val formats = Serialization.formats(NoTypeHints) 10 | 11 | def identifier = 123456789 12 | 13 | def includeManifest = true 14 | 15 | def toBinary(o: AnyRef) = Serialization.write(o).getBytes("UTF-8") 16 | 17 | def fromBinary(bytes: Array[Byte], manifest: Option[Class[_]]): AnyRef = { 18 | require(manifest.isDefined) 19 | val string = new String(bytes) 20 | implicit val mf = Manifest.classType(manifest.get) 21 | Serialization.read(string) 22 | } 23 | } 24 | 25 | -------------------------------------------------------------------------------- /src/main/scala/com/github.sstone/amqp/proxy/serializers/ProtobufSerializer.scala: -------------------------------------------------------------------------------- 1 | package com.github.sstone.amqp.proxy.serializers 2 | 3 | import akka.serialization.Serializer 4 | import com.google.protobuf.Message 5 | 6 | /** 7 | * Following code has been taken from Akka 8 | * This Serializer serializes `com.google.protobuf.Message`s 9 | */ 10 | object ProtobufSerializer extends Serializer { 11 | val ARRAY_OF_BYTE_ARRAY = Array[Class[_]](classOf[Array[Byte]]) 12 | def includeManifest: Boolean = true 13 | def identifier = 2 14 | 15 | def toBinary(obj: AnyRef): Array[Byte] = obj match { 16 | case m: Message ⇒ m.toByteArray 17 | case _ ⇒ throw new IllegalArgumentException("Can't serialize a non-protobuf message using protobuf [" + obj + "]") 18 | } 19 | 20 | def fromBinary(bytes: Array[Byte], clazz: Option[Class[_]]): AnyRef = 21 | clazz match { 22 | case None ⇒ throw new IllegalArgumentException("Need a protobuf message class to be able to serialize bytes using protobuf") 23 | case Some(c) ⇒ c.getDeclaredMethod("parseFrom", ARRAY_OF_BYTE_ARRAY: _*).invoke(null, bytes).asInstanceOf[Message] 24 | } 25 | } -------------------------------------------------------------------------------- /src/main/scala/com/github.sstone/amqp/proxy/serializers/SnappySerializer.scala: -------------------------------------------------------------------------------- 1 | package com.github.sstone.amqp.proxy.serializers 2 | 3 | import org.xerial.snappy.Snappy 4 | import akka.serialization.Serializer 5 | 6 | /** 7 | * adds snappy compression/decompression to an existing serializer 8 | * @param serializer original serializer. 9 | */ 10 | abstract class SnappySerializer(serializer: Serializer) extends Serializer { 11 | 12 | def identifier = 4 13 | 14 | def includeManifest = true 15 | 16 | def toBinary(o: AnyRef) = { 17 | val bytes = serializer.toBinary(o) 18 | val zipped = Snappy.compress(bytes) 19 | zipped 20 | } 21 | 22 | def fromBinary(bytes: Array[Byte], manifest: Option[Class[_]]): AnyRef = { 23 | val unzipped = Snappy.uncompress(bytes) 24 | serializer.fromBinary(unzipped, manifest) 25 | } 26 | 27 | } 28 | 29 | object SnappyJsonSerializer extends SnappySerializer(JsonSerializer) 30 | 31 | object SnappyProtobufSerializer extends SnappySerializer(ProtobufSerializer) 32 | 33 | object SnappyThriftSerializer extends SnappySerializer(ThriftSerializer) 34 | 35 | -------------------------------------------------------------------------------- /src/main/scala/com/github.sstone/amqp/proxy/serializers/ThriftSerializer.scala: -------------------------------------------------------------------------------- 1 | package com.github.sstone.amqp.proxy.serializers 2 | 3 | import org.apache.thrift.{TFieldIdEnum, TDeserializer, TBase, TSerializer} 4 | import akka.serialization.Serializer 5 | 6 | 7 | object ThriftSerializer extends Serializer { 8 | 9 | def includeManifest: Boolean = true 10 | def identifier = 3 11 | 12 | val serializer = new TSerializer() 13 | val deserializer = new TDeserializer() 14 | 15 | def toBinary(obj: AnyRef): Array[Byte] = obj match { 16 | case m: TBase[_, _] ⇒ serializer.serialize(m) 17 | case _ ⇒ throw new IllegalArgumentException("Can't serialize a non-thrift message using thrift [" + obj + "]") 18 | } 19 | 20 | def fromBinary(bytes: Array[Byte], clazz: Option[Class[_]]): AnyRef = 21 | clazz match { 22 | case None ⇒ throw new IllegalArgumentException("Need a thrift message class to be able to deserialize bytes using thrift") 23 | case Some(c) ⇒ { 24 | val o = c.getConstructor().newInstance().asInstanceOf[TBase[_ <: TBase[_, _], _ <: TFieldIdEnum]] 25 | deserializer.deserialize(o, bytes) 26 | o 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/test/java/com/github.sstone/amqp/proxy/calculator/Calculator.java: -------------------------------------------------------------------------------- 1 | // Generated by the protocol buffer compiler. DO NOT EDIT! 2 | // source: src/test/resource/calculator.proto 3 | 4 | package com.github.sstone.amqp.proxy.calculator; 5 | 6 | public final class Calculator { 7 | private Calculator() {} 8 | public static void registerAllExtensions( 9 | com.google.protobuf.ExtensionRegistry registry) { 10 | } 11 | public interface AddRequestOrBuilder 12 | extends com.google.protobuf.MessageOrBuilder { 13 | 14 | // required int32 x = 1; 15 | boolean hasX(); 16 | int getX(); 17 | 18 | // required int32 y = 2; 19 | boolean hasY(); 20 | int getY(); 21 | } 22 | public static final class AddRequest extends 23 | com.google.protobuf.GeneratedMessage 24 | implements AddRequestOrBuilder { 25 | // Use AddRequest.newBuilder() to construct. 26 | private AddRequest(Builder builder) { 27 | super(builder); 28 | } 29 | private AddRequest(boolean noInit) {} 30 | 31 | private static final AddRequest defaultInstance; 32 | public static AddRequest getDefaultInstance() { 33 | return defaultInstance; 34 | } 35 | 36 | public AddRequest getDefaultInstanceForType() { 37 | return defaultInstance; 38 | } 39 | 40 | public static final com.google.protobuf.Descriptors.Descriptor 41 | getDescriptor() { 42 | return com.github.sstone.amqp.proxy.calculator.Calculator.internal_static_com_github_sstone_amqp_proxy_calculator_AddRequest_descriptor; 43 | } 44 | 45 | protected com.google.protobuf.GeneratedMessage.FieldAccessorTable 46 | internalGetFieldAccessorTable() { 47 | return com.github.sstone.amqp.proxy.calculator.Calculator.internal_static_com_github_sstone_amqp_proxy_calculator_AddRequest_fieldAccessorTable; 48 | } 49 | 50 | private int bitField0_; 51 | // required int32 x = 1; 52 | public static final int X_FIELD_NUMBER = 1; 53 | private int x_; 54 | public boolean hasX() { 55 | return ((bitField0_ & 0x00000001) == 0x00000001); 56 | } 57 | public int getX() { 58 | return x_; 59 | } 60 | 61 | // required int32 y = 2; 62 | public static final int Y_FIELD_NUMBER = 2; 63 | private int y_; 64 | public boolean hasY() { 65 | return ((bitField0_ & 0x00000002) == 0x00000002); 66 | } 67 | public int getY() { 68 | return y_; 69 | } 70 | 71 | private void initFields() { 72 | x_ = 0; 73 | y_ = 0; 74 | } 75 | private byte memoizedIsInitialized = -1; 76 | public final boolean isInitialized() { 77 | byte isInitialized = memoizedIsInitialized; 78 | if (isInitialized != -1) return isInitialized == 1; 79 | 80 | if (!hasX()) { 81 | memoizedIsInitialized = 0; 82 | return false; 83 | } 84 | if (!hasY()) { 85 | memoizedIsInitialized = 0; 86 | return false; 87 | } 88 | memoizedIsInitialized = 1; 89 | return true; 90 | } 91 | 92 | public void writeTo(com.google.protobuf.CodedOutputStream output) 93 | throws java.io.IOException { 94 | getSerializedSize(); 95 | if (((bitField0_ & 0x00000001) == 0x00000001)) { 96 | output.writeInt32(1, x_); 97 | } 98 | if (((bitField0_ & 0x00000002) == 0x00000002)) { 99 | output.writeInt32(2, y_); 100 | } 101 | getUnknownFields().writeTo(output); 102 | } 103 | 104 | private int memoizedSerializedSize = -1; 105 | public int getSerializedSize() { 106 | int size = memoizedSerializedSize; 107 | if (size != -1) return size; 108 | 109 | size = 0; 110 | if (((bitField0_ & 0x00000001) == 0x00000001)) { 111 | size += com.google.protobuf.CodedOutputStream 112 | .computeInt32Size(1, x_); 113 | } 114 | if (((bitField0_ & 0x00000002) == 0x00000002)) { 115 | size += com.google.protobuf.CodedOutputStream 116 | .computeInt32Size(2, y_); 117 | } 118 | size += getUnknownFields().getSerializedSize(); 119 | memoizedSerializedSize = size; 120 | return size; 121 | } 122 | 123 | private static final long serialVersionUID = 0L; 124 | @java.lang.Override 125 | protected java.lang.Object writeReplace() 126 | throws java.io.ObjectStreamException { 127 | return super.writeReplace(); 128 | } 129 | 130 | public static com.github.sstone.amqp.proxy.calculator.Calculator.AddRequest parseFrom( 131 | com.google.protobuf.ByteString data) 132 | throws com.google.protobuf.InvalidProtocolBufferException { 133 | return newBuilder().mergeFrom(data).buildParsed(); 134 | } 135 | public static com.github.sstone.amqp.proxy.calculator.Calculator.AddRequest parseFrom( 136 | com.google.protobuf.ByteString data, 137 | com.google.protobuf.ExtensionRegistryLite extensionRegistry) 138 | throws com.google.protobuf.InvalidProtocolBufferException { 139 | return newBuilder().mergeFrom(data, extensionRegistry) 140 | .buildParsed(); 141 | } 142 | public static com.github.sstone.amqp.proxy.calculator.Calculator.AddRequest parseFrom(byte[] data) 143 | throws com.google.protobuf.InvalidProtocolBufferException { 144 | return newBuilder().mergeFrom(data).buildParsed(); 145 | } 146 | public static com.github.sstone.amqp.proxy.calculator.Calculator.AddRequest parseFrom( 147 | byte[] data, 148 | com.google.protobuf.ExtensionRegistryLite extensionRegistry) 149 | throws com.google.protobuf.InvalidProtocolBufferException { 150 | return newBuilder().mergeFrom(data, extensionRegistry) 151 | .buildParsed(); 152 | } 153 | public static com.github.sstone.amqp.proxy.calculator.Calculator.AddRequest parseFrom(java.io.InputStream input) 154 | throws java.io.IOException { 155 | return newBuilder().mergeFrom(input).buildParsed(); 156 | } 157 | public static com.github.sstone.amqp.proxy.calculator.Calculator.AddRequest parseFrom( 158 | java.io.InputStream input, 159 | com.google.protobuf.ExtensionRegistryLite extensionRegistry) 160 | throws java.io.IOException { 161 | return newBuilder().mergeFrom(input, extensionRegistry) 162 | .buildParsed(); 163 | } 164 | public static com.github.sstone.amqp.proxy.calculator.Calculator.AddRequest parseDelimitedFrom(java.io.InputStream input) 165 | throws java.io.IOException { 166 | Builder builder = newBuilder(); 167 | if (builder.mergeDelimitedFrom(input)) { 168 | return builder.buildParsed(); 169 | } else { 170 | return null; 171 | } 172 | } 173 | public static com.github.sstone.amqp.proxy.calculator.Calculator.AddRequest parseDelimitedFrom( 174 | java.io.InputStream input, 175 | com.google.protobuf.ExtensionRegistryLite extensionRegistry) 176 | throws java.io.IOException { 177 | Builder builder = newBuilder(); 178 | if (builder.mergeDelimitedFrom(input, extensionRegistry)) { 179 | return builder.buildParsed(); 180 | } else { 181 | return null; 182 | } 183 | } 184 | public static com.github.sstone.amqp.proxy.calculator.Calculator.AddRequest parseFrom( 185 | com.google.protobuf.CodedInputStream input) 186 | throws java.io.IOException { 187 | return newBuilder().mergeFrom(input).buildParsed(); 188 | } 189 | public static com.github.sstone.amqp.proxy.calculator.Calculator.AddRequest parseFrom( 190 | com.google.protobuf.CodedInputStream input, 191 | com.google.protobuf.ExtensionRegistryLite extensionRegistry) 192 | throws java.io.IOException { 193 | return newBuilder().mergeFrom(input, extensionRegistry) 194 | .buildParsed(); 195 | } 196 | 197 | public static Builder newBuilder() { return Builder.create(); } 198 | public Builder newBuilderForType() { return newBuilder(); } 199 | public static Builder newBuilder(com.github.sstone.amqp.proxy.calculator.Calculator.AddRequest prototype) { 200 | return newBuilder().mergeFrom(prototype); 201 | } 202 | public Builder toBuilder() { return newBuilder(this); } 203 | 204 | @java.lang.Override 205 | protected Builder newBuilderForType( 206 | com.google.protobuf.GeneratedMessage.BuilderParent parent) { 207 | Builder builder = new Builder(parent); 208 | return builder; 209 | } 210 | public static final class Builder extends 211 | com.google.protobuf.GeneratedMessage.Builder 212 | implements com.github.sstone.amqp.proxy.calculator.Calculator.AddRequestOrBuilder { 213 | public static final com.google.protobuf.Descriptors.Descriptor 214 | getDescriptor() { 215 | return com.github.sstone.amqp.proxy.calculator.Calculator.internal_static_com_github_sstone_amqp_proxy_calculator_AddRequest_descriptor; 216 | } 217 | 218 | protected com.google.protobuf.GeneratedMessage.FieldAccessorTable 219 | internalGetFieldAccessorTable() { 220 | return com.github.sstone.amqp.proxy.calculator.Calculator.internal_static_com_github_sstone_amqp_proxy_calculator_AddRequest_fieldAccessorTable; 221 | } 222 | 223 | // Construct using com.github.sstone.amqp.proxy.calculator.Calculator.AddRequest.newBuilder() 224 | private Builder() { 225 | maybeForceBuilderInitialization(); 226 | } 227 | 228 | private Builder(BuilderParent parent) { 229 | super(parent); 230 | maybeForceBuilderInitialization(); 231 | } 232 | private void maybeForceBuilderInitialization() { 233 | if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { 234 | } 235 | } 236 | private static Builder create() { 237 | return new Builder(); 238 | } 239 | 240 | public Builder clear() { 241 | super.clear(); 242 | x_ = 0; 243 | bitField0_ = (bitField0_ & ~0x00000001); 244 | y_ = 0; 245 | bitField0_ = (bitField0_ & ~0x00000002); 246 | return this; 247 | } 248 | 249 | public Builder clone() { 250 | return create().mergeFrom(buildPartial()); 251 | } 252 | 253 | public com.google.protobuf.Descriptors.Descriptor 254 | getDescriptorForType() { 255 | return com.github.sstone.amqp.proxy.calculator.Calculator.AddRequest.getDescriptor(); 256 | } 257 | 258 | public com.github.sstone.amqp.proxy.calculator.Calculator.AddRequest getDefaultInstanceForType() { 259 | return com.github.sstone.amqp.proxy.calculator.Calculator.AddRequest.getDefaultInstance(); 260 | } 261 | 262 | public com.github.sstone.amqp.proxy.calculator.Calculator.AddRequest build() { 263 | com.github.sstone.amqp.proxy.calculator.Calculator.AddRequest result = buildPartial(); 264 | if (!result.isInitialized()) { 265 | throw newUninitializedMessageException(result); 266 | } 267 | return result; 268 | } 269 | 270 | private com.github.sstone.amqp.proxy.calculator.Calculator.AddRequest buildParsed() 271 | throws com.google.protobuf.InvalidProtocolBufferException { 272 | com.github.sstone.amqp.proxy.calculator.Calculator.AddRequest result = buildPartial(); 273 | if (!result.isInitialized()) { 274 | throw newUninitializedMessageException( 275 | result).asInvalidProtocolBufferException(); 276 | } 277 | return result; 278 | } 279 | 280 | public com.github.sstone.amqp.proxy.calculator.Calculator.AddRequest buildPartial() { 281 | com.github.sstone.amqp.proxy.calculator.Calculator.AddRequest result = new com.github.sstone.amqp.proxy.calculator.Calculator.AddRequest(this); 282 | int from_bitField0_ = bitField0_; 283 | int to_bitField0_ = 0; 284 | if (((from_bitField0_ & 0x00000001) == 0x00000001)) { 285 | to_bitField0_ |= 0x00000001; 286 | } 287 | result.x_ = x_; 288 | if (((from_bitField0_ & 0x00000002) == 0x00000002)) { 289 | to_bitField0_ |= 0x00000002; 290 | } 291 | result.y_ = y_; 292 | result.bitField0_ = to_bitField0_; 293 | onBuilt(); 294 | return result; 295 | } 296 | 297 | public Builder mergeFrom(com.google.protobuf.Message other) { 298 | if (other instanceof com.github.sstone.amqp.proxy.calculator.Calculator.AddRequest) { 299 | return mergeFrom((com.github.sstone.amqp.proxy.calculator.Calculator.AddRequest)other); 300 | } else { 301 | super.mergeFrom(other); 302 | return this; 303 | } 304 | } 305 | 306 | public Builder mergeFrom(com.github.sstone.amqp.proxy.calculator.Calculator.AddRequest other) { 307 | if (other == com.github.sstone.amqp.proxy.calculator.Calculator.AddRequest.getDefaultInstance()) return this; 308 | if (other.hasX()) { 309 | setX(other.getX()); 310 | } 311 | if (other.hasY()) { 312 | setY(other.getY()); 313 | } 314 | this.mergeUnknownFields(other.getUnknownFields()); 315 | return this; 316 | } 317 | 318 | public final boolean isInitialized() { 319 | if (!hasX()) { 320 | 321 | return false; 322 | } 323 | if (!hasY()) { 324 | 325 | return false; 326 | } 327 | return true; 328 | } 329 | 330 | public Builder mergeFrom( 331 | com.google.protobuf.CodedInputStream input, 332 | com.google.protobuf.ExtensionRegistryLite extensionRegistry) 333 | throws java.io.IOException { 334 | com.google.protobuf.UnknownFieldSet.Builder unknownFields = 335 | com.google.protobuf.UnknownFieldSet.newBuilder( 336 | this.getUnknownFields()); 337 | while (true) { 338 | int tag = input.readTag(); 339 | switch (tag) { 340 | case 0: 341 | this.setUnknownFields(unknownFields.build()); 342 | onChanged(); 343 | return this; 344 | default: { 345 | if (!parseUnknownField(input, unknownFields, 346 | extensionRegistry, tag)) { 347 | this.setUnknownFields(unknownFields.build()); 348 | onChanged(); 349 | return this; 350 | } 351 | break; 352 | } 353 | case 8: { 354 | bitField0_ |= 0x00000001; 355 | x_ = input.readInt32(); 356 | break; 357 | } 358 | case 16: { 359 | bitField0_ |= 0x00000002; 360 | y_ = input.readInt32(); 361 | break; 362 | } 363 | } 364 | } 365 | } 366 | 367 | private int bitField0_; 368 | 369 | // required int32 x = 1; 370 | private int x_ ; 371 | public boolean hasX() { 372 | return ((bitField0_ & 0x00000001) == 0x00000001); 373 | } 374 | public int getX() { 375 | return x_; 376 | } 377 | public Builder setX(int value) { 378 | bitField0_ |= 0x00000001; 379 | x_ = value; 380 | onChanged(); 381 | return this; 382 | } 383 | public Builder clearX() { 384 | bitField0_ = (bitField0_ & ~0x00000001); 385 | x_ = 0; 386 | onChanged(); 387 | return this; 388 | } 389 | 390 | // required int32 y = 2; 391 | private int y_ ; 392 | public boolean hasY() { 393 | return ((bitField0_ & 0x00000002) == 0x00000002); 394 | } 395 | public int getY() { 396 | return y_; 397 | } 398 | public Builder setY(int value) { 399 | bitField0_ |= 0x00000002; 400 | y_ = value; 401 | onChanged(); 402 | return this; 403 | } 404 | public Builder clearY() { 405 | bitField0_ = (bitField0_ & ~0x00000002); 406 | y_ = 0; 407 | onChanged(); 408 | return this; 409 | } 410 | 411 | // @@protoc_insertion_point(builder_scope:com.github.sstone.amqp.proxy.calculator.AddRequest) 412 | } 413 | 414 | static { 415 | defaultInstance = new AddRequest(true); 416 | defaultInstance.initFields(); 417 | } 418 | 419 | // @@protoc_insertion_point(class_scope:com.github.sstone.amqp.proxy.calculator.AddRequest) 420 | } 421 | 422 | public interface AddResponseOrBuilder 423 | extends com.google.protobuf.MessageOrBuilder { 424 | 425 | // required int32 x = 1; 426 | boolean hasX(); 427 | int getX(); 428 | 429 | // required int32 y = 2; 430 | boolean hasY(); 431 | int getY(); 432 | 433 | // required int32 sum = 3; 434 | boolean hasSum(); 435 | int getSum(); 436 | } 437 | public static final class AddResponse extends 438 | com.google.protobuf.GeneratedMessage 439 | implements AddResponseOrBuilder { 440 | // Use AddResponse.newBuilder() to construct. 441 | private AddResponse(Builder builder) { 442 | super(builder); 443 | } 444 | private AddResponse(boolean noInit) {} 445 | 446 | private static final AddResponse defaultInstance; 447 | public static AddResponse getDefaultInstance() { 448 | return defaultInstance; 449 | } 450 | 451 | public AddResponse getDefaultInstanceForType() { 452 | return defaultInstance; 453 | } 454 | 455 | public static final com.google.protobuf.Descriptors.Descriptor 456 | getDescriptor() { 457 | return com.github.sstone.amqp.proxy.calculator.Calculator.internal_static_com_github_sstone_amqp_proxy_calculator_AddResponse_descriptor; 458 | } 459 | 460 | protected com.google.protobuf.GeneratedMessage.FieldAccessorTable 461 | internalGetFieldAccessorTable() { 462 | return com.github.sstone.amqp.proxy.calculator.Calculator.internal_static_com_github_sstone_amqp_proxy_calculator_AddResponse_fieldAccessorTable; 463 | } 464 | 465 | private int bitField0_; 466 | // required int32 x = 1; 467 | public static final int X_FIELD_NUMBER = 1; 468 | private int x_; 469 | public boolean hasX() { 470 | return ((bitField0_ & 0x00000001) == 0x00000001); 471 | } 472 | public int getX() { 473 | return x_; 474 | } 475 | 476 | // required int32 y = 2; 477 | public static final int Y_FIELD_NUMBER = 2; 478 | private int y_; 479 | public boolean hasY() { 480 | return ((bitField0_ & 0x00000002) == 0x00000002); 481 | } 482 | public int getY() { 483 | return y_; 484 | } 485 | 486 | // required int32 sum = 3; 487 | public static final int SUM_FIELD_NUMBER = 3; 488 | private int sum_; 489 | public boolean hasSum() { 490 | return ((bitField0_ & 0x00000004) == 0x00000004); 491 | } 492 | public int getSum() { 493 | return sum_; 494 | } 495 | 496 | private void initFields() { 497 | x_ = 0; 498 | y_ = 0; 499 | sum_ = 0; 500 | } 501 | private byte memoizedIsInitialized = -1; 502 | public final boolean isInitialized() { 503 | byte isInitialized = memoizedIsInitialized; 504 | if (isInitialized != -1) return isInitialized == 1; 505 | 506 | if (!hasX()) { 507 | memoizedIsInitialized = 0; 508 | return false; 509 | } 510 | if (!hasY()) { 511 | memoizedIsInitialized = 0; 512 | return false; 513 | } 514 | if (!hasSum()) { 515 | memoizedIsInitialized = 0; 516 | return false; 517 | } 518 | memoizedIsInitialized = 1; 519 | return true; 520 | } 521 | 522 | public void writeTo(com.google.protobuf.CodedOutputStream output) 523 | throws java.io.IOException { 524 | getSerializedSize(); 525 | if (((bitField0_ & 0x00000001) == 0x00000001)) { 526 | output.writeInt32(1, x_); 527 | } 528 | if (((bitField0_ & 0x00000002) == 0x00000002)) { 529 | output.writeInt32(2, y_); 530 | } 531 | if (((bitField0_ & 0x00000004) == 0x00000004)) { 532 | output.writeInt32(3, sum_); 533 | } 534 | getUnknownFields().writeTo(output); 535 | } 536 | 537 | private int memoizedSerializedSize = -1; 538 | public int getSerializedSize() { 539 | int size = memoizedSerializedSize; 540 | if (size != -1) return size; 541 | 542 | size = 0; 543 | if (((bitField0_ & 0x00000001) == 0x00000001)) { 544 | size += com.google.protobuf.CodedOutputStream 545 | .computeInt32Size(1, x_); 546 | } 547 | if (((bitField0_ & 0x00000002) == 0x00000002)) { 548 | size += com.google.protobuf.CodedOutputStream 549 | .computeInt32Size(2, y_); 550 | } 551 | if (((bitField0_ & 0x00000004) == 0x00000004)) { 552 | size += com.google.protobuf.CodedOutputStream 553 | .computeInt32Size(3, sum_); 554 | } 555 | size += getUnknownFields().getSerializedSize(); 556 | memoizedSerializedSize = size; 557 | return size; 558 | } 559 | 560 | private static final long serialVersionUID = 0L; 561 | @java.lang.Override 562 | protected java.lang.Object writeReplace() 563 | throws java.io.ObjectStreamException { 564 | return super.writeReplace(); 565 | } 566 | 567 | public static com.github.sstone.amqp.proxy.calculator.Calculator.AddResponse parseFrom( 568 | com.google.protobuf.ByteString data) 569 | throws com.google.protobuf.InvalidProtocolBufferException { 570 | return newBuilder().mergeFrom(data).buildParsed(); 571 | } 572 | public static com.github.sstone.amqp.proxy.calculator.Calculator.AddResponse parseFrom( 573 | com.google.protobuf.ByteString data, 574 | com.google.protobuf.ExtensionRegistryLite extensionRegistry) 575 | throws com.google.protobuf.InvalidProtocolBufferException { 576 | return newBuilder().mergeFrom(data, extensionRegistry) 577 | .buildParsed(); 578 | } 579 | public static com.github.sstone.amqp.proxy.calculator.Calculator.AddResponse parseFrom(byte[] data) 580 | throws com.google.protobuf.InvalidProtocolBufferException { 581 | return newBuilder().mergeFrom(data).buildParsed(); 582 | } 583 | public static com.github.sstone.amqp.proxy.calculator.Calculator.AddResponse parseFrom( 584 | byte[] data, 585 | com.google.protobuf.ExtensionRegistryLite extensionRegistry) 586 | throws com.google.protobuf.InvalidProtocolBufferException { 587 | return newBuilder().mergeFrom(data, extensionRegistry) 588 | .buildParsed(); 589 | } 590 | public static com.github.sstone.amqp.proxy.calculator.Calculator.AddResponse parseFrom(java.io.InputStream input) 591 | throws java.io.IOException { 592 | return newBuilder().mergeFrom(input).buildParsed(); 593 | } 594 | public static com.github.sstone.amqp.proxy.calculator.Calculator.AddResponse parseFrom( 595 | java.io.InputStream input, 596 | com.google.protobuf.ExtensionRegistryLite extensionRegistry) 597 | throws java.io.IOException { 598 | return newBuilder().mergeFrom(input, extensionRegistry) 599 | .buildParsed(); 600 | } 601 | public static com.github.sstone.amqp.proxy.calculator.Calculator.AddResponse parseDelimitedFrom(java.io.InputStream input) 602 | throws java.io.IOException { 603 | Builder builder = newBuilder(); 604 | if (builder.mergeDelimitedFrom(input)) { 605 | return builder.buildParsed(); 606 | } else { 607 | return null; 608 | } 609 | } 610 | public static com.github.sstone.amqp.proxy.calculator.Calculator.AddResponse parseDelimitedFrom( 611 | java.io.InputStream input, 612 | com.google.protobuf.ExtensionRegistryLite extensionRegistry) 613 | throws java.io.IOException { 614 | Builder builder = newBuilder(); 615 | if (builder.mergeDelimitedFrom(input, extensionRegistry)) { 616 | return builder.buildParsed(); 617 | } else { 618 | return null; 619 | } 620 | } 621 | public static com.github.sstone.amqp.proxy.calculator.Calculator.AddResponse parseFrom( 622 | com.google.protobuf.CodedInputStream input) 623 | throws java.io.IOException { 624 | return newBuilder().mergeFrom(input).buildParsed(); 625 | } 626 | public static com.github.sstone.amqp.proxy.calculator.Calculator.AddResponse parseFrom( 627 | com.google.protobuf.CodedInputStream input, 628 | com.google.protobuf.ExtensionRegistryLite extensionRegistry) 629 | throws java.io.IOException { 630 | return newBuilder().mergeFrom(input, extensionRegistry) 631 | .buildParsed(); 632 | } 633 | 634 | public static Builder newBuilder() { return Builder.create(); } 635 | public Builder newBuilderForType() { return newBuilder(); } 636 | public static Builder newBuilder(com.github.sstone.amqp.proxy.calculator.Calculator.AddResponse prototype) { 637 | return newBuilder().mergeFrom(prototype); 638 | } 639 | public Builder toBuilder() { return newBuilder(this); } 640 | 641 | @java.lang.Override 642 | protected Builder newBuilderForType( 643 | com.google.protobuf.GeneratedMessage.BuilderParent parent) { 644 | Builder builder = new Builder(parent); 645 | return builder; 646 | } 647 | public static final class Builder extends 648 | com.google.protobuf.GeneratedMessage.Builder 649 | implements com.github.sstone.amqp.proxy.calculator.Calculator.AddResponseOrBuilder { 650 | public static final com.google.protobuf.Descriptors.Descriptor 651 | getDescriptor() { 652 | return com.github.sstone.amqp.proxy.calculator.Calculator.internal_static_com_github_sstone_amqp_proxy_calculator_AddResponse_descriptor; 653 | } 654 | 655 | protected com.google.protobuf.GeneratedMessage.FieldAccessorTable 656 | internalGetFieldAccessorTable() { 657 | return com.github.sstone.amqp.proxy.calculator.Calculator.internal_static_com_github_sstone_amqp_proxy_calculator_AddResponse_fieldAccessorTable; 658 | } 659 | 660 | // Construct using com.github.sstone.amqp.proxy.calculator.Calculator.AddResponse.newBuilder() 661 | private Builder() { 662 | maybeForceBuilderInitialization(); 663 | } 664 | 665 | private Builder(BuilderParent parent) { 666 | super(parent); 667 | maybeForceBuilderInitialization(); 668 | } 669 | private void maybeForceBuilderInitialization() { 670 | if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { 671 | } 672 | } 673 | private static Builder create() { 674 | return new Builder(); 675 | } 676 | 677 | public Builder clear() { 678 | super.clear(); 679 | x_ = 0; 680 | bitField0_ = (bitField0_ & ~0x00000001); 681 | y_ = 0; 682 | bitField0_ = (bitField0_ & ~0x00000002); 683 | sum_ = 0; 684 | bitField0_ = (bitField0_ & ~0x00000004); 685 | return this; 686 | } 687 | 688 | public Builder clone() { 689 | return create().mergeFrom(buildPartial()); 690 | } 691 | 692 | public com.google.protobuf.Descriptors.Descriptor 693 | getDescriptorForType() { 694 | return com.github.sstone.amqp.proxy.calculator.Calculator.AddResponse.getDescriptor(); 695 | } 696 | 697 | public com.github.sstone.amqp.proxy.calculator.Calculator.AddResponse getDefaultInstanceForType() { 698 | return com.github.sstone.amqp.proxy.calculator.Calculator.AddResponse.getDefaultInstance(); 699 | } 700 | 701 | public com.github.sstone.amqp.proxy.calculator.Calculator.AddResponse build() { 702 | com.github.sstone.amqp.proxy.calculator.Calculator.AddResponse result = buildPartial(); 703 | if (!result.isInitialized()) { 704 | throw newUninitializedMessageException(result); 705 | } 706 | return result; 707 | } 708 | 709 | private com.github.sstone.amqp.proxy.calculator.Calculator.AddResponse buildParsed() 710 | throws com.google.protobuf.InvalidProtocolBufferException { 711 | com.github.sstone.amqp.proxy.calculator.Calculator.AddResponse result = buildPartial(); 712 | if (!result.isInitialized()) { 713 | throw newUninitializedMessageException( 714 | result).asInvalidProtocolBufferException(); 715 | } 716 | return result; 717 | } 718 | 719 | public com.github.sstone.amqp.proxy.calculator.Calculator.AddResponse buildPartial() { 720 | com.github.sstone.amqp.proxy.calculator.Calculator.AddResponse result = new com.github.sstone.amqp.proxy.calculator.Calculator.AddResponse(this); 721 | int from_bitField0_ = bitField0_; 722 | int to_bitField0_ = 0; 723 | if (((from_bitField0_ & 0x00000001) == 0x00000001)) { 724 | to_bitField0_ |= 0x00000001; 725 | } 726 | result.x_ = x_; 727 | if (((from_bitField0_ & 0x00000002) == 0x00000002)) { 728 | to_bitField0_ |= 0x00000002; 729 | } 730 | result.y_ = y_; 731 | if (((from_bitField0_ & 0x00000004) == 0x00000004)) { 732 | to_bitField0_ |= 0x00000004; 733 | } 734 | result.sum_ = sum_; 735 | result.bitField0_ = to_bitField0_; 736 | onBuilt(); 737 | return result; 738 | } 739 | 740 | public Builder mergeFrom(com.google.protobuf.Message other) { 741 | if (other instanceof com.github.sstone.amqp.proxy.calculator.Calculator.AddResponse) { 742 | return mergeFrom((com.github.sstone.amqp.proxy.calculator.Calculator.AddResponse)other); 743 | } else { 744 | super.mergeFrom(other); 745 | return this; 746 | } 747 | } 748 | 749 | public Builder mergeFrom(com.github.sstone.amqp.proxy.calculator.Calculator.AddResponse other) { 750 | if (other == com.github.sstone.amqp.proxy.calculator.Calculator.AddResponse.getDefaultInstance()) return this; 751 | if (other.hasX()) { 752 | setX(other.getX()); 753 | } 754 | if (other.hasY()) { 755 | setY(other.getY()); 756 | } 757 | if (other.hasSum()) { 758 | setSum(other.getSum()); 759 | } 760 | this.mergeUnknownFields(other.getUnknownFields()); 761 | return this; 762 | } 763 | 764 | public final boolean isInitialized() { 765 | if (!hasX()) { 766 | 767 | return false; 768 | } 769 | if (!hasY()) { 770 | 771 | return false; 772 | } 773 | if (!hasSum()) { 774 | 775 | return false; 776 | } 777 | return true; 778 | } 779 | 780 | public Builder mergeFrom( 781 | com.google.protobuf.CodedInputStream input, 782 | com.google.protobuf.ExtensionRegistryLite extensionRegistry) 783 | throws java.io.IOException { 784 | com.google.protobuf.UnknownFieldSet.Builder unknownFields = 785 | com.google.protobuf.UnknownFieldSet.newBuilder( 786 | this.getUnknownFields()); 787 | while (true) { 788 | int tag = input.readTag(); 789 | switch (tag) { 790 | case 0: 791 | this.setUnknownFields(unknownFields.build()); 792 | onChanged(); 793 | return this; 794 | default: { 795 | if (!parseUnknownField(input, unknownFields, 796 | extensionRegistry, tag)) { 797 | this.setUnknownFields(unknownFields.build()); 798 | onChanged(); 799 | return this; 800 | } 801 | break; 802 | } 803 | case 8: { 804 | bitField0_ |= 0x00000001; 805 | x_ = input.readInt32(); 806 | break; 807 | } 808 | case 16: { 809 | bitField0_ |= 0x00000002; 810 | y_ = input.readInt32(); 811 | break; 812 | } 813 | case 24: { 814 | bitField0_ |= 0x00000004; 815 | sum_ = input.readInt32(); 816 | break; 817 | } 818 | } 819 | } 820 | } 821 | 822 | private int bitField0_; 823 | 824 | // required int32 x = 1; 825 | private int x_ ; 826 | public boolean hasX() { 827 | return ((bitField0_ & 0x00000001) == 0x00000001); 828 | } 829 | public int getX() { 830 | return x_; 831 | } 832 | public Builder setX(int value) { 833 | bitField0_ |= 0x00000001; 834 | x_ = value; 835 | onChanged(); 836 | return this; 837 | } 838 | public Builder clearX() { 839 | bitField0_ = (bitField0_ & ~0x00000001); 840 | x_ = 0; 841 | onChanged(); 842 | return this; 843 | } 844 | 845 | // required int32 y = 2; 846 | private int y_ ; 847 | public boolean hasY() { 848 | return ((bitField0_ & 0x00000002) == 0x00000002); 849 | } 850 | public int getY() { 851 | return y_; 852 | } 853 | public Builder setY(int value) { 854 | bitField0_ |= 0x00000002; 855 | y_ = value; 856 | onChanged(); 857 | return this; 858 | } 859 | public Builder clearY() { 860 | bitField0_ = (bitField0_ & ~0x00000002); 861 | y_ = 0; 862 | onChanged(); 863 | return this; 864 | } 865 | 866 | // required int32 sum = 3; 867 | private int sum_ ; 868 | public boolean hasSum() { 869 | return ((bitField0_ & 0x00000004) == 0x00000004); 870 | } 871 | public int getSum() { 872 | return sum_; 873 | } 874 | public Builder setSum(int value) { 875 | bitField0_ |= 0x00000004; 876 | sum_ = value; 877 | onChanged(); 878 | return this; 879 | } 880 | public Builder clearSum() { 881 | bitField0_ = (bitField0_ & ~0x00000004); 882 | sum_ = 0; 883 | onChanged(); 884 | return this; 885 | } 886 | 887 | // @@protoc_insertion_point(builder_scope:com.github.sstone.amqp.proxy.calculator.AddResponse) 888 | } 889 | 890 | static { 891 | defaultInstance = new AddResponse(true); 892 | defaultInstance.initFields(); 893 | } 894 | 895 | // @@protoc_insertion_point(class_scope:com.github.sstone.amqp.proxy.calculator.AddResponse) 896 | } 897 | 898 | private static com.google.protobuf.Descriptors.Descriptor 899 | internal_static_com_github_sstone_amqp_proxy_calculator_AddRequest_descriptor; 900 | private static 901 | com.google.protobuf.GeneratedMessage.FieldAccessorTable 902 | internal_static_com_github_sstone_amqp_proxy_calculator_AddRequest_fieldAccessorTable; 903 | private static com.google.protobuf.Descriptors.Descriptor 904 | internal_static_com_github_sstone_amqp_proxy_calculator_AddResponse_descriptor; 905 | private static 906 | com.google.protobuf.GeneratedMessage.FieldAccessorTable 907 | internal_static_com_github_sstone_amqp_proxy_calculator_AddResponse_fieldAccessorTable; 908 | 909 | public static com.google.protobuf.Descriptors.FileDescriptor 910 | getDescriptor() { 911 | return descriptor; 912 | } 913 | private static com.google.protobuf.Descriptors.FileDescriptor 914 | descriptor; 915 | static { 916 | java.lang.String[] descriptorData = { 917 | "\n\"src/test/resource/calculator.proto\022\'co" + 918 | "m.github.sstone.amqp.proxy.calculator\"\"\n" + 919 | "\nAddRequest\022\t\n\001x\030\001 \002(\005\022\t\n\001y\030\002 \002(\005\"0\n\013Add" + 920 | "Response\022\t\n\001x\030\001 \002(\005\022\t\n\001y\030\002 \002(\005\022\013\n\003sum\030\003 " + 921 | "\002(\005" 922 | }; 923 | com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = 924 | new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() { 925 | public com.google.protobuf.ExtensionRegistry assignDescriptors( 926 | com.google.protobuf.Descriptors.FileDescriptor root) { 927 | descriptor = root; 928 | internal_static_com_github_sstone_amqp_proxy_calculator_AddRequest_descriptor = 929 | getDescriptor().getMessageTypes().get(0); 930 | internal_static_com_github_sstone_amqp_proxy_calculator_AddRequest_fieldAccessorTable = new 931 | com.google.protobuf.GeneratedMessage.FieldAccessorTable( 932 | internal_static_com_github_sstone_amqp_proxy_calculator_AddRequest_descriptor, 933 | new java.lang.String[] { "X", "Y", }, 934 | com.github.sstone.amqp.proxy.calculator.Calculator.AddRequest.class, 935 | com.github.sstone.amqp.proxy.calculator.Calculator.AddRequest.Builder.class); 936 | internal_static_com_github_sstone_amqp_proxy_calculator_AddResponse_descriptor = 937 | getDescriptor().getMessageTypes().get(1); 938 | internal_static_com_github_sstone_amqp_proxy_calculator_AddResponse_fieldAccessorTable = new 939 | com.google.protobuf.GeneratedMessage.FieldAccessorTable( 940 | internal_static_com_github_sstone_amqp_proxy_calculator_AddResponse_descriptor, 941 | new java.lang.String[] { "X", "Y", "Sum", }, 942 | com.github.sstone.amqp.proxy.calculator.Calculator.AddResponse.class, 943 | com.github.sstone.amqp.proxy.calculator.Calculator.AddResponse.Builder.class); 944 | return null; 945 | } 946 | }; 947 | com.google.protobuf.Descriptors.FileDescriptor 948 | .internalBuildGeneratedFileFrom(descriptorData, 949 | new com.google.protobuf.Descriptors.FileDescriptor[] { 950 | }, assigner); 951 | } 952 | 953 | // @@protoc_insertion_point(outer_class_scope) 954 | } 955 | -------------------------------------------------------------------------------- /src/test/java/com/github.sstone/amqp/proxy/gpbtest/Gpbtest.java: -------------------------------------------------------------------------------- 1 | // Generated by the protocol buffer compiler. DO NOT EDIT! 2 | // source: src/test/resource/gpbtest.proto 3 | 4 | package com.github.sstone.amqp.proxy.gpbtest; 5 | 6 | public final class Gpbtest { 7 | private Gpbtest() {} 8 | public static void registerAllExtensions( 9 | com.google.protobuf.ExtensionRegistry registry) { 10 | } 11 | public interface PersonOrBuilder 12 | extends com.google.protobuf.MessageOrBuilder { 13 | 14 | // required int32 id = 1; 15 | boolean hasId(); 16 | int getId(); 17 | 18 | // required string name = 2; 19 | boolean hasName(); 20 | String getName(); 21 | 22 | // optional string email = 3; 23 | boolean hasEmail(); 24 | String getEmail(); 25 | } 26 | public static final class Person extends 27 | com.google.protobuf.GeneratedMessage 28 | implements PersonOrBuilder { 29 | // Use Person.newBuilder() to construct. 30 | private Person(Builder builder) { 31 | super(builder); 32 | } 33 | private Person(boolean noInit) {} 34 | 35 | private static final Person defaultInstance; 36 | public static Person getDefaultInstance() { 37 | return defaultInstance; 38 | } 39 | 40 | public Person getDefaultInstanceForType() { 41 | return defaultInstance; 42 | } 43 | 44 | public static final com.google.protobuf.Descriptors.Descriptor 45 | getDescriptor() { 46 | return com.github.sstone.amqp.proxy.gpbtest.Gpbtest.internal_static_com_github_sstone_amqp_proxy_gpbtest_Person_descriptor; 47 | } 48 | 49 | protected com.google.protobuf.GeneratedMessage.FieldAccessorTable 50 | internalGetFieldAccessorTable() { 51 | return com.github.sstone.amqp.proxy.gpbtest.Gpbtest.internal_static_com_github_sstone_amqp_proxy_gpbtest_Person_fieldAccessorTable; 52 | } 53 | 54 | private int bitField0_; 55 | // required int32 id = 1; 56 | public static final int ID_FIELD_NUMBER = 1; 57 | private int id_; 58 | public boolean hasId() { 59 | return ((bitField0_ & 0x00000001) == 0x00000001); 60 | } 61 | public int getId() { 62 | return id_; 63 | } 64 | 65 | // required string name = 2; 66 | public static final int NAME_FIELD_NUMBER = 2; 67 | private java.lang.Object name_; 68 | public boolean hasName() { 69 | return ((bitField0_ & 0x00000002) == 0x00000002); 70 | } 71 | public String getName() { 72 | java.lang.Object ref = name_; 73 | if (ref instanceof String) { 74 | return (String) ref; 75 | } else { 76 | com.google.protobuf.ByteString bs = 77 | (com.google.protobuf.ByteString) ref; 78 | String s = bs.toStringUtf8(); 79 | if (com.google.protobuf.Internal.isValidUtf8(bs)) { 80 | name_ = s; 81 | } 82 | return s; 83 | } 84 | } 85 | private com.google.protobuf.ByteString getNameBytes() { 86 | java.lang.Object ref = name_; 87 | if (ref instanceof String) { 88 | com.google.protobuf.ByteString b = 89 | com.google.protobuf.ByteString.copyFromUtf8((String) ref); 90 | name_ = b; 91 | return b; 92 | } else { 93 | return (com.google.protobuf.ByteString) ref; 94 | } 95 | } 96 | 97 | // optional string email = 3; 98 | public static final int EMAIL_FIELD_NUMBER = 3; 99 | private java.lang.Object email_; 100 | public boolean hasEmail() { 101 | return ((bitField0_ & 0x00000004) == 0x00000004); 102 | } 103 | public String getEmail() { 104 | java.lang.Object ref = email_; 105 | if (ref instanceof String) { 106 | return (String) ref; 107 | } else { 108 | com.google.protobuf.ByteString bs = 109 | (com.google.protobuf.ByteString) ref; 110 | String s = bs.toStringUtf8(); 111 | if (com.google.protobuf.Internal.isValidUtf8(bs)) { 112 | email_ = s; 113 | } 114 | return s; 115 | } 116 | } 117 | private com.google.protobuf.ByteString getEmailBytes() { 118 | java.lang.Object ref = email_; 119 | if (ref instanceof String) { 120 | com.google.protobuf.ByteString b = 121 | com.google.protobuf.ByteString.copyFromUtf8((String) ref); 122 | email_ = b; 123 | return b; 124 | } else { 125 | return (com.google.protobuf.ByteString) ref; 126 | } 127 | } 128 | 129 | private void initFields() { 130 | id_ = 0; 131 | name_ = ""; 132 | email_ = ""; 133 | } 134 | private byte memoizedIsInitialized = -1; 135 | public final boolean isInitialized() { 136 | byte isInitialized = memoizedIsInitialized; 137 | if (isInitialized != -1) return isInitialized == 1; 138 | 139 | if (!hasId()) { 140 | memoizedIsInitialized = 0; 141 | return false; 142 | } 143 | if (!hasName()) { 144 | memoizedIsInitialized = 0; 145 | return false; 146 | } 147 | memoizedIsInitialized = 1; 148 | return true; 149 | } 150 | 151 | public void writeTo(com.google.protobuf.CodedOutputStream output) 152 | throws java.io.IOException { 153 | getSerializedSize(); 154 | if (((bitField0_ & 0x00000001) == 0x00000001)) { 155 | output.writeInt32(1, id_); 156 | } 157 | if (((bitField0_ & 0x00000002) == 0x00000002)) { 158 | output.writeBytes(2, getNameBytes()); 159 | } 160 | if (((bitField0_ & 0x00000004) == 0x00000004)) { 161 | output.writeBytes(3, getEmailBytes()); 162 | } 163 | getUnknownFields().writeTo(output); 164 | } 165 | 166 | private int memoizedSerializedSize = -1; 167 | public int getSerializedSize() { 168 | int size = memoizedSerializedSize; 169 | if (size != -1) return size; 170 | 171 | size = 0; 172 | if (((bitField0_ & 0x00000001) == 0x00000001)) { 173 | size += com.google.protobuf.CodedOutputStream 174 | .computeInt32Size(1, id_); 175 | } 176 | if (((bitField0_ & 0x00000002) == 0x00000002)) { 177 | size += com.google.protobuf.CodedOutputStream 178 | .computeBytesSize(2, getNameBytes()); 179 | } 180 | if (((bitField0_ & 0x00000004) == 0x00000004)) { 181 | size += com.google.protobuf.CodedOutputStream 182 | .computeBytesSize(3, getEmailBytes()); 183 | } 184 | size += getUnknownFields().getSerializedSize(); 185 | memoizedSerializedSize = size; 186 | return size; 187 | } 188 | 189 | private static final long serialVersionUID = 0L; 190 | @java.lang.Override 191 | protected java.lang.Object writeReplace() 192 | throws java.io.ObjectStreamException { 193 | return super.writeReplace(); 194 | } 195 | 196 | public static com.github.sstone.amqp.proxy.gpbtest.Gpbtest.Person parseFrom( 197 | com.google.protobuf.ByteString data) 198 | throws com.google.protobuf.InvalidProtocolBufferException { 199 | return newBuilder().mergeFrom(data).buildParsed(); 200 | } 201 | public static com.github.sstone.amqp.proxy.gpbtest.Gpbtest.Person parseFrom( 202 | com.google.protobuf.ByteString data, 203 | com.google.protobuf.ExtensionRegistryLite extensionRegistry) 204 | throws com.google.protobuf.InvalidProtocolBufferException { 205 | return newBuilder().mergeFrom(data, extensionRegistry) 206 | .buildParsed(); 207 | } 208 | public static com.github.sstone.amqp.proxy.gpbtest.Gpbtest.Person parseFrom(byte[] data) 209 | throws com.google.protobuf.InvalidProtocolBufferException { 210 | return newBuilder().mergeFrom(data).buildParsed(); 211 | } 212 | public static com.github.sstone.amqp.proxy.gpbtest.Gpbtest.Person parseFrom( 213 | byte[] data, 214 | com.google.protobuf.ExtensionRegistryLite extensionRegistry) 215 | throws com.google.protobuf.InvalidProtocolBufferException { 216 | return newBuilder().mergeFrom(data, extensionRegistry) 217 | .buildParsed(); 218 | } 219 | public static com.github.sstone.amqp.proxy.gpbtest.Gpbtest.Person parseFrom(java.io.InputStream input) 220 | throws java.io.IOException { 221 | return newBuilder().mergeFrom(input).buildParsed(); 222 | } 223 | public static com.github.sstone.amqp.proxy.gpbtest.Gpbtest.Person parseFrom( 224 | java.io.InputStream input, 225 | com.google.protobuf.ExtensionRegistryLite extensionRegistry) 226 | throws java.io.IOException { 227 | return newBuilder().mergeFrom(input, extensionRegistry) 228 | .buildParsed(); 229 | } 230 | public static com.github.sstone.amqp.proxy.gpbtest.Gpbtest.Person parseDelimitedFrom(java.io.InputStream input) 231 | throws java.io.IOException { 232 | Builder builder = newBuilder(); 233 | if (builder.mergeDelimitedFrom(input)) { 234 | return builder.buildParsed(); 235 | } else { 236 | return null; 237 | } 238 | } 239 | public static com.github.sstone.amqp.proxy.gpbtest.Gpbtest.Person parseDelimitedFrom( 240 | java.io.InputStream input, 241 | com.google.protobuf.ExtensionRegistryLite extensionRegistry) 242 | throws java.io.IOException { 243 | Builder builder = newBuilder(); 244 | if (builder.mergeDelimitedFrom(input, extensionRegistry)) { 245 | return builder.buildParsed(); 246 | } else { 247 | return null; 248 | } 249 | } 250 | public static com.github.sstone.amqp.proxy.gpbtest.Gpbtest.Person parseFrom( 251 | com.google.protobuf.CodedInputStream input) 252 | throws java.io.IOException { 253 | return newBuilder().mergeFrom(input).buildParsed(); 254 | } 255 | public static com.github.sstone.amqp.proxy.gpbtest.Gpbtest.Person parseFrom( 256 | com.google.protobuf.CodedInputStream input, 257 | com.google.protobuf.ExtensionRegistryLite extensionRegistry) 258 | throws java.io.IOException { 259 | return newBuilder().mergeFrom(input, extensionRegistry) 260 | .buildParsed(); 261 | } 262 | 263 | public static Builder newBuilder() { return Builder.create(); } 264 | public Builder newBuilderForType() { return newBuilder(); } 265 | public static Builder newBuilder(com.github.sstone.amqp.proxy.gpbtest.Gpbtest.Person prototype) { 266 | return newBuilder().mergeFrom(prototype); 267 | } 268 | public Builder toBuilder() { return newBuilder(this); } 269 | 270 | @java.lang.Override 271 | protected Builder newBuilderForType( 272 | com.google.protobuf.GeneratedMessage.BuilderParent parent) { 273 | Builder builder = new Builder(parent); 274 | return builder; 275 | } 276 | public static final class Builder extends 277 | com.google.protobuf.GeneratedMessage.Builder 278 | implements com.github.sstone.amqp.proxy.gpbtest.Gpbtest.PersonOrBuilder { 279 | public static final com.google.protobuf.Descriptors.Descriptor 280 | getDescriptor() { 281 | return com.github.sstone.amqp.proxy.gpbtest.Gpbtest.internal_static_com_github_sstone_amqp_proxy_gpbtest_Person_descriptor; 282 | } 283 | 284 | protected com.google.protobuf.GeneratedMessage.FieldAccessorTable 285 | internalGetFieldAccessorTable() { 286 | return com.github.sstone.amqp.proxy.gpbtest.Gpbtest.internal_static_com_github_sstone_amqp_proxy_gpbtest_Person_fieldAccessorTable; 287 | } 288 | 289 | // Construct using com.github.sstone.amqp.proxy.gpbtest.Gpbtest.Person.newBuilder() 290 | private Builder() { 291 | maybeForceBuilderInitialization(); 292 | } 293 | 294 | private Builder(BuilderParent parent) { 295 | super(parent); 296 | maybeForceBuilderInitialization(); 297 | } 298 | private void maybeForceBuilderInitialization() { 299 | if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { 300 | } 301 | } 302 | private static Builder create() { 303 | return new Builder(); 304 | } 305 | 306 | public Builder clear() { 307 | super.clear(); 308 | id_ = 0; 309 | bitField0_ = (bitField0_ & ~0x00000001); 310 | name_ = ""; 311 | bitField0_ = (bitField0_ & ~0x00000002); 312 | email_ = ""; 313 | bitField0_ = (bitField0_ & ~0x00000004); 314 | return this; 315 | } 316 | 317 | public Builder clone() { 318 | return create().mergeFrom(buildPartial()); 319 | } 320 | 321 | public com.google.protobuf.Descriptors.Descriptor 322 | getDescriptorForType() { 323 | return com.github.sstone.amqp.proxy.gpbtest.Gpbtest.Person.getDescriptor(); 324 | } 325 | 326 | public com.github.sstone.amqp.proxy.gpbtest.Gpbtest.Person getDefaultInstanceForType() { 327 | return com.github.sstone.amqp.proxy.gpbtest.Gpbtest.Person.getDefaultInstance(); 328 | } 329 | 330 | public com.github.sstone.amqp.proxy.gpbtest.Gpbtest.Person build() { 331 | com.github.sstone.amqp.proxy.gpbtest.Gpbtest.Person result = buildPartial(); 332 | if (!result.isInitialized()) { 333 | throw newUninitializedMessageException(result); 334 | } 335 | return result; 336 | } 337 | 338 | private com.github.sstone.amqp.proxy.gpbtest.Gpbtest.Person buildParsed() 339 | throws com.google.protobuf.InvalidProtocolBufferException { 340 | com.github.sstone.amqp.proxy.gpbtest.Gpbtest.Person result = buildPartial(); 341 | if (!result.isInitialized()) { 342 | throw newUninitializedMessageException( 343 | result).asInvalidProtocolBufferException(); 344 | } 345 | return result; 346 | } 347 | 348 | public com.github.sstone.amqp.proxy.gpbtest.Gpbtest.Person buildPartial() { 349 | com.github.sstone.amqp.proxy.gpbtest.Gpbtest.Person result = new com.github.sstone.amqp.proxy.gpbtest.Gpbtest.Person(this); 350 | int from_bitField0_ = bitField0_; 351 | int to_bitField0_ = 0; 352 | if (((from_bitField0_ & 0x00000001) == 0x00000001)) { 353 | to_bitField0_ |= 0x00000001; 354 | } 355 | result.id_ = id_; 356 | if (((from_bitField0_ & 0x00000002) == 0x00000002)) { 357 | to_bitField0_ |= 0x00000002; 358 | } 359 | result.name_ = name_; 360 | if (((from_bitField0_ & 0x00000004) == 0x00000004)) { 361 | to_bitField0_ |= 0x00000004; 362 | } 363 | result.email_ = email_; 364 | result.bitField0_ = to_bitField0_; 365 | onBuilt(); 366 | return result; 367 | } 368 | 369 | public Builder mergeFrom(com.google.protobuf.Message other) { 370 | if (other instanceof com.github.sstone.amqp.proxy.gpbtest.Gpbtest.Person) { 371 | return mergeFrom((com.github.sstone.amqp.proxy.gpbtest.Gpbtest.Person)other); 372 | } else { 373 | super.mergeFrom(other); 374 | return this; 375 | } 376 | } 377 | 378 | public Builder mergeFrom(com.github.sstone.amqp.proxy.gpbtest.Gpbtest.Person other) { 379 | if (other == com.github.sstone.amqp.proxy.gpbtest.Gpbtest.Person.getDefaultInstance()) return this; 380 | if (other.hasId()) { 381 | setId(other.getId()); 382 | } 383 | if (other.hasName()) { 384 | setName(other.getName()); 385 | } 386 | if (other.hasEmail()) { 387 | setEmail(other.getEmail()); 388 | } 389 | this.mergeUnknownFields(other.getUnknownFields()); 390 | return this; 391 | } 392 | 393 | public final boolean isInitialized() { 394 | if (!hasId()) { 395 | 396 | return false; 397 | } 398 | if (!hasName()) { 399 | 400 | return false; 401 | } 402 | return true; 403 | } 404 | 405 | public Builder mergeFrom( 406 | com.google.protobuf.CodedInputStream input, 407 | com.google.protobuf.ExtensionRegistryLite extensionRegistry) 408 | throws java.io.IOException { 409 | com.google.protobuf.UnknownFieldSet.Builder unknownFields = 410 | com.google.protobuf.UnknownFieldSet.newBuilder( 411 | this.getUnknownFields()); 412 | while (true) { 413 | int tag = input.readTag(); 414 | switch (tag) { 415 | case 0: 416 | this.setUnknownFields(unknownFields.build()); 417 | onChanged(); 418 | return this; 419 | default: { 420 | if (!parseUnknownField(input, unknownFields, 421 | extensionRegistry, tag)) { 422 | this.setUnknownFields(unknownFields.build()); 423 | onChanged(); 424 | return this; 425 | } 426 | break; 427 | } 428 | case 8: { 429 | bitField0_ |= 0x00000001; 430 | id_ = input.readInt32(); 431 | break; 432 | } 433 | case 18: { 434 | bitField0_ |= 0x00000002; 435 | name_ = input.readBytes(); 436 | break; 437 | } 438 | case 26: { 439 | bitField0_ |= 0x00000004; 440 | email_ = input.readBytes(); 441 | break; 442 | } 443 | } 444 | } 445 | } 446 | 447 | private int bitField0_; 448 | 449 | // required int32 id = 1; 450 | private int id_ ; 451 | public boolean hasId() { 452 | return ((bitField0_ & 0x00000001) == 0x00000001); 453 | } 454 | public int getId() { 455 | return id_; 456 | } 457 | public Builder setId(int value) { 458 | bitField0_ |= 0x00000001; 459 | id_ = value; 460 | onChanged(); 461 | return this; 462 | } 463 | public Builder clearId() { 464 | bitField0_ = (bitField0_ & ~0x00000001); 465 | id_ = 0; 466 | onChanged(); 467 | return this; 468 | } 469 | 470 | // required string name = 2; 471 | private java.lang.Object name_ = ""; 472 | public boolean hasName() { 473 | return ((bitField0_ & 0x00000002) == 0x00000002); 474 | } 475 | public String getName() { 476 | java.lang.Object ref = name_; 477 | if (!(ref instanceof String)) { 478 | String s = ((com.google.protobuf.ByteString) ref).toStringUtf8(); 479 | name_ = s; 480 | return s; 481 | } else { 482 | return (String) ref; 483 | } 484 | } 485 | public Builder setName(String value) { 486 | if (value == null) { 487 | throw new NullPointerException(); 488 | } 489 | bitField0_ |= 0x00000002; 490 | name_ = value; 491 | onChanged(); 492 | return this; 493 | } 494 | public Builder clearName() { 495 | bitField0_ = (bitField0_ & ~0x00000002); 496 | name_ = getDefaultInstance().getName(); 497 | onChanged(); 498 | return this; 499 | } 500 | void setName(com.google.protobuf.ByteString value) { 501 | bitField0_ |= 0x00000002; 502 | name_ = value; 503 | onChanged(); 504 | } 505 | 506 | // optional string email = 3; 507 | private java.lang.Object email_ = ""; 508 | public boolean hasEmail() { 509 | return ((bitField0_ & 0x00000004) == 0x00000004); 510 | } 511 | public String getEmail() { 512 | java.lang.Object ref = email_; 513 | if (!(ref instanceof String)) { 514 | String s = ((com.google.protobuf.ByteString) ref).toStringUtf8(); 515 | email_ = s; 516 | return s; 517 | } else { 518 | return (String) ref; 519 | } 520 | } 521 | public Builder setEmail(String value) { 522 | if (value == null) { 523 | throw new NullPointerException(); 524 | } 525 | bitField0_ |= 0x00000004; 526 | email_ = value; 527 | onChanged(); 528 | return this; 529 | } 530 | public Builder clearEmail() { 531 | bitField0_ = (bitField0_ & ~0x00000004); 532 | email_ = getDefaultInstance().getEmail(); 533 | onChanged(); 534 | return this; 535 | } 536 | void setEmail(com.google.protobuf.ByteString value) { 537 | bitField0_ |= 0x00000004; 538 | email_ = value; 539 | onChanged(); 540 | } 541 | 542 | // @@protoc_insertion_point(builder_scope:com.github.sstone.amqp.proxy.gpbtest.Person) 543 | } 544 | 545 | static { 546 | defaultInstance = new Person(true); 547 | defaultInstance.initFields(); 548 | } 549 | 550 | // @@protoc_insertion_point(class_scope:com.github.sstone.amqp.proxy.gpbtest.Person) 551 | } 552 | 553 | private static com.google.protobuf.Descriptors.Descriptor 554 | internal_static_com_github_sstone_amqp_proxy_gpbtest_Person_descriptor; 555 | private static 556 | com.google.protobuf.GeneratedMessage.FieldAccessorTable 557 | internal_static_com_github_sstone_amqp_proxy_gpbtest_Person_fieldAccessorTable; 558 | 559 | public static com.google.protobuf.Descriptors.FileDescriptor 560 | getDescriptor() { 561 | return descriptor; 562 | } 563 | private static com.google.protobuf.Descriptors.FileDescriptor 564 | descriptor; 565 | static { 566 | java.lang.String[] descriptorData = { 567 | "\n\037src/test/resource/gpbtest.proto\022$com.g" + 568 | "ithub.sstone.amqp.proxy.gpbtest\"1\n\006Perso" + 569 | "n\022\n\n\002id\030\001 \002(\005\022\014\n\004name\030\002 \002(\t\022\r\n\005email\030\003 \001" + 570 | "(\t" 571 | }; 572 | com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = 573 | new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() { 574 | public com.google.protobuf.ExtensionRegistry assignDescriptors( 575 | com.google.protobuf.Descriptors.FileDescriptor root) { 576 | descriptor = root; 577 | internal_static_com_github_sstone_amqp_proxy_gpbtest_Person_descriptor = 578 | getDescriptor().getMessageTypes().get(0); 579 | internal_static_com_github_sstone_amqp_proxy_gpbtest_Person_fieldAccessorTable = new 580 | com.google.protobuf.GeneratedMessage.FieldAccessorTable( 581 | internal_static_com_github_sstone_amqp_proxy_gpbtest_Person_descriptor, 582 | new java.lang.String[] { "Id", "Name", "Email", }, 583 | com.github.sstone.amqp.proxy.gpbtest.Gpbtest.Person.class, 584 | com.github.sstone.amqp.proxy.gpbtest.Gpbtest.Person.Builder.class); 585 | return null; 586 | } 587 | }; 588 | com.google.protobuf.Descriptors.FileDescriptor 589 | .internalBuildGeneratedFileFrom(descriptorData, 590 | new com.google.protobuf.Descriptors.FileDescriptor[] { 591 | }, assigner); 592 | } 593 | 594 | // @@protoc_insertion_point(outer_class_scope) 595 | } 596 | -------------------------------------------------------------------------------- /src/test/java/com/github.sstone/amqp/proxy/thrifttest/Person.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Autogenerated by Thrift Compiler (0.8.0) 3 | * 4 | * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING 5 | * @generated 6 | */ 7 | package com.github.sstone.amqp.proxy.thrifttest; 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 java.util.List; 16 | import java.util.ArrayList; 17 | import java.util.Map; 18 | import java.util.HashMap; 19 | import java.util.EnumMap; 20 | import java.util.Set; 21 | import java.util.HashSet; 22 | import java.util.EnumSet; 23 | import java.util.Collections; 24 | import java.util.BitSet; 25 | import java.nio.ByteBuffer; 26 | import java.util.Arrays; 27 | import org.slf4j.Logger; 28 | import org.slf4j.LoggerFactory; 29 | 30 | public class Person implements org.apache.thrift.TBase, java.io.Serializable, Cloneable { 31 | private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("Person"); 32 | 33 | private static final org.apache.thrift.protocol.TField ID_FIELD_DESC = new org.apache.thrift.protocol.TField("id", org.apache.thrift.protocol.TType.I32, (short)1); 34 | 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)2); 35 | private static final org.apache.thrift.protocol.TField EMAIL_FIELD_DESC = new org.apache.thrift.protocol.TField("email", org.apache.thrift.protocol.TType.STRING, (short)3); 36 | 37 | private static final Map, SchemeFactory> schemes = new HashMap, SchemeFactory>(); 38 | static { 39 | schemes.put(StandardScheme.class, new PersonStandardSchemeFactory()); 40 | schemes.put(TupleScheme.class, new PersonTupleSchemeFactory()); 41 | } 42 | 43 | public int id; // required 44 | public String name; // required 45 | public String email; // optional 46 | 47 | /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */ 48 | public enum _Fields implements org.apache.thrift.TFieldIdEnum { 49 | ID((short)1, "id"), 50 | NAME((short)2, "name"), 51 | EMAIL((short)3, "email"); 52 | 53 | private static final Map byName = new HashMap(); 54 | 55 | static { 56 | for (_Fields field : EnumSet.allOf(_Fields.class)) { 57 | byName.put(field.getFieldName(), field); 58 | } 59 | } 60 | 61 | /** 62 | * Find the _Fields constant that matches fieldId, or null if its not found. 63 | */ 64 | public static _Fields findByThriftId(int fieldId) { 65 | switch(fieldId) { 66 | case 1: // ID 67 | return ID; 68 | case 2: // NAME 69 | return NAME; 70 | case 3: // EMAIL 71 | return EMAIL; 72 | default: 73 | return null; 74 | } 75 | } 76 | 77 | /** 78 | * Find the _Fields constant that matches fieldId, throwing an exception 79 | * if it is not found. 80 | */ 81 | public static _Fields findByThriftIdOrThrow(int fieldId) { 82 | _Fields fields = findByThriftId(fieldId); 83 | if (fields == null) throw new IllegalArgumentException("Field " + fieldId + " doesn't exist!"); 84 | return fields; 85 | } 86 | 87 | /** 88 | * Find the _Fields constant that matches name, or null if its not found. 89 | */ 90 | public static _Fields findByName(String name) { 91 | return byName.get(name); 92 | } 93 | 94 | private final short _thriftId; 95 | private final String _fieldName; 96 | 97 | _Fields(short thriftId, String fieldName) { 98 | _thriftId = thriftId; 99 | _fieldName = fieldName; 100 | } 101 | 102 | public short getThriftFieldId() { 103 | return _thriftId; 104 | } 105 | 106 | public String getFieldName() { 107 | return _fieldName; 108 | } 109 | } 110 | 111 | // isset id assignments 112 | private static final int __ID_ISSET_ID = 0; 113 | private BitSet __isset_bit_vector = new BitSet(1); 114 | private _Fields optionals[] = {_Fields.EMAIL}; 115 | public static final Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap; 116 | static { 117 | Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class); 118 | tmpMap.put(_Fields.ID, new org.apache.thrift.meta_data.FieldMetaData("id", org.apache.thrift.TFieldRequirementType.REQUIRED, 119 | new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.I32))); 120 | tmpMap.put(_Fields.NAME, new org.apache.thrift.meta_data.FieldMetaData("name", org.apache.thrift.TFieldRequirementType.REQUIRED, 121 | new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING))); 122 | tmpMap.put(_Fields.EMAIL, new org.apache.thrift.meta_data.FieldMetaData("email", org.apache.thrift.TFieldRequirementType.OPTIONAL, 123 | new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING))); 124 | metaDataMap = Collections.unmodifiableMap(tmpMap); 125 | org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(Person.class, metaDataMap); 126 | } 127 | 128 | public Person() { 129 | } 130 | 131 | public Person( 132 | int id, 133 | String name) 134 | { 135 | this(); 136 | this.id = id; 137 | setIdIsSet(true); 138 | this.name = name; 139 | } 140 | 141 | /** 142 | * Performs a deep copy on other. 143 | */ 144 | public Person(Person other) { 145 | __isset_bit_vector.clear(); 146 | __isset_bit_vector.or(other.__isset_bit_vector); 147 | this.id = other.id; 148 | if (other.isSetName()) { 149 | this.name = other.name; 150 | } 151 | if (other.isSetEmail()) { 152 | this.email = other.email; 153 | } 154 | } 155 | 156 | public Person deepCopy() { 157 | return new Person(this); 158 | } 159 | 160 | @Override 161 | public void clear() { 162 | setIdIsSet(false); 163 | this.id = 0; 164 | this.name = null; 165 | this.email = null; 166 | } 167 | 168 | public int getId() { 169 | return this.id; 170 | } 171 | 172 | public Person setId(int id) { 173 | this.id = id; 174 | setIdIsSet(true); 175 | return this; 176 | } 177 | 178 | public void unsetId() { 179 | __isset_bit_vector.clear(__ID_ISSET_ID); 180 | } 181 | 182 | /** Returns true if field id is set (has been assigned a value) and false otherwise */ 183 | public boolean isSetId() { 184 | return __isset_bit_vector.get(__ID_ISSET_ID); 185 | } 186 | 187 | public void setIdIsSet(boolean value) { 188 | __isset_bit_vector.set(__ID_ISSET_ID, value); 189 | } 190 | 191 | public String getName() { 192 | return this.name; 193 | } 194 | 195 | public Person setName(String name) { 196 | this.name = name; 197 | return this; 198 | } 199 | 200 | public void unsetName() { 201 | this.name = null; 202 | } 203 | 204 | /** Returns true if field name is set (has been assigned a value) and false otherwise */ 205 | public boolean isSetName() { 206 | return this.name != null; 207 | } 208 | 209 | public void setNameIsSet(boolean value) { 210 | if (!value) { 211 | this.name = null; 212 | } 213 | } 214 | 215 | public String getEmail() { 216 | return this.email; 217 | } 218 | 219 | public Person setEmail(String email) { 220 | this.email = email; 221 | return this; 222 | } 223 | 224 | public void unsetEmail() { 225 | this.email = null; 226 | } 227 | 228 | /** Returns true if field email is set (has been assigned a value) and false otherwise */ 229 | public boolean isSetEmail() { 230 | return this.email != null; 231 | } 232 | 233 | public void setEmailIsSet(boolean value) { 234 | if (!value) { 235 | this.email = null; 236 | } 237 | } 238 | 239 | public void setFieldValue(_Fields field, Object value) { 240 | switch (field) { 241 | case ID: 242 | if (value == null) { 243 | unsetId(); 244 | } else { 245 | setId((Integer)value); 246 | } 247 | break; 248 | 249 | case NAME: 250 | if (value == null) { 251 | unsetName(); 252 | } else { 253 | setName((String)value); 254 | } 255 | break; 256 | 257 | case EMAIL: 258 | if (value == null) { 259 | unsetEmail(); 260 | } else { 261 | setEmail((String)value); 262 | } 263 | break; 264 | 265 | } 266 | } 267 | 268 | public Object getFieldValue(_Fields field) { 269 | switch (field) { 270 | case ID: 271 | return Integer.valueOf(getId()); 272 | 273 | case NAME: 274 | return getName(); 275 | 276 | case EMAIL: 277 | return getEmail(); 278 | 279 | } 280 | throw new IllegalStateException(); 281 | } 282 | 283 | /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */ 284 | public boolean isSet(_Fields field) { 285 | if (field == null) { 286 | throw new IllegalArgumentException(); 287 | } 288 | 289 | switch (field) { 290 | case ID: 291 | return isSetId(); 292 | case NAME: 293 | return isSetName(); 294 | case EMAIL: 295 | return isSetEmail(); 296 | } 297 | throw new IllegalStateException(); 298 | } 299 | 300 | @Override 301 | public boolean equals(Object that) { 302 | if (that == null) 303 | return false; 304 | if (that instanceof Person) 305 | return this.equals((Person)that); 306 | return false; 307 | } 308 | 309 | public boolean equals(Person that) { 310 | if (that == null) 311 | return false; 312 | 313 | boolean this_present_id = true; 314 | boolean that_present_id = true; 315 | if (this_present_id || that_present_id) { 316 | if (!(this_present_id && that_present_id)) 317 | return false; 318 | if (this.id != that.id) 319 | return false; 320 | } 321 | 322 | boolean this_present_name = true && this.isSetName(); 323 | boolean that_present_name = true && that.isSetName(); 324 | if (this_present_name || that_present_name) { 325 | if (!(this_present_name && that_present_name)) 326 | return false; 327 | if (!this.name.equals(that.name)) 328 | return false; 329 | } 330 | 331 | boolean this_present_email = true && this.isSetEmail(); 332 | boolean that_present_email = true && that.isSetEmail(); 333 | if (this_present_email || that_present_email) { 334 | if (!(this_present_email && that_present_email)) 335 | return false; 336 | if (!this.email.equals(that.email)) 337 | return false; 338 | } 339 | 340 | return true; 341 | } 342 | 343 | @Override 344 | public int hashCode() { 345 | return 0; 346 | } 347 | 348 | public int compareTo(Person other) { 349 | if (!getClass().equals(other.getClass())) { 350 | return getClass().getName().compareTo(other.getClass().getName()); 351 | } 352 | 353 | int lastComparison = 0; 354 | Person typedOther = (Person)other; 355 | 356 | lastComparison = Boolean.valueOf(isSetId()).compareTo(typedOther.isSetId()); 357 | if (lastComparison != 0) { 358 | return lastComparison; 359 | } 360 | if (isSetId()) { 361 | lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.id, typedOther.id); 362 | if (lastComparison != 0) { 363 | return lastComparison; 364 | } 365 | } 366 | lastComparison = Boolean.valueOf(isSetName()).compareTo(typedOther.isSetName()); 367 | if (lastComparison != 0) { 368 | return lastComparison; 369 | } 370 | if (isSetName()) { 371 | lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.name, typedOther.name); 372 | if (lastComparison != 0) { 373 | return lastComparison; 374 | } 375 | } 376 | lastComparison = Boolean.valueOf(isSetEmail()).compareTo(typedOther.isSetEmail()); 377 | if (lastComparison != 0) { 378 | return lastComparison; 379 | } 380 | if (isSetEmail()) { 381 | lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.email, typedOther.email); 382 | if (lastComparison != 0) { 383 | return lastComparison; 384 | } 385 | } 386 | return 0; 387 | } 388 | 389 | public _Fields fieldForId(int fieldId) { 390 | return _Fields.findByThriftId(fieldId); 391 | } 392 | 393 | public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException { 394 | schemes.get(iprot.getScheme()).getScheme().read(iprot, this); 395 | } 396 | 397 | public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException { 398 | schemes.get(oprot.getScheme()).getScheme().write(oprot, this); 399 | } 400 | 401 | @Override 402 | public String toString() { 403 | StringBuilder sb = new StringBuilder("Person("); 404 | boolean first = true; 405 | 406 | sb.append("id:"); 407 | sb.append(this.id); 408 | first = false; 409 | if (!first) sb.append(", "); 410 | sb.append("name:"); 411 | if (this.name == null) { 412 | sb.append("null"); 413 | } else { 414 | sb.append(this.name); 415 | } 416 | first = false; 417 | if (isSetEmail()) { 418 | if (!first) sb.append(", "); 419 | sb.append("email:"); 420 | if (this.email == null) { 421 | sb.append("null"); 422 | } else { 423 | sb.append(this.email); 424 | } 425 | first = false; 426 | } 427 | sb.append(")"); 428 | return sb.toString(); 429 | } 430 | 431 | public void validate() throws org.apache.thrift.TException { 432 | // check for required fields 433 | // alas, we cannot check 'id' because it's a primitive and you chose the non-beans generator. 434 | if (name == null) { 435 | throw new org.apache.thrift.protocol.TProtocolException("Required field 'name' was not present! Struct: " + toString()); 436 | } 437 | } 438 | 439 | private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException { 440 | try { 441 | write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out))); 442 | } catch (org.apache.thrift.TException te) { 443 | throw new java.io.IOException(te); 444 | } 445 | } 446 | 447 | private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, ClassNotFoundException { 448 | try { 449 | // it doesn't seem like you should have to do this, but java serialization is wacky, and doesn't call the default constructor. 450 | __isset_bit_vector = new BitSet(1); 451 | read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in))); 452 | } catch (org.apache.thrift.TException te) { 453 | throw new java.io.IOException(te); 454 | } 455 | } 456 | 457 | private static class PersonStandardSchemeFactory implements SchemeFactory { 458 | public PersonStandardScheme getScheme() { 459 | return new PersonStandardScheme(); 460 | } 461 | } 462 | 463 | private static class PersonStandardScheme extends StandardScheme { 464 | 465 | public void read(org.apache.thrift.protocol.TProtocol iprot, Person struct) throws org.apache.thrift.TException { 466 | org.apache.thrift.protocol.TField schemeField; 467 | iprot.readStructBegin(); 468 | while (true) 469 | { 470 | schemeField = iprot.readFieldBegin(); 471 | if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { 472 | break; 473 | } 474 | switch (schemeField.id) { 475 | case 1: // ID 476 | if (schemeField.type == org.apache.thrift.protocol.TType.I32) { 477 | struct.id = iprot.readI32(); 478 | struct.setIdIsSet(true); 479 | } else { 480 | org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); 481 | } 482 | break; 483 | case 2: // NAME 484 | if (schemeField.type == org.apache.thrift.protocol.TType.STRING) { 485 | struct.name = iprot.readString(); 486 | struct.setNameIsSet(true); 487 | } else { 488 | org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); 489 | } 490 | break; 491 | case 3: // EMAIL 492 | if (schemeField.type == org.apache.thrift.protocol.TType.STRING) { 493 | struct.email = iprot.readString(); 494 | struct.setEmailIsSet(true); 495 | } else { 496 | org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); 497 | } 498 | break; 499 | default: 500 | org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); 501 | } 502 | iprot.readFieldEnd(); 503 | } 504 | iprot.readStructEnd(); 505 | 506 | // check for required fields of primitive type, which can't be checked in the validate method 507 | if (!struct.isSetId()) { 508 | throw new org.apache.thrift.protocol.TProtocolException("Required field 'id' was not found in serialized data! Struct: " + toString()); 509 | } 510 | struct.validate(); 511 | } 512 | 513 | public void write(org.apache.thrift.protocol.TProtocol oprot, Person struct) throws org.apache.thrift.TException { 514 | struct.validate(); 515 | 516 | oprot.writeStructBegin(STRUCT_DESC); 517 | oprot.writeFieldBegin(ID_FIELD_DESC); 518 | oprot.writeI32(struct.id); 519 | oprot.writeFieldEnd(); 520 | if (struct.name != null) { 521 | oprot.writeFieldBegin(NAME_FIELD_DESC); 522 | oprot.writeString(struct.name); 523 | oprot.writeFieldEnd(); 524 | } 525 | if (struct.email != null) { 526 | if (struct.isSetEmail()) { 527 | oprot.writeFieldBegin(EMAIL_FIELD_DESC); 528 | oprot.writeString(struct.email); 529 | oprot.writeFieldEnd(); 530 | } 531 | } 532 | oprot.writeFieldStop(); 533 | oprot.writeStructEnd(); 534 | } 535 | 536 | } 537 | 538 | private static class PersonTupleSchemeFactory implements SchemeFactory { 539 | public PersonTupleScheme getScheme() { 540 | return new PersonTupleScheme(); 541 | } 542 | } 543 | 544 | private static class PersonTupleScheme extends TupleScheme { 545 | 546 | @Override 547 | public void write(org.apache.thrift.protocol.TProtocol prot, Person struct) throws org.apache.thrift.TException { 548 | TTupleProtocol oprot = (TTupleProtocol) prot; 549 | oprot.writeI32(struct.id); 550 | oprot.writeString(struct.name); 551 | BitSet optionals = new BitSet(); 552 | if (struct.isSetEmail()) { 553 | optionals.set(0); 554 | } 555 | oprot.writeBitSet(optionals, 1); 556 | if (struct.isSetEmail()) { 557 | oprot.writeString(struct.email); 558 | } 559 | } 560 | 561 | @Override 562 | public void read(org.apache.thrift.protocol.TProtocol prot, Person struct) throws org.apache.thrift.TException { 563 | TTupleProtocol iprot = (TTupleProtocol) prot; 564 | struct.id = iprot.readI32(); 565 | struct.setIdIsSet(true); 566 | struct.name = iprot.readString(); 567 | struct.setNameIsSet(true); 568 | BitSet incoming = iprot.readBitSet(1); 569 | if (incoming.get(0)) { 570 | struct.email = iprot.readString(); 571 | struct.setEmailIsSet(true); 572 | } 573 | } 574 | } 575 | 576 | } 577 | 578 | -------------------------------------------------------------------------------- /src/test/resource/calculator.proto: -------------------------------------------------------------------------------- 1 | package com.github.sstone.amqp.proxy.calculator; 2 | 3 | // simple calculator API 4 | 5 | // Add request 6 | // 7 | message AddRequest { 8 | required int32 x = 1; 9 | required int32 y = 2; 10 | } 11 | 12 | // Add response 13 | // 14 | message AddResponse { 15 | required int32 x = 1; 16 | required int32 y = 2; 17 | required int32 sum = 3; 18 | } 19 | -------------------------------------------------------------------------------- /src/test/resource/gpbtest.proto: -------------------------------------------------------------------------------- 1 | package com.github.sstone.amqp.proxy.gpbtest; 2 | 3 | message Person { 4 | required int32 id = 1; 5 | required string name = 2; 6 | optional string email = 3; 7 | } 8 | -------------------------------------------------------------------------------- /src/test/resource/reference.conf: -------------------------------------------------------------------------------- 1 | akka { 2 | event-handlers = ["akka.event.slf4j.Slf4jEventHandler"] 3 | loglevel = "DEBUG" 4 | actor { 5 | debug { 6 | # enable function of LoggingReceive, which is to log any received message at 7 | # DEBUG level 8 | receive = on 9 | } 10 | } 11 | } 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/test/scala/com/github.sstone/amqp/proxy/ErrorTest.scala: -------------------------------------------------------------------------------- 1 | package com.github.sstone.amqp.proxy 2 | 3 | import org.junit.runner.RunWith 4 | import org.scalatest.junit.JUnitRunner 5 | import org.scalatest.WordSpec 6 | import org.scalatest.matchers.ShouldMatchers 7 | import akka.testkit.{ImplicitSender, TestKit} 8 | import akka.actor.{Actor, Props, ActorSystem} 9 | import akka.pattern.{AskTimeoutException, ask} 10 | import concurrent.Await 11 | import concurrent.duration._ 12 | import com.rabbitmq.client.ConnectionFactory 13 | import com.github.sstone.amqp.{Amqp, RpcClient, RpcServer, ConnectionOwner} 14 | import com.github.sstone.amqp.Amqp._ 15 | import serializers.JsonSerializer 16 | import com.github.sstone.amqp.Amqp.ChannelParameters 17 | import scala.Some 18 | import com.github.sstone.amqp.Amqp.ExchangeParameters 19 | import com.github.sstone.amqp.Amqp.AddBinding 20 | import com.github.sstone.amqp.Amqp.QueueParameters 21 | import java.util.concurrent.TimeUnit 22 | 23 | object ErrorTest { 24 | case class ErrorRequest(foo: String) 25 | } 26 | 27 | @RunWith(classOf[JUnitRunner]) 28 | class ErrorTest extends TestKit(ActorSystem("TestSystem")) with ImplicitSender with WordSpec with ShouldMatchers { 29 | import ErrorTest.ErrorRequest 30 | implicit val timeout: akka.util.Timeout = 5 seconds 31 | 32 | "AMQP Proxy" should { 33 | 34 | "handle server errors in" in { 35 | pending 36 | val connFactory = new ConnectionFactory() 37 | val conn = system.actorOf(Props(new ConnectionOwner(connFactory)), name = "conn") 38 | val exchange = ExchangeParameters(name = "amq.direct", exchangeType = "", passive = true) 39 | val queue = QueueParameters(name = "error", passive = false, autodelete = true) 40 | val channelParams = ChannelParameters(qos = 1) 41 | 42 | 43 | val nogood = system.actorOf(Props(new Actor() { 44 | def receive = { 45 | case ErrorRequest(foo) => sender ! akka.actor.Status.Failure(new RuntimeException("crash")) 46 | } 47 | })) 48 | // create an AMQP proxy server which consumes messages from the "error" queue and passes 49 | // them to our nogood actor 50 | val server = ConnectionOwner.createChildActor( 51 | conn, 52 | RpcServer.props(queue, exchange, "error", new AmqpProxy.ProxyServer(nogood), channelParams)) 53 | 54 | // create an AMQP proxy client in front of the "error queue" 55 | val client = ConnectionOwner.createChildActor(conn, RpcClient.props()) 56 | val proxy = system.actorOf( 57 | AmqpProxy.ProxyClient.props(client, "amq.direct", "error", JsonSerializer), 58 | name = "proxy") 59 | 60 | Amqp.waitForConnection(system, server).await() 61 | 62 | val thrown = evaluating(Await.result(proxy ? ErrorRequest("test"), 5 seconds)) should produce[AmqpProxyException] 63 | thrown.getMessage should be("crash") 64 | } 65 | 66 | "handle client-side serialization errors" in { 67 | pending 68 | val connFactory = new ConnectionFactory() 69 | val conn = system.actorOf(Props(new ConnectionOwner(connFactory))) 70 | val client = ConnectionOwner.createChildActor(conn, RpcClient.props()) 71 | val proxy = system.actorOf(AmqpProxy.ProxyClient.props(client, "amq.direct", "client_side_error", JsonSerializer)) 72 | 73 | val badrequest = Map(1 -> 1) // lift-json will not serialize this, Map keys must be Strings 74 | val thrown = evaluating(Await.result(proxy ? badrequest, 5 seconds)) should produce[AmqpProxyException] 75 | thrown.getMessage should include("Serialization") 76 | } 77 | 78 | "handle server-side timeouts" in { 79 | val connFactory = new ConnectionFactory() 80 | val conn = system.actorOf(Props(new ConnectionOwner(connFactory))) 81 | 82 | // create an actor that does nothing 83 | val donothing = system.actorOf(Props(new Actor() { 84 | def receive = { 85 | case msg => {} 86 | } 87 | })) 88 | val exchange = ExchangeParameters(name = "amq.direct", exchangeType = "", passive = true) 89 | val queue = QueueParameters(name = "donothing", passive = false, autodelete = true) 90 | // val server = ConnectionOwner.createChildActor( 91 | // conn, 92 | // RpcServer.props(queue, exchange, "donothing", new AmqpProxy.ProxyServer(donothing, timeout = 1 second), channelParams)) 93 | val server = ConnectionOwner.createChildActor(conn, RpcServer.props(new AmqpProxy.ProxyServer(donothing, timeout = 1 second), channelParams = Some(ChannelParameters(qos = 1)))) 94 | Amqp.waitForConnection(system, server).await(5, TimeUnit.SECONDS) 95 | server ! AddBinding(Binding(exchange, queue, routingKey = "donothing")) 96 | val Amqp.Ok(AddBinding(_), _) = receiveOne(1 second) 97 | val client = ConnectionOwner.createChildActor(conn, RpcClient.props()) 98 | val proxy = system.actorOf(AmqpProxy.ProxyClient.props(client, "amq.direct", "donothing", JsonSerializer, timeout = 2 seconds)) 99 | 100 | Amqp.waitForConnection(system, server, client).await() 101 | evaluating(Await.result(proxy ? "test", 5 seconds)) should produce[AskTimeoutException] 102 | } 103 | } 104 | } -------------------------------------------------------------------------------- /src/test/scala/com/github.sstone/amqp/proxy/RemoteGpbCallTest.scala: -------------------------------------------------------------------------------- 1 | package com.github.sstone.amqp.proxy 2 | 3 | import akka.actor.{Actor, Props, ActorSystem} 4 | import akka.pattern.ask 5 | import akka.testkit.{ImplicitSender, TestKit} 6 | import calculator.Calculator.{AddResponse, AddRequest} 7 | import com.github.sstone.amqp.Amqp.Binding 8 | import com.github.sstone.amqp.Amqp.ChannelParameters 9 | import com.github.sstone.amqp.Amqp.ExchangeParameters 10 | import com.github.sstone.amqp.Amqp.QueueParameters 11 | import com.github.sstone.amqp.Amqp._ 12 | import com.github.sstone.amqp.{Amqp, RpcClient, RpcServer, ConnectionOwner} 13 | import com.rabbitmq.client.ConnectionFactory 14 | import concurrent.duration._ 15 | import concurrent.{Future, Await, ExecutionContext} 16 | import java.util.concurrent.TimeUnit 17 | import org.junit.runner.RunWith 18 | import org.scalatest.WordSpec 19 | import org.scalatest.junit.JUnitRunner 20 | import org.scalatest.matchers.ShouldMatchers 21 | import serializers.ProtobufSerializer 22 | 23 | @RunWith(classOf[JUnitRunner]) 24 | class RemoteGpbCallTest extends TestKit(ActorSystem("TestSystem")) with ImplicitSender with WordSpec with ShouldMatchers { 25 | "AMQP Proxy" should { 26 | "handle GPB calls" in { 27 | import ExecutionContext.Implicits.global 28 | val connFactory = new ConnectionFactory() 29 | val conn = system.actorOf(Props(new ConnectionOwner(connFactory)), name = "conn") 30 | val exchange = ExchangeParameters(name = "amq.direct", exchangeType = "", passive = true) 31 | val queue = QueueParameters(name = "calculator-gpb", passive = false, autodelete = true) 32 | 33 | // create a simple calculator actor 34 | val calc = system.actorOf(Props(new Actor() { 35 | def receive = { 36 | case request: AddRequest => sender ! AddResponse.newBuilder().setX(request.getX).setY(request.getY).setSum(request.getX + request.getY).build() 37 | } 38 | })) 39 | // create an AMQP proxy server which consumes messages from the "calculator" queue and passes 40 | // them to our Calculator actor 41 | val server = ConnectionOwner.createChildActor(conn, RpcServer.props(new AmqpProxy.ProxyServer(calc), channelParams = Some(ChannelParameters(qos = 1)))) 42 | Amqp.waitForConnection(system, server).await(5, TimeUnit.SECONDS) 43 | 44 | server ! AddBinding(Binding(exchange, queue, "calculator-gpb")) 45 | expectMsgPF() { 46 | case Amqp.Ok(AddBinding(_), _) => true 47 | } 48 | // create an AMQP proxy client in front of the "calculator queue" 49 | val client = ConnectionOwner.createChildActor(conn, RpcClient.props()) 50 | val proxy = system.actorOf( 51 | AmqpProxy.ProxyClient.props(client, "amq.direct", "calculator-gpb", ProtobufSerializer), 52 | name = "proxy") 53 | 54 | Amqp.waitForConnection(system, client).await(5, TimeUnit.SECONDS) 55 | implicit val timeout: akka.util.Timeout = 5 seconds 56 | 57 | val futures = for (x <- 0 until 5; y <- 0 until 5) yield (proxy ? AddRequest.newBuilder.setX(x).setY(y).build()).mapTo[AddResponse] 58 | val result = Await.result(Future.sequence(futures), 5 seconds) 59 | assert(result.length === 25) 60 | assert(result.filter(r => r.getSum != r.getX + r.getY).isEmpty) 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /src/test/scala/com/github.sstone/amqp/proxy/RemoteJsonCallTest.scala: -------------------------------------------------------------------------------- 1 | package com.github.sstone.amqp.proxy 2 | 3 | import akka.actor.{Props, Actor, ActorSystem} 4 | import akka.pattern.ask 5 | import akka.testkit.{ImplicitSender, TestKit} 6 | import com.github.sstone.amqp.Amqp.AddBinding 7 | import com.github.sstone.amqp.Amqp.ChannelParameters 8 | import com.github.sstone.amqp.Amqp.ExchangeParameters 9 | import com.github.sstone.amqp.Amqp.QueueParameters 10 | import com.github.sstone.amqp.Amqp._ 11 | import com.github.sstone.amqp.{RpcClient, Amqp, RpcServer, ConnectionOwner} 12 | import com.rabbitmq.client.ConnectionFactory 13 | import concurrent.duration._ 14 | import concurrent.{Await, Future, ExecutionContext} 15 | import java.util.concurrent.TimeUnit 16 | import org.junit.runner.RunWith 17 | import org.scalatest.WordSpec 18 | import org.scalatest.junit.JUnitRunner 19 | import org.scalatest.matchers.ShouldMatchers 20 | import serializers.JsonSerializer 21 | 22 | object RemoteJsonCallTest { 23 | case class AddRequest(x: Int, y: Int) 24 | case class AddResponse(x: Int, y: Int, sum: Int) 25 | } 26 | 27 | @RunWith(classOf[JUnitRunner]) 28 | class RemoteJsonCallTest extends TestKit(ActorSystem("TestSystem")) with ImplicitSender with WordSpec with ShouldMatchers { 29 | 30 | import RemoteJsonCallTest._ 31 | 32 | "AMQP Proxy" should { 33 | "handle JSON calls" in { 34 | import ExecutionContext.Implicits.global 35 | val connFactory = new ConnectionFactory() 36 | val conn = system.actorOf(Props(new ConnectionOwner(connFactory)), name = "conn") 37 | val exchange = ExchangeParameters(name = "amq.direct", exchangeType = "", passive = true) 38 | val queue = QueueParameters(name = "calculator-json", passive = false, autodelete = true) 39 | 40 | // create a simple calculator actor 41 | val calc = system.actorOf(Props(new Actor() { 42 | def receive = { 43 | case AddRequest(x, y) => sender ! AddResponse(x, y, x + y) 44 | } 45 | })) 46 | // create an AMQP proxy server which consumes messages from the "calculator" queue and passes 47 | // them to our Calculator actor 48 | val server = ConnectionOwner.createChildActor(conn, RpcServer.props(new AmqpProxy.ProxyServer(calc), channelParams = Some(ChannelParameters(qos = 1)))) 49 | Amqp.waitForConnection(system, server).await(5, TimeUnit.SECONDS) 50 | 51 | server ! AddBinding(Binding(exchange, queue, "calculator-json")) 52 | expectMsgPF() { 53 | case Amqp.Ok(AddBinding(_), _) => true 54 | } 55 | 56 | // create an AMQP proxy client in front of the "calculator queue" 57 | val client = ConnectionOwner.createChildActor(conn, RpcClient.props()) 58 | val proxy = system.actorOf( 59 | AmqpProxy.ProxyClient.props(client, "amq.direct", "calculator-json", JsonSerializer), 60 | name = "proxy") 61 | 62 | Amqp.waitForConnection(system, client).await(5, TimeUnit.SECONDS) 63 | implicit val timeout: akka.util.Timeout = 5 seconds 64 | 65 | val futures = for (x <- 0 until 5; y <- 0 until 5) yield (proxy ? AddRequest(x, y)).mapTo[AddResponse] 66 | val result = Await.result(Future.sequence(futures), 5 seconds) 67 | assert(result.length === 25) 68 | assert(result.filter(r => r.sum != r.x + r.y).isEmpty) 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/test/scala/com/github.sstone/amqp/proxy/SerializationTest.scala: -------------------------------------------------------------------------------- 1 | package com.github.sstone.amqp.proxy 2 | 3 | import gpbtest.Gpbtest 4 | import org.scalatest.junit.AssertionsForJUnit 5 | import org.junit.Test 6 | import serializers._ 7 | import thrifttest.Person 8 | import com.rabbitmq.client.AMQP.BasicProperties 9 | 10 | case class Message(a: String, b: Int) 11 | 12 | class SerializationTest extends AssertionsForJUnit { 13 | 14 | @Test def verifyJsonSerialization() { 15 | 16 | val serializer = JsonSerializer 17 | val msg = Message("toto", 123) 18 | 19 | val (body, props) = AmqpProxy.serialize(msg, serializer) 20 | 21 | assert(new String(body) === """{"a":"toto","b":123}""") 22 | assert(props.getContentEncoding === "json") 23 | assert(props.getContentType === "com.github.sstone.amqp.proxy.Message") 24 | 25 | val (deserialized, _) = AmqpProxy.deserialize(body, props) 26 | 27 | assert(deserialized === msg) 28 | } 29 | 30 | @Test def verifySnappyJsonSerialization() { 31 | 32 | val serializer = SnappyJsonSerializer 33 | val msg = Message("toto", 123) 34 | 35 | val (body, props) = AmqpProxy.serialize(msg, serializer) 36 | 37 | assert(props.getContentEncoding === "snappy-json") 38 | assert(props.getContentType === "com.github.sstone.amqp.proxy.Message") 39 | 40 | val (deserialized, _) = AmqpProxy.deserialize(body, props) 41 | 42 | assert(deserialized === msg) 43 | } 44 | 45 | @Test def verifyProtobufSerialization() { 46 | 47 | val serializer = ProtobufSerializer 48 | val msg = Gpbtest.Person.newBuilder().setId(123).setName("toto").setEmail("a@b.com").build 49 | 50 | val (body, props) = AmqpProxy.serialize(msg, serializer) 51 | 52 | assert(props.getContentEncoding === "protobuf") 53 | assert(props.getContentType === """com.github.sstone.amqp.proxy.gpbtest.Gpbtest$Person""") 54 | 55 | val (deserialized, _) = AmqpProxy.deserialize(body, props) 56 | 57 | assert(deserialized === msg) 58 | } 59 | 60 | @Test def verifySnappyProtobufSerialization() { 61 | 62 | val serializer = SnappyProtobufSerializer 63 | val msg = Gpbtest.Person.newBuilder().setId(123).setName("toto").setEmail("a@b.com").build 64 | 65 | val (body, props) = AmqpProxy.serialize(msg, serializer) 66 | 67 | assert(props.getContentEncoding === "snappy-protobuf") 68 | assert(props.getContentType === """com.github.sstone.amqp.proxy.gpbtest.Gpbtest$Person""") 69 | 70 | val (deserialized, _) = AmqpProxy.deserialize(body, props) 71 | 72 | assert(deserialized === msg) 73 | } 74 | 75 | @Test def verifyThriftSerialization() { 76 | 77 | val serializer = ThriftSerializer 78 | val msg = new Person().setId(123).setName("toto").setEmail("a@b.com") 79 | 80 | val (body, props) = AmqpProxy.serialize(msg, serializer) 81 | 82 | assert(props.getContentEncoding === "thrift") 83 | assert(props.getContentType === """com.github.sstone.amqp.proxy.thrifttest.Person""") 84 | 85 | val (deserialized, _) = AmqpProxy.deserialize(body, props) 86 | 87 | assert(deserialized === msg) 88 | } 89 | 90 | @Test def verifySnappyThriftSerialization() { 91 | 92 | val serializer = SnappyThriftSerializer 93 | val msg = new Person().setId(123).setName("toto").setEmail("a@b.com") 94 | 95 | val (body, props) = AmqpProxy.serialize(msg, serializer) 96 | 97 | assert(props.getContentEncoding === "snappy-thrift") 98 | assert(props.getContentType === """com.github.sstone.amqp.proxy.thrifttest.Person""") 99 | 100 | val (deserialized, _) = AmqpProxy.deserialize(body, props) 101 | 102 | assert(deserialized === msg) 103 | } 104 | 105 | @Test def verifDefaultSerialization() { 106 | val json = """{"a":"toto","b":123}""" 107 | val msg = Message("toto", 123) 108 | val props = new BasicProperties.Builder().contentType("com.github.sstone.amqp.proxy.Message").build 109 | val (deserialized, serializer) = AmqpProxy.deserialize(json.getBytes("UTF-8"), props) 110 | assert(deserialized === msg) 111 | assert(serializer === JsonSerializer) 112 | } 113 | } --------------------------------------------------------------------------------