source: xmlrpcnet/trunk/fuentes/src/XmlRpcProxyCodeGen.cs @ 379

Last change on this file since 379 was 379, checked in by hectorgh, 5 years ago

adding project files

File size: 26.0 KB
Line 
1/*
2XML-RPC.NET  proxy class code generator
3Copyright (c) 2003, Joe Bork <joe@headblender.com>
4Portions Copyright (c) 2001-2003, Charles Cook <ccook@cookcomputing.com>
5
6Permission is hereby granted, free of charge, to any person
7obtaining a copy of this software and associated documentation
8files (the "Software"), to deal in the Software without restriction,
9including without limitation the rights to use, copy, modify, merge,
10publish, distribute, sublicense, and/or sell copies of the Software,
11and to permit persons to whom the Software is furnished to do so,
12subject to the following conditions:
13
14The above copyright notice and this permission notice shall be
15included in all copies or substantial portions of the Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24DEALINGS IN THE SOFTWARE.
25*/
26
27namespace Headblender.XmlRpc
28{
29        using System;
30        using System.Collections;
31        using System.Reflection;
32
33        using System.Globalization;
34        using System.Text;
35        using System.IO;
36        using System.CodeDom;
37        using System.CodeDom.Compiler;
38
39        using CookComputing.XmlRpc;
40
41    public sealed class XmlRpcProxyCodeGenOptions
42        {
43                private string GenNamespace = "";
44                private string GenTypeName = "";
45                private bool GenImplicitAsync = false;
46                private bool GenFlattenInterfaces = false;
47
48                public XmlRpcProxyCodeGenOptions()
49                {
50                        GenNamespace = "";
51                        GenTypeName = "";
52                        GenImplicitAsync = false;
53                        GenFlattenInterfaces = false;
54                }
55
56                public XmlRpcProxyCodeGenOptions(
57                        string initNamespace,
58                        string initTypeName,
59                        bool initImplicitAsync,
60                        bool flattenInterfaces)
61                {
62                        GenNamespace = initNamespace;
63                        GenTypeName = initTypeName;
64                        GenImplicitAsync = initImplicitAsync;
65                        GenFlattenInterfaces = flattenInterfaces;
66                }
67
68                public string Namespace
69                {
70                        get
71                        {
72                                return GenNamespace;
73                        }
74
75                        set
76                        {
77                                GenNamespace = value;
78                        }
79                }
80
81                public string TypeName
82                {
83                        get
84                        {
85                                return GenTypeName;
86                        }
87
88                        set
89                        {
90                                GenTypeName = value;
91                        }
92                }
93
94                public bool ImplicitAsync
95                {
96                        get
97                        {
98                                return GenImplicitAsync;
99                        }
100
101                        set
102                        {
103                                GenImplicitAsync = value;
104                        }
105                }
106
107                public bool FlattenInterfaces
108                {
109                        get
110                        {
111                                return GenFlattenInterfaces;
112                        }
113
114                        set
115                        {
116                                GenFlattenInterfaces = value;
117                        }
118                }
119        }
120
121        public sealed class XmlRpcProxyCodeGen
122        {
123                const string DEFAULT_RET = "xrtReturn";
124                const string DEFAULT_TEMP = "xrtTemp";
125                const string DEFAULT_ARR = "xrtArray";
126                const string DEFAULT_CALLBACK = "xrtCallback";
127                const string DEFAULT_STATUS = "xrtStatus";
128                const string DEFAULT_RESULT = "xrtResult";
129
130                const string DEFAULT_SUFFIX = "RpcProxy";
131                const string DEFAULT_END = "End";
132                const string DEFAULT_BEGIN = "Begin";
133
134                private XmlRpcProxyCodeGen()
135                {
136                        // no public constructor where all public methods are static
137                }
138
139                private delegate void BuildMethodDelegate(
140                        CodeTypeDeclaration declaration, 
141                        string methodName,
142                        string rpcMethodName,
143                        Type[] argTypes,
144                        string[] argNames,
145                        Type returnType,
146                        Type implementationType);
147
148                public static string CreateCode(
149                        Type proxyType, 
150                        ICodeGenerator generator)
151                {
152                        return CreateCode(proxyType, generator, new XmlRpcProxyCodeGenOptions());
153                }
154
155                public static string CreateCode(
156                        Type proxyType, 
157                        ICodeGenerator generator,
158                        XmlRpcProxyCodeGenOptions options)
159                {
160                        if (options == null)
161                        {
162                                throw new ArgumentNullException(
163                                        "options",
164                                        "The options parameter cannot be null");
165                        }
166
167                        CodeCompileUnit ccu = CreateCodeCompileUnit(proxyType, generator, options);
168
169                        CodeGeneratorOptions cgo = new CodeGeneratorOptions();
170                        cgo.BlankLinesBetweenMembers = true;
171                        cgo.BracingStyle = "C";
172
173                        StringWriter sw = new StringWriter(CultureInfo.InvariantCulture);
174
175                        generator.GenerateCodeFromCompileUnit(ccu, sw, cgo);
176
177                        string ret = sw.ToString();
178
179                        return ret;
180                }
181
182                public static CodeCompileUnit CreateCodeCompileUnit(
183                        Type proxyType, 
184                        ICodeGenerator generator)
185                {
186                        return CreateCodeCompileUnit(proxyType, generator, new XmlRpcProxyCodeGenOptions());
187                }
188
189                public static CodeCompileUnit CreateCodeCompileUnit(
190                        Type proxyType, 
191                        ICodeGenerator generator, 
192                        XmlRpcProxyCodeGenOptions options)
193                {
194                        if (options == null)
195                        {
196                                throw new ArgumentNullException(
197                                        "options",
198                                        "The options parameter cannot be null");
199                        }
200
201                        // create unique names
202                        string baseName = proxyType.Name;
203
204                        // string leading "I"
205                        if (baseName.StartsWith("I") == true)
206                        {
207                                baseName = baseName.Remove(0,1);
208                        }
209
210                        string moduleName = String.Format(
211                                CultureInfo.InvariantCulture,
212                                "{0}{1}.dll",
213                                baseName,
214                                DEFAULT_SUFFIX);
215
216                        string assemblyName = "";
217                        if (options.Namespace.Length > 0)
218                        {
219                                assemblyName = options.Namespace;
220                        }
221                        else
222                        {
223                                assemblyName = String.Format(
224                                        CultureInfo.InvariantCulture,
225                                        "{0}{1}",
226                                        baseName,
227                                        DEFAULT_SUFFIX);
228                        }
229
230                        string typeName = "";
231                        if (options.TypeName.Length > 0)
232                        {
233                                typeName = options.TypeName;
234                        }
235                        else
236                        {
237                                typeName = assemblyName;
238                        }
239
240                        bool implicitAsync = options.ImplicitAsync;
241                        bool flattenInterfaces = options.FlattenInterfaces;
242
243                        CodeCompileUnit ccu = BuildCompileUnit(
244                                proxyType, 
245                                assemblyName, 
246                                moduleName, 
247                                typeName, 
248                                implicitAsync,
249                                flattenInterfaces);
250
251                        return ccu;
252                }
253
254                private static CodeCompileUnit BuildCompileUnit(
255                        Type proxyType, 
256                        string assemblyName,
257                        string moduleName,
258                        string typeName,
259                        bool implicitAsync,
260                        bool flattenInterfaces)
261                {
262                        string urlString = GetXmlRpcUrl(proxyType);
263                        Hashtable methods = GetXmlRpcMethods(proxyType, flattenInterfaces);
264                        Hashtable beginMethods = GetXmlRpcBeginMethods(proxyType, flattenInterfaces);
265                        Hashtable endMethods = GetXmlRpcEndMethods(proxyType, flattenInterfaces);
266
267                        // if there are no Begin and End methods,
268                        // we can implicitly generate them
269                        if ((beginMethods.Count == 0) && (endMethods.Count == 0) && (implicitAsync == true))
270                        {
271                                beginMethods = GetXmlRpcMethods(proxyType, flattenInterfaces);
272                                endMethods = GetXmlRpcMethods(proxyType, flattenInterfaces);
273                        }
274
275                        CodeCompileUnit ccu = new CodeCompileUnit();
276
277                        CodeNamespace cn = new CodeNamespace(assemblyName);
278
279                        cn.Imports.Add(new CodeNamespaceImport("System"));
280                        cn.Imports.Add(new CodeNamespaceImport(proxyType.Namespace));
281                        cn.Imports.Add(new CodeNamespaceImport("CookComputing.XmlRpc"));
282
283                        CodeTypeDeclaration ctd = new CodeTypeDeclaration(typeName);
284
285                        // its a class
286                        ctd.IsClass = true;
287                        // class is public and sealed
288                        ctd.TypeAttributes = TypeAttributes.Public | TypeAttributes.Sealed;
289                        // class derives from XmlRpcClientProtocol
290                        ctd.BaseTypes.Add(typeof(XmlRpcClientProtocol));
291                        // and implements I(itf)
292                        ctd.BaseTypes.Add(proxyType);
293
294                        BuildConstructor(ctd, typeof(XmlRpcClientProtocol), urlString);
295                        BuildMethods(ctd, methods, new BuildMethodDelegate(BuildStandardMethod));
296                        BuildMethods(ctd, beginMethods, new BuildMethodDelegate(BuildBeginMethod));
297                        BuildMethods(ctd, endMethods, new BuildMethodDelegate(BuildEndMethod));
298
299                        cn.Types.Add(ctd);
300                        ccu.Namespaces.Add(cn);
301
302                        return ccu;
303                }
304
305                private static void BuildMethods(
306                        CodeTypeDeclaration declaration, 
307                        Hashtable methods,
308                        BuildMethodDelegate buildDelegate)
309                {
310                        foreach (DictionaryEntry de in methods)
311                        {
312                                MethodData mthdData = (MethodData)de.Value;
313                                MethodInfo mi = mthdData.mi;
314                                Type[] argTypes = new Type[mi.GetParameters().Length];
315                                string[] argNames = new string[mi.GetParameters().Length];
316                                for(int i = 0; i < mi.GetParameters().Length; i++)
317                                {
318                                        argTypes[i] = mi.GetParameters()[i].ParameterType;
319                                        argNames[i] = mi.GetParameters()[i].Name;
320                                }
321                                //buildDelegate(declaration, mi.Name, mthdData.xmlRpcName, argTypes, argNames, mi.ReturnType);
322                                string n = (string)de.Key;
323                                buildDelegate(
324                                        declaration, 
325                                        n, 
326                                        mthdData.xmlRpcName, 
327                                        argTypes, 
328                                        argNames, 
329                                        mi.ReturnType, 
330                                        mthdData.implementationType);
331                        }
332                }
333
334                private static void BuildStandardMethod(
335                        CodeTypeDeclaration declaration, 
336                        string methodName,
337                        string rpcMethodName,
338                        Type[] argTypes,
339                        string[] argNames,
340                        Type returnType,
341                        Type implementationType)
342                {
343                        CodeMemberMethod cmm = new CodeMemberMethod();
344
345                        // set the attributes and name
346
347                        // normal, unqualified type names are public
348                        cmm.Attributes = MemberAttributes.Public | MemberAttributes.Final;
349
350                        cmm.ImplementationTypes.Add(implementationType);
351
352                        cmm.Name = methodName;
353                       
354                        // set the return type
355                        CodeTypeReference ctrReturn = new CodeTypeReference(returnType);
356                        cmm.ReturnType = ctrReturn;
357
358                        MakeParameterList(cmm, argTypes, argNames);
359
360                        // add an XmlRpcMethod attribute to the type
361                        CodeAttributeDeclaration cad = new CodeAttributeDeclaration();
362                        cad.Name = typeof(XmlRpcMethodAttribute).FullName;
363
364                        CodeAttributeArgument caa = new CodeAttributeArgument();
365                        CodePrimitiveExpression cpe = new CodePrimitiveExpression(rpcMethodName);
366                        caa.Value = cpe;
367
368                        cad.Arguments.Add(caa);
369
370                        cmm.CustomAttributes.Add(cad);
371
372                        // generate the method body:
373
374                        // if non-void return, declared locals for processing return value
375                        if (returnType != typeof(void))
376                        {
377                                // add some local variables
378                                MakeTempVariable(cmm, typeof(System.Object));
379                                MakeReturnVariable(cmm, returnType);
380                        }
381
382                        MakeTempParameterArray(cmm, argTypes, argNames);
383
384                        // construct a call to the base Invoke method
385                        CodeThisReferenceExpression ctre = new CodeThisReferenceExpression();
386
387                        CodeMethodReferenceExpression cmre = new CodeMethodReferenceExpression(ctre, "Invoke");
388                       
389                        CodeMethodInvokeExpression cmie = new CodeMethodInvokeExpression();
390                        cmie.Method = cmre;
391                        cmie.Parameters.Add(new CodePrimitiveExpression(methodName));
392                        cmie.Parameters.Add(new CodeVariableReferenceExpression(DEFAULT_ARR));
393
394                        if (returnType != typeof(void))
395                        {
396                                // assign the result to tempRetVal
397                                CodeAssignStatement casTemp = new CodeAssignStatement();
398                                casTemp.Left = new CodeVariableReferenceExpression(DEFAULT_TEMP);
399                                casTemp.Right = cmie;
400
401                                cmm.Statements.Add(casTemp);
402                        }
403                        else
404                        {
405                                // discard return type
406                                cmm.Statements.Add(cmie);
407                        }
408
409                        MakeReturnStatement(cmm, returnType);
410
411                        // add the finished method to the type
412                        declaration.Members.Add(cmm);
413                }
414
415                private static void BuildBeginMethod(
416                        CodeTypeDeclaration declaration, 
417                        string methodName,
418                        string rpcMethodName,
419                        Type[] argTypes,
420                        string[] argNames,
421                        Type returnType,
422                        Type implementationType)
423                {
424                        string beginMethodName = "";
425
426                        CodeMemberMethod cmm = new CodeMemberMethod();
427
428                        // set the attributes and name
429                        cmm.Attributes = MemberAttributes.Public | MemberAttributes.Final;
430
431                        if (methodName.StartsWith(DEFAULT_BEGIN) == true)
432                        {
433                                // strip method name prefix
434                                cmm.Name = methodName.Substring(DEFAULT_BEGIN.Length, methodName.Length - DEFAULT_BEGIN.Length);
435                        }
436                        beginMethodName = String.Format(CultureInfo.InvariantCulture, "{0}{1}", DEFAULT_BEGIN, methodName);
437
438                        cmm.Name = beginMethodName;
439
440                        //!cmm.ImplementationTypes.Add(implementationType);
441                       
442                        // set the return type (always IAsyncResult)
443                        cmm.ReturnType = new CodeTypeReference(typeof(System.IAsyncResult));
444
445                        MakeParameterList(cmm, argTypes, argNames);
446
447                        // add callback and state params
448                        cmm.Parameters.Add(new CodeParameterDeclarationExpression(
449                                typeof(System.AsyncCallback), 
450                                DEFAULT_CALLBACK)
451                                );
452
453                        cmm.Parameters.Add(new CodeParameterDeclarationExpression(
454                                typeof(System.Object),
455                                DEFAULT_STATUS)
456                                );
457
458                        MakeReturnVariable(cmm, typeof(System.IAsyncResult));
459
460                        MakeTempParameterArray(cmm, argTypes, argNames);
461
462                        // construct a call to the base beginInvoke method
463
464                        CodeThisReferenceExpression ctre = new CodeThisReferenceExpression();
465
466                        CodeMethodReferenceExpression cmre = new CodeMethodReferenceExpression(ctre, "BeginInvoke");
467                       
468                        CodeMethodInvokeExpression cmie = new CodeMethodInvokeExpression();
469                        cmie.Method = cmre;
470                        cmie.Parameters.Add(new CodePrimitiveExpression(methodName));
471                        cmie.Parameters.Add(new CodeVariableReferenceExpression(DEFAULT_ARR));
472                        cmie.Parameters.Add(new CodeVariableReferenceExpression(DEFAULT_CALLBACK));
473                        cmie.Parameters.Add(new CodeVariableReferenceExpression(DEFAULT_STATUS));
474
475                        // assign the result to RetVal
476                        CodeAssignStatement casTemp = new CodeAssignStatement();
477                        casTemp.Left = new CodeVariableReferenceExpression(DEFAULT_RET);
478                        casTemp.Right = cmie;
479
480                        cmm.Statements.Add(casTemp);
481
482                        // return retVal
483                        CodeMethodReturnStatement cmrsCast = new CodeMethodReturnStatement();
484                        cmrsCast.Expression = new CodeVariableReferenceExpression(DEFAULT_RET);
485
486                        cmm.Statements.Add(cmrsCast);
487
488                        // add the finished method to the type
489                        declaration.Members.Add(cmm);
490                }
491
492                private static void BuildEndMethod(
493                        CodeTypeDeclaration declaration, 
494                        string methodName,
495                        string rpcMethodName,
496                        Type[] argTypes,
497                        string[] argNames,
498                        Type returnType,
499                        Type implementationType)
500                {
501                        string endMethodName = "";
502
503                        CodeMemberMethod cmm = new CodeMemberMethod();
504
505                        // set the attributes and name
506                        cmm.Attributes = MemberAttributes.Public | MemberAttributes.Final;
507
508                        if (methodName.StartsWith(DEFAULT_END) == true)
509                        {
510                                // strip method name prefix
511                                cmm.Name = methodName.Substring(DEFAULT_END.Length, methodName.Length - DEFAULT_END.Length);
512                        }
513                        endMethodName = String.Format(CultureInfo.InvariantCulture, "{0}{1}", DEFAULT_END, methodName);
514
515                        cmm.Name = endMethodName;
516
517                        //!cmm.ImplementationTypes.Add(implementationType);
518                       
519                        // set the return type
520                        CodeTypeReference ctrReturn = new CodeTypeReference(returnType);
521                        cmm.ReturnType = ctrReturn;
522
523                        // set the parameter list (always a single IAsyncResult)
524                        CodeParameterDeclarationExpression cpde = new CodeParameterDeclarationExpression();
525
526                        cpde.Name = DEFAULT_RESULT;
527                        cpde.Type = new CodeTypeReference(typeof(System.IAsyncResult));
528
529                        cmm.Parameters.Add(cpde);
530
531                        // generate the method body:
532
533                        // if non-void return, declared locals for processing return value
534                        if (returnType != typeof(void))
535                        {
536                                // add some local variables:
537                                MakeTempVariable(cmm, typeof(System.Object));
538                                MakeReturnVariable(cmm, returnType);
539                        }
540
541                        // construct a call to the base EndInvoke method
542
543                        CodeThisReferenceExpression ctre = new CodeThisReferenceExpression();
544
545                        CodeMethodReferenceExpression cmre = new CodeMethodReferenceExpression(ctre, "EndInvoke");
546                       
547                        CodeMethodInvokeExpression cmie = new CodeMethodInvokeExpression();
548                        cmie.Method = cmre;
549                        cmie.Parameters.Add(new CodeVariableReferenceExpression(DEFAULT_RESULT));
550
551                        CodeIndexerExpression cie = new CodeIndexerExpression();
552                        cie.TargetObject = cmie;
553                        cie.Indices.Add(new CodePrimitiveExpression(0));
554
555                        if (returnType != typeof(void))
556                        {
557                                // assign the result to tempRetVal
558                                CodeAssignStatement casTemp = new CodeAssignStatement();
559                                casTemp.Left = new CodeVariableReferenceExpression(DEFAULT_TEMP);
560                                //!casTemp.Right = cie;
561                                casTemp.Right = cmie;
562
563                                cmm.Statements.Add(casTemp);
564                        }
565                        else
566                        {
567                                // discard return type
568                                //!cmm.Statements.Add(cie);
569                                cmm.Statements.Add(cmie);
570                        }
571
572                        MakeReturnStatement(cmm, returnType);
573
574                        // add the finished method to the type
575                        declaration.Members.Add(cmm);
576                }
577
578                private static void BuildConstructor(
579                        CodeTypeDeclaration declaration, 
580                        Type baseType,
581                        string urlStr)
582                {
583                        CodeConstructor cc = new CodeConstructor();
584
585                        if (urlStr != null && urlStr.Length > 0)
586                        {
587                                // add an XmlRpcUrl attribute to the type
588                                CodeAttributeDeclaration cad = new CodeAttributeDeclaration();
589                                cad.Name = typeof(XmlRpcUrlAttribute).FullName;
590
591                                CodeAttributeArgument caa = new CodeAttributeArgument();
592                                CodePrimitiveExpression cpe = new CodePrimitiveExpression(urlStr);
593                                caa.Value = cpe;
594
595                                cad.Arguments.Add(caa);
596                                declaration.CustomAttributes.Add(cad);
597                        }
598
599                        // call the base constructor:
600                        cc.Attributes = MemberAttributes.Public;
601
602                        // add the constructor to the type
603                        declaration.Members.Add(cc);
604                }
605
606
607                // ==========================================================================
608
609                private static string GetXmlRpcUrl(Type proxyType)
610                {
611                        Attribute attr = Attribute.GetCustomAttribute(
612                                proxyType, 
613                                typeof(XmlRpcUrlAttribute));
614                        if (attr == null)
615                                return null;
616                        XmlRpcUrlAttribute xruAttr = attr as XmlRpcUrlAttribute;
617                        string url = xruAttr.Uri;
618                        return url;
619                }
620
621
622                private static Hashtable GetXmlRpcMethods(Type proxyType, bool flatten)
623                {
624                        Hashtable ret = new Hashtable();
625
626                        RecurseGetXmlRpcMethods(proxyType, ref ret, flatten);
627
628            return ret;
629                }
630
631                private static void RecurseGetXmlRpcMethods(Type proxyType, ref Hashtable h, bool flatten)
632                {                       
633                        if (!proxyType.IsInterface)
634                                throw new Exception("type not interface");
635
636                        foreach(MethodInfo mi in proxyType.GetMethods())
637                        {
638                                string xmlRpcName = GetXmlRpcMethodName(mi);
639                                if (xmlRpcName == null)
640                                        continue;
641
642                                string n = mi.Name;
643
644                                if (h.Contains(n) == true)
645                                {
646                                        throw new Exception("duplicate method name encountered in type hierarchy");
647                                }
648
649                                // add new method
650                                h.Add(n, new MethodData(mi, xmlRpcName, mi.ReturnType, proxyType));
651                        }
652
653                        if (flatten == true)
654                        {
655                                Type[] ifs = proxyType.GetInterfaces();
656                                for (int i = 0; i < ifs.Length; ++i)
657                                {
658                                        RecurseGetXmlRpcMethods(ifs[i], ref h, flatten);
659                                }
660                        }
661                }
662
663               
664                private static Hashtable GetXmlRpcBeginMethods(Type proxyType, bool flatten)
665                {
666                        Hashtable ret = new Hashtable();
667
668                        RecurseGetXmlRpcBeginMethods(proxyType, ref ret, flatten);
669
670                        return ret;
671                }
672
673                private static void RecurseGetXmlRpcBeginMethods(Type proxyType, ref Hashtable h, bool flatten)
674                {
675                        if (!proxyType.IsInterface)
676                                throw new Exception("type not interface");
677                        foreach(MethodInfo mi in proxyType.GetMethods())
678                        {
679                                Attribute attr = Attribute.GetCustomAttribute(mi, 
680                                        typeof(XmlRpcBeginAttribute));
681                                if (attr == null)
682                                        continue;
683                                string rpcMethod = ((XmlRpcBeginAttribute)attr).Method;
684                                if (rpcMethod.Length == 0) 
685                                {
686                                        if (!mi.Name.StartsWith("Begin") || mi.Name.Length <= 5)
687                                                throw new Exception(String.Format(
688                                                        CultureInfo.InvariantCulture, 
689                                                        "method {0} has invalid signature for begin method", 
690                                                        mi.Name));
691                                        rpcMethod = mi.Name.Substring(5);
692                                }
693                                int paramCount = mi.GetParameters().Length;
694                                int i;
695                                for (i = 0; i < paramCount; i++)
696                                {
697                                        Type paramType = mi.GetParameters()[0].ParameterType;
698                                        if (paramType == typeof(System.AsyncCallback))
699                                                break;
700                                }
701                                if (paramCount > 1)
702                                {
703                                        if (i < paramCount - 2)
704                                                throw new Exception(String.Format(
705                                                        CultureInfo.InvariantCulture, 
706                                                        "method {0} has invalid signature for begin method", mi.Name));
707                                        if (i == (paramCount - 2))
708                                        {
709                                                Type paramType = mi.GetParameters()[i+1].ParameterType;
710                                                if (paramType != typeof(System.Object))
711                                                        throw new Exception(String.Format(
712                                                                CultureInfo.InvariantCulture, 
713                                                                "method {0} has invalid signature for begin method", 
714                                                                mi.Name));
715                                        }
716                                }
717                                string n = mi.Name;
718
719                                if (h.Contains(n) == true)
720                                {
721                                        throw new Exception("duplicate begin method name encountered in type hierarchy");
722                                }
723
724                                h.Add(n, new MethodData(mi, rpcMethod, null, null));
725                        }
726
727
728                        if (flatten == true)
729                        {
730                                Type[] ifs = proxyType.GetInterfaces();
731                                for (int i = 0; i < ifs.Length; ++i)
732                                {
733                                        RecurseGetXmlRpcBeginMethods(ifs[i], ref h, flatten);
734                                }
735                        }                       
736                }
737
738
739                private static Hashtable GetXmlRpcEndMethods(Type proxyType, bool flatten)
740                {
741                        Hashtable ret = new Hashtable();
742
743                        RecurseGetXmlRpcEndMethods(proxyType, ref ret, flatten);
744
745                        return ret;
746                }
747
748                private static void RecurseGetXmlRpcEndMethods(Type proxyType, ref Hashtable h, bool flatten)
749                {                       
750                        if (!proxyType.IsInterface)
751                                throw new Exception("type not interface");
752                        foreach(MethodInfo mi in proxyType.GetMethods())
753                        {
754                                Attribute attr = Attribute.GetCustomAttribute(mi, 
755                                        typeof(XmlRpcEndAttribute));
756                                if (attr == null)
757                                        continue;
758                                if (mi.GetParameters().Length != 1)
759                                        throw new Exception(String.Format(
760                                                CultureInfo.InvariantCulture, 
761                                                "method {0} has invalid signature for end method", mi.Name));
762                                Type paramType = mi.GetParameters()[0].ParameterType;
763                                if (paramType != typeof(System.IAsyncResult))
764                                        throw new Exception(String.Format(
765                                                CultureInfo.InvariantCulture, 
766                                                "method {0} has invalid signature for end method", mi.Name));
767                               
768                                string n = mi.Name;
769
770                                if (h.Contains(n) == true)
771                                {
772                                        throw new Exception("duplicate end method name encountered in type hierarchy");
773                                }
774
775                                h.Add(h, new MethodData(mi, "", null, null));
776                        }
777
778                        if (flatten == true)
779                        {
780                                Type[] ifs = proxyType.GetInterfaces();
781                                for (int i = 0; i < ifs.Length; ++i)
782                                {
783                                        RecurseGetXmlRpcEndMethods(ifs[i], ref h, flatten);
784                                }
785                        }
786                }
787
788               
789                private static string GetXmlRpcMethodName(MethodInfo mi)
790                {
791                        Attribute attr = Attribute.GetCustomAttribute(mi, 
792                                typeof(XmlRpcMethodAttribute));
793                        if (attr == null)
794                                return null;
795                        XmlRpcMethodAttribute xrmAttr = attr as XmlRpcMethodAttribute;
796                        string rpcMethod = xrmAttr.Method;
797                        if (rpcMethod.Length == 0)
798                        {
799                                rpcMethod = mi.Name;
800                        }
801                        return rpcMethod;
802                }
803
804                private class MethodData
805                {
806                        public MethodData(MethodInfo Mi, string XmlRpcName, Type ReturnType, Type ImplementationType)
807                        {
808                                m_mi = Mi;
809                                m_xmlRpcName = XmlRpcName;
810                                m_returnType = ReturnType;
811                                m_implementationType = ImplementationType;
812                        }
813
814                        private MethodInfo m_mi;
815                        private string m_xmlRpcName;
816                        private Type m_returnType;
817                        private Type m_implementationType;
818
819                        public MethodInfo mi
820                        {
821                                get { return m_mi; }
822                                set { m_mi = value; }
823                        }
824
825                        public string xmlRpcName
826                        {
827                                get { return m_xmlRpcName; }
828                                set { m_xmlRpcName = value; }
829                        }
830
831                        public Type returnType
832                        {
833                                get { return m_returnType; }
834                                set { m_returnType = value; }
835                        }
836
837                        public Type implementationType
838                        {
839                                get { return m_implementationType; }
840                                set { m_implementationType = value; }
841                        }
842                }
843
844
845                // ==========================================================================
846
847                private static void MakeParameterList(CodeMemberMethod method, Type[] types, string[] names)
848                {
849                        // set the parameter list
850                        for (int i = 0; i < types.Length; ++i)
851                        {
852                                CodeParameterDeclarationExpression cpde = new CodeParameterDeclarationExpression();
853
854                                cpde.Name = names[i];
855
856                                CodeTypeReference ctr = new CodeTypeReference(types[i]);
857                                cpde.Type = ctr;
858
859                                method.Parameters.Add(cpde);
860                        }
861                }
862
863                private static void MakeReturnVariable(CodeMemberMethod method, Type returnType)
864                {
865                        // return variable
866                        CodeVariableDeclarationStatement cvdsRet = new CodeVariableDeclarationStatement();
867                        cvdsRet.Name = DEFAULT_RET;
868                        cvdsRet.Type = new CodeTypeReference(returnType);
869
870                        if (returnType.IsValueType == false)
871                        {
872                                cvdsRet.InitExpression = new CodePrimitiveExpression(null);
873                        }
874
875                        method.Statements.Add(cvdsRet);
876                }
877
878                private static void MakeTempVariable(CodeMemberMethod method, Type tempType)
879                {
880                        // temp object variable
881                        CodeVariableDeclarationStatement cvdsTemp = new CodeVariableDeclarationStatement();
882                        cvdsTemp.Name = DEFAULT_TEMP;
883                        cvdsTemp.Type = new CodeTypeReference(tempType);
884
885                        if (tempType.IsValueType == false)
886                        {
887                                cvdsTemp.InitExpression = new CodePrimitiveExpression(null);
888                        }
889
890                        method.Statements.Add(cvdsTemp);
891                }
892
893                private static void MakeTempParameterArray(CodeMemberMethod method, Type[] types, string[] names)
894                {
895                       
896                        // declare array variable to store method args
897                        CodeVariableDeclarationStatement cvdsArr = new CodeVariableDeclarationStatement();
898                        cvdsArr.Name = DEFAULT_ARR;
899                       
900                        CodeTypeReference ctrArrType = new CodeTypeReference(typeof(System.Object));
901                        CodeTypeReference ctrArr = new CodeTypeReference(ctrArrType, 1);
902
903                        cvdsArr.Type = ctrArr;
904                       
905                        // gen code to initialize the array
906                        CodeArrayCreateExpression cace = new CodeArrayCreateExpression(typeof(System.Object), 1);
907
908                        // create array initializers
909                        for (int i = 0; i < types.Length; ++i)
910                        {
911                                CodeArgumentReferenceExpression care = new CodeArgumentReferenceExpression();
912                                care.ParameterName = names[i];
913
914                                cace.Initializers.Add(care);
915                        }
916
917                        cvdsArr.InitExpression = cace;
918
919                        method.Statements.Add(cvdsArr);
920                }
921
922                private static void MakeReturnStatement(CodeMemberMethod method, Type returnType)
923                {
924                        if (returnType != typeof(void))
925                        {
926                                // create a cast statement
927                                CodeCastExpression cce = new CodeCastExpression(
928                                        returnType, 
929                                        new CodeVariableReferenceExpression(DEFAULT_TEMP)
930                                        );
931
932                                CodeAssignStatement casCast = new CodeAssignStatement();
933                                casCast.Left = new CodeVariableReferenceExpression(DEFAULT_RET);
934                                casCast.Right = cce;
935
936                                method.Statements.Add(casCast);
937
938                                // return retVal
939                                CodeMethodReturnStatement cmrsCast = new CodeMethodReturnStatement();
940                                cmrsCast.Expression = new CodeVariableReferenceExpression(DEFAULT_RET);
941
942                                method.Statements.Add(cmrsCast);
943                        }
944                        else
945                        {
946                                // construct an undecorated return statement
947                                method.Statements.Add(new CodeMethodReturnStatement());
948                        }
949                }
950
951               
952        }
953}
Note: See TracBrowser for help on using the repository browser.