Added generalized installation capabilities to Windsor (analogous to Kernel registration)
[castle.git] / Tools / DynamicProxy / Castle.DynamicProxy / Builder / CodeGenerators / ClassProxyGenerator.cs
blobb314606c9d0730d620a78d1e81db8ef7a67d8408
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.DynamicProxy.Builder.CodeGenerators
17 using System;
18 using System.Text;
19 using System.Reflection;
20 using System.Runtime.Serialization;
21 using System.Collections;
22 using System.Collections.Specialized;
23 using System.Threading;
25 using Castle.DynamicProxy.Builder.CodeBuilder;
26 using Castle.DynamicProxy.Builder.CodeBuilder.SimpleAST;
27 using Castle.DynamicProxy.Builder.CodeBuilder.Utils;
29 /// <summary>
30 /// Summary description for ClassProxyGenerator.
31 /// </summary>
32 [CLSCompliant(false)]
33 public class ClassProxyGenerator : BaseCodeGenerator
35 private bool _delegateToBaseGetObjectData;
37 protected ConstructorInfo _serializationConstructor;
39 public ClassProxyGenerator(ModuleScope scope) : base(scope)
43 public ClassProxyGenerator(ModuleScope scope, GeneratorContext context) : base(scope, context)
47 protected override Type InvocationType
49 get { return Context.SameClassInvocation; }
52 protected override String GenerateTypeName(Type type, Type[] interfaces)
54 StringBuilder sb = new StringBuilder();
55 foreach (Type inter in interfaces)
57 sb.Append('_');
58 sb.Append(GetTypeName(inter));
60 return String.Format("CProxyType{0}{3}{1}{2}", GetTypeName(type), sb.ToString(), interfaces.Length, NormalizeNamespaceName(type.Namespace));
63 /// <summary>
64 /// Generates one public constructor receiving
65 /// the <see cref="IInterceptor"/> instance and instantiating a hashtable
66 /// </summary>
67 protected virtual EasyConstructor GenerateConstructor( ConstructorInfo baseConstructor )
69 ArrayList arguments = new ArrayList();
71 ArgumentReference arg1 = new ArgumentReference( Context.Interceptor );
72 ArgumentReference arg2 = new ArgumentReference( typeof(object[]) );
74 arguments.Add( arg1 );
76 ParameterInfo[] parameters = baseConstructor.GetParameters();
78 if (Context.HasMixins)
80 arguments.Add( arg2 );
83 ArgumentReference[] originalArguments =
84 ArgumentsUtil.ConvertToArgumentReference(parameters);
86 arguments.AddRange(originalArguments);
88 EasyConstructor constructor = MainTypeBuilder.CreateConstructor(
89 (ArgumentReference[]) arguments.ToArray( typeof(ArgumentReference) ) );
91 GenerateConstructorCode(constructor.CodeBuilder, arg1, SelfReference.Self, arg2);
93 constructor.CodeBuilder.InvokeBaseConstructor( baseConstructor, originalArguments );
95 constructor.CodeBuilder.AddStatement( new ReturnStatement() );
97 return constructor;
100 protected void GenerateSerializationConstructor()
102 ArgumentReference arg1 = new ArgumentReference( typeof(SerializationInfo) );
103 ArgumentReference arg2 = new ArgumentReference( typeof(StreamingContext) );
105 EasyConstructor constr = MainTypeBuilder.CreateConstructor( arg1, arg2 );
107 constr.CodeBuilder.AddStatement( new ExpressionStatement(
108 new ConstructorInvocationExpression( _serializationConstructor,
109 arg1.ToExpression(), arg2.ToExpression() )) );
111 Type[] object_arg = new Type[] { typeof (String), typeof(Type) };
112 MethodInfo getValueMethod = typeof (SerializationInfo).GetMethod("GetValue", object_arg);
114 VirtualMethodInvocationExpression getInterceptorInvocation =
115 new VirtualMethodInvocationExpression(arg1, getValueMethod,
116 new FixedReference("__interceptor").ToExpression(),
117 new TypeTokenExpression( Context.Interceptor ) );
119 VirtualMethodInvocationExpression getMixinsInvocation =
120 new VirtualMethodInvocationExpression(arg1, getValueMethod,
121 new FixedReference("__mixins").ToExpression(),
122 new TypeTokenExpression( typeof(object[]) ) );
124 constr.CodeBuilder.AddStatement( new AssignStatement(
125 InterceptorField, getInterceptorInvocation) );
127 constr.CodeBuilder.AddStatement( new AssignStatement(
128 CacheField, new NewInstanceExpression(
129 typeof(HybridDictionary).GetConstructor( new Type[0] )) ) );
131 constr.CodeBuilder.AddStatement( new AssignStatement(
132 MixinField,
133 getMixinsInvocation) );
135 // Initialize the delegate fields
136 foreach(CallableField field in _cachedFields)
138 field.WriteInitialization(constr.CodeBuilder, SelfReference.Self, MixinField);
141 constr.CodeBuilder.AddStatement( new ReturnStatement() );
144 protected override void CustomizeGetObjectData(AbstractCodeBuilder codebuilder,
145 ArgumentReference arg1, ArgumentReference arg2)
147 Type[] key_and_object = new Type[] {typeof (String), typeof (Object)};
148 Type[] key_and_bool = new Type[] {typeof (String), typeof (bool)};
149 MethodInfo addValueMethod = typeof (SerializationInfo).GetMethod("AddValue", key_and_object);
150 MethodInfo addValueBoolMethod = typeof (SerializationInfo).GetMethod("AddValue", key_and_bool);
152 codebuilder.AddStatement( new ExpressionStatement(
153 new VirtualMethodInvocationExpression(arg1, addValueBoolMethod,
154 new FixedReference("__delegateToBase").ToExpression(),
155 new FixedReference( _delegateToBaseGetObjectData ? 1 : 0 ).ToExpression() ) ) );
157 if (_delegateToBaseGetObjectData)
159 MethodInfo baseGetObjectData = _baseType.GetMethod("GetObjectData",
160 new Type[] { typeof(SerializationInfo), typeof(StreamingContext) });
162 codebuilder.AddStatement( new ExpressionStatement(
163 new MethodInvocationExpression( baseGetObjectData,
164 arg1.ToExpression(), arg2.ToExpression() )) );
166 else
168 LocalReference members_ref = codebuilder.DeclareLocal( typeof(MemberInfo[]) );
169 LocalReference data_ref = codebuilder.DeclareLocal( typeof(object[]) );
171 MethodInfo getSerMembers = typeof(FormatterServices).GetMethod("GetSerializableMembers",
172 new Type[] { typeof(Type) });
173 MethodInfo getObjData = typeof(FormatterServices).GetMethod("GetObjectData",
174 new Type[] { typeof(object), typeof(MemberInfo[]) });
176 codebuilder.AddStatement( new AssignStatement( members_ref,
177 new MethodInvocationExpression( null, getSerMembers,
178 new TypeTokenExpression( _baseType ) )) );
180 codebuilder.AddStatement( new AssignStatement( data_ref,
181 new MethodInvocationExpression( null, getObjData,
182 SelfReference.Self.ToExpression(), members_ref.ToExpression() )) );
184 codebuilder.AddStatement( new ExpressionStatement(
185 new VirtualMethodInvocationExpression(arg1, addValueMethod,
186 new FixedReference("__data").ToExpression(),
187 data_ref.ToExpression() ) ) );
191 public virtual Type GenerateCode(Type baseClass)
193 return GenerateCode(baseClass, new Type[0]);
196 public virtual Type GenerateCode(Type baseClass, Type[] interfaces)
198 if (baseClass.IsSerializable)
200 _delegateToBaseGetObjectData = VerifyIfBaseImplementsGetObjectData(baseClass);
201 interfaces = AddISerializable( interfaces );
204 ReaderWriterLock rwlock = ModuleScope.RWLock;
206 rwlock.AcquireReaderLock(-1);
208 Type cacheType = GetFromCache(baseClass, interfaces);
210 if (cacheType != null)
212 rwlock.ReleaseReaderLock();
214 return cacheType;
217 rwlock.UpgradeToWriterLock(-1);
221 cacheType = GetFromCache(baseClass, interfaces);
223 if (cacheType != null)
225 return cacheType;
228 CreateTypeBuilder( GenerateTypeName(baseClass, interfaces), baseClass, interfaces );
229 GenerateFields();
231 if (baseClass.IsSerializable)
233 ImplementGetObjectData( interfaces );
236 ImplementCacheInvocationCache();
237 GenerateTypeImplementation( baseClass, true );
238 GenerateInterfaceImplementation(interfaces);
239 GenerateConstructors(baseClass);
241 if (_delegateToBaseGetObjectData)
243 GenerateSerializationConstructor();
246 return CreateType();
248 finally
250 rwlock.ReleaseWriterLock();
254 public virtual Type GenerateCustomCode(Type baseClass, Type[] interfaces)
256 if (!Context.HasMixins)
258 return GenerateCode(baseClass);
261 _mixins = Context.MixinsAsArray();
262 Type[] mixinInterfaces = InspectAndRegisterInterfaces( _mixins );
263 interfaces = Join(interfaces, mixinInterfaces);
265 return GenerateCode(baseClass, mixinInterfaces);
268 protected virtual void GenerateConstructors(Type baseClass)
270 ConstructorInfo[] constructors =
271 baseClass.GetConstructors( BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic );
273 foreach(ConstructorInfo constructor in constructors)
275 if (constructor.IsPrivate)
277 continue;
279 if (constructor.IsAssembly && !IsInternalToDynamicProxy(baseClass.Assembly))
281 continue;
283 GenerateConstructor(constructor);
287 protected bool VerifyIfBaseImplementsGetObjectData(Type baseType)
289 // If base type implements ISerializable, we have to make sure
290 // the GetObjectData is marked as virtual
292 if (typeof(ISerializable).IsAssignableFrom(baseType))
294 MethodInfo getObjectDataMethod = baseType.GetMethod("GetObjectData",
295 new Type[] { typeof(SerializationInfo), typeof(StreamingContext) });
297 if (getObjectDataMethod==null)//explicit interface implementation
299 return false;
302 if (!getObjectDataMethod.IsVirtual || getObjectDataMethod.IsFinal)
304 String message = String.Format("The type {0} implements ISerializable, but GetObjectData is not marked as virtual",
305 baseType.FullName);
306 throw new ProxyGenerationException(message);
309 Context.AddMethodToSkip(getObjectDataMethod);
311 _serializationConstructor = baseType.GetConstructor(
312 BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic,
313 null,
314 new Type[] { typeof(SerializationInfo), typeof(StreamingContext) },
315 null);
317 if (_serializationConstructor == null)
319 String message = String.Format("The type {0} implements ISerializable, but failed to provide a deserialization constructor",
320 baseType.FullName);
321 throw new ProxyGenerationException(message);
324 return true;
326 return false;
329 protected void SkipDefaultInterfaceImplementation(Type[] interfaces)
331 foreach( Type inter in interfaces )
333 Context.AddInterfaceToSkip(inter);
337 protected Type[] Join(Type[] interfaces, Type[] mixinInterfaces)
339 if (interfaces == null) interfaces = new Type[0];
340 if (mixinInterfaces == null) mixinInterfaces = new Type[0];
341 Type[] union = new Type[ interfaces.Length + mixinInterfaces.Length ];
342 Array.Copy( interfaces, 0, union, 0, interfaces.Length );
343 Array.Copy( mixinInterfaces, 0, union, interfaces.Length, mixinInterfaces.Length );
344 return union;