2 // XQueryCliFunction.cs
5 // Atsushi Enomoto <atsushi@ximian.com>
8 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
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:
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
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.
35 using System
.Collections
;
36 using System
.Reflection
;
37 using System
.Security
;
38 using System
.Security
.Policy
;
40 using System
.Xml
.Schema
;
41 using System
.Xml
.Query
;
42 using System
.Xml
.XPath
;
46 namespace Mono
.Xml
.XPath2
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
);
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
)
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)
111 MethodInfo m
= (MethodInfo
) methods
[(int) maxArgs
];
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
))
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
),
130 private XQueryCliFunction (XmlQualifiedName name
,
131 XQueryFunctionArgument
[] args
,
132 SequenceType returnType
,
136 : base (name
, args
, returnType
)
138 this.methods
= methods
;
139 this.maxArgs
= maxArgs
;
140 this.minArgs
= minArgs
;
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 ();
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
;
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
;
172 SecurityManager
.ResolvePolicy (e
).Demand ();
174 Type t
= prms
.Length
> 0 ? prms
[0].ParameterType
: null;
175 bool ctxSeq
= mi
.GetCustomAttributes (
176 typeof (XQueryFunctionContextAttribute
),
178 if (t
== typeof (XQueryContext
)) {
179 ArrayList pl
= new ArrayList (args
);
180 pl
.Insert (0, current
.Context
);
181 args
= pl
.ToArray ();
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
;
197 item
= args
[i
] == null ? null : new XPathAtomicValue (args
[i
], InternalPool
.GetBuiltInType (InternalPool
.XmlTypeCodeFromRuntimeType (prms
[i
].ParameterType
, true)));
199 args
[i
] = new XPathEmptySequence (current
.Context
);
201 args
[i
] = new SingleItemIterator (item
, current
.Context
);
205 return mi
.Invoke (null, args
);