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