[bcl] Rename aot_hybrid profile to testing_aot_hybrid
[mono.git] / mcs / class / System.Web.Services / System.Web.Services.Protocols / LogicalMethodInfo.cs
1 // 
2 // System.Web.Services.Protocols.LogicalMethodInfo.cs
3 //
4 // Authors:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //   Tim Coleman (tim@timcoleman.com)
7 //   Lluis Sanchez Gual (lluis@ximian.com)
8 //
9 // Copyright (C) Tim Coleman, 2002
10 // Copyright (C) Ximian, Inc,  2003
11 //
12 // TODO:
13 //    BeginInvoke, EndInvoke are missing.
14 //    AsyncResultParameter
15 //
16 // WILD GUESS:
17 //   The reason for this class is so that it can cluster method/begin/end methods
18 //   together, as the begin/end methods in generated files from WSDL does *NOT*
19 //   contain all the information required to make a request.
20 //
21 //   Either that, or the Begin*/End* versions probe the attributes on the regular
22 //   method (which seems simpler). 
23 //
24
25 //
26 // Permission is hereby granted, free of charge, to any person obtaining
27 // a copy of this software and associated documentation files (the
28 // "Software"), to deal in the Software without restriction, including
29 // without limitation the rights to use, copy, modify, merge, publish,
30 // distribute, sublicense, and/or sell copies of the Software, and to
31 // permit persons to whom the Software is furnished to do so, subject to
32 // the following conditions:
33 // 
34 // The above copyright notice and this permission notice shall be
35 // included in all copies or substantial portions of the Software.
36 // 
37 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
38 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
39 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
40 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
41 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
42 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
43 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
44 //
45
46 using System.Reflection;
47 using System.Collections;
48 using System.Text;
49 using System.Web.Services;
50
51 namespace System.Web.Services.Protocols {
52         public sealed class LogicalMethodInfo {
53                 #region Fields
54
55                 MethodInfo method_info, end_method_info;
56                 ParameterInfo [] parameters;
57                 ParameterInfo [] out_parameters;
58                 ParameterInfo [] in_parameters;
59                 WebMethodAttribute attribute;
60
61                 #endregion // Fields.
62                 
63                 #region Constructors
64         
65                 public LogicalMethodInfo (MethodInfo method_info)
66                 {
67                         if (method_info == null)
68                                 throw new ArgumentNullException ("method_info should be non-null");
69                         if (method_info.IsStatic)
70                                 throw new InvalidOperationException ("method is static");
71                         
72                         this.method_info = method_info;
73                 }
74
75                 //
76                 // Only an internal contructor, called from "Create"
77                 //
78                 LogicalMethodInfo (MethodInfo method_info, MethodInfo end_method_info)
79                 {
80                         if (method_info == null)
81                                 throw new ArgumentNullException ("method_info should be non-null");
82                         if (method_info.IsStatic)
83                                 throw new InvalidOperationException ("method is static");
84                         
85                         this.method_info = method_info;
86                         this.end_method_info = end_method_info;
87                 }
88                 
89                 #endregion // Constructors
90
91                 #region Properties
92
93                 //
94                 // Signatures for Begin/End methods:
95                 //
96                 //        public System.IAsyncResult BeginHelloWorld(ARG1, ARG2, System.AsyncCallback callback, object asyncState) {
97                 //        public string EndHelloWorld(System.IAsyncResult asyncResult) {
98
99                 public ParameterInfo AsyncCallbackParameter {
100                         get {
101                                 ParameterInfo [] pi = method_info.GetParameters ();
102                                 return pi [pi.Length-2];
103                         }
104                 }
105
106                 public ParameterInfo AsyncResultParameter {
107                         get {
108                                 ParameterInfo [] pi = end_method_info.GetParameters ();
109                                 return pi [pi.Length-1];
110                         }
111                 }
112
113                 public ParameterInfo AsyncStateParameter {
114                         get {
115                                 ParameterInfo [] pi = method_info.GetParameters ();
116                                 return pi [pi.Length-1];
117                         }
118                 }
119
120                 public MethodInfo BeginMethodInfo {
121                         get {
122                                 if (IsBeginMethod (method_info))
123                                         return method_info;
124                                 return null;
125                         }
126                 }
127
128                 public ICustomAttributeProvider CustomAttributeProvider {
129                         get {
130                                 return method_info;
131                         }
132                 }
133
134                 public Type DeclaringType {
135                         get {
136                                 return method_info.DeclaringType;
137                         }
138                 }
139
140                 public MethodInfo EndMethodInfo {
141                         get {
142                                 return end_method_info;
143                         }
144                 }
145
146                 public ParameterInfo[] InParameters {
147                         get {
148                                 if (parameters == null)
149                                         ComputeParameters ();
150                                 return in_parameters;
151                         }
152                 }
153
154                 public bool IsAsync {
155                         get {
156                                 return end_method_info != null;
157                         }
158                 }
159
160                 public bool IsVoid {
161                         get {
162                                 return ReturnType == typeof (void);
163                         }
164                 }
165
166                 public MethodInfo MethodInfo {
167                         get {
168                                 if (IsBeginMethod (method_info))
169                                         return null;
170                                 return method_info;
171                         }
172                 }
173
174                 public string Name {
175                         get {
176                                 return method_info.Name;
177                         }
178                 }
179
180                 internal MethodInfo ActualMethodInfo {
181                         get { return method_info; }
182                 }
183
184                 void ComputeParameters ()
185                 {
186                         ParameterInfo[] pars = method_info.GetParameters ();
187                         if (IsAsync)
188                         {
189                                 parameters = new ParameterInfo [pars.Length - 2];
190                                 Array.Copy (pars, 0, parameters, 0, pars.Length - 2);
191                                 in_parameters = new ParameterInfo [parameters.Length];
192                                 parameters.CopyTo (in_parameters, 0);
193                                 
194                                 ParameterInfo[] outPars = end_method_info.GetParameters ();
195                                 out_parameters = new ParameterInfo [outPars.Length - 1];
196                                 Array.Copy (outPars, 0, out_parameters, 0, out_parameters.Length);
197                         }
198                         else
199                         {
200                                 parameters = pars;
201                                 int out_count = 0;
202                                 int in_count = 0;
203                                 
204                                 foreach (ParameterInfo p in parameters){
205                                         Type ptype = p.ParameterType;
206                                         if (ptype.IsByRef){
207                                                 out_count++;
208                                                 if (!p.IsOut)
209                                                         in_count++;
210                                         } else
211                                                 in_count++;
212                                 }
213                                 out_parameters = new ParameterInfo [out_count];
214                                 int i = 0;
215                                 for (int j = 0; j < parameters.Length; j++){
216                                         if (parameters [j].ParameterType.IsByRef)
217                                                 out_parameters [i++] = parameters [j];
218                                 }
219                                 in_parameters = new ParameterInfo [in_count];
220                                 i = 0;
221                                 for (int j = 0; j < parameters.Length; j++){
222                                         if (parameters [j].ParameterType.IsByRef){
223                                                 if (!parameters [j].IsOut)
224                                                         in_parameters [i++] = parameters [j];
225                                         } else
226                                                 in_parameters [i++] = parameters [j];
227                                 }
228                         }
229                 }
230                 
231                 public ParameterInfo[] OutParameters {
232                         get {
233                                 if (parameters == null)
234                                         ComputeParameters ();
235                                 return out_parameters;
236                         }
237                 }
238
239                 public ParameterInfo[] Parameters {
240                         get {
241                                 if (parameters == null)
242                                         ComputeParameters ();
243                                 return parameters;
244                         }
245                 }
246
247                 public Type ReturnType {
248                         get {
249                                 if (IsAsync)
250                                         return end_method_info.ReturnType;
251                                 else
252                                         return method_info.ReturnType;
253                         }
254                 }
255
256                 public ICustomAttributeProvider ReturnTypeCustomAttributeProvider {
257                         get {
258                                 return method_info.ReturnTypeCustomAttributes;
259                         }
260                 }
261
262                 internal bool EnableSession {
263                         get {
264                                 if (method_info == null)
265                                         return false;
266
267                                 if (attribute == null) {
268                                         object [] o = method_info.GetCustomAttributes (false);
269                                         foreach (Attribute att in o) {
270                                                 if (att is WebMethodAttribute) {
271                                                         attribute = (WebMethodAttribute) att;
272                                                         break;
273                                                 }
274                                         }
275                                 }
276
277                                 return (attribute != null) ? attribute.EnableSession : false;
278                         }
279                 }
280                 internal int CacheDuration {
281                         get {
282                                 if (method_info == null)
283                                         return -1;
284
285                                 if (attribute == null) {
286                                         object [] o = method_info.GetCustomAttributes (false);
287                                         foreach (Attribute att in o) {
288                                                 if (att is WebMethodAttribute) {
289                                                         attribute = (WebMethodAttribute) att;
290                                                         break;
291                                                 }
292                                         }
293                                 }
294
295                                 return (attribute != null) ? attribute.CacheDuration : -1;
296                         }
297                 }
298                 #endregion // Properties
299
300                 #region Methods
301
302                 public IAsyncResult BeginInvoke (object target, object[] values, AsyncCallback callback, object asyncState)
303                 {
304                         int len = (values!=null) ? values.Length : 0;
305                         object[] pars = new object [len + 2];
306                         
307                         if (len > 0)
308                                 values.CopyTo (pars, 0);
309                         
310                         pars [len] = callback;
311                         pars [len+1] = asyncState;
312                                 
313                         return (IAsyncResult) method_info.Invoke (target, pars);
314                 }
315
316                 public static LogicalMethodInfo[] Create (MethodInfo[] method_infos)
317                 {
318                         return Create (method_infos, LogicalMethodTypes.Sync | LogicalMethodTypes.Async);
319                 }
320
321                 public static LogicalMethodInfo[] Create (MethodInfo[] method_infos, LogicalMethodTypes types)
322                 {
323                         ArrayList sync = ((types & LogicalMethodTypes.Sync) != 0) ? new ArrayList () : null;
324                         ArrayList begin, end;
325
326                         if ((types & LogicalMethodTypes.Async) != 0){
327                                 begin = new ArrayList ();
328                                 end = new ArrayList ();
329                         } else 
330                                 begin = end = null;
331
332                         foreach (MethodInfo mi in method_infos){
333                                 if (IsBeginMethod (mi) && begin != null)
334                                         begin.Add (mi);
335                                 else if (IsEndMethod (mi) && end != null)
336                                         end.Add (mi);
337                                 else if (sync != null)
338                                         sync.Add (mi);
339                         }
340
341                         int bcount = 0, count = 0;
342                         if (begin != null){
343                                 bcount = count = begin.Count;
344                                 if (count != end.Count)
345                                         throw new InvalidOperationException ("Imbalance of begin/end methods");
346                         }
347                         if (sync != null)
348                                 count += sync.Count;
349
350                         LogicalMethodInfo [] res = new LogicalMethodInfo [count];
351                         int dest = 0;
352                         if (begin != null){
353                                 foreach (MethodInfo bm in begin){
354                                         string end_name = "End" + bm.Name.Substring (5);
355
356                                         for (int i = 0; i < bcount; i++){
357                                                 MethodInfo em = (MethodInfo) end [i];
358                                                 if (em.Name == end_name){
359                                                         res [dest++] = new LogicalMethodInfo (bm, em);
360                                                         break;
361                                                 }
362                                                 throw new InvalidOperationException ("Imbalance of begin/end methods");
363                                         }
364                                 }
365                         }
366
367
368                         if (sync != null)
369                                 foreach (MethodInfo mi in sync){
370                                         res [dest++] = new LogicalMethodInfo (mi);
371                                 }
372                         
373                         return res;
374                 }
375
376                 public object[] EndInvoke (object target, IAsyncResult asyncResult)
377                 {
378                         if (parameters == null)
379                                 ComputeParameters ();
380
381                         object[] values = new object [out_parameters.Length + 1];
382                         values [values.Length - 1] = asyncResult;
383                         object res = end_method_info.Invoke (target, values);
384                         
385                         int retc = IsVoid ? 0 : 1;
386                         object [] ret = new object [retc + out_parameters.Length];
387                         
388                         if (retc == 1) ret [0] = res;
389                         
390                         Array.Copy (values, 0, ret, retc, out_parameters.Length);
391                         return ret;
392                 }
393
394                 public object GetCustomAttribute (Type type)
395                 {
396                         return Attribute.GetCustomAttribute (method_info, type, false);
397                 }
398
399                 public object[] GetCustomAttributes (Type type)
400                 {
401                         return method_info.GetCustomAttributes (type, false);
402                 }
403
404                 public object[] Invoke (object target, object[] values)
405                 {
406                         if (parameters == null)
407                                 ComputeParameters ();
408
409                         int retc = IsVoid ? 0 : 1;
410                         object [] ret = new object [retc + out_parameters.Length];
411                         object res = method_info.Invoke (target, values);
412                         if (retc == 1) ret [0] = res;
413
414                         int j = retc;
415                         for (int i = 0; i < parameters.Length; i++){
416                                 if (parameters [i].ParameterType.IsByRef)
417                                         ret [j++] = values [i];
418                         }
419
420                         return ret;
421                 }
422
423                 public static bool IsBeginMethod (MethodInfo method_info)
424                 {
425                         if (method_info == null)
426                                 throw new ArgumentNullException ("method_info can not be null");
427
428                         if (method_info.ReturnType != typeof (IAsyncResult))
429                                 return false;
430
431                         if (method_info.Name.StartsWith ("Begin"))
432                                 return true;
433
434                         return false;
435                 }
436
437                 public static bool IsEndMethod (MethodInfo method_info)
438                 {
439                         if (method_info == null)
440                                 throw new ArgumentNullException ("method_info can not be null");
441
442                         ParameterInfo [] parameter_info = method_info.GetParameters ();
443                         if (parameter_info.Length != 1)
444                                 return false;
445                         if (parameter_info [0].ParameterType != typeof (IAsyncResult))
446                                 return false;
447                         if (method_info.Name.StartsWith ("End"))
448                                 return true;
449
450                         return false;
451                 }
452
453                 public override string ToString ()
454                 {
455                         StringBuilder sb = new StringBuilder ();
456                         if (parameters == null)
457                                 ComputeParameters ();
458                         
459                         for (int i = 0; i < parameters.Length; i++){
460                                 sb.Append (parameters [i].ParameterType);
461                                 if (parameters [i].ParameterType.IsByRef)
462                                         sb.Append (" ByRef");
463                                 
464                                 if (i+1 != parameters.Length)
465                                         sb.Append (", ");
466                         }
467                         
468                         return String.Format (
469                                 "{0} {1} ({2})",
470                                 method_info.ReturnType, method_info.Name,
471                                 sb.ToString ());
472                 }
473
474                 #endregion // Methods
475         }
476 }