1 // Copyright 2004-2007 Castle Project - http://www.castleproject.org/
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
7 // http://www.apache.org/licenses/LICENSE-2.0
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
18 using System
.Collections
;
19 using System
.Configuration
;
20 using System
.Reflection
;
23 using Castle
.Core
.Configuration
;
25 using Castle
.MicroKernel
.SubSystems
.Conversion
;
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
34 /// Implementors should override the <see cref="ObtainNodeName"/> return
35 /// the name of the node to be inspected. For example:
39 /// <method name="Save" transaction="requires" />
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
)
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)
126 // foreach(MethodInfo method in methods)
128 // if (signature != null && signature.Length != 0)
130 // model.MethodMetaModels.MethodInfo2Model[method] = metaModel;
134 // if (!model.MethodMetaModels.MethodInfo2Model.Contains(method))
136 // model.MethodMetaModels.MethodInfo2Model[method] = metaModel;
142 private void AssertNameIsNotNull(string name
, ComponentModel model
)
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)
178 return (MethodInfo
[]) methods
.ToArray( typeof(MethodInfo
) );
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
) ) );
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
) );