Skip to content
This repository has been archived by the owner on Jul 16, 2018. It is now read-only.

Commit

Permalink
Merge pull request #7 from Abc-Arbitrage/SubscriptionMode
Browse files Browse the repository at this point in the history
LGTM
  • Loading branch information
alprema committed Aug 26, 2014
2 parents a2cdaed + dd31b77 commit 635b6ca
Show file tree
Hide file tree
Showing 9 changed files with 118 additions and 11 deletions.
2 changes: 2 additions & 0 deletions src/Abc.Zebus.Tests/Abc.Zebus.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@
<Compile Include="Dispatch\DispatchMessages\ForwardCommand.cs" />
<Compile Include="Dispatch\DispatchMessages\ForwardCommandHandler.cs" />
<Compile Include="Dispatch\DispatcherTaskSchedulerTests.cs" />
<Compile Include="Dispatch\DispatchMessages\ManualCommand.cs" />
<Compile Include="Dispatch\DispatchMessages\ManualCommandHandler.cs" />
<Compile Include="Dispatch\MessageDispatcherTests.CustomQueues.cs" />
<Compile Include="Dispatch\DispatchMessages\Namespace1\UseOtherQueue.cs" />
<Compile Include="Dispatch\DispatchMessages\Namespace1\Namespace2\SyncCommandHandlerWithOtherQueueName.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using ProtoBuf;

namespace Abc.Zebus.Tests.Dispatch.DispatchMessages
{
[ProtoContract]
public class ManualCommand : ICommand
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Abc.Zebus.Tests.Dispatch.DispatchMessages
{
public class ManualCommandHandler
{

}
}
44 changes: 42 additions & 2 deletions src/Abc.Zebus.Tests/Scan/SyncMessageHandlerInvokerLoaderTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Linq;
using Abc.Zebus.Dispatch;
using Abc.Zebus.Routing;
using Abc.Zebus.Scan;
using Abc.Zebus.Testing.Extensions;
using Abc.Zebus.Util;
Expand All @@ -16,9 +17,27 @@ public class SyncMessageHandlerInvokerLoaderTests
public void should_load_queue_name()
{
var invokerLoader = new SyncMessageHandlerInvokerLoader(new Container());
var invokers = invokerLoader.LoadMessageHandlerInvokers(TypeSource.FromType<FakeHandlerWithQueueName1>()).ToList();
var invoker = invokerLoader.LoadMessageHandlerInvokers(TypeSource.FromType<FakeHandlerWithQueueName1>()).ExpectedSingle();

invokers[0].DispatchQueueName.ShouldEqual("DispatchQueue1");
invoker.DispatchQueueName.ShouldEqual("DispatchQueue1");
}

[Test]
public void should_switch_to_manual_subscription_mode_when_specified()
{
var invokerLoader = new SyncMessageHandlerInvokerLoader(new Container());
var invoker = invokerLoader.LoadMessageHandlerInvokers(TypeSource.FromType<FakeHandlerWithManualSubscriptionMode>()).ExpectedSingle();

invoker.ShouldBeSubscribedOnStartup.ShouldBeFalse();
}

[Test]
public void should_switch_to_auto_subscription_mode_when_specified()
{
var invokerLoader = new SyncMessageHandlerInvokerLoader(new Container());
var invoker = invokerLoader.LoadMessageHandlerInvokers(TypeSource.FromType<FakeRoutableHandlerWithAutoSubscriptionMode>()).ExpectedSingle();

invoker.ShouldBeSubscribedOnStartup.ShouldBeTrue();
}

[Test]
Expand All @@ -43,6 +62,11 @@ public class FakeMessage2 : IMessage
{
}

[Routable]
public class FakeRoutableMessage : IMessage
{
}

public class FakeHandler : IMessageHandler<FakeMessage>, IMessageHandler<FakeMessage2>
{
public void Handle(FakeMessage message)
Expand Down Expand Up @@ -71,5 +95,21 @@ public void Handle(FakeMessage message)
{
}
}

[SubscriptionMode(SubscriptionMode.Manual)]
public class FakeHandlerWithManualSubscriptionMode : IMessageHandler<FakeMessage>
{
public void Handle(FakeMessage message)
{
}
}

[SubscriptionMode(SubscriptionMode.Auto)]
public class FakeRoutableHandlerWithAutoSubscriptionMode : IMessageHandler<FakeRoutableMessage>
{
public void Handle(FakeRoutableMessage message)
{
}
}
}
}
2 changes: 2 additions & 0 deletions src/Abc.Zebus/Abc.Zebus.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,8 @@
<Compile Include="Routing\Routable.cs" />
<Compile Include="Routing\RoutingPositionAttribute.cs" />
<Compile Include="EventSourcing\SerializationIdAttribute.cs" />
<Compile Include="SubscriptionMode.cs" />
<Compile Include="SubscriptionModeAttribute.cs" />
<Compile Include="TransientAttribute.cs" />
<Compile Include="Subscription.cs" />
<Compile Include="Serialization\IMessageSerializer.cs" />
Expand Down
7 changes: 5 additions & 2 deletions src/Abc.Zebus/Dispatch/MessageHandlerInvoker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,12 @@ public virtual Task InvokeMessageHandlerAsync(IMessageHandlerInvocation invocati
return new Task(() => InvokeMessageHandler(invocation), TaskCreationOptions.HideScheduler);
}

protected internal static bool MessageShouldBeSubscribedOnStartup(Type messageType, bool isNoScanHandler = false)
protected internal static bool MessageShouldBeSubscribedOnStartup(Type messageType, SubscriptionMode? subscriptionMode = null)
{
return !isNoScanHandler && !Attribute.IsDefined(messageType, typeof(Routable));
if (subscriptionMode != null)
return subscriptionMode == SubscriptionMode.Auto;

return !Attribute.IsDefined(messageType, typeof(Routable));
}

protected object CreateHandler(IContainer container, MessageContext messageContext)
Expand Down
25 changes: 18 additions & 7 deletions src/Abc.Zebus/Scan/MessageHandlerInvokerLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,13 @@ protected MessageHandlerInvokerLoader(IContainer container, Type genericHandlerT

public IEnumerable<IMessageHandlerInvoker> LoadMessageHandlerInvokers(TypeSource typeSource)
{
foreach (var type in typeSource.GetTypes())
foreach (var handlerType in typeSource.GetTypes())
{
if (!type.IsClass || type.IsAbstract || !type.IsVisible || !_handlerType.IsAssignableFrom(type))
if (!handlerType.IsClass || handlerType.IsAbstract || !handlerType.IsVisible || !_handlerType.IsAssignableFrom(handlerType))
continue;

var isNoScanHandler = Attribute.IsDefined(type, typeof(NoScanAttribute));

var interfaces = type.GetInterfaces();
var subscriptionMode = GetExplicitSubscriptionMode(handlerType);
var interfaces = handlerType.GetInterfaces();

var excludedMessageTypes = interfaces.Where(IsExtendedMessageHandlerInterface)
.Select(handleInterface => handleInterface.GetGenericArguments()[0])
Expand All @@ -44,13 +43,25 @@ public IEnumerable<IMessageHandlerInvoker> LoadMessageHandlerInvokers(TypeSource
if (excludedMessageTypes.Contains(messageType))
continue;

var shouldBeSubscribedOnStartup = MessageHandlerInvoker.MessageShouldBeSubscribedOnStartup(messageType, isNoScanHandler);
var invoker = BuildMessageHandlerInvoker(type, messageType, shouldBeSubscribedOnStartup);
var shouldBeSubscribedOnStartup = MessageHandlerInvoker.MessageShouldBeSubscribedOnStartup(messageType, subscriptionMode);
var invoker = BuildMessageHandlerInvoker(handlerType, messageType, shouldBeSubscribedOnStartup);
yield return invoker;
}
}
}

private SubscriptionMode? GetExplicitSubscriptionMode(Type handlerType)
{
var subscriptionModeAttribute = (SubscriptionModeAttribute)Attribute.GetCustomAttribute(handlerType, typeof(SubscriptionModeAttribute));
if (subscriptionModeAttribute != null)
return subscriptionModeAttribute.SubscriptionMode;

var isNoScanHandler = Attribute.IsDefined(handlerType, typeof(NoScanAttribute));
if (isNoScanHandler)
return SubscriptionMode.Manual;

return null;
}

protected abstract IMessageHandlerInvoker BuildMessageHandlerInvoker(Type handlerType, Type messageType, bool shouldBeSubscribedOnStartup);

Expand Down
16 changes: 16 additions & 0 deletions src/Abc.Zebus/SubscriptionMode.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace Abc.Zebus
{
public enum SubscriptionMode
{
/// <summary>
/// A subscription for the handler message type will be automatically performed on startup.
/// This is the default mode for non-routable messages.
/// </summary>
Auto,
/// <summary>
/// The subscription for the handler message type must be manually performed with <code>IBus.Subscribe</code>.
/// This is the default mode for routable messages.
/// </summary>
Manual,
}
}
17 changes: 17 additions & 0 deletions src/Abc.Zebus/SubscriptionModeAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System;

namespace Abc.Zebus
{
/// <summary>
/// Specifies the subscription mode of the target message handler.
/// </summary>
public class SubscriptionModeAttribute : Attribute
{
public SubscriptionModeAttribute(SubscriptionMode subscriptionMode)
{
SubscriptionMode = subscriptionMode;
}

public SubscriptionMode SubscriptionMode { get; private set; }
}
}

0 comments on commit 635b6ca

Please sign in to comment.