{"id":1214,"date":"2011-12-29T21:04:22","date_gmt":"2011-12-30T02:04:22","guid":{"rendered":"http:\/\/hstore.cs.brown.edu\/?page_id=1214"},"modified":"2013-10-21T19:56:19","modified_gmt":"2013-10-21T23:56:19","slug":"protorpc","status":"publish","type":"page","link":"https:\/\/hstore.cs.brown.edu\/documentation\/development\/protorpc\/","title":{"rendered":"ProtoRPC RPC System"},"content":{"rendered":"
ProtoRPC is an RPC<\/a> library built on top of Google Protocol Buffers<\/a>. It permits programs written in different languages to exchange messages using RPC calls. The original version of this document can be found here<\/a> [Source<\/a>].<\/p>\n Users write a .proto<\/a> file that defines an RPC service<\/a>. A service is composed of a set of methods, each of which takes an input message and returns an output message. This .proto file is then used to generate interface classes<\/a>, in C++ or Java. See the original Protocol Buffer documentation<\/a> for details on this stuff.<\/p>\n This interface is written in an event-driven, asynchronous style. This means that a single threaded program can have multiple pending RPCs at any time. RPCs complete by calling callbacks. On the client side, protorpc will call a callback when the server’s results have been returned. On the server side, results are returned to the client when a callback is invoked.<\/p>\n On the server side, an abstract class with a set of abstract methods is generated. To implement a service, this class is implemented, and an instance is registered (see the example below). When the RPC is invoked, the abstract methods will be called. See the protocol buffer service documentation<\/a> for details about these methods.<\/p>\n On the client side, a class with the interface methods is generated. This class is connected to a remote service (see the example below). Then, the abstract methods are invoked to start the RPC. When the RPC completes, a callback will be invoked.<\/p>\n Note: It is possible to use this interface in a blocking fashion, if that is easier to understand. However, some code is currently not completed to make this work.<\/p>\n The heart of non-blocking operations is the EventLoop interface. This interface runs the event loop. While inside the run() or runOnce() methods, implementations of this interface will wait for events to occur. When they occur, they will call the appropriate callback. An instance of this interface can be shared by any number of classes. Typically, a single instance is created for the entire program.<\/p>\n The key to making this work, is that when you need to wait for an event, you create a callback, and pass that to the appropriate API. When the event occurs, the EventLoop will call the callback.<\/p>\n The concrete implementation of this interface is typically NIOEventLoop.<\/p>\n This example uses the ca.evanjones.protorpc.Counter example defined in the source repository. The Java implementation of both the client and server are included in ca.evanjones.protorpc.CounterExample.<\/p>\nBrief Overview<\/h2>\n
Non-Blocking Operations<\/h2>\n
Client Example<\/h2>\n
\n
NIOEventLoop eventLoop =<\/span> new<\/span> NIOEventLoop(<\/span>)<\/span>;<\/span><\/pre><\/td><\/tr><\/table><\/div>\n\n
ProtoRpcChannel channel =<\/span> new<\/span> ProtoRpcChannel(<\/span>eventLoop, new<\/span> InetSocketAddress(<\/span>host, port)<\/span>)<\/span>;<\/span><\/pre><\/td><\/tr><\/table><\/div>\n\n
CounterService stub =<\/span> CounterService.newStub<\/span>(<\/span>channel)<\/span>;<\/span><\/pre><\/td><\/tr><\/table><\/div>\n\n
ProtoRpcController rpc =<\/span> new<\/span> ProtoRpcController(<\/span>)<\/span>;<\/span>\nGetRequest request =<\/span> GetRequest.newBuilder<\/span>(<\/span>)<\/span>.setName<\/span>(<\/span>"foo"<\/span>)<\/span>.build<\/span>(<\/span>)<\/span>;<\/span>\nStoreResultCallback<<\/span>Value><\/span> callback =<\/span> new<\/span> StoreResultCallback<<\/span>Value><\/span>(<\/span>)<\/span>;<\/span>\nstub.get<\/span>(<\/span>rpc, request, callback)<\/span>;<\/span><\/pre><\/td><\/tr><\/table><\/div>\n\n
rpc.block<\/span>(<\/span>)<\/span>;<\/span><\/pre><\/td><\/tr><\/table><\/div>\n\n
assert<\/span> !<\/span>rpc.failed<\/span>(<\/span>)<\/span>;<\/span><\/pre><\/td><\/tr><\/table><\/div>\n\n<\/ol>\n
Server Example<\/h2>\n
\n
NIOEventLoop eventLoop =<\/span> new<\/span> NIOEventLoop(<\/span>)<\/span>;<\/span>\nProtoServer server =<\/span> new<\/span> ProtoServer(<\/span>eventLoop)<\/span>;<\/span><\/pre><\/td><\/tr><\/table><\/div>\n\n
CounterExample counter =<\/span> new<\/span> CounterExample(<\/span>)<\/span>;<\/span>\nserver.register<\/span>(<\/span>counter)<\/span>;<\/span><\/pre><\/td><\/tr><\/table><\/div>\n\n
server.bind<\/span>(<\/span>port)<\/span>;<\/span>\neventLoop.setExitOnSigInt<\/span>(<\/span>true<\/span>)<\/span>;<\/span>\neventLoop.run<\/span>(<\/span>)<\/span>;<\/span><\/pre><\/td><\/tr><\/table><\/div>\n\n<\/ol>\n