Commit 13dce8c

mo khan <mo@mokhan.ca>
2009-05-08 15:02:01
created a context factory to create a context for different scoped storage like thread scope
1 parent 34c3af3
product/Gorilla.Commons.Infrastructure/Transactions/Context.cs
@@ -6,9 +6,9 @@ namespace Gorilla.Commons.Infrastructure.Transactions
     {
         readonly IDictionary items;
 
-        public Context() : this(new Hashtable())
-        {
-        }
+        //public Context() : this(new Hashtable())
+        //{
+        //}
 
         public Context(IDictionary items)
         {
product/Gorilla.Commons.Infrastructure/Transactions/ContextFactory.cs
@@ -0,0 +1,15 @@
+namespace Gorilla.Commons.Infrastructure.Transactions
+{
+    public interface IContextFactory
+    {
+        IContext create_for(IScopedStorage storage);
+    }
+
+    public class ContextFactory : IContextFactory
+    {
+        public IContext create_for(IScopedStorage storage)
+        {
+            return new Context(storage.provide_storage());
+        }
+    }
+}
\ No newline at end of file
product/Gorilla.Commons.Infrastructure/Transactions/ContextFactorySpecs.cs
@@ -0,0 +1,30 @@
+using System.Collections;
+using developwithpassion.bdd.contexts;
+using Gorilla.Commons.Testing;
+
+namespace Gorilla.Commons.Infrastructure.Transactions
+{
+    public class ContextFactorySpecs
+    {
+    }
+
+    public class when_creating_a_new_context : concerns_for<IContextFactory, ContextFactory>
+    {
+        context c = () =>
+                        {
+                            scope = an<IScopedStorage>();
+                            storage = an<IDictionary>();
+
+                            when_the(scope).is_told_to(x => x.provide_storage()).it_will_return(storage);
+                        };
+
+        because b = () => { result = sut.create_for(scope); };
+
+        it should_return_a_context_that_represents_the_specified_scope =
+            () => result.should_be_an_instance_of<Context>();
+
+        static IDictionary storage;
+        static IScopedStorage scope;
+        static IContext result;
+    }
+}
\ No newline at end of file
product/Gorilla.Commons.Infrastructure/Transactions/IScopedStorage.cs
@@ -0,0 +1,9 @@
+using System.Collections;
+
+namespace Gorilla.Commons.Infrastructure.Transactions
+{
+    public interface IScopedStorage
+    {
+        IDictionary provide_storage();
+    }
+}
\ No newline at end of file
product/Gorilla.Commons.Infrastructure/Transactions/IThread.cs
@@ -0,0 +1,7 @@
+namespace Gorilla.Commons.Infrastructure.Transactions
+{
+    public interface IThread
+    {
+        T provide_slot_for<T>() where T : new();
+    }
+}
\ No newline at end of file
product/Gorilla.Commons.Infrastructure/Transactions/PerThread.cs
@@ -37,17 +37,17 @@ namespace Gorilla.Commons.Infrastructure.Transactions
 
         IDictionary get_items()
         {
-            var id = Thread.CurrentThread.ManagedThreadId;
+            var id = System.Threading.Thread.CurrentThread.ManagedThreadId;
             within_lock(() =>
                             {
                                 if (!slots.ContainsKey(id))
                                 {
-                                    var slot = Thread.GetNamedDataSlot(GetType().FullName);
+                                    var slot = System.Threading.Thread.GetNamedDataSlot(GetType().FullName);
                                     slots.Add(id, slot);
-                                    Thread.SetData(slot, new Hashtable());
+                                    System.Threading.Thread.SetData(slot, new Hashtable());
                                 }
                             });
-            return (IDictionary) Thread.GetData(slots[id]);
+            return (IDictionary) System.Threading.Thread.GetData(slots[id]);
         }
 
         void within_lock(Action action)
product/Gorilla.Commons.Infrastructure/Transactions/PerThreadScopedStorage.cs
@@ -0,0 +1,19 @@
+using System.Collections;
+
+namespace Gorilla.Commons.Infrastructure.Transactions
+{
+    public class PerThreadScopedStorage : IScopedStorage
+    {
+        readonly IThread current_thread;
+
+        public PerThreadScopedStorage(IThread current_thread)
+        {
+            this.current_thread = current_thread;
+        }
+
+        public IDictionary provide_storage()
+        {
+            return current_thread.provide_slot_for<Hashtable>();
+        }
+    }
+}
\ No newline at end of file
product/Gorilla.Commons.Infrastructure/Transactions/PerThreadScopedStorageSpecs.cs
@@ -0,0 +1,34 @@
+using System;
+using System.Collections;
+using developwithpassion.bdd.contexts;
+using Gorilla.Commons.Testing;
+
+namespace Gorilla.Commons.Infrastructure.Transactions
+{
+    public class PerThreadScopedStorageSpecs
+    {
+    }
+
+    public class when_retrieving_the_storage_for_a_specific_thread :
+        concerns_for<IScopedStorage, PerThreadScopedStorage>
+    {
+        context c = () =>
+                        {
+                            thread_id = DateTime.Now.Ticks;
+                            thread = the_dependency<IThread>();
+                            storage = new Hashtable();
+                            when_the(thread)
+                                .is_told_to(x => x.provide_slot_for<Hashtable>())
+                                .it_will_return(storage);
+                        };
+
+        because b = () => { result = sut.provide_storage(); };
+
+        it should_return_the_storage_the_corresponds_to_the_current_thread = () => result.should_be_equal_to(storage);
+
+        static IDictionary result;
+        static IThread thread;
+        static long thread_id;
+        static Hashtable storage;
+    }
+}
\ No newline at end of file
product/Gorilla.Commons.Infrastructure/Transactions/Thread.cs
@@ -0,0 +1,36 @@
+using System;
+using System.Collections.Generic;
+
+namespace Gorilla.Commons.Infrastructure.Transactions
+{
+    public class Thread : IThread
+    {
+        readonly object mutex = new object();
+        readonly IDictionary<int, LocalDataStoreSlot> slots;
+
+        public Thread()
+        {
+            slots = new Dictionary<int, LocalDataStoreSlot>();
+        }
+
+        public T provide_slot_for<T>() where T : new()
+        {
+            var id = System.Threading.Thread.CurrentThread.ManagedThreadId;
+            within_lock(() =>
+                            {
+                                if (!slots.ContainsKey(id))
+                                {
+                                    var slot = System.Threading.Thread.GetNamedDataSlot(GetType().FullName);
+                                    slots.Add(id, slot);
+                                    System.Threading.Thread.SetData(slot, new T());
+                                }
+                            });
+            return (T) System.Threading.Thread.GetData(slots[id]);
+        }
+
+        void within_lock(Action action)
+        {
+            lock (mutex) action();
+        }
+    }
+}
\ No newline at end of file
product/Gorilla.Commons.Infrastructure/Gorilla.Commons.Infrastructure.csproj
@@ -130,6 +130,9 @@
     <Compile Include="Transactions\ChangeTrackerFactorySpecs.cs" />
     <Compile Include="Transactions\ChangeTrackerSpecs.cs" />
     <Compile Include="Transactions\Context.cs" />
+    <Compile Include="Transactions\ContextFactory.cs" />
+    <Compile Include="Transactions\ContextFactorySpecs.cs" />
+    <Compile Include="Transactions\Thread.cs" />
     <Compile Include="Transactions\EmptyUnitOfWork.cs" />
     <Compile Include="Transactions\IChangeTracker.cs" />
     <Compile Include="Transactions\IChangeTrackerFactory.cs" />
@@ -140,9 +143,13 @@
     <Compile Include="Transactions\IdentityMapSpecs.cs" />
     <Compile Include="Transactions\IIdentityMap.cs" />
     <Compile Include="Transactions\IKey.cs" />
+    <Compile Include="Transactions\IScopedStorage.cs" />
     <Compile Include="Transactions\IStatement.cs" />
     <Compile Include="Transactions\IStatementRegistry.cs" />
+    <Compile Include="Transactions\IThread.cs" />
     <Compile Include="Transactions\PerThread.cs" />
+    <Compile Include="Transactions\PerThreadScopedStorage.cs" />
+    <Compile Include="Transactions\PerThreadScopedStorageSpecs.cs" />
     <Compile Include="Transactions\Session.cs" />
     <Compile Include="Transactions\SessionFactory.cs" />
     <Compile Include="Transactions\SessionFactorySpecs.cs" />