Commit 6a443a9
Changed files (10)
trunk
product
MyMoney
DataAccess
repositories
Infrastructure
Container
Threading
Juval
transactions
trunk/product/MyMoney/DataAccess/repositories/bill_repository_specs.cs → trunk/product/MyMoney/DataAccess/repositories/BillRepositorySpecs.cs
File renamed without changes
trunk/product/MyMoney/Infrastructure/Container/Windsor/configuration/ComponentExclusionSpecification.cs
@@ -10,6 +10,7 @@ namespace MoMoney.Infrastructure.Container.Windsor.configuration
return new NoInterfaces()
.or(new SubclassesForm())
.or(new ImplementationOfDependencyRegistry())
+ .or(new IsAnEntity())
.is_satisfied_by(type);
}
}
trunk/product/MyMoney/Infrastructure/Container/Windsor/configuration/ComponentExclusionSpecificationSpecs.cs
@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Windows.Forms;
using developwithpassion.bdd.contexts;
+using MoMoney.Domain.Core;
using MoMoney.Testing.spechelpers.contexts;
using MoMoney.Testing.spechelpers.core;
@@ -31,15 +32,24 @@ namespace MoMoney.Infrastructure.Container.Windsor.configuration
static bool result;
}
- public class when_checking_if_a_status_class_should_be_excluded : behaves_like_component_exclusion_specification
+ public class when_checking_if_a_static_class_should_be_excluded : behaves_like_component_exclusion_specification
{
- it should_be_excluded = () => { result.should_be_true(); };
-
+ it should_be_excluded = () => result.should_be_true();
+
because b = () => { result = sut.is_satisfied_by(typeof (FakeStaticClass)); };
static bool result;
}
+ public class when_checking_if_an_domain_entity_should_be_excluded : behaves_like_component_exclusion_specification
+ {
+ it should_be_excluded = () => result.should_be_true();
+
+ because b = () => { result = sut.is_satisfied_by(typeof (FakeEntity)); };
+
+ static bool result;
+ }
+
//public class when_checking_if_a_set_of_observations_should_be_excluded : behaves_like_component_exclusion_specification
//{
@@ -66,7 +76,15 @@ namespace MoMoney.Infrastructure.Container.Windsor.configuration
}
}
- public static class FakeStaticClass
+ static public class FakeStaticClass
{
}
+
+ public class FakeEntity : IEntity
+ {
+ public Guid Id
+ {
+ get { throw new NotImplementedException(); }
+ }
+ }
}
\ No newline at end of file
trunk/product/MyMoney/Infrastructure/Container/Windsor/configuration/ImplementationOfDependencyRegistry.cs
@@ -6,7 +6,7 @@ namespace MoMoney.Infrastructure.Container.Windsor.configuration
{
public bool is_satisfied_by(Type item)
{
- return item.IsAssignableFrom(typeof (IDependencyRegistry));
+ return typeof (IDependencyRegistry).IsAssignableFrom(item);
}
}
}
\ No newline at end of file
trunk/product/MyMoney/Infrastructure/Container/Windsor/configuration/IsAnEntity.cs
@@ -0,0 +1,14 @@
+using System;
+using MoMoney.Domain.Core;
+using MoMoney.Utility.Core;
+
+namespace MoMoney.Infrastructure.Container.Windsor.configuration
+{
+ public class IsAnEntity : ISpecification<Type>
+ {
+ public bool is_satisfied_by(Type item)
+ {
+ return typeof (IEntity).IsAssignableFrom(item);
+ }
+ }
+}
\ No newline at end of file
trunk/product/MyMoney/Infrastructure/Container/Windsor/WindsorDependencyRegistrySpecs.cs
@@ -8,24 +8,24 @@ using MoMoney.Testing.spechelpers.core;
namespace MoMoney.Infrastructure.Container.Windsor
{
[Concern(typeof (WindsorDependencyRegistry))]
- [run_in_real_container]
- public class when_registering_a_singleton_component_with_the_windsor_container : concerns_for<IDependencyRegistry>
+ internal class behaves_like_windsor_dependency_registry :
+ concerns_for<IDependencyRegistry, WindsorDependencyRegistry>
+ {
+ }
+
+ internal class when_registering_a_singleton_component_with_the_windsor_container :
+ behaves_like_windsor_dependency_registry
{
it should_return_the_same_instance_each_time_its_resolved =
() => result.should_be_the_same_instance_as(sut.get_a<IBird>());
it should_not_return_null = () => result.should_not_be_null();
- public override IDependencyRegistry create_sut()
- {
- return resolve.dependency_for<IDependencyRegistry>();
- }
-
context c = () =>
{
var container = the_dependency<IWindsorContainer>();
var bird = new BlueBird();
- container.is_told_to(x => x.Resolve<IBird>()).it_will_return(bird);
+ container.is_told_to(x => x.Resolve<IBird>()).it_will_return(bird).Repeat.Any();
};
because b = () => { result = sut.get_a<IBird>(); };
trunk/product/MyMoney/Infrastructure/Threading/Juval/Synchronizer.cs
@@ -0,0 +1,189 @@
+using System;
+using System.Collections;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.Security.Permissions;
+using System.Threading;
+
+namespace MoMoney.Infrastructure.Threading.Juval
+{
+ [SecurityPermission(SecurityAction.Demand, ControlThread = true)]
+ public class Synchronizer : ISynchronizeInvoke, IDisposable
+ {
+ readonly WorkerThread worker_thread;
+
+ public Synchronizer()
+ {
+ worker_thread = new WorkerThread(this);
+ }
+
+ public bool InvokeRequired
+ {
+ get { return ReferenceEquals(Thread.CurrentThread, worker_thread); }
+ }
+
+ public IAsyncResult BeginInvoke(Delegate method, object[] args)
+ {
+ var result = new WorkItem(null, method, args);
+ worker_thread.QueueWorkItem(result);
+ return result;
+ }
+
+ public object EndInvoke(IAsyncResult result)
+ {
+ result.AsyncWaitHandle.WaitOne();
+ return ((WorkItem) result).MethodReturnedValue;
+ }
+
+ public object Invoke(Delegate method, object[] args)
+ {
+ return EndInvoke(BeginInvoke(method, args));
+ }
+
+ ~Synchronizer()
+ {
+ }
+
+ public void Dispose()
+ {
+ worker_thread.Kill();
+ }
+
+ class WorkerThread
+ {
+ Thread thread;
+ bool end_loop;
+ readonly Mutex end_loop_mutex;
+ readonly AutoResetEvent item_added;
+ Synchronizer synchronizer;
+ readonly Queue work_item_queue;
+
+ internal WorkerThread(Synchronizer synchronizer)
+ {
+ this.synchronizer = synchronizer;
+ end_loop = false;
+ thread = null;
+ end_loop_mutex = new Mutex();
+ item_added = new AutoResetEvent(false);
+ work_item_queue = new Queue();
+ CreateThread(true);
+ }
+
+ internal void QueueWorkItem(WorkItem workItem)
+ {
+ lock (work_item_queue.SyncRoot)
+ {
+ work_item_queue.Enqueue(workItem);
+ item_added.Set();
+ }
+ }
+
+ bool EndLoop
+ {
+ set
+ {
+ end_loop_mutex.WaitOne();
+ end_loop = value;
+ end_loop_mutex.ReleaseMutex();
+ }
+ get
+ {
+ var result = false;
+ end_loop_mutex.WaitOne();
+ result = end_loop;
+ end_loop_mutex.ReleaseMutex();
+ return result;
+ }
+ }
+
+ Thread CreateThread(bool autoStart)
+ {
+ if (thread != null)
+ {
+ Debug.Assert(false);
+ return thread;
+ }
+ thread = new Thread(Run) {Name = "Synchronizer Worker Thread"};
+ if (autoStart)
+ {
+ thread.Start();
+ }
+ return thread;
+ }
+
+ void Start()
+ {
+ Debug.Assert(thread != null);
+ Debug.Assert(thread.IsAlive == false);
+ thread.Start();
+ }
+
+ bool QueueEmpty
+ {
+ get
+ {
+ lock (work_item_queue.SyncRoot)
+ {
+ if (work_item_queue.Count > 0)
+ {
+ return false;
+ }
+ return true;
+ }
+ }
+ }
+
+ WorkItem GetNext()
+ {
+ if (QueueEmpty)
+ {
+ return null;
+ }
+ lock (work_item_queue.SyncRoot)
+ {
+ return (WorkItem) work_item_queue.Dequeue();
+ }
+ }
+
+ void Run()
+ {
+ while (EndLoop == false)
+ {
+ while (QueueEmpty == false)
+ {
+ if (EndLoop)
+ {
+ return;
+ }
+ var workItem = GetNext();
+ workItem.CallBack();
+ }
+ item_added.WaitOne();
+ }
+ }
+
+ public void Kill()
+ {
+ //Kill is called on client thread - must use cached thread object
+ Debug.Assert(thread != null);
+ if (thread.IsAlive == false)
+ {
+ return;
+ }
+ EndLoop = true;
+ item_added.Set();
+
+ //Wait for thread to die
+ thread.Join();
+ if (end_loop_mutex != null)
+ {
+ end_loop_mutex.Close();
+ }
+ if (item_added != null)
+ {
+ item_added.Close();
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
trunk/product/MyMoney/Infrastructure/Threading/Juval/WorkItem.cs
@@ -0,0 +1,93 @@
+using System;
+using System.Threading;
+
+namespace MoMoney.Infrastructure.Threading.Juval
+{
+ [Serializable]
+ internal class WorkItem : IAsyncResult
+ {
+ readonly object[] m_Args;
+ readonly object m_AsyncState;
+ bool m_Completed;
+ readonly Delegate m_Method;
+ readonly ManualResetEvent m_Event;
+ object m_MethodReturnedValue;
+
+ internal WorkItem(object AsyncState, Delegate method, object[] args)
+ {
+ m_AsyncState = AsyncState;
+ m_Method = method;
+ m_Args = args;
+ m_Event = new ManualResetEvent(false);
+ m_Completed = false;
+ }
+
+ //IAsyncResult properties
+ object IAsyncResult.AsyncState
+ {
+ get { return m_AsyncState; }
+ }
+
+ WaitHandle IAsyncResult.AsyncWaitHandle
+ {
+ get { return m_Event; }
+ }
+
+ bool IAsyncResult.CompletedSynchronously
+ {
+ get { return false; }
+ }
+
+ bool IAsyncResult.IsCompleted
+ {
+ get { return Completed; }
+ }
+
+ bool Completed
+ {
+ get
+ {
+ lock (this)
+ {
+ return m_Completed;
+ }
+ }
+ set
+ {
+ lock (this)
+ {
+ m_Completed = value;
+ }
+ }
+ }
+
+ //This method is called on the worker thread to execute the method
+ internal void CallBack()
+ {
+ MethodReturnedValue = m_Method.DynamicInvoke(m_Args);
+ //Method is done. Signal the world
+ m_Event.Set();
+ Completed = true;
+ }
+
+ internal object MethodReturnedValue
+ {
+ get
+ {
+ object methodReturnedValue;
+ lock (this)
+ {
+ methodReturnedValue = m_MethodReturnedValue;
+ }
+ return methodReturnedValue;
+ }
+ set
+ {
+ lock (this)
+ {
+ m_MethodReturnedValue = value;
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
trunk/product/MyMoney/Infrastructure/transactions/UnitOfWork.cs
@@ -1,5 +1,7 @@
+using System;
using MoMoney.Domain.Core;
using MoMoney.Infrastructure.Container;
+using MoMoney.Infrastructure.Logging;
namespace MoMoney.Infrastructure.transactions
{
@@ -7,11 +9,19 @@ namespace MoMoney.Infrastructure.transactions
{
static public IUnitOfWork<T> For<T>() where T : IEntity
{
+ IUnitOfWork<T> unit_of_work = null;
if (resolve.is_initialized())
{
- return resolve.dependency_for<IUnitOfWorkRegistry>().start_unit_of_work_for<T>();
+ try
+ {
+ unit_of_work = resolve.dependency_for<IUnitOfWorkRegistry>().start_unit_of_work_for<T>();
+ }
+ catch (Exception exception)
+ {
+ Log.For(typeof (UnitOfWork)).error(exception);
+ }
}
- return new NullUnitOfWork<T>();
+ return unit_of_work ?? new NullUnitOfWork<T>();
}
}
}
\ No newline at end of file
trunk/product/MyMoney/MyMoney.csproj
@@ -178,7 +178,7 @@
<Compile Include="DataAccess\db40\Session.cs" />
<Compile Include="DataAccess\db40\spiking\db40_spike_specs.cs" />
<Compile Include="DataAccess\repositories\BillRepository.cs" />
- <Compile Include="DataAccess\repositories\bill_repository_specs.cs" />
+ <Compile Include="DataAccess\repositories\BillRepositorySpecs.cs" />
<Compile Include="DataAccess\repositories\CompanyRepository.cs" />
<Compile Include="Domain\accounting\billing\IEmployee.cs" />
<Compile Include="Domain\accounting\financial_growth\income.cs" />
@@ -226,6 +226,7 @@
<Compile Include="Infrastructure\Container\Windsor\configuration\ConfigureComponentLifestyle.cs" />
<Compile Include="Infrastructure\Container\Windsor\configuration\IComponentExclusionSpecification.cs" />
<Compile Include="Infrastructure\Container\Windsor\configuration\ImplementationOfDependencyRegistry.cs" />
+ <Compile Include="Infrastructure\Container\Windsor\configuration\IsAnEntity.cs" />
<Compile Include="Infrastructure\Container\Windsor\configuration\LogComponent.cs" />
<Compile Include="Infrastructure\Container\Windsor\configuration\NoInterfaces.cs" />
<Compile Include="Infrastructure\Container\Windsor\configuration\RegisterComponentContract.cs" />
@@ -282,6 +283,8 @@
<Compile Include="Infrastructure\Threading\BackgroundThread.cs">
</Compile>
<Compile Include="Infrastructure\Threading\IntervalTimer.cs" />
+ <Compile Include="Infrastructure\Threading\Juval\Synchronizer.cs" />
+ <Compile Include="Infrastructure\Threading\Juval\WorkItem.cs" />
<Compile Include="Infrastructure\Threading\TimerFactory.cs" />
<Compile Include="Infrastructure\Threading\WorkerThread.cs">
<SubType>Component</SubType>