blob: 4aa8ffaa4ea4b87e3d955823be92716da5455eea [file] [log] [blame]
csharptest68d831e2011-05-03 13:47:34 -05001#region Copyright notice and license
2// Protocol Buffers - Google's data interchange format
3// Copyright 2008 Google Inc. All rights reserved.
4// http://github.com/jskeet/dotnet-protobufs/
5// Original C++/Java/Python code:
6// http://code.google.com/p/protobuf/
7//
8// Redistribution and use in source and binary forms, with or without
9// modification, are permitted provided that the following conditions are
10// met:
11//
12// * Redistributions of source code must retain the above copyright
13// notice, this list of conditions and the following disclaimer.
14// * Redistributions in binary form must reproduce the above
15// copyright notice, this list of conditions and the following disclaimer
16// in the documentation and/or other materials provided with the
17// distribution.
18// * Neither the name of Google Inc. nor the names of its
19// contributors may be used to endorse or promote products derived from
20// this software without specific prior written permission.
21//
22// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33#endregion
34
35using System;
36using System.Collections.Generic;
37using Google.ProtocolBuffers.DescriptorProtos;
38using Google.ProtocolBuffers.Descriptors;
39
40namespace Google.ProtocolBuffers.ProtoGen {
41 internal class ServiceGenerator : SourceGeneratorBase<ServiceDescriptor>, ISourceGenerator {
42
43 readonly CSharpServiceType svcType;
44 ISourceGenerator _generator;
45
46 internal ServiceGenerator(ServiceDescriptor descriptor)
47 : base(descriptor) {
48 svcType = descriptor.File.CSharpOptions.ServiceGeneratorType;
49 switch (svcType) {
50 case CSharpServiceType.GENERIC:
51 _generator = new GenericServiceGenerator(descriptor);
52 break;
53 case CSharpServiceType.INTERFACE:
54 _generator = new ServiceInterfaceGenerator(descriptor);
55 break;
56 case CSharpServiceType.IRPCDISPATCH:
57 _generator = new RpcServiceGenerator(descriptor);
58 break;
59 default: throw new ApplicationException("Unknown ServiceGeneratorType = " + svcType.ToString());
60 }
61 }
62
63 public void Generate(TextGenerator writer) {
64 _generator.Generate(writer);
65 }
66
67 class ServiceInterfaceGenerator : SourceGeneratorBase<ServiceDescriptor>, ISourceGenerator {
68
69 public ServiceInterfaceGenerator(ServiceDescriptor descriptor)
70 : base(descriptor) {
71 }
72
73 public virtual void Generate(TextGenerator writer) {
74
75 CSharpServiceOptions options = Descriptor.Options.GetExtension(CSharpOptions.CsharpServiceOptions);
76 if (options != null && options.HasInterfaceId) {
77 writer.WriteLine("[global::System.Runtime.InteropServices.GuidAttribute(\"{0}\")]", new Guid(options.InterfaceId));
78 }
79 writer.WriteLine("{0} partial interface I{1} {{", ClassAccessLevel, Descriptor.Name);
80 writer.Indent();
81
82 foreach (MethodDescriptor method in Descriptor.Methods)
83 {
84 CSharpMethodOptions mth = method.Options.GetExtension(CSharpOptions.CsharpMethodOptions);
85 if(mth.HasDispatchId) {
86 writer.WriteLine("[global::System.Runtime.InteropServices.DispId({0})]", mth.DispatchId);
87 }
88 writer.WriteLine("{0} {1}({2} {3});", GetClassName(method.OutputType), NameHelpers.UnderscoresToPascalCase(method.Name), GetClassName(method.InputType), NameHelpers.UnderscoresToCamelCase(method.InputType.Name));
89 }
90
91 writer.Outdent();
92 writer.WriteLine("}");
93 }
94 }
95
96 class RpcServiceGenerator : ServiceInterfaceGenerator {
97
98 public RpcServiceGenerator(ServiceDescriptor descriptor)
99 : base(descriptor) {
100 }
101
102 public override void Generate(TextGenerator writer)
103 {
104 base.Generate(writer);
105
106 writer.WriteLine();
107
108 // CLIENT Proxy
109 {
110 if (Descriptor.File.CSharpOptions.ClsCompliance)
111 writer.WriteLine("[global::System.CLSCompliant(false)]");
112 writer.WriteLine("{0} partial class {1} : I{1}, pb::IRpcDispatch, global::System.IDisposable {{", ClassAccessLevel, Descriptor.Name);
113 writer.Indent();
114 writer.WriteLine("private readonly bool dispose;");
115 writer.WriteLine("private readonly pb::IRpcDispatch dispatch;");
116
117 writer.WriteLine("public {0}(pb::IRpcDispatch dispatch) : this(dispatch, true) {{", Descriptor.Name);
118 writer.WriteLine("}");
119 writer.WriteLine("public {0}(pb::IRpcDispatch dispatch, bool dispose) {{", Descriptor.Name);
120 writer.WriteLine(" if (null == (this.dispatch = dispatch)) throw new global::System.ArgumentNullException();");
121 writer.WriteLine(" this.dispose = dispose && dispatch is global::System.IDisposable;");
122 writer.WriteLine("}");
123 writer.WriteLine();
124
125 writer.WriteLine("public void Dispose() {");
126 writer.WriteLine(" if (dispose) ((global::System.IDisposable)dispatch).Dispose();");
127 writer.WriteLine("}");
128 writer.WriteLine();
129 writer.WriteLine("TMessage pb::IRpcDispatch.CallMethod<TMessage, TBuilder>(string method, pb::IMessageLite request, pb::IBuilderLite<TMessage, TBuilder> response) {");
130 writer.WriteLine(" return dispatch.CallMethod(method, request, response);");
131 writer.WriteLine("}");
132 writer.WriteLine();
133
134 foreach (MethodDescriptor method in Descriptor.Methods) {
135 writer.WriteLine("public {0} {1}({2} {3}) {{", GetClassName(method.OutputType), NameHelpers.UnderscoresToPascalCase(method.Name), GetClassName(method.InputType), NameHelpers.UnderscoresToCamelCase(method.InputType.Name));
136 writer.WriteLine(" return dispatch.CallMethod(\"{0}\", {1}, {2}.CreateBuilder());",
137 method.Name,
138 NameHelpers.UnderscoresToCamelCase(method.InputType.Name),
139 GetClassName(method.OutputType)
140 );
141 writer.WriteLine("}");
142 writer.WriteLine();
143 }
144 }
145 // SERVER - DISPATCH
146 {
147 if (Descriptor.File.CSharpOptions.ClsCompliance)
148 writer.WriteLine("[global::System.CLSCompliant(false)]");
149 writer.WriteLine("public partial class Dispatch : pb::IRpcDispatch, global::System.IDisposable {");
150 writer.Indent();
151 writer.WriteLine("private readonly bool dispose;");
152 writer.WriteLine("private readonly I{0} implementation;", Descriptor.Name);
153
154 writer.WriteLine("public Dispatch(I{0} implementation) : this(implementation, true) {{", Descriptor.Name);
155 writer.WriteLine("}");
156 writer.WriteLine("public Dispatch(I{0} implementation, bool dispose) {{", Descriptor.Name);
157 writer.WriteLine(" if (null == (this.implementation = implementation)) throw new global::System.ArgumentNullException();");
158 writer.WriteLine(" this.dispose = dispose && implementation is global::System.IDisposable;");
159 writer.WriteLine("}");
160 writer.WriteLine();
161
162 writer.WriteLine("public void Dispose() {");
163 writer.WriteLine(" if (dispose) ((global::System.IDisposable)implementation).Dispose();");
164 writer.WriteLine("}");
165 writer.WriteLine();
166
167 writer.WriteLine("public TMessage CallMethod<TMessage, TBuilder>(string methodName, pb::IMessageLite request, pb::IBuilderLite<TMessage, TBuilder> response)");
168 writer.WriteLine(" where TMessage : IMessageLite<TMessage, TBuilder>");
169 writer.WriteLine(" where TBuilder : IBuilderLite<TMessage, TBuilder> {");
170 writer.Indent();
171 writer.WriteLine("switch(methodName) {");
172 writer.Indent();
173
174 foreach (MethodDescriptor method in Descriptor.Methods) {
175 writer.WriteLine("case \"{0}\": return response.MergeFrom(implementation.{1}(({2})request)).Build();", method.Name, NameHelpers.UnderscoresToPascalCase(method.Name), GetClassName(method.InputType));
176 }
177 writer.WriteLine("default: throw new global::System.MissingMethodException(typeof(ISearchService).FullName, methodName);");
178 writer.Outdent();
179 writer.WriteLine("}");//end switch
180 writer.Outdent();
181 writer.WriteLine("}");//end invoke
182 writer.Outdent();
183 writer.WriteLine("}");//end server
184 }
185 // SERVER - STUB
186 {
187 if (Descriptor.File.CSharpOptions.ClsCompliance)
188 writer.WriteLine("[global::System.CLSCompliant(false)]");
189 writer.WriteLine("public partial class ServerStub : pb::IRpcServerStub, global::System.IDisposable {");
190 writer.Indent();
191 writer.WriteLine("private readonly bool dispose;");
192 writer.WriteLine("private readonly pb::IRpcDispatch implementation;", Descriptor.Name);
193
194 writer.WriteLine("public ServerStub(I{0} implementation) : this(implementation, true) {{", Descriptor.Name);
195 writer.WriteLine("}");
196 writer.WriteLine("public ServerStub(I{0} implementation, bool dispose) : this(new Dispatch(implementation, dispose), dispose) {{", Descriptor.Name);
197 writer.WriteLine("}");
198
199 writer.WriteLine("public ServerStub(pb::IRpcDispatch implementation) : this(implementation, true) {");
200 writer.WriteLine("}");
201 writer.WriteLine("public ServerStub(pb::IRpcDispatch implementation, bool dispose) {");
202 writer.WriteLine(" if (null == (this.implementation = implementation)) throw new global::System.ArgumentNullException();");
203 writer.WriteLine(" this.dispose = dispose && implementation is global::System.IDisposable;");
204 writer.WriteLine("}");
205 writer.WriteLine();
206
207 writer.WriteLine("public void Dispose() {");
208 writer.WriteLine(" if (dispose) ((global::System.IDisposable)implementation).Dispose();");
209 writer.WriteLine("}");
210 writer.WriteLine();
211
212 writer.WriteLine("public pb::IMessageLite CallMethod(string methodName, pb::CodedInputStream input, pb::ExtensionRegistry registry) {{", Descriptor.Name);
213 writer.Indent();
214 writer.WriteLine("switch(methodName) {");
215 writer.Indent();
216
217 foreach (MethodDescriptor method in Descriptor.Methods)
218 {
219 writer.WriteLine("case \"{0}\": return implementation.CallMethod(methodName, {1}.ParseFrom(input, registry), {2}.CreateBuilder());", method.Name, GetClassName(method.InputType), GetClassName(method.OutputType));
220 }
221 writer.WriteLine("default: throw new global::System.MissingMethodException(typeof(ISearchService).FullName, methodName);");
222 writer.Outdent();
223 writer.WriteLine("}");//end switch
224 writer.Outdent();
225 writer.WriteLine("}");//end invoke
226 writer.Outdent();
227 writer.WriteLine("}");//end server
228 }
229
230 writer.Outdent();
231 writer.WriteLine("}");
232 }
233 }
234 }
235}