//****************************************************************************************************** // 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(); } } }