New tests.
[mono.git] / mcs / tools / svcutil / MoonlightChannelBaseExtension.cs
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.
27 //
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;
39
40 namespace Mono.ServiceContractTool
41 {
42         class MoonlightChannelBaseContext
43         {
44                 public MoonlightChannelBaseContractExtension Contract;
45                 public List<MoonlightChannelBaseOperationExtension> Operations = new List<MoonlightChannelBaseOperationExtension> ();
46
47                 public CodeTypeDeclaration ClientType { get; set; }
48                 public CodeTypeDeclaration ChannelType { get; set; }
49
50                 public void FindClientType (ServiceContractGenerationContext context)
51                 {
52                         var cd = context.Contract;
53                         string name = cd.Name + "Client";
54                         if (name [0] == 'I')
55                                 name = name.Substring (1);
56
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;
64                                                         }
65                         throw new Exception (String.Format ("Contract '{0}' not found", name));
66                 }
67
68                 public void Fixup ()
69                 {
70                         Contract.Fixup ();
71                         foreach (var op in Operations)
72                                 op.Fixup ();
73                 }
74         }
75
76         class MoonlightChannelBaseContractExtension : IContractBehavior, IServiceContractGenerationExtension
77         {
78                 public MoonlightChannelBaseContractExtension (MoonlightChannelBaseContext mlContext)
79                 {
80                         ml_context = mlContext;
81                 }
82
83                 MoonlightChannelBaseContext ml_context;
84
85                 // IContractBehavior
86                 public void AddBindingParameters (ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
87                 {
88                         throw new NotSupportedException ();
89                 }
90
91                 public void ApplyClientBehavior (
92                         ContractDescription description,
93                         ServiceEndpoint endpoint,
94                         ClientRuntime proxy)
95                 {
96                         throw new NotSupportedException ();
97                 }
98
99                 public void ApplyDispatchBehavior (
100                         ContractDescription description,
101                         ServiceEndpoint endpoint,
102                         DispatchRuntime dispatch)
103                 {
104                         throw new NotSupportedException ();
105                 }
106
107                 public void Validate (
108                         ContractDescription description,
109                         ServiceEndpoint endpoint)
110                 {
111                         throw new NotSupportedException ();
112                 }
113
114                 // IServiceContractGenerationExtensions
115
116                 public void GenerateContract (
117                         ServiceContractGenerationContext context)
118                 {
119                         this.context = context;
120                         ml_context.Contract = this;
121                 }
122
123                 ServiceContractGenerationContext context;
124
125                 public void Fixup ()
126                 {
127                         ContractDescription cd = context.Contract;
128                         ml_context.FindClientType (context);
129                         var parentClass = ml_context.ClientType;
130
131                         string name = cd.Name + "Channel";
132                         if (name [0] == 'I')
133                                 name = name.Substring (1);
134
135                         var gt = new CodeTypeReference (cd.Name);
136                         var clientBaseType = new CodeTypeReference ("System.ServiceModel.ClientBase", gt);
137                         // this omits namespace, but should compile
138                         var channelBase = new CodeTypeReference ("ChannelBase", gt);
139                         var type = new CodeTypeDeclaration (name);
140                         parentClass.Members.Add (type);
141                         type.BaseTypes.Add (channelBase);
142                         type.BaseTypes.Add (new CodeTypeReference (cd.Name));
143                         type.TypeAttributes |= TypeAttributes.NestedPrivate;
144
145                         ml_context.ChannelType = type;
146
147                         // .ctor(ClientBase<T> client)
148                         var ctor = new CodeConstructor ();
149                         ctor.Attributes = MemberAttributes.Public;
150                         ctor.Parameters.Add (
151                                 new CodeParameterDeclarationExpression (
152                                         clientBaseType, "client"));
153                         ctor.BaseConstructorArgs.Add (
154                                 new CodeArgumentReferenceExpression ("client"));
155                         type.Members.Add (ctor);
156                 }
157         }
158
159         class MoonlightChannelBaseOperationExtension : IOperationBehavior, IOperationContractGenerationExtension
160         {
161                 public MoonlightChannelBaseOperationExtension (MoonlightChannelBaseContext mlContext)
162                 {
163                         ml_context = mlContext;
164                 }
165
166                 MoonlightChannelBaseContext ml_context;
167
168                 // IOperationBehavior
169
170                 public void AddBindingParameters (
171                         OperationDescription description,
172                         BindingParameterCollection parameters)
173                 {
174                         throw new NotSupportedException ();
175                 }
176
177                 public void ApplyDispatchBehavior (
178                         OperationDescription description,
179                         DispatchOperation dispatch)
180                 {
181                         throw new NotSupportedException ();
182                 }
183
184                 public void ApplyClientBehavior (
185                         OperationDescription description,
186                         ClientOperation proxy)
187                 {
188                         throw new NotSupportedException ();
189                 }
190
191                 public void Validate (
192                         OperationDescription description)
193                 {
194                         throw new NotSupportedException ();
195                 }
196
197                 // IOperationContractGenerationContext
198
199                 public void GenerateOperation (OperationContractGenerationContext context)
200                 {
201                         this.context = context;
202                         ml_context.Operations.Add (this);
203                 }
204
205                 OperationContractGenerationContext context;
206
207                 public void Fixup ()
208                 {
209                         var type = ml_context.ChannelType;
210                         var od = context.Operation;
211
212                         CodeMemberMethod cm = new CodeMemberMethod ();
213                         type.Members.Add (cm);
214                         cm.Name = "Begin" + od.Name;
215                         cm.Attributes = MemberAttributes.Public 
216                                         | MemberAttributes.Final;
217
218                         var inArgs = new List<CodeParameterDeclarationExpression > ();
219                         var outArgs = new List<CodeParameterDeclarationExpression > ();
220
221                         foreach (CodeParameterDeclarationExpression p in context.BeginMethod.Parameters) {
222                                 inArgs.Add (p);
223                                 cm.Parameters.Add (p);
224                         }
225                         inArgs.RemoveAt (inArgs.Count - 1);
226                         inArgs.RemoveAt (inArgs.Count - 1);
227
228 //                      cm.Parameters.Add (new CodeParameterDeclarationExpression (new CodeTypeReference (typeof (AsyncCallback)), "asyncCallback"));
229 //                      cm.Parameters.Add (new CodeParameterDeclarationExpression (new CodeTypeReference (typeof (object)), "userState"));
230                         cm.ReturnType = new CodeTypeReference (typeof (IAsyncResult));
231
232                         var argsDecl = new CodeVariableDeclarationStatement (
233                                 typeof (object []),
234                                 "args",
235                                 new CodeArrayCreateExpression (typeof (object), inArgs.ConvertAll<CodeExpression> (decl => new CodeArgumentReferenceExpression (decl.Name)).ToArray ()));
236                         cm.Statements.Add (argsDecl);
237
238                         var args = new List<CodeExpression> ();
239                         args.Add (new CodePrimitiveExpression (od.Name));
240                         args.Add (new CodeVariableReferenceExpression ("args"));
241                         args.Add (new CodeArgumentReferenceExpression ("asyncCallback"));
242                         args.Add (new CodeArgumentReferenceExpression ("userState"));
243
244                         CodeExpression call = new CodeMethodInvokeExpression (
245                                 new CodeBaseReferenceExpression (),
246                                 "BeginInvoke",
247                                 args.ToArray ());
248
249                         if (cm.ReturnType.BaseType == "System.Void")
250                                 cm.Statements.Add (new CodeExpressionStatement (call));
251                         else
252                                 cm.Statements.Add (new CodeMethodReturnStatement (call));
253
254                         // EndXxx() implementation
255
256                         cm = new CodeMemberMethod ();
257                         cm.Attributes = MemberAttributes.Public 
258                                         | MemberAttributes.Final;
259                         type.Members.Add (cm);
260                         cm.Name = "End" + od.Name;
261
262                         var res = new CodeParameterDeclarationExpression (new CodeTypeReference (typeof (IAsyncResult)), "result");
263                         cm.Parameters.Add (res);
264
265                         cm.ReturnType = context.EndMethod.ReturnType;
266
267                         string resultArgName = "result";
268                         argsDecl = new CodeVariableDeclarationStatement (
269                                 typeof (object []),
270                                 "args",
271                                 new CodeArrayCreateExpression (typeof (object), new CodePrimitiveExpression (outArgs.Count)));
272                         cm.Statements.Add (argsDecl);
273
274                         call = new CodeCastExpression (
275                                 context.EndMethod.ReturnType,
276                                 new CodeMethodInvokeExpression (
277                                 new CodeBaseReferenceExpression (),
278                                 "EndInvoke",
279                                 new CodePrimitiveExpression (od.Name),
280                                 new CodeVariableReferenceExpression ("args"),
281                                 new CodeArgumentReferenceExpression (resultArgName)));
282
283                         if (cm.ReturnType.BaseType == "System.Void")
284                                 cm.Statements.Add (new CodeExpressionStatement (call));
285                         else
286                                 cm.Statements.Add (new CodeMethodReturnStatement (call));
287                 }
288         }
289 }