// Handler mapping class.
// Copyright (C) 2009-2010 Lex Li
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using GSF.Net.Snmp.Messaging;
namespace GSF.Net.Snmp.Pipeline
{
///
/// Handler mapping class, who is used to map incoming messages to their handlers.
///
[SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")]
public sealed class HandlerMapping
{
#if !NET471
///
/// .NET standard 1.3 only helper.
///
public static ITypeResolver TypeResolver { get; set; } = new DefaultTypeResolver();
#endif
private readonly string[] _version;
private readonly bool _catchAll;
private readonly string _command;
private readonly IMessageHandler _handler;
///
/// Initializes a new instance of the class.
///
/// The version.
/// The command.
/// The handler.
[SuppressMessage("StyleCop.CSharp.SpacingRules", "SA1027:TabsMustNotBeUsed", Justification = "Reviewed. Suppression is OK here.")]
public HandlerMapping(string version, string command, IMessageHandler handler)
{
if (version == null)
{
throw new ArgumentNullException(nameof(version));
}
if (command == null)
{
throw new ArgumentNullException(nameof(command));
}
if (handler == null)
{
throw new ArgumentNullException(nameof(handler));
}
_catchAll = version == "*";
_version = _catchAll ?
new string[0] :
version.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
;
_command = command;
_handler = handler;
}
///
/// Initializes a new instance of the class.
///
/// The version.
/// The command.
/// The type.
/// The assembly.
public HandlerMapping(string version, string command, string type, string assembly)
{
if (version == null)
{
throw new ArgumentNullException(nameof(version));
}
if (command == null)
{
throw new ArgumentNullException(nameof(command));
}
if (type == null)
{
throw new ArgumentNullException(nameof(type));
}
if (assembly == null)
{
throw new ArgumentNullException(nameof(assembly));
}
_catchAll = version == "*";
_version = _catchAll ? new string[0] : version.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
_command = command;
_handler = CreateMessageHandler(assembly, type);
}
private static IMessageHandler CreateMessageHandler(string assemblyName, string type)
{
#if NET471
foreach (Assembly assembly in from assembly in AppDomain.CurrentDomain.GetAssemblies()
let name = assembly.GetName().Name
where string.Compare(name, assemblyName, StringComparison.OrdinalIgnoreCase) == 0
select assembly)
{
return (IMessageHandler)Activator.CreateInstance(assembly.GetType(type));
}
return (IMessageHandler)Activator.CreateInstance(AppDomain.CurrentDomain.Load(assemblyName).GetType(type));
#else
foreach (var assembly in from assembly in TypeResolver.GetAssemblies()
let name = assembly.GetName().Name
where string.Compare(name, assemblyName, StringComparison.OrdinalIgnoreCase) == 0
select assembly)
{
return (IMessageHandler)Activator.CreateInstance(assembly.GetType(type));
}
return (IMessageHandler)Activator.CreateInstance(TypeResolver.Load(assemblyName, type));
#endif
}
///
/// Gets the handler.
///
/// The handler.
public IMessageHandler Handler
{
get { return _handler; }
}
///
/// Determines whether this instance can handle the specified message.
///
/// The message.
///
/// true if this instance can handle the specified message; otherwise, false.
///
public bool CanHandle(ISnmpMessage message)
{
return VersionMatched(message) && CommandMatched(message);
}
private bool CommandMatched(ISnmpMessage message)
{
string codeString = message.Pdu().TypeCode.ToString();
return StringEquals(_command, "*") || StringEquals(_command + "RequestPdu", codeString) ||
StringEquals(_command + "Pdu", codeString);
}
private bool VersionMatched(ISnmpMessage message)
{
return _catchAll || _version.Any(v => StringEquals(message.Version.ToString(), v));
}
private static bool StringEquals(string left, string right)
{
return string.Compare(left, right, StringComparison.OrdinalIgnoreCase) == 0;
}
}
}