svn commit: rev 43496 - in avalon/trunk/central/laboratory/avalon-net/DynamicProxy: . Builder Builder/CodeGenerators DynamicProxyTest

[email protected] 8 Sep 2004 04:04:05 -0000
Newsgroups gmane.comp.jakarta.avalon.cvs
Message-ID <[email protected]>
Author: hammett
Date: Tue Sep  7 21:04:03 2004
New Revision: 43496

Added:
   avalon/trunk/central/laboratory/avalon-net/DynamicProxy/DynamicProxyTest/CustomProxyGeneratorTestCase.cs   (contents, props changed)
Modified:
   avalon/trunk/central/laboratory/avalon-net/DynamicProxy/Builder/CodeGenerators/BaseCodeGenerator.cs
   avalon/trunk/central/laboratory/avalon-net/DynamicProxy/Builder/CodeGenerators/ClassProxyGenerator.cs
   avalon/trunk/central/laboratory/avalon-net/DynamicProxy/Builder/CodeGenerators/InterfaceProxyGenerator.cs
   avalon/trunk/central/laboratory/avalon-net/DynamicProxy/Builder/IProxyBuilder.cs
   avalon/trunk/central/laboratory/avalon-net/DynamicProxy/Builder/ProxyBuilderImpl.cs
   avalon/trunk/central/laboratory/avalon-net/DynamicProxy/DynamicProxyTest/Apache.Avalon.DynamicProxy.Test.csproj
   avalon/trunk/central/laboratory/avalon-net/DynamicProxy/ProxyGenerator.cs
Log:
Dynamic Proxy now supports customization during the proxy code generation.

Modified: avalon/trunk/central/laboratory/avalon-net/DynamicProxy/Builder/CodeGenerators/BaseCodeGenerator.cs
==============================================================================
--- avalon/trunk/central/laboratory/avalon-net/DynamicProxy/Builder/CodeGenerators/BaseCodeGenerator.cs	(original)
+++ avalon/trunk/central/laboratory/avalon-net/DynamicProxy/Builder/CodeGenerators/BaseCodeGenerator.cs	Tue Sep  7 21:04:03 2004
@@ -26,8 +26,33 @@
 	{
 		private TypeBuilder m_typeBuilder;
 		private FieldBuilder m_handlerField;
+		private ConstructorBuilder m_constBuilder;
 		private IList m_generated = new ArrayList();
 
+		private EnhanceTypeDelegate m_enhanceDelegate;
+		private ScreenInterfacesDelegate m_screenInterfacesDelegate;
+
+		protected BaseCodeGenerator()
+		{
+		}
+
+		protected BaseCodeGenerator(EnhanceTypeDelegate enhance, 
+			ScreenInterfacesDelegate screenInterfaces)
+		{
+			m_enhanceDelegate = enhance;
+			m_screenInterfacesDelegate = screenInterfaces;
+		}
+
+		protected EnhanceTypeDelegate EnhanceTypeDelegate
+		{
+			get { return m_enhanceDelegate; }
+		}
+
+		protected ScreenInterfacesDelegate ScreenInterfacesDelegate
+		{
+			get { return m_screenInterfacesDelegate; }
+		}
+
 		protected TypeBuilder MainTypeBuilder
 		{
 			get { return m_typeBuilder; }
@@ -38,6 +63,11 @@
 			get { return m_handlerField; }
 		}
 
+		protected ConstructorBuilder DefaultConstructorBuilder
+		{
+			get { return m_constBuilder; }
+		}
+
 		protected virtual ModuleBuilder CreateDynamicModule()
 		{
 			AssemblyName assemblyName = new AssemblyName();
@@ -59,7 +89,7 @@
 				"ProxyType", TypeAttributes.Public | TypeAttributes.Class, baseType, interfaces);
 
 			m_handlerField = GenerateField();
-			ConstructorBuilder constr = GenerateConstructor();
+			m_constBuilder = GenerateConstructor();
 
 			return m_typeBuilder;
 		}
@@ -129,6 +159,7 @@
 			if (!ignoreInterfaces)
 			{
 				Type[] baseInterfaces = type.FindInterfaces(new TypeFilter(NoFilterImpl), type);
+
 				GenerateInterfaceImplementation(baseInterfaces);
 			}
 

Modified: avalon/trunk/central/laboratory/avalon-net/DynamicProxy/Builder/CodeGenerators/ClassProxyGenerator.cs
==============================================================================
--- avalon/trunk/central/laboratory/avalon-net/DynamicProxy/Builder/CodeGenerators/ClassProxyGenerator.cs	(original)
+++ avalon/trunk/central/laboratory/avalon-net/DynamicProxy/Builder/CodeGenerators/ClassProxyGenerator.cs	Tue Sep  7 21:04:03 2004
@@ -21,12 +21,31 @@
 	/// </summary>
 	public class ClassProxyGenerator : BaseCodeGenerator
 	{
+		public ClassProxyGenerator() : base()
+		{
+		}
+
+		public ClassProxyGenerator(EnhanceTypeDelegate enhance, ScreenInterfacesDelegate screenInterfaces) : 
+			base(enhance, screenInterfaces)
+		{
+		}
+
 		public Type GenerateCode(Type baseClass)
 		{
-			// TODO: interfaces of base class
-			
-			CreateTypeBuilder( baseClass, new Type[0] );
+			Type[] interfaces = new Type[0];
+
+			if (ScreenInterfacesDelegate != null)
+			{
+				interfaces = ScreenInterfacesDelegate(interfaces);
+			}
+
+			CreateTypeBuilder( baseClass, interfaces );
 			GenerateTypeImplementation( baseClass, true );
+
+			if (EnhanceTypeDelegate != null)
+			{
+				EnhanceTypeDelegate(MainTypeBuilder, HandlerFieldBuilder, DefaultConstructorBuilder);
+			}
 
 			return MainTypeBuilder.CreateType();
 		}

Modified: avalon/trunk/central/laboratory/avalon-net/DynamicProxy/Builder/CodeGenerators/InterfaceProxyGenerator.cs
==============================================================================
--- avalon/trunk/central/laboratory/avalon-net/DynamicProxy/Builder/CodeGenerators/InterfaceProxyGenerator.cs	(original)
+++ avalon/trunk/central/laboratory/avalon-net/DynamicProxy/Builder/CodeGenerators/InterfaceProxyGenerator.cs	Tue Sep  7 21:04:03 2004
@@ -23,14 +23,31 @@
 	/// </summary>
 	public class InterfaceProxyGenerator : BaseCodeGenerator
 	{
-		public InterfaceProxyGenerator()
+		public InterfaceProxyGenerator() : base()
 		{
 		}
 
+		public InterfaceProxyGenerator(EnhanceTypeDelegate enhance, ScreenInterfacesDelegate screenInterfaces) : 
+			base(enhance, screenInterfaces)
+		{
+
+		}
+
 		public Type GenerateCode(Type[] interfaces)
 		{
+			if (ScreenInterfacesDelegate != null)
+			{
+				interfaces = ScreenInterfacesDelegate(interfaces);
+			}
+
 			CreateTypeBuilder( null, interfaces );
 			GenerateInterfaceImplementation( interfaces );
+
+			if (EnhanceTypeDelegate != null)
+			{
+				EnhanceTypeDelegate(MainTypeBuilder, HandlerFieldBuilder, DefaultConstructorBuilder);
+			}
+
 			return MainTypeBuilder.CreateType();
 		}
 	}

Modified: avalon/trunk/central/laboratory/avalon-net/DynamicProxy/Builder/IProxyBuilder.cs
==============================================================================
--- avalon/trunk/central/laboratory/avalon-net/DynamicProxy/Builder/IProxyBuilder.cs	(original)
+++ avalon/trunk/central/laboratory/avalon-net/DynamicProxy/Builder/IProxyBuilder.cs	Tue Sep  7 21:04:03 2004
@@ -23,6 +23,12 @@
 	{
 		Type CreateInterfaceProxy( Type[] interfaces );
 
+		Type CreateCustomInterfaceProxy( Type[] interfaces, EnhanceTypeDelegate enhance, 
+			ScreenInterfacesDelegate screenInterfaces );
+
 		Type CreateClassProxy( Type theClass );
+
+		Type CreateCustomClassProxy( Type theClass, EnhanceTypeDelegate enhance, 
+			ScreenInterfacesDelegate screenInterfaces );
 	}
 }

Modified: avalon/trunk/central/laboratory/avalon-net/DynamicProxy/Builder/ProxyBuilderImpl.cs
==============================================================================
--- avalon/trunk/central/laboratory/avalon-net/DynamicProxy/Builder/ProxyBuilderImpl.cs	(original)
+++ avalon/trunk/central/laboratory/avalon-net/DynamicProxy/Builder/ProxyBuilderImpl.cs	Tue Sep  7 21:04:03 2004
@@ -36,6 +36,20 @@
 			return generator.GenerateCode( theClass );
 		}
 
+		public Type CreateCustomInterfaceProxy(Type[] interfaces, EnhanceTypeDelegate enhance, 
+			ScreenInterfacesDelegate screenInterfaces)
+		{
+			InterfaceProxyGenerator generator = new InterfaceProxyGenerator(enhance, screenInterfaces);
+			return generator.GenerateCode( interfaces );
+		}
+
+		public Type CreateCustomClassProxy(Type theClass, EnhanceTypeDelegate enhance, 
+			ScreenInterfacesDelegate screenInterfaces)
+		{
+			ClassProxyGenerator generator = new ClassProxyGenerator(enhance, screenInterfaces);
+			return generator.GenerateCode( theClass );
+		}
+
 		#endregion
 	}
 }

Modified: avalon/trunk/central/laboratory/avalon-net/DynamicProxy/DynamicProxyTest/Apache.Avalon.DynamicProxy.Test.csproj
==============================================================================
--- avalon/trunk/central/laboratory/avalon-net/DynamicProxy/DynamicProxyTest/Apache.Avalon.DynamicProxy.Test.csproj	(original)
+++ avalon/trunk/central/laboratory/avalon-net/DynamicProxy/DynamicProxyTest/Apache.Avalon.DynamicProxy.Test.csproj	Tue Sep  7 21:04:03 2004
@@ -99,6 +99,11 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "CustomProxyGeneratorTestCase.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "ProxyGeneratorTestCase.cs"
                     SubType = "Code"
                     BuildAction = "Compile"

Added: avalon/trunk/central/laboratory/avalon-net/DynamicProxy/DynamicProxyTest/CustomProxyGeneratorTestCase.cs
==============================================================================
--- (empty file)
+++ avalon/trunk/central/laboratory/avalon-net/DynamicProxy/DynamicProxyTest/CustomProxyGeneratorTestCase.cs	Tue Sep  7 21:04:03 2004
@@ -0,0 +1,107 @@
+using Apache.Avalon.DynamicProxy.Test.Classes;
+// Copyright 2004 The Apache Software Foundation
+// 
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// 
+//     http://www.apache.org/licenses/LICENSE-2.0
+// 
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+namespace Apache.Avalon.DynamicProxy.Test
+{
+	using System;
+	using System.Reflection.Emit;
+
+	using NUnit.Framework;
+
+	using Apache.Avalon.DynamicProxy.Test.ClassInterfaces;
+
+	/// <summary>
+	/// Summary description for CustomProxyGeneratorTestCase.
+	/// </summary>
+	[TestFixture]
+	public class CustomProxyGeneratorTestCase : Assertion
+	{
+		private bool m_enhanceInvoked;
+		private bool m_screenInvoked;
+		private bool m_constructorInvoked;
+
+		[SetUp]
+		public void Init()
+		{
+			m_enhanceInvoked = false;
+			m_screenInvoked = false;
+			m_constructorInvoked = false;
+		}
+
+		[Test]
+		public void CreateCustomProxy()
+		{
+			object proxy = ProxyGenerator.CreateCustomProxy(
+				typeof (IMyInterface), 
+				new StandardInvocationHandler(new MyInterfaceImpl()),
+				new EnhanceTypeDelegate(EnhanceType), 
+				new ScreenInterfacesDelegate(ScreenInterfaces), 
+				new ConstructorArgumentsDelegate(BuildConstructorArguments));
+
+			Assert( m_enhanceInvoked );
+			Assert( m_screenInvoked );
+			Assert( m_constructorInvoked );
+		}
+
+		[Test]
+		public void CreateCustomClassProxy()
+		{
+			object proxy = ProxyGenerator.CreateCustomClassProxy(
+				typeof (ServiceClass), 
+				new StandardInvocationHandler(new ServiceClass()),
+				new EnhanceTypeDelegate(EnhanceType), 
+				new ScreenInterfacesDelegate(ScreenInterfaces), 
+				new ConstructorArgumentsDelegate(BuildConstructorArguments));
+
+			Assert( m_enhanceInvoked );
+			Assert( m_screenInvoked );
+			Assert( m_constructorInvoked );
+		}
+
+		private void EnhanceType(TypeBuilder mainType, FieldBuilder handlerFieldBuilder, ConstructorBuilder constructorBuilder)
+		{
+			Assert( !m_enhanceInvoked );
+
+			AssertNotNull(mainType);
+			AssertNotNull(handlerFieldBuilder);
+			AssertNotNull(constructorBuilder);
+
+			m_enhanceInvoked = true;
+		}
+
+		private Type[] ScreenInterfaces(Type[] interfaces)
+		{
+			Assert( !m_screenInvoked );
+
+			AssertNotNull(interfaces);
+
+			m_screenInvoked = true;
+
+			return interfaces;
+		}
+		
+		private object[] BuildConstructorArguments(Type generatedType, IInvocationHandler handler)
+		{
+			Assert( !m_constructorInvoked );
+
+			AssertNotNull( generatedType );
+			AssertNotNull( handler );
+
+			m_constructorInvoked = true;
+
+			return new object[] { handler };
+		}
+	}
+}
\ No newline at end of file

Modified: avalon/trunk/central/laboratory/avalon-net/DynamicProxy/ProxyGenerator.cs
==============================================================================
--- avalon/trunk/central/laboratory/avalon-net/DynamicProxy/ProxyGenerator.cs	(original)
+++ avalon/trunk/central/laboratory/avalon-net/DynamicProxy/ProxyGenerator.cs	Tue Sep  7 21:04:03 2004
@@ -1,4 +1,4 @@
- // Copyright 2004 The Apache Software Foundation
+// Copyright 2004 The Apache Software Foundation
 // 
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -15,11 +15,16 @@
 namespace Apache.Avalon.DynamicProxy
 {
 	using System;
-	using System.Reflection;
 	using System.Reflection.Emit;
 
 	using Apache.Avalon.DynamicProxy.Builder;
 
+	public delegate void EnhanceTypeDelegate( TypeBuilder mainType, FieldBuilder handlerFieldBuilder, ConstructorBuilder constructorBuilder );
+
+	public delegate Type[] ScreenInterfacesDelegate( Type[] interfaces );
+
+	public delegate object[] ConstructorArgumentsDelegate( Type generatedType, IInvocationHandler handler );
+
 	/// <summary>
 	/// Generates a Java style proxy. This overrides the .Net proxy requirements 
 	/// that forces one to extend MarshalByRefObject or (for a different purpose)
@@ -53,23 +58,23 @@
 
 		public static object CreateClassProxy(Type baseClass, IInvocationHandler handler)
 		{
-			if (baseClass == null)
-			{
-				throw new ArgumentNullException("theClass");
-			}
-			if (baseClass.IsInterface)
-			{
-				throw new ArgumentException("'baseClass' must be a class, not an interface");
-			}
-			if (handler == null)
-			{
-				throw new ArgumentNullException("handler");
-			}
+			AssertCreateClassProxyArguments(baseClass, handler);
 
 			Type newType = ProxyBuilder.CreateClassProxy(baseClass);
 			return CreateProxyInstance( newType, handler );
 		}
 
+		public static object CreateCustomClassProxy(Type baseClass, IInvocationHandler handler, 
+			EnhanceTypeDelegate enhance, 
+			ScreenInterfacesDelegate screenInterfaces, 
+			ConstructorArgumentsDelegate constructorArguments)
+		{
+			AssertCreateClassProxyArguments(baseClass, handler);
+
+			Type newType = ProxyBuilder.CreateCustomClassProxy(baseClass, enhance, screenInterfaces);
+			return CreateCustomProxyInstance( newType, handler, constructorArguments );
+		}
+
 		/// <summary>
 		/// Generates a proxy implementing all the specified interfaces and
 		/// redirecting method invocations to the specifed handler.
@@ -91,6 +96,69 @@
 		/// <returns>Proxy instance</returns>
 		public static object CreateProxy(Type[] interfaces, IInvocationHandler handler)
 		{
+			AssertCreateProxyArguments(interfaces, handler);
+
+			Type newType = ProxyBuilder.CreateInterfaceProxy(interfaces);
+			return CreateProxyInstance( newType, handler );
+		}
+
+		/// <summary>
+		/// 
+		/// </summary>
+		/// <param name="theInterface"></param>
+		/// <param name="handler"></param>
+		/// <param name="enhance"></param>
+		/// <param name="screenInterfaces"></param>
+		/// <param name="constructorArguments"></param>
+		/// <returns></returns>
+		public static object CreateCustomProxy(Type theInterface, 
+			IInvocationHandler handler, EnhanceTypeDelegate enhance, 
+			ScreenInterfacesDelegate screenInterfaces, 
+			ConstructorArgumentsDelegate constructorArguments )
+		{
+			return CreateCustomProxy( new Type[] { theInterface }, handler, 
+				enhance, screenInterfaces, constructorArguments );
+		}
+
+		/// <summary>
+		/// 
+		/// </summary>
+		/// <param name="interfaces"></param>
+		/// <param name="handler"></param>
+		/// <param name="enhance"></param>
+		/// <param name="screenInterfaces"></param>
+		/// <param name="constructorArguments"></param>
+		/// <returns></returns>
+		public static object CreateCustomProxy(Type[] interfaces, 
+			IInvocationHandler handler, EnhanceTypeDelegate enhance, 
+			ScreenInterfacesDelegate screenInterfaces, 
+			ConstructorArgumentsDelegate constructorArguments )
+		{
+			AssertCreateProxyArguments( interfaces, handler);
+			Type newType = ProxyBuilder.CreateCustomInterfaceProxy(interfaces, enhance, screenInterfaces);
+			return CreateCustomProxyInstance( newType, handler, constructorArguments );
+		}
+
+		private static object CreateProxyInstance(Type type, IInvocationHandler handler)
+		{
+			return Activator.CreateInstance(type, new object[] {handler});
+		}
+
+		private static object CreateCustomProxyInstance(Type type, IInvocationHandler handler, ConstructorArgumentsDelegate constructorArguments)
+		{
+			if (constructorArguments != null)
+			{
+				object[] arguments = constructorArguments( type, handler );
+				return Activator.CreateInstance(type, arguments);
+			}
+			else
+			{
+				return CreateProxyInstance( type, handler );
+			}
+		}
+
+		private static void AssertCreateProxyArguments(Type[] interfaces, IInvocationHandler handler)
+		{
 			if (interfaces == null)
 			{
 				throw new ArgumentNullException("interfaces");
@@ -103,14 +171,22 @@
 			{
 				throw new ArgumentException("Can't handle an empty interface array");
 			}
-
-			Type newType = ProxyBuilder.CreateInterfaceProxy(interfaces);
-			return CreateProxyInstance( newType, handler );
 		}
 
-		private static object CreateProxyInstance(Type type, IInvocationHandler handler)
+		private static void AssertCreateClassProxyArguments(Type baseClass, IInvocationHandler handler)
 		{
-			return Activator.CreateInstance(type, new object[] {handler});
+			if (baseClass == null)
+			{
+				throw new ArgumentNullException("theClass");
+			}
+			if (baseClass.IsInterface)
+			{
+				throw new ArgumentException("'baseClass' must be a class, not an interface");
+			}
+			if (handler == null)
+			{
+				throw new ArgumentNullException("handler");
+			}
 		}
 	}
 }