aboutsummaryrefslogtreecommitdiff
path: root/csharp
diff options
context:
space:
mode:
authorJon Skeet <skeet@pobox.com>2008-08-14 20:35:31 +0100
committerJon Skeet <skeet@pobox.com>2008-08-14 20:35:31 +0100
commit3ae573c17475021046f3d3b2b5f01de91c80aa1d (patch)
treeafbb78dc737e949a7aa0da2859d4589ca81ce7fb /csharp
parent1e42fdde2ebf34dddf1297bbecc56439ecef323f (diff)
downloadprotobuf-3ae573c17475021046f3d3b2b5f01de91c80aa1d.tar.gz
protobuf-3ae573c17475021046f3d3b2b5f01de91c80aa1d.tar.bz2
protobuf-3ae573c17475021046f3d3b2b5f01de91c80aa1d.zip
Fleshed out service interfaces, and wrote the simpler service tests. Mocking tests still to be done.
Diffstat (limited to 'csharp')
-rw-r--r--csharp/ProtocolBuffers.Test/ServiceTest.cs38
-rw-r--r--csharp/ProtocolBuffers/IRpcChannel.cs21
-rw-r--r--csharp/ProtocolBuffers/IRpcController.cs80
-rw-r--r--csharp/ProtocolBuffers/IService.cs59
4 files changed, 188 insertions, 10 deletions
diff --git a/csharp/ProtocolBuffers.Test/ServiceTest.cs b/csharp/ProtocolBuffers.Test/ServiceTest.cs
index 0f706a43..82da04ba 100644
--- a/csharp/ProtocolBuffers.Test/ServiceTest.cs
+++ b/csharp/ProtocolBuffers.Test/ServiceTest.cs
@@ -1,10 +1,44 @@
using System;
-using System.Collections.Generic;
-using System.Text;
+using Google.ProtocolBuffers.Descriptors;
+using Google.ProtocolBuffers.TestProtos;
using NUnit.Framework;
namespace Google.ProtocolBuffers {
+
+ /// <summary>
+ /// Tests for generated service classes.
+ /// TODO(jonskeet): Convert the mocking tests using Rhino.Mocks.
+ /// </summary>
[TestFixture]
public class ServiceTest {
+
+ private static readonly MethodDescriptor FooDescriptor = TestService.Descriptor.Methods[0];
+ private static readonly MethodDescriptor BarDescriptor = TestService.Descriptor.Methods[1];
+
+ [Test]
+ public void GetRequestPrototype() {
+ TestService mockService = new TestServiceImpl();
+
+ Assert.AreSame(mockService.GetRequestPrototype(FooDescriptor), FooRequest.DefaultInstance);
+ Assert.AreSame(mockService.GetRequestPrototype(BarDescriptor), BarRequest.DefaultInstance);
+ }
+
+ [Test]
+ public void GetResponsePrototype() {
+ TestService mockService = new TestServiceImpl();
+
+ Assert.AreSame(mockService.GetResponsePrototype(FooDescriptor), FooResponse.DefaultInstance);
+ Assert.AreSame(mockService.GetResponsePrototype(BarDescriptor), BarResponse.DefaultInstance);
+ }
+
+ class TestServiceImpl : TestService {
+ public override void Foo(IRpcController controller, FooRequest request, Action<FooResponse> done) {
+ throw new System.NotImplementedException();
+ }
+
+ public override void Bar(IRpcController controller, BarRequest request, Action<BarResponse> done) {
+ throw new System.NotImplementedException();
+ }
+ }
}
}
diff --git a/csharp/ProtocolBuffers/IRpcChannel.cs b/csharp/ProtocolBuffers/IRpcChannel.cs
index 96c82e16..28b321c6 100644
--- a/csharp/ProtocolBuffers/IRpcChannel.cs
+++ b/csharp/ProtocolBuffers/IRpcChannel.cs
@@ -1,14 +1,25 @@
using System;
-using System.Collections.Generic;
-using System.Text;
using Google.ProtocolBuffers.Descriptors;
namespace Google.ProtocolBuffers {
/// <summary>
- /// TODO(jonskeet): Do this properly.
+ /// Interface for an RPC channel. A channel represents a communication line to
+ /// a service (IService implementation) which can be used to call that service's
+ /// methods. The service may be running on another machine. Normally, you should
+ /// not call an IRpcChannel directly, but instead construct a stub wrapping it.
+ /// Generated service classes contain a CreateStub method for precisely this purpose.
/// </summary>
public interface IRpcChannel {
- void CallMethod<T>(MethodDescriptor method, IRpcController controller,
- IMessage request, IMessage responsePrototype, Action<T> done);
+ /// <summary>
+ /// Calls the given method of the remote service. This method is similar
+ /// to <see cref="IService.CallMethod" /> with one important difference: the
+ /// caller decides the types of the IMessage objects, not the implementation.
+ /// The request may be of any type as long as <c>request.Descriptor == method.InputType</c>.
+ /// The response passed to the callback will be of the same type as
+ /// <paramref name="responsePrototype"/> (which must be such that
+ /// <c>responsePrototype.Descriptor == method.OutputType</c>).
+ /// </summary>
+ void CallMethod(MethodDescriptor method, IRpcController controller,
+ IMessage request, IMessage responsePrototype, Action<IMessage> done);
}
}
diff --git a/csharp/ProtocolBuffers/IRpcController.cs b/csharp/ProtocolBuffers/IRpcController.cs
index 81348fde..f4e29ad4 100644
--- a/csharp/ProtocolBuffers/IRpcController.cs
+++ b/csharp/ProtocolBuffers/IRpcController.cs
@@ -1,8 +1,84 @@
using System;
-using System.Collections.Generic;
-using System.Text;
namespace Google.ProtocolBuffers {
+ /// <summary>
+ /// Mediates a single method call. The primary purpose of the controller
+ /// is to provide a way to manipulate settings specific to the
+ /// RPC implementation and to find out about RPC-level errors.
+ ///
+ /// The methods provided by this interface are intended to be a "least
+ /// common denominator" set of features which we expect all implementations to
+ /// support. Specific implementations may provide more advanced features,
+ /// (e.g. deadline propagation).
+ /// </summary>
public interface IRpcController {
+
+ #region Client side calls
+ // These calls may be made from the client side only. Their results
+ // are undefined on the server side (may throw exceptions).
+
+ /// <summary>
+ /// Resets the controller to its initial state so that it may be reused in
+ /// a new call. This can be called from the client side only. It must not
+ /// be called while an RPC is in progress.
+ /// </summary>
+ void Reset();
+
+ /// <summary>
+ /// After a call has finished, returns true if the call failed. The possible
+ /// reasons for failure depend on the RPC implementation. Failed must
+ /// only be called on the client side, and must not be called before a call has
+ /// finished.
+ /// </summary>
+ bool Failed { get; }
+
+ /// <summary>
+ /// If Failed is true, ErrorText returns a human-readable description of the error.
+ /// </summary>
+ string ErrorText { get; }
+
+ /// <summary>
+ /// Advises the RPC system that the caller desires that the RPC call be
+ /// canceled. The RPC system may cancel it immediately, may wait awhile and
+ /// then cancel it, or may not even cancel the call at all. If the call is
+ /// canceled, the "done" callback will still be called and the RpcController
+ /// will indicate that the call failed at that time.
+ /// </summary>
+ void StartCancel();
+ #endregion
+
+ #region Server side calls
+ // These calls may be made from the server side only. Their results
+ // are undefined on the client side (may throw exceptions).
+
+ /// <summary>
+ /// Causes Failed to return true on the client side. <paramref name="reason"/>
+ /// will be incorporated into the message returned by ErrorText.
+ /// If you find you need to return machine-readable information about
+ /// failures, you should incorporate it into your response protocol buffer
+ /// and should *not* call SetFailed.
+ /// </summary>
+ void SetFailed(string reason);
+
+ /// <summary>
+ /// If true, indicates that the client canceled the RPC, so the server may as
+ /// well give up on replying to it. This method must be called on the server
+ /// side only. The server should still call the final "done" callback.
+ /// </summary>
+ bool isCanceled();
+
+ /// <summary>
+ /// Requests that the given callback be called when the RPC is canceled.
+ /// The parameter passed to the callback will always be null. The callback will
+ /// be called exactly once. If the RPC completes without being canceled, the
+ /// callback will be called after completion. If the RPC has already been canceled
+ /// when NotifyOnCancel is called, the callback will be called immediately.
+ ///
+ /// NotifyOnCancel must be called no more than once per request. It must be
+ /// called on the server side only.
+ /// </summary>
+ /// <param name="callback"></param>
+ void NotifyOnCancel(Action<object> callback);
+ #endregion
}
}
diff --git a/csharp/ProtocolBuffers/IService.cs b/csharp/ProtocolBuffers/IService.cs
index d53395aa..1405fbb9 100644
--- a/csharp/ProtocolBuffers/IService.cs
+++ b/csharp/ProtocolBuffers/IService.cs
@@ -1,9 +1,66 @@
using System;
using System.Collections.Generic;
using System.Text;
+using Google.ProtocolBuffers.Descriptors;
namespace Google.ProtocolBuffers {
+ /// <summary>
+ /// Base interface for protocol-buffer-based RPC services. Services themselves
+ /// are abstract classes (implemented either by servers or as stubs) but they
+ /// implement this itnerface. The methods of this interface can be used to call
+ /// the methods of the service without knowing its exact type at compile time
+ /// (analagous to the IMessage interface).
+ /// </summary>
public interface IService {
- // TODO(jonskeet): Fill this in
+ /// <summary>
+ /// The ServiceDescriptor describing this service and its methods.
+ /// </summary>
+ ServiceDescriptor DescriptorForType { get; }
+
+ /// <summary>
+ /// Call a method of the service specified by MethodDescriptor. This is
+ /// normally implemented as a simple switch that calls the standard
+ /// definitions of the service's methods.
+ /// <para>
+ /// Preconditions
+ /// <list>
+ /// <item><c>method.Service == DescriptorForType</c></item>
+ /// <item>request is of the exact same class as the object returned by GetRequestPrototype(method)</item>
+ /// <item>controller is of the correct type for the RPC implementation being used by this service.
+ /// For stubs, the "correct type" depends on the IRpcChannel which the stub is using. Server-side
+ /// implementations are expected to accept whatever type of IRpcController the server-side RPC implementation
+ /// uses.</item>
+ /// </list>
+ /// </para>
+ /// <para>
+ /// Postconditions
+ /// <list>
+ /// <item><paramref name="done" /> will be called when the method is complete.
+ /// This may before CallMethod returns or it may be at some point in the future.</item>
+ /// <item>The parameter to <paramref name="done"/> is the response. It will be of the
+ /// exact same type as would be returned by <see cref="GetResponsePrototype"/>.</item>
+ /// <item>If the RPC failed, the parameter to <paramref name="done"/> will be null.
+ /// Further details about the failure can be found by querying <paramref name="controller"/>.</item>
+ /// </list>
+ /// </para>
+ /// </summary>
+ void CallMethod(MethodDescriptor method, IRpcController controller,
+ IMessage request, Action<IMessage> done);
+
+ /// <summary>
+ /// CallMethod requires that the request passed in is of a particular implementation
+ /// of IMessage. This method gets the default instance of this type of a given method.
+ /// You can then call WeakCreateBuilderForType to create a builder to build an object which
+ /// you can then pass to CallMethod.
+ /// </summary>
+ IMessage GetRequestPrototype(MethodDescriptor method);
+
+ /// <summary>
+ /// Like GetRequestPrototype, but returns a prototype of the response message.
+ /// This is generally not needed because the IService implementation contructs
+ /// the response message itself, but it may be useful in some cases to know ahead
+ /// of time what type of object will be returned.
+ /// </summary>
+ IMessage GetResponsePrototype(MethodDescriptor method);
}
}