Fixing an issue with output parameters that are of type IntPtr
[castle.git] / InversionOfControl / Castle.MicroKernel / ModelBuilder / Inspectors / MethodMetaInspector.cs
blobca9910c22d4cb6924487fceaff8d07d5d8f8f6c6
1 // Copyright 2004-2008 Castle Project - http://www.castleproject.org/
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
15 namespace Castle.MicroKernel.ModelBuilder.Inspectors
17 using System;
18 using System.Collections;
19 using System.Configuration;
20 using System.Reflection;
22 using Castle.Core;
23 using Castle.Core.Configuration;
25 using Castle.MicroKernel.SubSystems.Conversion;
27 /// <summary>
28 /// Base for inspectors that want configuration associated with methods.
29 /// For each child a <see cref="MethodMetaModel"/> is created
30 /// and added to ComponentModel's methods collection
31 /// </summary>
32 /// <remarks>
33 /// Implementors should override the <see cref="ObtainNodeName"/> return
34 /// the name of the node to be inspected. For example:
35 /// <code>
36 /// <![CDATA[
37 /// <transactions>
38 /// <method name="Save" transaction="requires" />
39 /// </transactions>
40 /// ]]>
41 /// </code>
42 /// </remarks>
43 public abstract class MethodMetaInspector : IContributeComponentModelConstruction
45 private static readonly BindingFlags AllMethods =
46 BindingFlags.Public|BindingFlags.NonPublic|
47 BindingFlags.Instance|BindingFlags.Static|
48 BindingFlags.IgnoreCase|BindingFlags.IgnoreReturn;
50 private ITypeConverter converter;
52 public virtual void ProcessModel(IKernel kernel, ComponentModel model)
54 if (model == null) throw new ArgumentNullException("model");
56 if (model.Configuration == null || model.Implementation == null) return;
58 IConfiguration methodsNode = model.Configuration.Children[ObtainNodeName()];
60 if (methodsNode == null) return;
62 EnsureHasReferenceToConverter(kernel);
64 foreach(IConfiguration methodNode in methodsNode.Children)
66 String name = methodNode.Name;
68 if ("method".Equals(name))
70 name = methodNode.Attributes["name"];
73 AssertNameIsNotNull(name, model);
75 MethodMetaModel metaModel = new MethodMetaModel(methodNode);
77 if (IsValidMeta(model, metaModel))
79 if (ShouldUseMetaModel)
81 // model.MethodMetaModels.Add( metaModel );
84 String signature = methodNode.Attributes["signature"];
86 MethodInfo[] methods = GetMethods(model.Implementation, name, signature);
88 if (methods.Length == 0)
90 String message = String.Format( "The class {0} has tried to expose configuration for " +
91 "a method named {1} which could not be found.", model.Implementation.FullName, name );
93 throw new ConfigurationErrorsException(message);
96 ProcessMeta(model, methods, metaModel);
98 if (ShouldUseMetaModel)
100 // RegisterMethodsForFastAccess(methods, signature, metaModel, model);
106 protected virtual void ProcessMeta(ComponentModel model, MethodInfo[] methods, MethodMetaModel metaModel)
110 protected virtual bool IsValidMeta(ComponentModel model, MethodMetaModel metaModel)
112 return true;
115 protected virtual bool ShouldUseMetaModel
117 get { return false; }
120 protected abstract String ObtainNodeName();
122 private void AssertNameIsNotNull(string name, ComponentModel model)
124 if (name == null)
126 String message = String.Format("The configuration nodes within 'methods' " +
127 "for the component '{0}' does not have a name. You can either name " +
128 "the node as the method name or provide an attribute 'name'", model.Name);
130 throw new ConfigurationErrorsException(message);
134 private void EnsureHasReferenceToConverter(IKernel kernel)
136 if (converter != null) return;
138 converter = (ITypeConverter)
139 kernel.GetSubSystem( SubSystemConstants.ConversionManagerKey );
142 private MethodInfo[] GetMethods(Type implementation, String name, String signature)
144 if (signature == null || signature.Length == 0)
146 MethodInfo[] allmethods = implementation.GetMethods(AllMethods);
148 ArrayList methods = new ArrayList();
150 foreach(MethodInfo method in allmethods)
152 if (String.Compare(method.Name, name, true) == 0)
154 methods.Add(method);
158 return (MethodInfo[]) methods.ToArray( typeof(MethodInfo) );
160 else
162 MethodInfo methodInfo = implementation.GetMethod(name, AllMethods, null, ConvertSignature(signature), null );
164 if (methodInfo == null) return new MethodInfo[0];
166 return new MethodInfo[] { methodInfo };
170 private Type[] ConvertSignature(string signature)
172 String[] parameters = signature.Split(';');
174 ArrayList types = new ArrayList();
176 foreach(String param in parameters)
180 types.Add( converter.PerformConversion( param, typeof(Type) ) );
182 catch(Exception)
184 String message = String.Format("The signature {0} contains an entry type {1} " +
185 "that could not be converted to System.Type. Check the inner exception for " +
186 "details", signature, param);
188 throw new ConfigurationErrorsException(message);
192 return (Type[]) types.ToArray( typeof(Type) );