//******************************************************************************************************
// LogSubscriberInternal.cs - Gbtc
//
// Copyright © 2016, Grid Protection Alliance. All Rights Reserved.
//
// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
// the NOTICE file distributed with this work for additional information regarding copyright ownership.
// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain a copy of the License at:
//
// http://www.opensource.org/licenses/eclipse-1.0.php
//
// Unless agreed to in writing, the subject software distributed under the License is distributed on an
// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
// License for the specific language governing permissions and limitations.
//
// Code Modification History:
// ----------------------------------------------------------------------------------------------------
// 10/24/2016 - Steven E. Chisholm
// Generated original version of source code.
//
//
//******************************************************************************************************
using System;
using System.Collections.Generic;
// ReSharper disable InconsistentlySynchronizedField
namespace GSF.Diagnostics
{
///
/// A that collects logs
///
internal class LogSubscriberInternal
{
private class SubscriptionInfo
{
public PublisherFilter PublisherFilter;
public MessageAttributeFilter AttributeFilter;
public bool IsIgnoreSubscription;
public SubscriptionInfo(PublisherFilter publisherFilter, MessageAttributeFilter attributeFilter, bool isIgnoreSubscription)
{
PublisherFilter = publisherFilter;
AttributeFilter = attributeFilter;
IsIgnoreSubscription = isIgnoreSubscription;
}
}
///
/// Event handler for the logs that are raised.
///
///
/// Any exceptions generated by this callback will be ignored.
///
public event NewLogMessageEventHandler NewLogMessage;
private Action m_recalculateRoutingTable;
private readonly object m_syncRoot;
private bool m_disposed;
private List m_allSubscriptions;
///
/// Since weak references are linked to this class, this is a common one that everyone can use when storing this weak reference.
///
public readonly NullableWeakReference Reference;
///
/// Creates a
///
public LogSubscriberInternal(Action recalculateRoutingTable)
{
Reference = new NullableWeakReference(this);
m_recalculateRoutingTable = recalculateRoutingTable;
m_syncRoot = new object();
m_allSubscriptions = null;
}
///
/// Clears all subscriptions
///
public void Clear()
{
if (m_disposed)
return;
lock (m_syncRoot)
{
if (m_disposed)
return;
m_allSubscriptions = null;
}
m_recalculateRoutingTable();
}
///
/// Adds/Modify/Deletes an existing subscription
///
public void Subscribe(PublisherFilter publisherFilter, MessageAttributeFilter attributeFilter, bool isIgnoreSubscription)
{
if (publisherFilter == null)
throw new ArgumentNullException(nameof(publisherFilter));
if (m_disposed)
return;
lock (m_syncRoot)
{
if (m_disposed)
return;
if (m_allSubscriptions == null)
{
if (attributeFilter == null)
return;
m_allSubscriptions = new List();
m_allSubscriptions.Add(new SubscriptionInfo(publisherFilter, attributeFilter, isIgnoreSubscription));
}
else
{
for (int x = 0; x < m_allSubscriptions.Count; x++)
{
if (m_allSubscriptions[x].PublisherFilter.ContainsTheSameLogSearchCriteria(publisherFilter))
{
if (attributeFilter == null)
{
m_allSubscriptions.RemoveAt(x);
return;
}
m_allSubscriptions[x].AttributeFilter = attributeFilter;
m_allSubscriptions[x].IsIgnoreSubscription = isIgnoreSubscription;
return;
}
}
if (attributeFilter == null)
return;
m_allSubscriptions.Add(new SubscriptionInfo(publisherFilter, attributeFilter, isIgnoreSubscription));
}
}
m_recalculateRoutingTable();
}
///
/// Assigns the supplied message to this subscriber.
///
/// the message
public void RaiseLogMessages(LogMessage log)
{
if (m_disposed)
return;
lock (m_syncRoot)
{
if (m_disposed)
return;
if (m_allSubscriptions == null || m_allSubscriptions.Count == 0)
return;
OnLog(log);
}
}
public MessageAttributeFilter GetSubscription(LogPublisherInternal publisher)
{
lock (m_syncRoot)
{
if (m_allSubscriptions == null)
m_allSubscriptions = new List();
MessageAttributeFilter filter = new MessageAttributeFilter();
foreach (var subscription in m_allSubscriptions)
{
if (subscription.PublisherFilter.ContainsPublisher(publisher))
{
if (subscription.IsIgnoreSubscription)
{
filter.Remove(subscription.AttributeFilter);
}
else
{
filter.Append(subscription.AttributeFilter);
}
}
}
return filter;
}
}
///
/// Raises the event.
///
/// the message to raise.
private void OnLog(LogMessage logMessage)
{
if (logMessage == null)
return;
try
{
using (Logger.SuppressFirstChanceExceptionLogMessages())
{
NewLogMessage?.Invoke(logMessage);
}
}
catch (Exception)
{
//Swallow this exception
//This is because if a subscriber throws an exception, creating a new log
//might cause an infinite loop.
}
}
///
/// Disposes this class so future messages will not route.
///
public void Dispose()
{
m_disposed = true;
m_allSubscriptions = null;
Reference.Clear();
}
public static readonly LogSubscriberInternal DisposedSubscriber;
static LogSubscriberInternal()
{
DisposedSubscriber = new LogSubscriberInternal(null);
DisposedSubscriber.Dispose();
}
}
}