2009-12-01 Jb Evain <jbevain@novell.com>
[mcs.git] / tools / svcutil / MoonlightChannelBaseExtension.cs
blob66b872a01678b13379b2e32881d89e80252d5ebc
1 //
2 // MoonlightChannelBaseExtension.cs
3 //
4 // Author:
5 // Atsushi Enomoto <atsushi@ximian.com>
6 //
7 // Copyright (C) 2009 Novell, Inc. http://www.novell.com
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 using System;
29 using System.CodeDom;
30 using System.CodeDom.Compiler;
31 using System.Collections.Generic;
32 using System.Collections.ObjectModel;
33 using System.IO;
34 using System.Reflection;
35 using System.ServiceModel;
36 using System.ServiceModel.Channels;
37 using System.ServiceModel.Description;
38 using System.ServiceModel.Dispatcher;
40 namespace Mono.ServiceContractTool
42 class MoonlightChannelBaseContext
44 public MoonlightChannelBaseContractExtension Contract;
45 public List<MoonlightChannelBaseOperationExtension> Operations = new List<MoonlightChannelBaseOperationExtension> ();
47 public CodeTypeDeclaration ClientType { get; set; }
48 public CodeTypeDeclaration ChannelType { get; set; }
50 public void FindClientType (ServiceContractGenerationContext context)
52 var cd = context.Contract;
53 string name = cd.Name + "Client";
54 if (name [0] == 'I')
55 name = name.Substring (1);
57 foreach (CodeNamespace cns in context.ServiceContractGenerator.TargetCompileUnit.Namespaces)
58 foreach (CodeTypeDeclaration ct in cns.Types)
59 if (ct == context.ContractType)
60 foreach (CodeTypeDeclaration ct2 in cns.Types)
61 if (ct2.Name == name) {
62 ClientType = ct2;
63 return;
65 throw new Exception (String.Format ("Contract '{0}' not found", name));
68 public void Fixup ()
70 Contract.Fixup ();
71 foreach (var op in Operations)
72 op.Fixup ();
76 class MoonlightChannelBaseContractExtension : IContractBehavior, IServiceContractGenerationExtension
78 public MoonlightChannelBaseContractExtension (MoonlightChannelBaseContext mlContext, bool generateAsync)
80 ml_context = mlContext;
81 generate_async = generateAsync;
84 MoonlightChannelBaseContext ml_context;
85 bool generate_async;
87 // IContractBehavior
88 public void AddBindingParameters (ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
90 throw new NotSupportedException ();
93 public void ApplyClientBehavior (
94 ContractDescription description,
95 ServiceEndpoint endpoint,
96 ClientRuntime proxy)
98 throw new NotSupportedException ();
101 public void ApplyDispatchBehavior (
102 ContractDescription description,
103 ServiceEndpoint endpoint,
104 DispatchRuntime dispatch)
106 throw new NotSupportedException ();
109 public void Validate (
110 ContractDescription description,
111 ServiceEndpoint endpoint)
113 throw new NotSupportedException ();
116 // IServiceContractGenerationExtensions
118 public void GenerateContract (
119 ServiceContractGenerationContext context)
121 this.context = context;
122 ml_context.Contract = this;
125 ServiceContractGenerationContext context;
127 public void Fixup ()
129 ContractDescription cd = context.Contract;
130 ml_context.FindClientType (context);
131 var parentClass = ml_context.ClientType;
133 string name = cd.Name + "Channel";
134 if (name [0] == 'I')
135 name = name.Substring (1);
137 var gt = new CodeTypeReference (cd.Name);
138 var clientBaseType = new CodeTypeReference ("System.ServiceModel.ClientBase", gt);
139 // this omits namespace, but should compile
140 var channelBase = new CodeTypeReference ("ChannelBase", gt);
141 var type = new CodeTypeDeclaration (name);
142 parentClass.Members.Add (type);
143 type.BaseTypes.Add (channelBase);
144 type.BaseTypes.Add (new CodeTypeReference (cd.Name));
145 type.TypeAttributes |= TypeAttributes.NestedPrivate;
147 ml_context.ChannelType = type;
149 // .ctor(ClientBase<T> client)
150 var ctor = new CodeConstructor ();
151 ctor.Attributes = MemberAttributes.Public;
152 ctor.Parameters.Add (
153 new CodeParameterDeclarationExpression (
154 clientBaseType, "client"));
155 ctor.BaseConstructorArgs.Add (
156 new CodeArgumentReferenceExpression ("client"));
157 type.Members.Add (ctor);
159 // In Client type:
160 // protected override TChannel CreateChannel()
161 var creator = new CodeMemberMethod ();
162 creator.Name = "CreateChannel";
163 creator.Attributes = MemberAttributes.Family | MemberAttributes.Override;
164 creator.ReturnType = gt;
165 creator.Statements.Add (
166 new CodeMethodReturnStatement (
167 new CodeCastExpression (
169 new CodeObjectCreateExpression (
170 new CodeTypeReference (name),
171 new CodeThisReferenceExpression ()))));
172 parentClass.Members.Add (creator);
176 class MoonlightChannelBaseOperationExtension : IOperationBehavior, IOperationContractGenerationExtension
178 public MoonlightChannelBaseOperationExtension (MoonlightChannelBaseContext mlContext, bool generateAsync)
180 ml_context = mlContext;
181 generate_async = generateAsync;
184 MoonlightChannelBaseContext ml_context;
185 bool generate_async;
187 // IOperationBehavior
189 public void AddBindingParameters (
190 OperationDescription description,
191 BindingParameterCollection parameters)
193 throw new NotSupportedException ();
196 public void ApplyDispatchBehavior (
197 OperationDescription description,
198 DispatchOperation dispatch)
200 throw new NotSupportedException ();
203 public void ApplyClientBehavior (
204 OperationDescription description,
205 ClientOperation proxy)
207 throw new NotSupportedException ();
210 public void Validate (
211 OperationDescription description)
213 throw new NotSupportedException ();
216 // IOperationContractGenerationContext
218 public void GenerateOperation (OperationContractGenerationContext context)
220 this.context = context;
221 ml_context.Operations.Add (this);
224 OperationContractGenerationContext context;
226 public void Fixup ()
228 if (generate_async)
229 FixupAsync ();
230 else
231 FixupSync ();
234 public void FixupSync ()
236 var type = ml_context.ChannelType;
237 var od = context.Operation;
239 // sync method implementation
240 CodeMemberMethod cm = new CodeMemberMethod ();
241 type.Members.Add (cm);
242 cm.Name = od.Name;
243 cm.Attributes = MemberAttributes.Public
244 | MemberAttributes.Final;
246 var inArgs = new List<CodeParameterDeclarationExpression > ();
247 var outArgs = new List<CodeParameterDeclarationExpression > ();
249 foreach (CodeParameterDeclarationExpression p in context.SyncMethod.Parameters) {
250 inArgs.Add (p);
251 cm.Parameters.Add (p);
254 cm.ReturnType = context.SyncMethod.ReturnType;
256 var argsDecl = new CodeVariableDeclarationStatement (
257 typeof (object []),
258 "args",
259 new CodeArrayCreateExpression (typeof (object), inArgs.ConvertAll<CodeExpression> (decl => new CodeArgumentReferenceExpression (decl.Name)).ToArray ()));
260 cm.Statements.Add (argsDecl);
262 var args = new List<CodeExpression> ();
263 args.Add (new CodePrimitiveExpression (od.Name));
264 args.Add (new CodeVariableReferenceExpression ("args"));
266 CodeExpression call = new CodeMethodInvokeExpression (
267 new CodeBaseReferenceExpression (),
268 "Invoke",
269 args.ToArray ());
271 if (cm.ReturnType.BaseType == "System.Void")
272 cm.Statements.Add (new CodeExpressionStatement (call));
273 else
274 cm.Statements.Add (new CodeMethodReturnStatement (new CodeCastExpression (context.SyncMethod.ReturnType, call)));
277 public void FixupAsync ()
279 var type = ml_context.ChannelType;
280 var od = context.Operation;
282 // BeginXxx() implementation
283 CodeMemberMethod cm = new CodeMemberMethod ();
284 type.Members.Add (cm);
285 cm.Name = "Begin" + od.Name;
286 cm.Attributes = MemberAttributes.Public
287 | MemberAttributes.Final;
289 var inArgs = new List<CodeParameterDeclarationExpression > ();
290 var outArgs = new List<CodeParameterDeclarationExpression > ();
292 foreach (CodeParameterDeclarationExpression p in context.BeginMethod.Parameters) {
293 inArgs.Add (p);
294 cm.Parameters.Add (p);
296 inArgs.RemoveAt (inArgs.Count - 1);
297 inArgs.RemoveAt (inArgs.Count - 1);
299 // cm.Parameters.Add (new CodeParameterDeclarationExpression (new CodeTypeReference (typeof (AsyncCallback)), "asyncCallback"));
300 // cm.Parameters.Add (new CodeParameterDeclarationExpression (new CodeTypeReference (typeof (object)), "userState"));
301 cm.ReturnType = new CodeTypeReference (typeof (IAsyncResult));
303 var argsDecl = new CodeVariableDeclarationStatement (
304 typeof (object []),
305 "args",
306 new CodeArrayCreateExpression (typeof (object), inArgs.ConvertAll<CodeExpression> (decl => new CodeArgumentReferenceExpression (decl.Name)).ToArray ()));
307 cm.Statements.Add (argsDecl);
309 var args = new List<CodeExpression> ();
310 args.Add (new CodePrimitiveExpression (od.Name));
311 args.Add (new CodeVariableReferenceExpression ("args"));
312 args.Add (new CodeArgumentReferenceExpression ("asyncCallback"));
313 args.Add (new CodeArgumentReferenceExpression ("userState"));
315 CodeExpression call = new CodeMethodInvokeExpression (
316 new CodeBaseReferenceExpression (),
317 "BeginInvoke",
318 args.ToArray ());
320 if (cm.ReturnType.BaseType == "System.Void")
321 cm.Statements.Add (new CodeExpressionStatement (call));
322 else
323 cm.Statements.Add (new CodeMethodReturnStatement (call));
325 // EndXxx() implementation
327 cm = new CodeMemberMethod ();
328 cm.Attributes = MemberAttributes.Public
329 | MemberAttributes.Final;
330 type.Members.Add (cm);
331 cm.Name = "End" + od.Name;
333 var res = new CodeParameterDeclarationExpression (new CodeTypeReference (typeof (IAsyncResult)), "result");
334 cm.Parameters.Add (res);
336 cm.ReturnType = context.EndMethod.ReturnType;
338 string resultArgName = "result";
339 argsDecl = new CodeVariableDeclarationStatement (
340 typeof (object []),
341 "args",
342 new CodeArrayCreateExpression (typeof (object), new CodePrimitiveExpression (outArgs.Count)));
343 cm.Statements.Add (argsDecl);
345 call = new CodeCastExpression (
346 context.EndMethod.ReturnType,
347 new CodeMethodInvokeExpression (
348 new CodeBaseReferenceExpression (),
349 "EndInvoke",
350 new CodePrimitiveExpression (od.Name),
351 new CodeVariableReferenceExpression ("args"),
352 new CodeArgumentReferenceExpression (resultArgName)));
354 if (cm.ReturnType.BaseType == "System.Void")
355 cm.Statements.Add (new CodeExpressionStatement (call));
356 else
357 cm.Statements.Add (new CodeMethodReturnStatement (call));