├── .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 | [](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 | *
45 | * - contentEncoding is set to the name of the serializer that is used
46 | * - contentType is set to the name of the message class
47 | *
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 | }
--------------------------------------------------------------------------------