**** Merged from MCS ****
[mono-project.git] / mcs / class / Mono.Xml.Ext / Mono.Xml.XPath2 / XQueryCliFunction.cs
blobc081a5b6cdbd4427cb3c596e2fa8ccf400f10dfa
1 //
2 // XQueryCliFunction.cs
3 //
4 // Author:
5 // Atsushi Enomoto <atsushi@ximian.com>
6 //
7 //
8 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 //
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 //
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 // Runtime type method wrapper for XPath2 function.
33 #if NET_2_0
34 using System;
35 using System.Collections;
36 using System.Reflection;
37 using System.Security;
38 using System.Security.Policy;
39 using System.Xml;
40 using System.Xml.Schema;
41 using System.Xml.Query;
42 using System.Xml.XPath;
43 using System.Xml.Xsl;
44 using Mono.Xml;
46 namespace Mono.Xml.XPath2
49 // Ideas:
50 // declare function namespace cli = "http://mono-project.com/xquery/function/cli"
51 // declare variable v = cli:invoke (cli:new (Microsoft.CSharp:CSharpCodeProvider), CreateCompiler);
52 // declare variable v2 = System.Math:Abs (0.5);
55 public class XQueryCliFunction : XQueryFunction
57 internal static XQueryCliFunction CreateFromMethodInfo (MethodInfo mi)
59 return CreateFromMethodInfo (null, mi);
62 internal static XQueryCliFunction CreateFromMethodInfo (XmlQualifiedName name, MethodInfo mi)
64 return CreateFromMethodInfo (name, new MethodInfo [] {mi});
67 internal static XQueryCliFunction CreateFromMethodInfo (MethodInfo [] methods)
69 return CreateFromMethodInfo (null, methods);
72 internal static XQueryCliFunction CreateFromMethodInfo (XmlQualifiedName name, MethodInfo [] methodList)
74 if (methodList == null || methodList.Length == 0)
75 throw new ArgumentException (String.Format ("Argument methods is missing or zero-length array. Name is {0}", name));
77 Type cliReturnType = null;
78 ArrayList arguments = new ArrayList ();
80 if (name == null || name == XmlQualifiedName.Empty)
81 name = new XmlQualifiedName (methodList [0].Name, methodList [0].DeclaringType.FullName);
83 int maxArgs = 0;
84 int minArgs = -1;
85 Hashtable methods = new Hashtable ();
87 foreach (MethodInfo mi in methodList) {
88 if (cliReturnType == null)
89 cliReturnType = mi.ReturnType;
90 else if (mi.ReturnType != cliReturnType)
91 throw new ArgumentException (String.Format ("Every XQuery functions which share the same name must have the same return type. Method name is {0}.", mi.Name));
92 ParameterInfo [] prms = mi.GetParameters ();
94 int args = prms.Length;
96 // Whether it takes "current context" or not.
97 Type t = args > 0 ? prms [0].ParameterType : null;
98 bool ctxSeq = mi.GetCustomAttributes (typeof (XQueryFunctionContextAttribute), false).Length > 0;
99 bool hasContextArg = ctxSeq || t == typeof (XQueryContext);
100 if (ctxSeq || hasContextArg)
101 args--;
102 if (methods [args] != null)
103 throw new ArgumentException (String.Format ("XQuery does not allow functions that accepts such methods that have the same number of parameters in different types. Method name is {0}", mi.Name));
104 methods.Add ((int) args, mi);
105 if (args < minArgs || minArgs < 0)
106 minArgs = args;
107 if (args > maxArgs)
108 maxArgs = args;
111 MethodInfo m = (MethodInfo) methods [(int) maxArgs];
112 if (m == null)
113 throw new SystemException ("Should not happen: maxArgs is " + maxArgs);
114 ParameterInfo [] pl = m.GetParameters ();
115 for (int i = 0; i < pl.Length; i++) {
116 Type t = pl [i].ParameterType;
117 if (t != typeof (XQueryContext))
118 arguments.Add (
119 new XQueryFunctionArgument (new XmlQualifiedName (pl [i].Name), SequenceType.Create (pl [i].ParameterType)));
122 return new XQueryCliFunction (name,
123 arguments.ToArray (typeof (XQueryFunctionArgument)) as XQueryFunctionArgument [],
124 SequenceType.Create (cliReturnType),
125 methods,
126 minArgs,
127 maxArgs);
130 private XQueryCliFunction (XmlQualifiedName name,
131 XQueryFunctionArgument [] args,
132 SequenceType returnType,
133 Hashtable methods,
134 int minArgs,
135 int maxArgs)
136 : base (name, args, returnType)
138 this.methods = methods;
139 this.maxArgs = maxArgs;
140 this.minArgs = minArgs;
143 // instance members
145 // [int argsize] -> MethodInfo (according to the spec 1.1,
146 // there should be no overloads that accepts the same parameter
147 // count in different types).
148 Hashtable methods = new Hashtable ();
149 int maxArgs = 0;
150 int minArgs = -1;
151 SequenceType returnType;
153 public override int MinArgs {
154 get { return minArgs; }
157 public override int MaxArgs {
158 get { return maxArgs; }
161 public override object Invoke (XPathSequence current, object [] args)
163 MethodInfo mi = methods [args.Length] as MethodInfo;
164 if (mi == null)
165 throw new ArgumentException ("The number of custom function parameter does not match with the registered method's signature.");
166 ParameterInfo [] prms = mi.GetParameters ();
168 // Use Evidence and PermissionSet.Demand() here
169 // before invoking external function.
170 Evidence e = current.Context.StaticContext.Evidence;
171 if (e != null)
172 SecurityManager.ResolvePolicy (e).Demand ();
174 Type t = prms.Length > 0 ? prms [0].ParameterType : null;
175 bool ctxSeq = mi.GetCustomAttributes (
176 typeof (XQueryFunctionContextAttribute),
177 false).Length > 0;
178 if (t == typeof (XQueryContext)) {
179 ArrayList pl = new ArrayList (args);
180 pl.Insert (0, current.Context);
181 args = pl.ToArray ();
183 else if (ctxSeq) {
184 ArrayList pl = new ArrayList (args);
185 pl.Insert (0, current);
186 args = pl.ToArray ();
189 if (args.Length != prms.Length)
190 throw new XmlQueryException (String.Format ("Argument numbers were different for function {0}. Signature requires {1} while actual call was {2}.", mi.Name, prms.Length, args.Length));
192 // If native parameter type is XPathSequence and the actual values are not, adjust them
193 for (int i = 0; i < args.Length; i++) {
194 if (prms [i].ParameterType == typeof (XPathSequence) && !(args [i] is XPathSequence)) {
195 XPathItem item = args [i] as XPathItem;
196 if (item == null)
197 item = args [i] == null ? null : new XPathAtomicValue (args [i], InternalPool.GetBuiltInType (InternalPool.XmlTypeCodeFromRuntimeType (prms [i].ParameterType, true)));
198 if (item == null)
199 args [i] = new XPathEmptySequence (current.Context);
200 else
201 args [i] = new SingleItemIterator (item, current.Context);
205 return mi.Invoke (null, args);
210 #endif