Commit d6d35f2

mokhan <mokhan@ce5e1baf-6525-42e4-a1b2-857ea38da20a>
2009-04-19 15:14:57
created real proxy implementation using just the .net framework.
git-svn-id: https://svn.xp-dev.com/svn/mokhan-mo.money@176 ce5e1baf-6525-42e4-a1b2-857ea38da20a
1 parent 312bdd9
trunk/product/Gorilla.Commons.Infrastructure/Proxies/ExceptionExtensions.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Reflection;
+
+namespace Gorilla.Commons.Infrastructure.Proxies
+{
+    static public class ExceptionExtensions
+    {
+        static readonly MethodInfo method =
+            typeof (Exception).GetMethod("InternalPreserveStackTrace",
+                                         BindingFlags.NonPublic | BindingFlags.Instance);
+
+        static public Exception preserve_stack_trace(this Exception exception)
+        {
+            method.Invoke(exception, new object[0]);
+            return exception;
+        }
+    }
+}
\ No newline at end of file
trunk/product/Gorilla.Commons.Infrastructure/Proxies/IInterceptor.cs
@@ -0,0 +1,7 @@
+namespace Gorilla.Commons.Infrastructure.Proxies
+{
+    public interface IInterceptor
+    {
+        void Intercept(IInvocation invocation);
+    }
+}
\ No newline at end of file
trunk/product/Gorilla.Commons.Infrastructure/Proxies/IInvocation.cs
@@ -0,0 +1,12 @@
+using System.Reflection;
+
+namespace Gorilla.Commons.Infrastructure.Proxies
+{
+    public interface IInvocation
+    {
+        void Proceed();
+        object[] Arguments { get; }
+        MethodInfo Method { get; }
+        object ReturnValue { get; set; }
+    }
+}
\ No newline at end of file
trunk/product/Gorilla.Commons.Infrastructure/Proxies/MethodCallInvocation.cs
@@ -0,0 +1,47 @@
+using System.Collections.Generic;
+using System.Reflection;
+using System.Runtime.Remoting.Messaging;
+using Gorilla.Commons.Utility.Extensions;
+
+namespace Gorilla.Commons.Infrastructure.Proxies
+{
+    public class MethodCallInvocation<T> : IInvocation
+    {
+        readonly IMethodCallMessage call;
+        readonly T target;
+        readonly Stack<IInterceptor> interceptors;
+
+        public MethodCallInvocation(IEnumerable<IInterceptor> interceptors, IMethodCallMessage call, T target)
+        {
+            this.call = call;
+            this.target = target;
+            this.interceptors = new Stack<IInterceptor>(interceptors);
+            Arguments = call.Properties["__Args"].downcast_to<object[]>();
+            Method = call.MethodBase.downcast_to<MethodInfo>();
+        }
+
+        public object[] Arguments { get; set; }
+
+        public MethodInfo Method { get; set; }
+
+        public object ReturnValue { get; set; }
+
+        public void Proceed()
+        {
+            if (interceptors.Count > 0)
+            {
+                interceptors.Pop().Intercept(this);
+                return;
+            }
+
+            try
+            {
+                ReturnValue = call.MethodBase.Invoke(target, Arguments);
+            }
+            catch (TargetInvocationException e)
+            {
+                throw e.InnerException.preserve_stack_trace();
+            }
+        }
+    }
+}
\ No newline at end of file
trunk/product/Gorilla.Commons.Infrastructure/Proxies/ProxyFactory.cs
@@ -0,0 +1,10 @@
+namespace Gorilla.Commons.Infrastructure.Proxies
+{
+    static public class ProxyFactory
+    {
+        static public T Create<T>(T target, params IInterceptor[] interceptors)
+        {
+            return new RemotingProxyFactory<T>(target, interceptors).CreateProxy();
+        }
+    }
+}
\ No newline at end of file
trunk/product/Gorilla.Commons.Infrastructure/Proxies/ProxyFactorySpecs.cs
@@ -0,0 +1,57 @@
+using developwithpassion.bdd.contexts;
+using Gorilla.Commons.Testing;
+
+namespace Gorilla.Commons.Infrastructure.Proxies
+{
+    public class ProxyFactorySpecs
+    {
+    }
+
+    public class when_proxying_a_class_with_interceptors_applied : concerns
+    {
+        context c = () =>
+                        {
+                            interceptors = new MyNameIsSlimShadyInterceptor();
+                            marshal_mathers = new Person("marshall mathers");
+                        };
+
+        because b =
+            () => { some_celebrity = ProxyFactory.Create<IPerson>(marshal_mathers, interceptors); };
+
+        it should_all_each_interceptor_to_intercept_the_invocation =
+            () => some_celebrity.what_is_your_name().should_be_equal_to("slim shady");
+
+        static Person marshal_mathers;
+        static IPerson some_celebrity;
+        static IInterceptor interceptors;
+    }
+
+    public interface IPerson
+    {
+        string what_is_your_name();
+    }
+
+    public class Person : IPerson
+    {
+        readonly string my_name;
+
+        public Person(string my_name)
+        {
+            this.my_name = my_name;
+        }
+
+        public string what_is_your_name()
+        {
+            return my_name;
+        }
+    }
+
+    public class MyNameIsSlimShadyInterceptor : IInterceptor
+    {
+        public void Intercept(IInvocation invocation)
+        {
+            invocation.Proceed();
+            invocation.ReturnValue = "slim shady";
+        }
+    }
+}
\ No newline at end of file
trunk/product/Gorilla.Commons.Infrastructure/Proxies/RemotingProxyFactory.cs
@@ -0,0 +1,49 @@
+using System.Collections.Generic;
+using System.Runtime.Remoting.Messaging;
+using System.Runtime.Remoting.Proxies;
+using Gorilla.Commons.Utility.Extensions;
+
+namespace Gorilla.Commons.Infrastructure.Proxies
+{
+    public interface IProxyFactory<T>
+    {
+        T CreateProxy();
+    }
+
+    public class RemotingProxyFactory<T> : RealProxy, IProxyFactory<T>
+    {
+        readonly T target;
+        readonly IEnumerable<IInterceptor> interceptors;
+
+        public RemotingProxyFactory(T target, IEnumerable<IInterceptor> interceptors) : base(typeof (T))
+        {
+            this.target = target;
+            this.interceptors = interceptors;
+        }
+
+        public override IMessage Invoke(IMessage message)
+        {
+            if (message.is_an_implementation_of<IMethodCallMessage>())
+            {
+                var call = message.downcast_to<IMethodCallMessage>();
+                var invocation = new MethodCallInvocation<T>(interceptors, call, target);
+                invocation.Proceed();
+                return ReturnValue(invocation.ReturnValue, invocation.Arguments, call);
+            }
+            return null;
+        }
+
+        IMessage ReturnValue(object return_value, object[] out_parameters, IMethodCallMessage call)
+        {
+            return new ReturnMessage(return_value,
+                                     out_parameters,
+                                     out_parameters == null ? 0 : out_parameters.Length,
+                                     call.LogicalCallContext, call);
+        }
+
+        public T CreateProxy()
+        {
+            return GetTransparentProxy().downcast_to<T>();
+        }
+    }
+}
\ No newline at end of file
trunk/product/Gorilla.Commons.Infrastructure/Gorilla.Commons.Infrastructure.csproj
@@ -84,6 +84,13 @@
     <Compile Include="Logging\Log.cs" />
     <Compile Include="Logging\LoggingExtensions.cs" />
     <Compile Include="Logging\LogSpecs.cs" />
+    <Compile Include="Proxies\ExceptionExtensions.cs" />
+    <Compile Include="Proxies\IInterceptor.cs" />
+    <Compile Include="Proxies\IInvocation.cs" />
+    <Compile Include="Proxies\MethodCallInvocation.cs" />
+    <Compile Include="Proxies\ProxyFactory.cs" />
+    <Compile Include="Proxies\ProxyFactorySpecs.cs" />
+    <Compile Include="Proxies\RemotingProxyFactory.cs" />
     <Compile Include="Reflection\ApplicationAssembly.cs" />
     <Compile Include="Reflection\EnvironmentExtensions.cs" />
     <Compile Include="Reflection\IAssembly.cs" />
trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Proxies/Interceptors/IMethodCallTracker.cs → trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Castle/DynamicProxy/Interceptors/IMethodCallTracker.cs
File renamed without changes
trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Proxies/Interceptors/MethodCallTracker.cs → trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Castle/DynamicProxy/Interceptors/MethodCallTracker.cs
File renamed without changes
trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Proxies/Interceptors/MethodCallTrackerSpecs.cs → trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Castle/DynamicProxy/Interceptors/MethodCallTrackerSpecs.cs
File renamed without changes
trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Proxies/Interceptors/RunOnBackgroundThreadInterceptor.cs → trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Castle/DynamicProxy/Interceptors/RunOnBackgroundThreadInterceptor.cs
File renamed without changes
trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Proxies/Interceptors/RunOnBackgrounThreadInterceptorSpecs.cs → trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Castle/DynamicProxy/Interceptors/RunOnBackgrounThreadInterceptorSpecs.cs
File renamed without changes
trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Proxies/Interceptors/SelectiveInterceptor.cs → trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Castle/DynamicProxy/Interceptors/SelectiveInterceptor.cs
File renamed without changes
trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Proxies/IConstraintSelector.cs → trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Castle/DynamicProxy/IConstraintSelector.cs
File renamed without changes
trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Proxies/IInterceptorConstraint.cs → trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Castle/DynamicProxy/IInterceptorConstraint.cs
File renamed without changes
trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Proxies/IInterceptorConstraintFactory.cs → trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Castle/DynamicProxy/IInterceptorConstraintFactory.cs
File renamed without changes
trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Proxies/IMethodCallTrackerFactory.cs → trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Castle/DynamicProxy/IMethodCallTrackerFactory.cs
File renamed without changes
trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Proxies/InterceptorConstraintFactorySpecs.cs → trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Castle/DynamicProxy/InterceptorConstraintFactorySpecs.cs
File renamed without changes
trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Proxies/InterceptorConstraintSpecs.cs → trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Castle/DynamicProxy/InterceptorConstraintSpecs.cs
File renamed without changes
trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Proxies/IProxyBuilder.cs → trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Castle/DynamicProxy/IProxyBuilder.cs
File renamed without changes
trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Proxies/IProxyFactory.cs → trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Castle/DynamicProxy/IProxyFactory.cs
File renamed without changes
trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Proxies/Lazy.cs → trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Castle/DynamicProxy/Lazy.cs
File renamed without changes
trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Proxies/LazyLoadedInterceptor.cs → trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Castle/DynamicProxy/LazyLoadedInterceptor.cs
File renamed without changes
trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Proxies/LazySpecs.cs → trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Castle/DynamicProxy/LazySpecs.cs
File renamed without changes
trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Proxies/ProxyBuilder.cs → trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Castle/DynamicProxy/ProxyBuilder.cs
File renamed without changes
trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Proxies/ProxyBuilderSpecs.cs → trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Castle/DynamicProxy/ProxyBuilderSpecs.cs
File renamed without changes
trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Proxies/ProxyFactory.cs → trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Castle/DynamicProxy/ProxyFactory.cs
File renamed without changes
trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Proxies/ProxyFactorySpecs.cs → trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Castle/DynamicProxy/ProxyFactorySpecs.cs
File renamed without changes
trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Windsor/Configuration/ApplyLoggingInterceptor.cs → trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Castle/Windsor/Configuration/ApplyLoggingInterceptor.cs
File renamed without changes
trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Windsor/Configuration/ComponentRegistrationConfiguration.cs → trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Castle/Windsor/Configuration/ComponentRegistrationConfiguration.cs
File renamed without changes
trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Windsor/Configuration/ConfigureComponentLifestyle.cs → trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Castle/Windsor/Configuration/ConfigureComponentLifestyle.cs
File renamed without changes
trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Windsor/Configuration/IComponentExclusionSpecification.cs → trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Castle/Windsor/Configuration/IComponentExclusionSpecification.cs
File renamed without changes
trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Windsor/Configuration/LogComponent.cs → trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Castle/Windsor/Configuration/LogComponent.cs
File renamed without changes
trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Windsor/Configuration/LoggingInterceptor.cs → trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Castle/Windsor/Configuration/LoggingInterceptor.cs
File renamed without changes
trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Windsor/Configuration/RegisterComponentContract.cs → trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Castle/Windsor/Configuration/RegisterComponentContract.cs
File renamed without changes
trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Windsor/WindsorContainerFactory.cs → trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Castle/Windsor/WindsorContainerFactory.cs
File renamed without changes
trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Windsor/WindsorDependencyRegistry.cs → trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Castle/Windsor/WindsorDependencyRegistry.cs
File renamed without changes
trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Windsor/WindsorDependencyRegistrySpecs.cs → trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Castle/Windsor/WindsorDependencyRegistrySpecs.cs
File renamed without changes
trunk/product/Gorilla.Commons.Infrastructure.ThirdParty/Gorilla.Commons.Infrastructure.ThirdParty.csproj
@@ -95,37 +95,37 @@
     <Compile Include="IDependencyRegistration.cs" />
     <Compile Include="Log4Net\Log4NetLogFactory.cs" />
     <Compile Include="Log4Net\Log4NetLogger.cs" />
-    <Compile Include="Proxies\IConstraintSelector.cs" />
-    <Compile Include="Proxies\IInterceptorConstraint.cs" />
-    <Compile Include="Proxies\IInterceptorConstraintFactory.cs" />
-    <Compile Include="Proxies\IMethodCallTrackerFactory.cs" />
-    <Compile Include="Proxies\InterceptorConstraintFactorySpecs.cs" />
-    <Compile Include="Proxies\InterceptorConstraintSpecs.cs" />
-    <Compile Include="Proxies\Interceptors\IMethodCallTracker.cs" />
-    <Compile Include="Proxies\Interceptors\MethodCallTracker.cs" />
-    <Compile Include="Proxies\Interceptors\MethodCallTrackerSpecs.cs" />
-    <Compile Include="Proxies\Interceptors\RunOnBackgroundThreadInterceptor.cs" />
-    <Compile Include="Proxies\Interceptors\RunOnBackgrounThreadInterceptorSpecs.cs" />
-    <Compile Include="Proxies\Interceptors\SelectiveInterceptor.cs" />
-    <Compile Include="Proxies\IProxyBuilder.cs" />
-    <Compile Include="Proxies\IProxyFactory.cs" />
-    <Compile Include="Proxies\Lazy.cs" />
-    <Compile Include="Proxies\LazyLoadedInterceptor.cs" />
-    <Compile Include="Proxies\LazySpecs.cs" />
-    <Compile Include="Proxies\ProxyBuilder.cs" />
-    <Compile Include="Proxies\ProxyBuilderSpecs.cs" />
-    <Compile Include="Proxies\ProxyFactory.cs" />
-    <Compile Include="Proxies\ProxyFactorySpecs.cs" />
-    <Compile Include="Windsor\Configuration\ApplyLoggingInterceptor.cs" />
-    <Compile Include="Windsor\Configuration\ComponentRegistrationConfiguration.cs" />
-    <Compile Include="Windsor\Configuration\ConfigureComponentLifestyle.cs" />
-    <Compile Include="Windsor\Configuration\IComponentExclusionSpecification.cs" />
-    <Compile Include="Windsor\Configuration\LogComponent.cs" />
-    <Compile Include="Windsor\Configuration\LoggingInterceptor.cs" />
-    <Compile Include="Windsor\Configuration\RegisterComponentContract.cs" />
-    <Compile Include="Windsor\WindsorContainerFactory.cs" />
-    <Compile Include="Windsor\WindsorDependencyRegistry.cs" />
-    <Compile Include="Windsor\WindsorDependencyRegistrySpecs.cs" />
+    <Compile Include="Castle\DynamicProxy\IConstraintSelector.cs" />
+    <Compile Include="Castle\DynamicProxy\IInterceptorConstraint.cs" />
+    <Compile Include="Castle\DynamicProxy\IInterceptorConstraintFactory.cs" />
+    <Compile Include="Castle\DynamicProxy\IMethodCallTrackerFactory.cs" />
+    <Compile Include="Castle\DynamicProxy\InterceptorConstraintFactorySpecs.cs" />
+    <Compile Include="Castle\DynamicProxy\InterceptorConstraintSpecs.cs" />
+    <Compile Include="Castle\DynamicProxy\Interceptors\IMethodCallTracker.cs" />
+    <Compile Include="Castle\DynamicProxy\Interceptors\MethodCallTracker.cs" />
+    <Compile Include="Castle\DynamicProxy\Interceptors\MethodCallTrackerSpecs.cs" />
+    <Compile Include="Castle\DynamicProxy\Interceptors\RunOnBackgroundThreadInterceptor.cs" />
+    <Compile Include="Castle\DynamicProxy\Interceptors\RunOnBackgrounThreadInterceptorSpecs.cs" />
+    <Compile Include="Castle\DynamicProxy\Interceptors\SelectiveInterceptor.cs" />
+    <Compile Include="Castle\DynamicProxy\IProxyBuilder.cs" />
+    <Compile Include="Castle\DynamicProxy\IProxyFactory.cs" />
+    <Compile Include="Castle\DynamicProxy\Lazy.cs" />
+    <Compile Include="Castle\DynamicProxy\LazyLoadedInterceptor.cs" />
+    <Compile Include="Castle\DynamicProxy\LazySpecs.cs" />
+    <Compile Include="Castle\DynamicProxy\ProxyBuilder.cs" />
+    <Compile Include="Castle\DynamicProxy\ProxyBuilderSpecs.cs" />
+    <Compile Include="Castle\DynamicProxy\ProxyFactory.cs" />
+    <Compile Include="Castle\DynamicProxy\ProxyFactorySpecs.cs" />
+    <Compile Include="Castle\Windsor\Configuration\ApplyLoggingInterceptor.cs" />
+    <Compile Include="Castle\Windsor\Configuration\ComponentRegistrationConfiguration.cs" />
+    <Compile Include="Castle\Windsor\Configuration\ConfigureComponentLifestyle.cs" />
+    <Compile Include="Castle\Windsor\Configuration\IComponentExclusionSpecification.cs" />
+    <Compile Include="Castle\Windsor\Configuration\LogComponent.cs" />
+    <Compile Include="Castle\Windsor\Configuration\LoggingInterceptor.cs" />
+    <Compile Include="Castle\Windsor\Configuration\RegisterComponentContract.cs" />
+    <Compile Include="Castle\Windsor\WindsorContainerFactory.cs" />
+    <Compile Include="Castle\Windsor\WindsorDependencyRegistry.cs" />
+    <Compile Include="Castle\Windsor\WindsorDependencyRegistrySpecs.cs" />
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\Gorilla.Commons.Infrastructure\Gorilla.Commons.Infrastructure.csproj">
@@ -142,8 +142,6 @@
     </ProjectReference>
   </ItemGroup>
   <ItemGroup>
-    <Folder Include="Castle\DynamicProxy\Interceptors\" />
-    <Folder Include="Castle\Windsor\Configuration\" />
     <Folder Include="Properties\" />
   </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
trunk/product/MoMoney.Infrastructure/MoMoney.Infrastructure.csproj
@@ -115,11 +115,7 @@
     </ProjectReference>
   </ItemGroup>
   <ItemGroup>
-    <Folder Include="Container\Autofac\" />
-    <Folder Include="Container\Windsor\Configuration\" />
-    <Folder Include="Logging\Log4Net\" />
     <Folder Include="Properties\" />
-    <Folder Include="Proxies\Interceptors\" />
   </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it.