Added container accessor to Castle.Core
[castle.git] / InversionOfControl / Castle.MicroKernel / ModelBuilder / Inspectors / MethodMetaInspector.cs
blob878857db245b55c850513ed42e1b31e191b4f77b
1 // Copyright 2004-2007 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;
28 /// <summary>
29 /// Base for inspectors that want configuration associated with methods.
30 /// For each child a <see cref="MethodMetaModel"/> is created
31 /// and added to ComponentModel's methods collection
32 /// </summary>
33 /// <remarks>
34 /// Implementors should override the <see cref="ObtainNodeName"/> return
35 /// the name of the node to be inspected. For example:
36 /// <code>
37 /// <pre>
38 /// <transactions>
39 /// <method name="Save" transaction="requires" />
40 /// </transactions>
41 /// </pre>
42 /// </code>
43 /// </remarks>
44 public abstract class MethodMetaInspector : IContributeComponentModelConstruction
46 private static readonly BindingFlags AllMethods =
47 BindingFlags.Public|BindingFlags.NonPublic|
48 BindingFlags.Instance|BindingFlags.Static|
49 BindingFlags.IgnoreCase|BindingFlags.IgnoreReturn;
51 private ITypeConverter converter;
53 public virtual void ProcessModel(IKernel kernel, ComponentModel model)
55 if (model == null) throw new ArgumentNullException("model");
57 if (model.Configuration == null || model.Implementation == null) return;
59 IConfiguration methodsNode = model.Configuration.Children[ObtainNodeName()];
61 if (methodsNode == null) return;
63 EnsureHasReferenceToConverter(kernel);
65 foreach(IConfiguration methodNode in methodsNode.Children)
67 String name = methodNode.Name;
69 if ("method".Equals(name))
71 name = methodNode.Attributes["name"];
74 AssertNameIsNotNull(name, model);
76 MethodMetaModel metaModel = new MethodMetaModel(methodNode);
78 if (IsValidMeta(model, metaModel))
80 if (ShouldUseMetaModel)
82 // model.MethodMetaModels.Add( metaModel );
85 String signature = methodNode.Attributes["signature"];
87 MethodInfo[] methods = GetMethods(model.Implementation, name, signature);
89 if (methods.Length == 0)
91 String message = String.Format( "The class {0} has tried to expose configuration for " +
92 "a method named {1} which could not be found.", model.Implementation.FullName, name );
94 throw new ConfigurationErrorsException(message);
97 ProcessMeta(model, methods, metaModel);
99 if (ShouldUseMetaModel)
101 // RegisterMethodsForFastAccess(methods, signature, metaModel, model);
107 protected virtual void ProcessMeta(ComponentModel model, MethodInfo[] methods, MethodMetaModel metaModel)
111 protected virtual bool IsValidMeta(ComponentModel model, MethodMetaModel metaModel)
113 return true;
116 protected virtual bool ShouldUseMetaModel
118 get { return false; }
121 protected abstract String ObtainNodeName();
123 // private void RegisterMethodsForFastAccess(MethodInfo[] methods,
124 // String signature, MethodMetaModel metaModel, ComponentModel model)
125 // {
126 // foreach(MethodInfo method in methods)
127 // {
128 // if (signature != null && signature.Length != 0)
129 // {
130 // model.MethodMetaModels.MethodInfo2Model[method] = metaModel;
131 // }
132 // else
133 // {
134 // if (!model.MethodMetaModels.MethodInfo2Model.Contains(method))
135 // {
136 // model.MethodMetaModels.MethodInfo2Model[method] = metaModel;
137 // }
138 // }
139 // }
140 // }
142 private void AssertNameIsNotNull(string name, ComponentModel model)
144 if (name == null)
146 String message = String.Format("The configuration nodes within 'methods' " +
147 "for the component '{0}' does not have a name. You can either name " +
148 "the node as the method name or provide an attribute 'name'", model.Name);
150 throw new ConfigurationErrorsException(message);
154 private void EnsureHasReferenceToConverter(IKernel kernel)
156 if (converter != null) return;
158 converter = (ITypeConverter)
159 kernel.GetSubSystem( SubSystemConstants.ConversionManagerKey );
162 private MethodInfo[] GetMethods(Type implementation, String name, String signature)
164 if (signature == null || signature.Length == 0)
166 MethodInfo[] allmethods = implementation.GetMethods(AllMethods);
168 ArrayList methods = new ArrayList();
170 foreach(MethodInfo method in allmethods)
172 if (String.Compare(method.Name, name, true) == 0)
174 methods.Add(method);
178 return (MethodInfo[]) methods.ToArray( typeof(MethodInfo) );
180 else
182 MethodInfo methodInfo = implementation.GetMethod(name, AllMethods, null, ConvertSignature(signature), null );
184 if (methodInfo == null) return new MethodInfo[0];
186 return new MethodInfo[] { methodInfo };
190 private Type[] ConvertSignature(string signature)
192 String[] parameters = signature.Split(';');
194 ArrayList types = new ArrayList();
196 foreach(String param in parameters)
200 types.Add( converter.PerformConversion( param, typeof(Type) ) );
202 catch(Exception)
204 String message = String.Format("The signature {0} contains an entry type {1} " +
205 "that could not be converted to System.Type. Check the inner exception for " +
206 "details", signature, param);
208 throw new ConfigurationErrorsException(message);
212 return (Type[]) types.ToArray( typeof(Type) );