1 // Copyright 2004-2008 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
;
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
33 /// Implementors should override the <see cref="ObtainNodeName"/> return
34 /// the name of the node to be inspected. For example:
38 /// <method name="Save" transaction="requires" />
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
)
115 protected virtual bool ShouldUseMetaModel
117 get { return false; }
120 protected abstract String
ObtainNodeName();
122 private void AssertNameIsNotNull(string name
, ComponentModel model
)
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)
158 return (MethodInfo
[]) methods
.ToArray( typeof(MethodInfo
) );
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
) ) );
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
) );