Skip to content

Commit

Permalink
Merge pull request #766 from bnordli/issue/686_part_2a
Browse files Browse the repository at this point in the history
Ensure Initialize is run only once in CommandHandlerInvoker #686
  • Loading branch information
einari authored Jan 20, 2017
2 parents 656e256 + 7e7ceb0 commit 3fb40ad
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 14 deletions.
1 change: 1 addition & 0 deletions Source/Bifrost.Specs/Bifrost.Specs.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@
<Compile Include="Commands\for_CommandHandlerInvoker\Subjects.cs" />
<Compile Include="Commands\for_CommandHandlerInvoker\when_handling_with_automatically_discovered_command_handlers.cs" />
<Compile Include="Commands\for_CommandHandlerInvoker\when_handling_with_manually_registered_command_handlers.cs" />
<Compile Include="Commands\for_CommandHandlerInvoker\when_receiving_asynchronous_initialization.cs" />
<Compile Include="Commands\for_CommandHandlerInvoker\when_handling_with_no_command_handlers.cs" />
<Compile Include="Commands\for_CommandHandlerManager\given\a_command_handler_manager.cs" />
<Compile Include="Commands\for_CommandHandlerManager\when_handling_a_command_without_a_command_handler.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using System;
using System.Threading;
using Bifrost.Commands;
using Machine.Specifications;
using Moq;
using It = Machine.Specifications.It;

namespace Bifrost.Specs.Commands.for_CommandHandlerInvoker
{
[Subject(Subjects.handling_commands)]
public class when_receiving_asynchronous_initialization : given.a_command_handler_invoker_with_no_command_handlers
{
protected static bool result;

Because of = () =>
{
var command = new Command();
var thread = new Thread(() => invoker.TryHandle(command));

type_discoverer_mock
.Setup(t => t.FindMultiple<IHandleCommands>())
.Callback(
() =>
{
thread.Start();
Thread.Sleep(50);
})
.Returns(new Type[0]);
result = invoker.TryHandle(command);
thread.Join();
};

It should_initialize_only_once = () =>
type_discoverer_mock.Verify(m => m.FindMultiple<IHandleCommands>(), Times.Once);
}
}
45 changes: 31 additions & 14 deletions Source/Bifrost/Commands/CommandHandlerInvoker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public class CommandHandlerInvoker : ICommandHandlerInvoker
readonly ITypeDiscoverer _discoverer;
readonly IContainer _container;
readonly Dictionary<Type, MethodInfo> _commandHandlers = new Dictionary<Type, MethodInfo>();
readonly object _initializationLock = new object();
bool _initialized;

/// <summary>
Expand All @@ -38,40 +39,56 @@ public CommandHandlerInvoker(ITypeDiscoverer discoverer, IContainer container)
_initialized = false;
}

private void Initialize()
void EnsureInitialized()
{
if (_initialized)
{
return;
}

lock (_initializationLock)
{
if (!_initialized)
{
Initialize();
_initialized = true;
}
}
}

void Initialize()
{
var handlers = _discoverer.FindMultiple<IHandleCommands>();
handlers.ForEach(Register);
_initialized = true;
}

/// <summary>
/// Register a command handler explicitly
/// Register a command handler explicitly
/// </summary>
/// <param name="handlerType"></param>
/// <remarks>
/// The registration process will look into the handler and find methods that
/// The registration process will look into the handler and find methods that
/// are called Handle() and takes a command as parameter
/// </remarks>
public void Register(Type handlerType)
{
var allMethods = handlerType.GetRuntimeMethods().Where(m => m.IsPublic || !m.IsStatic);
var query = from m in allMethods
where m.Name.Equals(HandleMethodName) &&
m.GetParameters().Length == 1 &&
typeof(ICommand)
.GetTypeInfo().IsAssignableFrom(m.GetParameters()[0].ParameterType.GetTypeInfo())
select m;
var handleMethods = handlerType
.GetRuntimeMethods()
.Where(m => m.IsPublic || !m.IsStatic)
.Where(m => m.Name.Equals(HandleMethodName))
.Where(m => m.GetParameters().Length == 1)
.Where(m => typeof(ICommand).GetTypeInfo().IsAssignableFrom(m.GetParameters()[0].ParameterType));

foreach (var method in query)
foreach (var method in handleMethods)
{
_commandHandlers[method.GetParameters()[0].ParameterType] = method;
}
}

#pragma warning disable 1591 // Xml Comments
public bool TryHandle(ICommand command)
{
if( !_initialized)
Initialize();
EnsureInitialized();

var commandType = command.GetType();
if (_commandHandlers.ContainsKey(commandType))
Expand Down

0 comments on commit 3fb40ad

Please sign in to comment.