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

Nuclei.Communication: Allow mapping notification interface to known events on a given object #31

Merged
merged 10 commits into from
Apr 28, 2014
Merged
1 change: 1 addition & 0 deletions Settings.StyleCop
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
<Value>serializer</Value>
<Value>serializers</Value>
<Value>simple-auto-update-for-wpf-apps</Value>
<Value>stackoverflow</Value>
<Value>tcp</Value>
<Value>unregistration</Value>
<Value>UUID</Value>
Expand Down
21 changes: 9 additions & 12 deletions src/nuclei.communication/CommunicationModule.Interaction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,11 @@
// </copyright>
//-----------------------------------------------------------------------

using System;
using System.Collections.Generic;
using Autofac;
using Nuclei.Communication.Interaction;
using Nuclei.Communication.Interaction.Transport;
using Nuclei.Communication.Interaction.Transport.Messages.Processors;
using Nuclei.Communication.Properties;
using Nuclei.Communication.Protocol;
using Nuclei.Configuration;
using Nuclei.Diagnostics;
Expand Down Expand Up @@ -63,6 +61,7 @@ private static void RegisterNotificationHub(ContainerBuilder builder)
c.Resolve<SystemDiagnostics>()))
.As<INotifyOfRemoteEndpointEvents>()
.As<IStoreRemoteNotificationProxies>()
.As<IRaiseProxyNotifications>()
.SingleInstance();

builder.Register(
Expand Down Expand Up @@ -122,7 +121,7 @@ private static void RegisterInteractionMessageProcessingActions(ContainerBuilder
.As<IMessageProcessAction>();

builder.Register(c => new NotificationRaisedProcessAction(
c.Resolve<INotifyOfRemoteEndpointEvents>(),
c.Resolve<IRaiseProxyNotifications>(),
c.Resolve<SystemDiagnostics>()))
.As<IMessageProcessAction>();
}
Expand Down Expand Up @@ -204,21 +203,19 @@ private static void RegisterNotificationRegistrationFunctions(ContainerBuilder b
c =>
{
var ctx = c.Resolve<IComponentContext>();
RegisterNotification func = (type, notification, subjects) =>
RegisterNotification func = (map, subjects) =>
{
type.VerifyThatTypeIsACorrectNotificationSet();
if (!type.IsInstanceOfType(notification))
{
throw new ArgumentException(Resources.Exceptions_Messages_NotificationObjectMustImplementNotificationInterface);
}

var collection = ctx.Resolve<INotificationCollection>();
var subjectCollection = ctx.Resolve<IRegisterSubjectGroups>();

collection.Register(type, notification);
collection.Register(map.Definitions);
foreach (var subject in subjects)
{
subjectCollection.RegisterNotificationForProvidedSubjectGroup(subject.Subject, type, subject.Version, subject.Group);
subjectCollection.RegisterNotificationForProvidedSubjectGroup(
subject.Subject,
map.NotificationType,
subject.Version,
subject.Group);
}
};

Expand Down
2 changes: 1 addition & 1 deletion src/nuclei.communication/Interaction/CommandDefinition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
namespace Nuclei.Communication.Interaction
{
/// <summary>
/// Stores information about a single method of a <see cref="ICommandSet"/>.
/// Stores information about the mapping of a single method of a <see cref="ICommandSet"/>.
/// </summary>
internal sealed class CommandDefinition
{
Expand Down
2 changes: 1 addition & 1 deletion src/nuclei.communication/Interaction/CommandMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ namespace Nuclei.Communication.Interaction
{
/// <summary>
/// Defines methods to map the methods on a <see cref="ICommandSet"/> to methods on one or more objects
/// which may or may not implement the interface..
/// which may or may not implement the interface.
/// </summary>
/// <typeparam name="TCommand">The interface type for which the command methods should be mapped.</typeparam>
public sealed class CommandMapper<TCommand> where TCommand : ICommandSet
Expand Down
73 changes: 73 additions & 0 deletions src/nuclei.communication/Interaction/EventMapper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
//-----------------------------------------------------------------------
// <copyright company="Nuclei">
// Copyright 2013 Nuclei. Licensed under the Apache License, Version 2.0.
// </copyright>
//-----------------------------------------------------------------------

using System;

namespace Nuclei.Communication.Interaction
{
/// <summary>
/// Defines methods for mapping a <see cref="INotificationSet"/> event to an event on a given object.
/// </summary>
public sealed class EventMapper
{
/// <summary>
/// The action that is used to store the notification definition.
/// </summary>
private readonly Action<NotificationDefinition> m_StoreDefinition;

/// <summary>
/// The ID for the notification interface event.
/// </summary>
private readonly NotificationId m_NotificationId;

/// <summary>
/// Initializes a new instance of the <see cref="EventMapper"/> class.
/// </summary>
/// <param name="storeDefinition">The action that is used to store the notification definition.</param>
/// <param name="notificationId">The ID for the notification interface event.</param>
/// <exception cref="ArgumentNullException">
/// Thrown if <paramref name="storeDefinition"/> is <see langword="null" />.
/// </exception>
/// <exception cref="ArgumentNullException">
/// Thrown if <paramref name="notificationId"/> is <see langword="null" />.
/// </exception>
internal EventMapper(Action<NotificationDefinition> storeDefinition, NotificationId notificationId)
{
{
Lokad.Enforce.Argument(() => storeDefinition);
Lokad.Enforce.Argument(() => notificationId);
}

m_StoreDefinition = storeDefinition;
m_NotificationId = notificationId;
}

/// <summary>
/// Generates an event handler that can be attached to the notification instance event.
/// </summary>
/// <returns>The event handler that can be attached to the notification instance event.</returns>
public EventHandler GenerateHandler()
{
var definition = new NotificationDefinition(m_NotificationId);

m_StoreDefinition(definition);
return definition.ForwardToListeners;
}

/// <summary>
/// Generates an event handler that can be attached to the notification instance event.
/// </summary>
/// <typeparam name="T">The type of the event handler.</typeparam>
/// <returns>The event handler that can be attached to the notification instance event.</returns>
public EventHandler<T> GenerateHandler<T>() where T : EventArgs
{
var definition = new NotificationDefinition(m_NotificationId);

m_StoreDefinition(definition);
return definition.ForwardToListeners;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace Nuclei.Communication.Interaction
/// Defines the interface for collections that store one or more <see cref="INotificationSet"/>
/// objects.
/// </summary>
internal interface INotificationCollection : IEnumerable<Tuple<Type, INotificationSet>>
internal interface INotificationCollection : IEnumerable<NotificationId>
{
/// <summary>
/// Registers a <see cref="INotificationSet"/> object.
Expand All @@ -40,8 +40,7 @@ internal interface INotificationCollection : IEnumerable<Tuple<Type, INotificati
/// </list>
/// </para>
/// </remarks>
/// <param name="notificationType">The interface that defines the notification events.</param>
/// <param name="notifications">The notification object.</param>
void Register(Type notificationType, INotificationSet notifications);
/// <param name="definitions">The definitions that map the notification interface events to the object events.</param>
void Register(NotificationDefinition[] definitions);
}
}
4 changes: 2 additions & 2 deletions src/nuclei.communication/Interaction/ISendNotifications.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@ internal interface ISendNotifications
/// </summary>
/// <param name="endpoint">The endpoint.</param>
/// <param name="notification">The object that describes to which event the endpoint wants to be subscribed.</param>
void RegisterForNotification(EndpointId endpoint, NotificationData notification);
void RegisterForNotification(EndpointId endpoint, NotificationId notification);

/// <summary>
/// Deregisters a specific endpoint so that it will no longer be notified when the specified event
/// is raised.
/// </summary>
/// <param name="endpoint">The endpoint.</param>
/// <param name="notification">The object that describes from which event the endpoint wants to be unsubscribed.</param>
void UnregisterFromNotification(EndpointId endpoint, NotificationData notification);
void UnregisterFromNotification(EndpointId endpoint, NotificationId notification);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
//-----------------------------------------------------------------------
// <copyright company="Nuclei">
// Copyright 2013 Nuclei. Licensed under the Apache License, Version 2.0.
// </copyright>
//-----------------------------------------------------------------------

using System;
using System.Runtime.Serialization;
using Nuclei.Communication.Properties;

namespace Nuclei.Communication.Interaction
{
/// <summary>
/// An exception thrown when the mapping expression in the <c>From</c> method on the
/// <see cref="NotificationMapper{TNotification}"/> is not a valid event registration expression.
/// </summary>
[Serializable]
public sealed class InvalidNotificationMethodExpressionException : Exception
{
/// <summary>
/// Initializes a new instance of the <see cref="InvalidNotificationMethodExpressionException"/> class.
/// </summary>
public InvalidNotificationMethodExpressionException()
: this(Resources.Exceptions_Messages_InvalidNotificationMethodExpression)
{
}

/// <summary>
/// Initializes a new instance of the <see cref="InvalidNotificationMethodExpressionException"/> class.
/// </summary>
/// <param name="message">The message.</param>
public InvalidNotificationMethodExpressionException(string message)
: base(message)
{
}

/// <summary>
/// Initializes a new instance of the <see cref="InvalidNotificationMethodExpressionException"/> class.
/// </summary>
/// <param name="message">The message.</param>
/// <param name="innerException">The inner exception.</param>
public InvalidNotificationMethodExpressionException(string message, Exception innerException)
: base(message, innerException)
{
}

/// <summary>
/// Initializes a new instance of the <see cref="InvalidNotificationMethodExpressionException"/> class.
/// </summary>
/// <param name="info">
/// The <see cref="T:System.Runtime.Serialization.SerializationInfo"/> that holds the serialized object
/// data about the exception being thrown.
/// </param>
/// <param name="context">
/// The <see cref="T:System.Runtime.Serialization.StreamingContext"/> that contains contextual information
/// about the source or destination.
/// </param>
/// <exception cref="T:System.ArgumentNullException">
/// The <paramref name="info"/> parameter is null.
/// </exception>
/// <exception cref="T:System.Runtime.Serialization.SerializationException">
/// The class name is null or <see cref="P:System.Exception.HResult"/> is zero (0).
/// </exception>
private InvalidNotificationMethodExpressionException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
}
}
Loading