Commit 19e4419

mokhan <mokhan@ce5e1baf-6525-42e4-a1b2-857ea38da20a>
2009-03-25 19:16:52
updated interceptor contraint to intercept all public methods on a contract.
git-svn-id: https://svn.xp-dev.com/svn/mokhan-mo.money@108 ce5e1baf-6525-42e4-a1b2-857ea38da20a
1 parent b62a86e
trunk/product/MyMoney/boot/container/registration/wire_up_the_essential_services_into_the.cs
@@ -1,6 +1,8 @@
+using System.Threading;
 using MoMoney.Infrastructure.Container.Windsor;
 using MoMoney.Infrastructure.Logging;
 using MoMoney.Infrastructure.Logging.Log4NetLogging;
+using MoMoney.Infrastructure.Threading;
 using MoMoney.Utility.Core;
 
 namespace MoMoney.boot.container.registration
@@ -18,6 +20,7 @@ namespace MoMoney.boot.container.registration
         {
             registration.singleton<IDependencyRegistration>(registration);
             registration.singleton<ILogFactory, Log4NetLogFactory>();
+            registration.singleton<ISynchronizationContext>(new SynchronizedContext(SynchronizationContext.Current));
         }
     }
 }
\ No newline at end of file
trunk/product/MyMoney/boot/container/registration/wire_up_the_views_in_to_the.cs
@@ -2,6 +2,7 @@ using System.ComponentModel;
 using MoMoney.Infrastructure.Container.Windsor;
 using MoMoney.Infrastructure.interceptors;
 using MoMoney.Infrastructure.proxies;
+using MoMoney.Infrastructure.Threading;
 using MoMoney.Presentation.Views;
 using MoMoney.Presentation.Views.billing;
 using MoMoney.Presentation.Views.dialogs;
@@ -28,6 +29,7 @@ namespace MoMoney.boot.container.registration
         {
             var shell = new ApplicationShell();
             register.singleton<IShell>(shell);
+            //register.proxy<IShell>(new SynchronizedConfiguration<IShell>(), () => shell);
             register.singleton(shell);
             //register.proxy(new SynchronizedViewProxyConfiguration<IShell>(), () => new ApplicationShell());
             register.transient<IAboutApplicationView, AboutTheApplicationView>();
@@ -56,4 +58,12 @@ namespace MoMoney.boot.container.registration
             item.add_interceptor<SynchronizedInterceptor<T>>();
         }
     }
+
+    internal class SynchronizedConfiguration<T> : IConfiguration<IProxyBuilder<T>>
+    {
+        public void configure(IProxyBuilder<T> item)
+        {
+            item.add_interceptor<IThreadSafeInterceptor>( new ThreadSafeInterceptor(Lazy.load<ISynchronizationContextFactory>())).InterceptAll();
+        }
+    }
 }
\ No newline at end of file
trunk/product/MyMoney/Infrastructure/proxies/Interceptors/MethodCallTracker.cs
@@ -1,6 +1,8 @@
 using System;
 using System.Collections.Generic;
 using Castle.Core.Interceptor;
+using MoMoney.Infrastructure.Extensions;
+using MoMoney.Utility.Extensions;
 
 namespace MoMoney.Infrastructure.proxies.Interceptors
 {
@@ -21,6 +23,7 @@ namespace MoMoney.Infrastructure.proxies.Interceptors
 
         public void Intercept(IInvocation invocation)
         {
+            this.log().debug("recording: {0}", invocation.Method);
             set_return_value_for(invocation);
             if (the_name_of_each_method_to_intercept.Contains(invocation.Method.Name))
             {
@@ -38,12 +41,12 @@ namespace MoMoney.Infrastructure.proxies.Interceptors
         {
             var return_type = invocation.Method.ReturnType;
             if (return_type == typeof (void)) return;
-            invocation.ReturnValue = get_default_value_for(return_type);
+            invocation.ReturnValue = return_type.default_value();
         }
 
-        static object get_default_value_for(Type return_type)
-        {
-            return (return_type.IsValueType ? Activator.CreateInstance(return_type) : null);
-        }
+        //static object get_default_value_for(Type return_type)
+        //{
+        //    return (return_type.IsValueType ? Activator.CreateInstance(return_type) : null);
+        //}
     }
 }
\ No newline at end of file
trunk/product/MyMoney/Infrastructure/proxies/IConstraintSelector.cs
@@ -3,5 +3,6 @@ namespace MoMoney.Infrastructure.proxies
     public interface IConstraintSelector<TypeToPutConstraintOn>
     {
         TypeToPutConstraintOn InterceptOn { get; }
+        void InterceptAll();
     }
 }
\ No newline at end of file
trunk/product/MyMoney/Infrastructure/proxies/IInterceptorConstraint.cs
@@ -1,5 +1,9 @@
 using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using MoMoney.Infrastructure.Extensions;
 using MoMoney.Infrastructure.proxies.Interceptors;
+using MoMoney.Utility.Extensions;
 
 namespace MoMoney.Infrastructure.proxies
 {
@@ -10,7 +14,7 @@ namespace MoMoney.Infrastructure.proxies
 
     public class InterceptorConstraint<TypeToPutConstraintOn> : IInterceptorConstraint<TypeToPutConstraintOn>
     {
-        private readonly IMethodCallTracker<TypeToPutConstraintOn> call_tracker;
+        readonly IMethodCallTracker<TypeToPutConstraintOn> call_tracker;
 
         public InterceptorConstraint(IMethodCallTracker<TypeToPutConstraintOn> call_tracker)
         {
@@ -22,6 +26,24 @@ namespace MoMoney.Infrastructure.proxies
             get { return call_tracker.target; }
         }
 
+        public void InterceptAll()
+        {
+            var methods = typeof (TypeToPutConstraintOn).GetMethods(BindingFlags.Public | BindingFlags.Instance);
+            foreach (var method in methods)
+            {
+                method.Invoke(InterceptOn, get_stub_parameters_for(method).ToArray());
+            }
+        }
+
+        IEnumerable<object> get_stub_parameters_for(MethodInfo method)
+        {
+            foreach (var parameter in method.GetParameters())
+            {
+                this.log().debug("method: {0}, param: {1}", method, parameter);
+                yield return parameter.ParameterType.default_value();
+            }
+        }
+
         public IEnumerable<string> methods_to_intercept()
         {
             return call_tracker.methods_to_intercept();
trunk/product/MyMoney/Infrastructure/proxies/ProxyBuilderSpecs.cs
@@ -85,6 +85,37 @@ namespace MoMoney.Infrastructure.proxies
         static IAnInterface an_implementation;
     }
 
+    public class when_proxying_all_calls_on_a_target : behaves_like_proxy_builder
+    {
+        it should_intercept_each_call =
+            () =>
+                {
+                    SomeInterceptor.MethodsCalled.Count().should_be_equal_to(2);
+                    SomeInterceptor.MethodsCalled.First().Name.should_be_equal_to("OneMethod");
+                    SomeInterceptor.MethodsCalled.Skip(1).First().Name.should_be_equal_to( "SecondMethod");
+                };
+
+        context c = () => { an_implementation = an<IAnInterface>(); };
+
+        because b = () =>
+                        {
+                            var constraint = sut.add_interceptor<SomeInterceptor>();
+                            constraint.InterceptAll();
+
+                            var proxy = sut.create_proxy_for(() => an_implementation);
+                            proxy.OneMethod();
+                            proxy.SecondMethod();
+                        };
+
+        after_each_observation ae = () =>
+                                        {
+                                            SomeInterceptor.Cleanup();
+                                            AnotherInterceptor.Cleanup();
+                                        };
+
+        static IAnInterface an_implementation;
+    }
+
     public interface IAnInterface
     {
         string GetterAndSetterProperty { get; set; }
@@ -96,8 +127,8 @@ namespace MoMoney.Infrastructure.proxies
 
     public class SomeInterceptor : IInterceptor
     {
-        public static bool WasCalled;
-        public static IList<MethodInfo> MethodsCalled;
+        static public bool WasCalled;
+        static public IList<MethodInfo> MethodsCalled;
 
         static SomeInterceptor()
         {
@@ -111,7 +142,7 @@ namespace MoMoney.Infrastructure.proxies
             invocation.Proceed();
         }
 
-        public static void Cleanup()
+        static public void Cleanup()
         {
             WasCalled = false;
             MethodsCalled.Clear();
@@ -120,8 +151,8 @@ namespace MoMoney.Infrastructure.proxies
 
     public class AnotherInterceptor : IInterceptor
     {
-        public static bool WasCalled;
-        public static IList<MethodInfo> MethodsCalled;
+        static public bool WasCalled;
+        static public IList<MethodInfo> MethodsCalled;
 
         static AnotherInterceptor()
         {
@@ -135,7 +166,7 @@ namespace MoMoney.Infrastructure.proxies
             invocation.Proceed();
         }
 
-        public static void Cleanup()
+        static public void Cleanup()
         {
             WasCalled = false;
             MethodsCalled.Clear();
trunk/product/MyMoney/Infrastructure/Threading/SynchronizationContext.cs
@@ -0,0 +1,24 @@
+using System.Threading;
+using MoMoney.Utility.Core;
+
+namespace MoMoney.Infrastructure.Threading
+{
+    public interface ISynchronizationContext : IParameterizedCommand<ICommand>
+    {
+    }
+
+    public class SynchronizedContext : ISynchronizationContext
+    {
+        readonly SynchronizationContext context;
+
+        public SynchronizedContext(SynchronizationContext context)
+        {
+            this.context = context;
+        }
+
+        public void run(ICommand item)
+        {
+            context.Post(x => item.run(), null);
+        }
+    }
+}
\ No newline at end of file
trunk/product/MyMoney/Infrastructure/Threading/SynchronizationContextFactory.cs
@@ -0,0 +1,23 @@
+using MoMoney.Utility.Core;
+
+namespace MoMoney.Infrastructure.Threading
+{
+    public interface ISynchronizationContextFactory : IFactory<ISynchronizationContext>
+    {
+    }
+
+    public class SynchronizationContextFactory : ISynchronizationContextFactory
+    {
+        readonly ISynchronizationContext context;
+
+        public SynchronizationContextFactory(ISynchronizationContext context)
+        {
+            this.context = context;
+        }
+
+        public ISynchronizationContext create()
+        {
+            return context;
+        }
+    }
+}
\ No newline at end of file
trunk/product/MyMoney/Infrastructure/Threading/ThreadSafeInterceptor.cs
@@ -0,0 +1,24 @@
+using Castle.Core.Interceptor;
+using MoMoney.Utility.Core;
+
+namespace MoMoney.Infrastructure.Threading
+{
+    public interface IThreadSafeInterceptor : IInterceptor
+    {
+    }
+
+    public class ThreadSafeInterceptor : IThreadSafeInterceptor
+    {
+        readonly ISynchronizationContextFactory factory;
+
+        public ThreadSafeInterceptor(ISynchronizationContextFactory factory)
+        {
+            this.factory = factory;
+        }
+
+        public void Intercept(IInvocation invocation)
+        {
+            factory.create().run(new ActionCommand(invocation.Proceed));
+        }
+    }
+}
\ No newline at end of file
trunk/product/MyMoney/Utility/Extensions/TypeExtensions.cs
@@ -2,22 +2,27 @@ using System;
 
 namespace MoMoney.Utility.Extensions
 {
-    public static class TypeExtensions
+    static public class TypeExtensions
     {
-        public static Type last_interface(this Type type)
+        static public Type last_interface(this Type type)
         {
             return type.GetInterfaces()[type.GetInterfaces().Length - 1];
         }
 
-        public static Type first_interface(this Type type)
+        static public Type first_interface(this Type type)
         {
             return type.GetInterfaces()[0];
         }
 
-        public static bool is_a_generic_type(this Type type)
+        static public bool is_a_generic_type(this Type type)
         {
             //return type.IsGenericType;
             return type.IsGenericTypeDefinition;
         }
+
+        static public object default_value(this Type type)
+        {
+            return (type.IsValueType ? Activator.CreateInstance(type) : null);
+        }
     }
 }
\ No newline at end of file
trunk/product/MyMoney/MyMoney.csproj
@@ -282,6 +282,9 @@
     <Compile Include="Infrastructure\Threading\IntervalTimer.cs" />
     <Compile Include="Infrastructure\Threading\Juval\Synchronizer.cs" />
     <Compile Include="Infrastructure\Threading\Juval\WorkItem.cs" />
+    <Compile Include="Infrastructure\Threading\SynchronizationContext.cs" />
+    <Compile Include="Infrastructure\Threading\SynchronizationContextFactory.cs" />
+    <Compile Include="Infrastructure\Threading\ThreadSafeInterceptor.cs" />
     <Compile Include="Infrastructure\Threading\TimerFactory.cs" />
     <Compile Include="Infrastructure\Threading\WorkerThread.cs">
       <SubType>Component</SubType>