History

Converted TFS repository to Git.

StephenCWills committed 11 years ago

Commit dd143d71 parent ab7f4b62684 files · +766031 −765809Browse files

Showing the changes to Source/Libraries/GSF.Unity/GSF.Core/Parsing/MultiSourceFrameImageParserBase.cs (1 of 2684 files). Show all

Unified · Split

Source/Libraries/GSF.Unity/GSF.Core/Parsing/MultiSourceFrameImageParserBase.cs+805−805
@@ -1,805 +1,805 @@
1−//*******************************************************************************************************
2−// MultiSourceFrameImageParserBase.cs - Gbtc
3−//
4−// Tennessee Valley Authority, 2011
5−// No copyright is claimed pursuant to 17 USC § 105. All Other Rights Reserved.
6−//
7−// This software is made freely available under the TVA Open Source Agreement (see below).
8−// Code in this file licensed to GSF under one or more contributor license agreements listed below.
9−//
10−// Code Modification History:
11−// -----------------------------------------------------------------------------------------------------
12−// 12/03/2008 - J. Ritchie Carroll
13−// Generated original version of source code.
14−// 06/19/2009 - Pinal C. Patel
15−// Parsed output is now being delivered in a new collection instead of reusing a single collection.
16−// 08/07/2009 - Josh L. Patterson
17−// Edited Comments.
18−// 09/14/2009 - Stephen C. Wills
19−// Added new header and license agreement.
20−// 11/01/2012 - J. Ritchie Carroll
21−// Updated to use concurrent dictionaries and new recreate parsed output list.
22−//
23−//*******************************************************************************************************
24−
25−#region [ TVA Open Source Agreement ]
26−/*
27−
28− THIS OPEN SOURCE AGREEMENT ("AGREEMENT") DEFINES THE RIGHTS OF USE,REPRODUCTION, DISTRIBUTION,
29− MODIFICATION AND REDISTRIBUTION OF CERTAIN COMPUTER SOFTWARE ORIGINALLY RELEASED BY THE
30− TENNESSEE VALLEY AUTHORITY, A CORPORATE AGENCY AND INSTRUMENTALITY OF THE UNITED STATES GOVERNMENT
31− ("GOVERNMENT AGENCY"). GOVERNMENT AGENCY IS AN INTENDED THIRD-PARTY BENEFICIARY OF ALL SUBSEQUENT
32− DISTRIBUTIONS OR REDISTRIBUTIONS OF THE SUBJECT SOFTWARE. ANYONE WHO USES, REPRODUCES, DISTRIBUTES,
33− MODIFIES OR REDISTRIBUTES THE SUBJECT SOFTWARE, AS DEFINED HEREIN, OR ANY PART THEREOF, IS, BY THAT
34− ACTION, ACCEPTING IN FULL THE RESPONSIBILITIES AND OBLIGATIONS CONTAINED IN THIS AGREEMENT.
35−
36− Original Software Designation: openPDC
37− Original Software Title: The GSF Open Source Phasor Data Concentrator
38− User Registration Requested. Please Visit https://naspi.tva.com/Registration/
39− Point of Contact for Original Software: J. Ritchie Carroll <mailto:jrcarrol@tva.gov>
40−
41− 1. DEFINITIONS
42−
43− A. "Contributor" means Government Agency, as the developer of the Original Software, and any entity
44− that makes a Modification.
45−
46− B. "Covered Patents" mean patent claims licensable by a Contributor that are necessarily infringed by
47− the use or sale of its Modification alone or when combined with the Subject Software.
48−
49− C. "Display" means the showing of a copy of the Subject Software, either directly or by means of an
50− image, or any other device.
51−
52− D. "Distribution" means conveyance or transfer of the Subject Software, regardless of means, to
53− another.
54−
55− E. "Larger Work" means computer software that combines Subject Software, or portions thereof, with
56− software separate from the Subject Software that is not governed by the terms of this Agreement.
57−
58− F. "Modification" means any alteration of, including addition to or deletion from, the substance or
59− structure of either the Original Software or Subject Software, and includes derivative works, as that
60− term is defined in the Copyright Statute, 17 USC § 101. However, the act of including Subject Software
61− as part of a Larger Work does not in and of itself constitute a Modification.
62−
63− G. "Original Software" means the computer software first released under this Agreement by Government
64− Agency entitled openPDC, including source code, object code and accompanying documentation, if any.
65−
66− H. "Recipient" means anyone who acquires the Subject Software under this Agreement, including all
67− Contributors.
68−
69− I. "Redistribution" means Distribution of the Subject Software after a Modification has been made.
70−
71− J. "Reproduction" means the making of a counterpart, image or copy of the Subject Software.
72−
73− K. "Sale" means the exchange of the Subject Software for money or equivalent value.
74−
75− L. "Subject Software" means the Original Software, Modifications, or any respective parts thereof.
76−
77− M. "Use" means the application or employment of the Subject Software for any purpose.
78−
79− 2. GRANT OF RIGHTS
80−
81− A. Under Non-Patent Rights: Subject to the terms and conditions of this Agreement, each Contributor,
82− with respect to its own contribution to the Subject Software, hereby grants to each Recipient a
83− non-exclusive, world-wide, royalty-free license to engage in the following activities pertaining to
84− the Subject Software:
85−
86− 1. Use
87−
88− 2. Distribution
89−
90− 3. Reproduction
91−
92− 4. Modification
93−
94− 5. Redistribution
95−
96− 6. Display
97−
98− B. Under Patent Rights: Subject to the terms and conditions of this Agreement, each Contributor, with
99− respect to its own contribution to the Subject Software, hereby grants to each Recipient under Covered
100− Patents a non-exclusive, world-wide, royalty-free license to engage in the following activities
101− pertaining to the Subject Software:
102−
103− 1. Use
104−
105− 2. Distribution
106−
107− 3. Reproduction
108−
109− 4. Sale
110−
111− 5. Offer for Sale
112−
113− C. The rights granted under Paragraph B. also apply to the combination of a Contributor's Modification
114− and the Subject Software if, at the time the Modification is added by the Contributor, the addition of
115− such Modification causes the combination to be covered by the Covered Patents. It does not apply to
116− any other combinations that include a Modification.
117−
118− D. The rights granted in Paragraphs A. and B. allow the Recipient to sublicense those same rights.
119− Such sublicense must be under the same terms and conditions of this Agreement.
120−
121− 3. OBLIGATIONS OF RECIPIENT
122−
123− A. Distribution or Redistribution of the Subject Software must be made under this Agreement except for
124− additions covered under paragraph 3H.
125−
126− 1. Whenever a Recipient distributes or redistributes the Subject Software, a copy of this Agreement
127− must be included with each copy of the Subject Software; and
128−
129− 2. If Recipient distributes or redistributes the Subject Software in any form other than source code,
130− Recipient must also make the source code freely available, and must provide with each copy of the
131− Subject Software information on how to obtain the source code in a reasonable manner on or through a
132− medium customarily used for software exchange.
133−
134− B. Each Recipient must ensure that the following copyright notice appears prominently in the Subject
135− Software:
136−
137− No copyright is claimed pursuant to 17 USC § 105. All Other Rights Reserved.
138−
139− C. Each Contributor must characterize its alteration of the Subject Software as a Modification and
140− must identify itself as the originator of its Modification in a manner that reasonably allows
141− subsequent Recipients to identify the originator of the Modification. In fulfillment of these
142− requirements, Contributor must include a file (e.g., a change log file) that describes the alterations
143− made and the date of the alterations, identifies Contributor as originator of the alterations, and
144− consents to characterization of the alterations as a Modification, for example, by including a
145− statement that the Modification is derived, directly or indirectly, from Original Software provided by
146− Government Agency. Once consent is granted, it may not thereafter be revoked.
147−
148− D. A Contributor may add its own copyright notice to the Subject Software. Once a copyright notice has
149− been added to the Subject Software, a Recipient may not remove it without the express permission of
150− the Contributor who added the notice.
151−
152− E. A Recipient may not make any representation in the Subject Software or in any promotional,
153− advertising or other material that may be construed as an endorsement by Government Agency or by any
154− prior Recipient of any product or service provided by Recipient, or that may seek to obtain commercial
155− advantage by the fact of Government Agency's or a prior Recipient's participation in this Agreement.
156−
157− F. In an effort to track usage and maintain accurate records of the Subject Software, each Recipient,
158− upon receipt of the Subject Software, is requested to register with Government Agency by visiting the
159− following website: https://naspi.tva.com/Registration/. Recipient's name and personal information
160− shall be used for statistical purposes only. Once a Recipient makes a Modification available, it is
161− requested that the Recipient inform Government Agency at the web site provided above how to access the
162− Modification.
163−
164− G. Each Contributor represents that that its Modification does not violate any existing agreements,
165− regulations, statutes or rules, and further that Contributor has sufficient rights to grant the rights
166− conveyed by this Agreement.
167−
168− H. A Recipient may choose to offer, and to charge a fee for, warranty, support, indemnity and/or
169− liability obligations to one or more other Recipients of the Subject Software. A Recipient may do so,
170− however, only on its own behalf and not on behalf of Government Agency or any other Recipient. Such a
171− Recipient must make it absolutely clear that any such warranty, support, indemnity and/or liability
172− obligation is offered by that Recipient alone. Further, such Recipient agrees to indemnify Government
173− Agency and every other Recipient for any liability incurred by them as a result of warranty, support,
174− indemnity and/or liability offered by such Recipient.
175−
176− I. A Recipient may create a Larger Work by combining Subject Software with separate software not
177− governed by the terms of this agreement and distribute the Larger Work as a single product. In such
178− case, the Recipient must make sure Subject Software, or portions thereof, included in the Larger Work
179− is subject to this Agreement.
180−
181− J. Notwithstanding any provisions contained herein, Recipient is hereby put on notice that export of
182− any goods or technical data from the United States may require some form of export license from the
183− U.S. Government. Failure to obtain necessary export licenses may result in criminal liability under
184− U.S. laws. Government Agency neither represents that a license shall not be required nor that, if
185− required, it shall be issued. Nothing granted herein provides any such export license.
186−
187− 4. DISCLAIMER OF WARRANTIES AND LIABILITIES; WAIVER AND INDEMNIFICATION
188−
189− A. No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY KIND, EITHER
190− EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY THAT THE SUBJECT
191− SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
192− PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE ERROR
193− FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. THIS
194− AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR
195− RECIPIENT OF ANY RESULTS, RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS
196− RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY DISCLAIMS ALL WARRANTIES AND
197− LIABILITIES REGARDING THIRD-PARTY SOFTWARE, IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT
198− "AS IS."
199−
200− B. Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST GOVERNMENT AGENCY, ITS
201− AGENTS, EMPLOYEES, CONTRACTORS AND SUBCONTRACTORS, AS WELL AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE
202− OF THE SUBJECT SOFTWARE RESULTS IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM
203− SUCH USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, RECIPIENT'S USE OF THE
204− SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD HARMLESS GOVERNMENT AGENCY, ITS AGENTS,
205− EMPLOYEES, CONTRACTORS AND SUBCONTRACTORS, AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY
206− LAW. THE FOREGOING RELEASE AND INDEMNIFICATION SHALL APPLY EVEN IF THE LIABILITIES, DEMANDS, DAMAGES,
207− EXPENSES OR LOSSES ARE CAUSED, OCCASIONED, OR CONTRIBUTED TO BY THE NEGLIGENCE, SOLE OR CONCURRENT, OF
208− GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT. RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE
209− IMMEDIATE, UNILATERAL TERMINATION OF THIS AGREEMENT.
210−
211− 5. GENERAL TERMS
212−
213− A. Termination: This Agreement and the rights granted hereunder will terminate automatically if a
214− Recipient fails to comply with these terms and conditions, and fails to cure such noncompliance within
215− thirty (30) days of becoming aware of such noncompliance. Upon termination, a Recipient agrees to
216− immediately cease use and distribution of the Subject Software. All sublicenses to the Subject
217− Software properly granted by the breaching Recipient shall survive any such termination of this
218− Agreement.
219−
220− B. Severability: If any provision of this Agreement is invalid or unenforceable under applicable law,
221− it shall not affect the validity or enforceability of the remainder of the terms of this Agreement.
222−
223− C. Applicable Law: This Agreement shall be subject to United States federal law only for all purposes,
224− including, but not limited to, determining the validity of this Agreement, the meaning of its
225− provisions and the rights, obligations and remedies of the parties.
226−
227− D. Entire Understanding: This Agreement constitutes the entire understanding and agreement of the
228− parties relating to release of the Subject Software and may not be superseded, modified or amended
229− except by further written agreement duly executed by the parties.
230−
231− E. Binding Authority: By accepting and using the Subject Software under this Agreement, a Recipient
232− affirms its authority to bind the Recipient to all terms and conditions of this Agreement and that
233− Recipient hereby agrees to all terms and conditions herein.
234−
235− F. Point of Contact: Any Recipient contact with Government Agency is to be directed to the designated
236− representative as follows: J. Ritchie Carroll <mailto:jrcarrol@tva.gov>.
237−
238−*/
239−#endregion
240−
241−#region [ Contributor License Agreements ]
242−
243−//******************************************************************************************************
244−//
245−// Copyright © 2011, Grid Protection Alliance. All Rights Reserved.
246−//
247−// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may
248−// not use this file except in compliance with the License. You may obtain a copy of the License at:
249−//
250−// http://www.opensource.org/licenses/eclipse-1.0.php
251−//
252−// Unless agreed to in writing, the subject software distributed under the License is distributed on an
253−// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
254−// License for the specific language governing permissions and limitations.
255−//
256−//******************************************************************************************************
257−
258−#endregion
259−
260−#pragma warning disable 0809
261−
262−using GSF.Collections;
263−using System;
264−using System.Collections.Concurrent;
265−using System.Collections.Generic;
266−using System.ComponentModel;
267−using System.Text;
268−using System.Threading;
269−
270−namespace GSF.Parsing
271−{
272− /// <summary>
273− /// This class defines a basic implementation of parsing functionality suitable for automating the parsing of multiple
274− /// binary data streams, each represented as frames with common headers and returning the parsed data via an event.
275− /// </summary>
276− /// <remarks>
277− /// <para>
278− /// This parser is designed as a write-only stream such that data can come from any source.
279− /// </para>
280− /// <para>
281− /// This class is more specific than the <see cref="BinaryImageParserBase"/> in that it can automate the parsing of a
282− /// particular protocol that is formatted as a series of frames that have a common method of identification.
283− /// Automation of type creation occurs by loading implementations of common types that implement the
284− /// <see cref="ISupportSourceIdentifiableFrameImage{TSourceIdentifier,TTypeIdentifier}"/> interface. The common method of
285− /// identification is handled by creating a class derived from the <see cref="ICommonHeader{TTypeIdentifier}"/> which primarily
286− /// includes a TypeID property, but also should include any state information needed to parse a particular frame if necessary.
287− /// Derived classes override the <see cref="FrameImageParserBase{TTypeIdentifier, TOutputType}.ParseCommonHeader"/>
288− /// method in order to parse the <see cref="ICommonHeader{TTypeIdentifier}"/> from a provided binary image.
289− /// </para>
290− /// </remarks>
291− /// <typeparam name="TSourceIdentifier">Type of identifier for the data source.</typeparam>
292− /// <typeparam name="TTypeIdentifier">Type of identifier used to distinguish output types.</typeparam>
293− /// <typeparam name="TOutputType">Type of the interface or class used to represent outputs.</typeparam>
294− public abstract class MultiSourceFrameImageParserBase<TSourceIdentifier, TTypeIdentifier, TOutputType> : FrameImageParserBase<TTypeIdentifier, TOutputType> where TOutputType : ISupportSourceIdentifiableFrameImage<TSourceIdentifier, TTypeIdentifier>
295− {
296− #region [ Members ]
297−
298− // Nested Types
299−
300− /// <summary>
301− /// Represents a source identifiable buffer.
302− /// </summary>
303− /// <remarks>
304− /// This class implements <see cref="ISupportLifecycle"/> such that it will support
305− /// automatic object pool handling, e.g., returning object to pool when disposed.
306− /// </remarks>
307− public class SourceIdentifiableBuffer : ISupportLifecycle
308− {
309− #region [ Members ]
310−
311− // Events
312−
313− /// <summary>
314− /// Occurs when <see cref="SourceIdentifiableBuffer"/> is disposed.
315− /// </summary>
316− public event EventHandler Disposed;
317−
318− // Fields
319−
320− /// <summary>
321− /// Defines the source identifier of the <see cref="Buffer"/>.
322− /// </summary>
323− public TSourceIdentifier Source;
324−
325− /// <summary>
326− /// Defines the buffer which is identifiable by its associated <see cref="Source"/>.
327− /// </summary>
328− public byte[] Buffer;
329−
330− private int m_count;
331− private bool m_disposed;
332−
333− #endregion
334−
335− #region [ Constructors ]
336−
337− /// <summary>
338− /// Releases the unmanaged resources before the <see cref="SourceIdentifiableBuffer"/> object is reclaimed by <see cref="GC"/>.
339− /// </summary>
340− ~SourceIdentifiableBuffer()
341− {
342− Dispose(false);
343− }
344−
345− #endregion
346−
347− #region [ Properties ]
348−
349− /// <summary>
350− /// Gets or sets enabled state of <see cref="SourceIdentifiableBuffer"/>.
351− /// </summary>
352− public bool Enabled
353− {
354− get;
355− set;
356− }
357−
358− /// <summary>
359− /// Gets or sets valid number of bytes within the <see cref="Buffer"/>.
360− /// </summary>
361− /// <remarks>
362− /// This property will automatically initialize buffer. Set to zero to release buffer.
363− /// </remarks>
364− public int Count
365− {
366− get
367− {
368− return m_count;
369− }
370− set
371− {
372− m_count = value;
373−
374− if ((object)Buffer != null)
375− BufferPool.ReturnBuffer(Buffer);
376−
377− if (m_count > 0)
378− Buffer = BufferPool.TakeBuffer(m_count);
379− else
380− Buffer = null;
381− }
382− }
383−
384− #endregion
385−
386− #region [ Methods ]
387−
388− /// <summary>
389− /// Releases all the resources used by the <see cref="SourceIdentifiableBuffer"/> object.
390− /// </summary>
391− public void Dispose()
392− {
393− Dispose(true);
394− GC.SuppressFinalize(this);
395− }
396−
397− /// <summary>
398− /// Releases the unmanaged resources used by the <see cref="SourceIdentifiableBuffer"/> object and optionally releases the managed resources.
399− /// </summary>
400− /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
401− protected virtual void Dispose(bool disposing)
402− {
403− if (!m_disposed)
404− {
405− try
406− {
407− // Return any existing buffer to the pool
408− Count = 0;
409− }
410− finally
411− {
412− m_disposed = true; // Prevent duplicate dispose.
413−
414− if (Disposed != null)
415− Disposed(this, EventArgs.Empty);
416− }
417− }
418− }
419−
420− /// <summary>
421− /// Initializes (or reinitializes) <see cref="SourceIdentifiableBuffer"/> state.
422− /// </summary>
423− public void Initialize()
424− {
425− // Undispose class instance if it is being reused
426− if (m_disposed)
427− {
428− m_disposed = false;
429− GC.ReRegisterForFinalize(this);
430− }
431− }
432−
433− #endregion
434− }
435−
436− // Fields
437− private ProcessQueue<SourceIdentifiableBuffer> m_bufferQueue;
438− private readonly ConcurrentDictionary<TSourceIdentifier, bool> m_sourceInitialized;
439− private readonly ConcurrentDictionary<TSourceIdentifier, byte[]> m_unparsedBuffers;
440− private TSourceIdentifier m_source;
441− private bool m_disposed;
442−
443− #endregion
444−
445− #region [ Constructors ]
446−
447− /// <summary>
448− /// Creates a new instance of the <see cref="MultiSourceFrameImageParserBase{TSourceIdentifier,TTypeIdentifier,TOutputType}"/> class.
449− /// </summary>
450− protected MultiSourceFrameImageParserBase()
451− {
452− m_bufferQueue = CreateBufferQueue();
453− m_bufferQueue.ProcessException += ProcessExceptionHandler;
454−
455− if (ProtocolUsesSyncBytes)
456− m_sourceInitialized = new ConcurrentDictionary<TSourceIdentifier, bool>();
457−
458− m_unparsedBuffers = new ConcurrentDictionary<TSourceIdentifier, byte[]>();
459− }
460−
461− #endregion
462−
463− #region [ Properties ]
464−
465− /// <summary>
466− /// Gets the total number of buffers that are currently queued for processing, if any.
467− /// </summary>
468− public virtual int QueuedBuffers
469− {
470− get
471− {
472− if ((object)m_bufferQueue != null)
473− return m_bufferQueue.Count;
474−
475− return 0;
476− }
477− }
478−
479− /// <summary>
480− /// Gets the current run-time statistics of the <see cref="MultiSourceFrameImageParserBase{TSourceIdentifier,TTypeIdentifier,TOutputType}"/>.
481− /// </summary>
482− public virtual ProcessQueueStatistics CurrentStatistics
483− {
484− get
485− {
486− return m_bufferQueue.CurrentStatistics;
487− }
488− }
489−
490− /// <summary>
491− /// Gets current status of <see cref="MultiSourceFrameImageParserBase{TSourceIdentifier,TTypeIdentifier,TOutputType}"/>.
492− /// </summary>
493− public override string Status
494− {
495− get
496− {
497− StringBuilder status = new StringBuilder();
498−
499− status.Append(base.Status);
500− status.Append(m_bufferQueue.Status);
501−
502− return status.ToString();
503− }
504− }
505−
506− #endregion
507−
508− #region [ Methods ]
509−
510− /// <summary>
511− /// Releases the unmanaged resources used by the <see cref="MultiSourceFrameImageParserBase{TSourceIdentifier,TTypeIdentifier,TOutputType}"/> object and optionally releases the managed resources.
512− /// </summary>
513− /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
514− protected override void Dispose(bool disposing)
515− {
516− if (!m_disposed)
517− {
518− try
519− {
520− if (disposing)
521− {
522− if ((object)m_bufferQueue != null)
523− {
524− m_bufferQueue.ProcessException -= ProcessExceptionHandler;
525− m_bufferQueue.Dispose();
526− }
527− m_bufferQueue = null;
528− }
529− }
530− finally
531− {
532− m_disposed = true; // Prevent duplicate dispose.
533− base.Dispose(disposing); // Call base class Dispose().
534− }
535− }
536− }
537−
538− /// <summary>
539− /// Start the streaming data parser.
540− /// </summary>
541− public override void Start()
542− {
543− base.Start();
544−
545− if ((object)m_sourceInitialized != null)
546− m_sourceInitialized.Clear();
547−
548− m_unparsedBuffers.Clear();
549− m_bufferQueue.Start();
550− }
551−
552− /// <summary>
553− /// Starts the data parser given the specified type implementations.
554− /// </summary>
555− /// <param name="implementations">Output type implementations to establish for the parser.</param>
556− public override void Start(IEnumerable<Type> implementations)
557− {
558− base.Start(implementations);
559−
560− if ((object)m_sourceInitialized != null)
561− m_sourceInitialized.Clear();
562−
563− m_unparsedBuffers.Clear();
564− m_bufferQueue.Start();
565− }
566−
567− /// <summary>
568− /// Stops the streaming data parser.
569− /// </summary>
570− public override void Stop()
571− {
572− m_bufferQueue.Stop();
573− base.Stop();
574− }
575−
576− /// <summary>
577− /// Queues a sequence of bytes, from the specified data source, onto the stream for parsing.
578− /// </summary>
579− /// <param name="source">Identifier of the data source.</param>
580− /// <param name="buffer">An array of bytes to queue for parsing</param>
581− public virtual void Parse(TSourceIdentifier source, byte[] buffer)
582− {
583− if ((object)buffer == null)
584− throw new ArgumentNullException("buffer");
585−
586− Parse(source, buffer, 0, buffer.Length);
587− }
588−
589− /// <summary>
590− /// Queues a sequence of bytes, from the specified data source, onto the stream for parsing.
591− /// </summary>
592− /// <param name="source">Identifier of the data source.</param>
593− /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the queue.</param>
594− /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current stream.</param>
595− /// <param name="count">The number of bytes to be written to the current stream.</param>
596− /// <remarks>
597− /// This method associates a buffer with its data source identifier.
598− /// </remarks>
599− public virtual void Parse(TSourceIdentifier source, byte[] buffer, int offset, int count)
600− {
601− SourceIdentifiableBuffer identifiableBuffer = null;
602−
603− buffer.ValidateParameters(offset, count);
604−
605− try
606− {
607− // Get an identifiable buffer object
608− identifiableBuffer = ReusableObjectPool<SourceIdentifiableBuffer>.Default.TakeObject();
609− identifiableBuffer.Source = source;
610− identifiableBuffer.Count = count;
611−
612− // Copy buffer data for processing (destination buffer preallocated from buffer pool)
613− Buffer.BlockCopy(buffer, offset, identifiableBuffer.Buffer, 0, count);
614−
615− // Add buffer to the queue for parsing
616− m_bufferQueue.Add(identifiableBuffer);
617− }
618− catch
619− {
620− // Return source buffer to object pool if we failed to queue it for processing
621− if ((object)identifiableBuffer != null)
622− identifiableBuffer.Dispose();
623−
624− throw;
625− }
626− }
627−
628− /// <summary>
629− /// Queues the object implementing the <see cref="ISupportBinaryImage"/> interface, from the specified data source, onto the stream for parsing.
630− /// </summary>
631− /// <param name="source">Identifier of the data source.</param>
632− /// <param name="image">Object to be parsed that implements the <see cref="ISupportBinaryImage"/> interface.</param>
633− /// <remarks>
634− /// This method takes the binary image from <see cref="ISupportBinaryImage"/> and writes the buffer to the <see cref="BinaryImageParserBase"/> stream for parsing.
635− /// </remarks>
636− public virtual void Parse(TSourceIdentifier source, ISupportBinaryImage image)
637− {
638− Parse(source, image.BinaryImage());
639− }
640−
641− /// <summary>
642− /// Clears the internal buffer of unparsed data received from the specified <paramref name="source"/>.
643− /// </summary>
644− /// <param name="source">Identifier of the data source.</param>
645− /// <remarks>
646− /// This method can be used to ensure that partial data received from the <paramref name="source"/> is not kept in memory indefinitely.
647− /// </remarks>
648− public virtual void PurgeBuffer(TSourceIdentifier source)
649− {
650− byte[] buffer;
651− m_unparsedBuffers.TryRemove(source, out buffer);
652− }
653−
654− /// <summary>
655− /// Not implemented. Consumers should call the <see cref="Parse(TSourceIdentifier,ISupportBinaryImage)"/> method instead to make sure data source source ID gets tracked with data buffer.
656− /// </summary>
657− /// <exception cref="NotImplementedException">This method should not be called directly.</exception>
658− /// <param name="image">A <see cref="ISupportBinaryImage"/>.</param>
659− [EditorBrowsable(EditorBrowsableState.Never), Obsolete("MultiSourceFrameImageParserBase requires consumers call Parse overload that takes data source identifier as an argument", true)]
660− public override void Parse(ISupportBinaryImage image)
661− {
662− throw new NotImplementedException("This method should not be called directly, call the Parse(TSourceIdentifier,ISupportBinaryImage) method to queue data for parsing instead.");
663− }
664−
665− /// <summary>
666− /// Not implemented. Consumers should call the <see cref="Parse(TSourceIdentifier,byte[],int,int)"/> method instead to make sure data source source ID gets tracked with data buffer.
667− /// </summary>
668− /// <exception cref="NotImplementedException">This method should not be called directly.</exception>
669− /// <param name="buffer">A <see cref="Byte"/> array.</param>
670− /// <param name="count">An <see cref="Int32"/> for the offset.</param>
671− /// <param name="offset">An <see cref="Int32"/> for the count.</param>
672− [EditorBrowsable(EditorBrowsableState.Never), Obsolete("MultiSourceFrameImageParserBase requires consumers call Parse overload that takes data source identifier as an argument", true)]
673− public override void Write(byte[] buffer, int offset, int count)
674− {
675− throw new NotImplementedException("This method should not be called directly, call the Parse(TSourceIdentifier,byte[],int,int) method to queue data for parsing instead.");
676− }
677−
678− /// <summary>
679− /// Clears all buffers for this stream and causes any buffered data to be parsed immediately.
680− /// </summary>
681− /// <remarks>
682− /// <para>
683− /// If the user has called <see cref="Start()"/> method, this method will process all remaining buffers on the calling thread until all
684− /// queued buffers have been parsed - the <see cref="MultiSourceFrameImageParserBase{TSourceIdentifier,TTypeIdentifier,TOutputType}"/>
685− /// will then be automatically stopped. This method is typically called on shutdown to make sure any remaining queued buffers get
686− /// parsed before the class instance is destructed.
687− /// </para>
688− /// <para>
689− /// It is possible for items to be queued while the flush is executing. The flush will continue to parse buffers as quickly
690− /// as possible until the internal buffer queue is empty. Unless the user stops queueing data to be parsed (i.e. calling the
691− /// <see cref="Parse(TSourceIdentifier,byte[])"/> method), the flush call may never return (not a happy situtation on shutdown).
692− /// </para>
693− /// <para>
694− /// The <see cref="MultiSourceFrameImageParserBase{TSourceIdentifier,TTypeIdentifier,TOutputType}"/> does not clear queue prior to destruction.
695− /// If the user fails to call this method before the class is destructed, there may be data that remains unparsed in the internal buffer.
696− /// </para>
697− /// </remarks>
698− public override void Flush()
699− {
700− m_bufferQueue.Flush();
701− }
702−
703− /// <summary>
704− /// Creates the internal buffer queue.
705− /// </summary>
706− /// <remarks>
707− /// <para>
708− /// This method is virtual to allow derived classes to customize the style of processing queue used when consumers
709− /// choose to implement an internal buffer queue. Default type is a real-time queue with the default settings.
710− /// When overriding, use the <see cref="ParseQueuedBuffers"/> method for the <see cref="ProcessQueue{T}"/>) item
711− /// processing delegate.
712− /// </para>
713− /// <para>
714− /// Note that current design only supports serial processing - consumer overriding this method to return an asynchronous
715− /// process queue to process multiple items at once on separate threads will need to redesign the processing delegate.
716− /// </para>
717− /// </remarks>
718− /// <returns>New internal buffer processing queue (i.e., a new <see cref="ProcessQueue{T}"/>).</returns>
719− protected virtual ProcessQueue<SourceIdentifiableBuffer> CreateBufferQueue()
720− {
721− return ProcessQueue<SourceIdentifiableBuffer>.CreateRealTimeQueue(ParseQueuedBuffers);
722− }
723−
724− /// <summary>
725− /// This method is used by the internal <see cref="ProcessQueue{T}"/> to process all queued data buffers.
726− /// </summary>
727− /// <param name="buffers">Identifiable buffers to process.</param>
728− /// <remarks>
729− /// This is the <see cref="SourceIdentifiableBuffer"/> processing delegate to use when overriding the <see cref="CreateBufferQueue"/> method.
730− /// </remarks>
731− protected virtual void ParseQueuedBuffers(SourceIdentifiableBuffer[] buffers)
732− {
733− // Process all queued data buffers...
734− foreach (SourceIdentifiableBuffer buffer in buffers)
735− {
736− // Track current buffer source
737− m_source = buffer.Source;
738−
739− // Check to see if this data source has been initialized
740− if ((object)m_sourceInitialized != null)
741− StreamInitialized = m_sourceInitialized.GetOrAdd(m_source, true);
742−
743− // Restore any unparsed buffers for this data source, if any
744− UnparsedBuffer = m_unparsedBuffers.GetOrAdd(m_source, (byte[])null);
745−
746− // Start parsing sequence for this buffer - this will begin publication of new parsed outputs
747− base.Write(buffer.Buffer, 0, buffer.Count);
748−
749− // Track last unparsed buffer for this data source
750− m_unparsedBuffers[m_source] = UnparsedBuffer;
751− }
752−
753− // Dispose of source buffers - no rush
754− ThreadPool.QueueUserWorkItem(DisposeSourceBuffers, buffers);
755− }
756−
757− // Handle disposing of source buffers (this will return items to the resuable object pool)
758− private void DisposeSourceBuffers(object state)
759− {
760− SourceIdentifiableBuffer[] buffers = state as SourceIdentifiableBuffer[];
761−
762− if ((object)buffers != null)
763− {
764− foreach (SourceIdentifiableBuffer buffer in buffers)
765− {
766− if ((object)buffer != null)
767− buffer.Dispose();
768− }
769− }
770− }
771−
772− /// <summary>
773− /// Raises the <see cref="FrameImageParserBase{TTypeIdentifier, TOutputType}.DataParsed"/> event.
774− /// </summary>
775− /// <param name="output">The object that was deserialized from binary image.</param>
776− protected override void OnDataParsed(TOutputType output)
777− {
778− // Make sure output gets associated with its data source prior to publication
779− output.Source = m_source;
780−
781− base.OnDataParsed(output);
782− }
783−
784− /// <summary>
785− /// Raises the <see cref="BinaryImageParserBase.DataDiscarded"/> event.
786− /// </summary>
787− /// <param name="buffer">Source buffer that contains output that failed to parse.</param>
788− protected override void OnDataDiscarded(byte[] buffer)
789− {
790− // If an error occurs during parsing from a data source, we reset its initialization state
791− if ((object)m_sourceInitialized != null)
792− m_sourceInitialized[m_source] = false;
793−
794− base.OnDataDiscarded(buffer);
795− }
796−
797− // We just bubble any exceptions captured in process queue out to parsing exception event...
798− private void ProcessExceptionHandler(object sender, EventArgs<Exception> e)
799− {
800− OnParsingException(e.Argument);
801− }
802−
803− #endregion
804− }
805−}
1+//*******************************************************************************************************
2+// MultiSourceFrameImageParserBase.cs - Gbtc
3+//
4+// Tennessee Valley Authority, 2011
5+// No copyright is claimed pursuant to 17 USC § 105. All Other Rights Reserved.
6+//
7+// This software is made freely available under the TVA Open Source Agreement (see below).
8+// Code in this file licensed to GSF under one or more contributor license agreements listed below.
9+//
10+// Code Modification History:
11+// -----------------------------------------------------------------------------------------------------
12+// 12/03/2008 - J. Ritchie Carroll
13+// Generated original version of source code.
14+// 06/19/2009 - Pinal C. Patel
15+// Parsed output is now being delivered in a new collection instead of reusing a single collection.
16+// 08/07/2009 - Josh L. Patterson
17+// Edited Comments.
18+// 09/14/2009 - Stephen C. Wills
19+// Added new header and license agreement.
20+// 11/01/2012 - J. Ritchie Carroll
21+// Updated to use concurrent dictionaries and new recreate parsed output list.
22+//
23+//*******************************************************************************************************
24+
25+#region [ TVA Open Source Agreement ]
26+/*
27+
28+ THIS OPEN SOURCE AGREEMENT ("AGREEMENT") DEFINES THE RIGHTS OF USE,REPRODUCTION, DISTRIBUTION,
29+ MODIFICATION AND REDISTRIBUTION OF CERTAIN COMPUTER SOFTWARE ORIGINALLY RELEASED BY THE
30+ TENNESSEE VALLEY AUTHORITY, A CORPORATE AGENCY AND INSTRUMENTALITY OF THE UNITED STATES GOVERNMENT
31+ ("GOVERNMENT AGENCY"). GOVERNMENT AGENCY IS AN INTENDED THIRD-PARTY BENEFICIARY OF ALL SUBSEQUENT
32+ DISTRIBUTIONS OR REDISTRIBUTIONS OF THE SUBJECT SOFTWARE. ANYONE WHO USES, REPRODUCES, DISTRIBUTES,
33+ MODIFIES OR REDISTRIBUTES THE SUBJECT SOFTWARE, AS DEFINED HEREIN, OR ANY PART THEREOF, IS, BY THAT
34+ ACTION, ACCEPTING IN FULL THE RESPONSIBILITIES AND OBLIGATIONS CONTAINED IN THIS AGREEMENT.
35+
36+ Original Software Designation: openPDC
37+ Original Software Title: The GSF Open Source Phasor Data Concentrator
38+ User Registration Requested. Please Visit https://naspi.tva.com/Registration/
39+ Point of Contact for Original Software: J. Ritchie Carroll <mailto:jrcarrol@tva.gov>
40+
41+ 1. DEFINITIONS
42+
43+ A. "Contributor" means Government Agency, as the developer of the Original Software, and any entity
44+ that makes a Modification.
45+
46+ B. "Covered Patents" mean patent claims licensable by a Contributor that are necessarily infringed by
47+ the use or sale of its Modification alone or when combined with the Subject Software.
48+
49+ C. "Display" means the showing of a copy of the Subject Software, either directly or by means of an
50+ image, or any other device.
51+
52+ D. "Distribution" means conveyance or transfer of the Subject Software, regardless of means, to
53+ another.
54+
55+ E. "Larger Work" means computer software that combines Subject Software, or portions thereof, with
56+ software separate from the Subject Software that is not governed by the terms of this Agreement.
57+
58+ F. "Modification" means any alteration of, including addition to or deletion from, the substance or
59+ structure of either the Original Software or Subject Software, and includes derivative works, as that
60+ term is defined in the Copyright Statute, 17 USC § 101. However, the act of including Subject Software
61+ as part of a Larger Work does not in and of itself constitute a Modification.
62+
63+ G. "Original Software" means the computer software first released under this Agreement by Government
64+ Agency entitled openPDC, including source code, object code and accompanying documentation, if any.
65+
66+ H. "Recipient" means anyone who acquires the Subject Software under this Agreement, including all
67+ Contributors.
68+
69+ I. "Redistribution" means Distribution of the Subject Software after a Modification has been made.
70+
71+ J. "Reproduction" means the making of a counterpart, image or copy of the Subject Software.
72+
73+ K. "Sale" means the exchange of the Subject Software for money or equivalent value.
74+
75+ L. "Subject Software" means the Original Software, Modifications, or any respective parts thereof.
76+
77+ M. "Use" means the application or employment of the Subject Software for any purpose.
78+
79+ 2. GRANT OF RIGHTS
80+
81+ A. Under Non-Patent Rights: Subject to the terms and conditions of this Agreement, each Contributor,
82+ with respect to its own contribution to the Subject Software, hereby grants to each Recipient a
83+ non-exclusive, world-wide, royalty-free license to engage in the following activities pertaining to
84+ the Subject Software:
85+
86+ 1. Use
87+
88+ 2. Distribution
89+
90+ 3. Reproduction
91+
92+ 4. Modification
93+
94+ 5. Redistribution
95+
96+ 6. Display
97+
98+ B. Under Patent Rights: Subject to the terms and conditions of this Agreement, each Contributor, with
99+ respect to its own contribution to the Subject Software, hereby grants to each Recipient under Covered
100+ Patents a non-exclusive, world-wide, royalty-free license to engage in the following activities
101+ pertaining to the Subject Software:
102+
103+ 1. Use
104+
105+ 2. Distribution
106+
107+ 3. Reproduction
108+
109+ 4. Sale
110+
111+ 5. Offer for Sale
112+
113+ C. The rights granted under Paragraph B. also apply to the combination of a Contributor's Modification
114+ and the Subject Software if, at the time the Modification is added by the Contributor, the addition of
115+ such Modification causes the combination to be covered by the Covered Patents. It does not apply to
116+ any other combinations that include a Modification.
117+
118+ D. The rights granted in Paragraphs A. and B. allow the Recipient to sublicense those same rights.
119+ Such sublicense must be under the same terms and conditions of this Agreement.
120+
121+ 3. OBLIGATIONS OF RECIPIENT
122+
123+ A. Distribution or Redistribution of the Subject Software must be made under this Agreement except for
124+ additions covered under paragraph 3H.
125+
126+ 1. Whenever a Recipient distributes or redistributes the Subject Software, a copy of this Agreement
127+ must be included with each copy of the Subject Software; and
128+
129+ 2. If Recipient distributes or redistributes the Subject Software in any form other than source code,
130+ Recipient must also make the source code freely available, and must provide with each copy of the
131+ Subject Software information on how to obtain the source code in a reasonable manner on or through a
132+ medium customarily used for software exchange.
133+
134+ B. Each Recipient must ensure that the following copyright notice appears prominently in the Subject
135+ Software:
136+
137+ No copyright is claimed pursuant to 17 USC § 105. All Other Rights Reserved.
138+
139+ C. Each Contributor must characterize its alteration of the Subject Software as a Modification and
140+ must identify itself as the originator of its Modification in a manner that reasonably allows
141+ subsequent Recipients to identify the originator of the Modification. In fulfillment of these
142+ requirements, Contributor must include a file (e.g., a change log file) that describes the alterations
143+ made and the date of the alterations, identifies Contributor as originator of the alterations, and
144+ consents to characterization of the alterations as a Modification, for example, by including a
145+ statement that the Modification is derived, directly or indirectly, from Original Software provided by
146+ Government Agency. Once consent is granted, it may not thereafter be revoked.
147+
148+ D. A Contributor may add its own copyright notice to the Subject Software. Once a copyright notice has
149+ been added to the Subject Software, a Recipient may not remove it without the express permission of
150+ the Contributor who added the notice.
151+
152+ E. A Recipient may not make any representation in the Subject Software or in any promotional,
153+ advertising or other material that may be construed as an endorsement by Government Agency or by any
154+ prior Recipient of any product or service provided by Recipient, or that may seek to obtain commercial
155+ advantage by the fact of Government Agency's or a prior Recipient's participation in this Agreement.
156+
157+ F. In an effort to track usage and maintain accurate records of the Subject Software, each Recipient,
158+ upon receipt of the Subject Software, is requested to register with Government Agency by visiting the
159+ following website: https://naspi.tva.com/Registration/. Recipient's name and personal information
160+ shall be used for statistical purposes only. Once a Recipient makes a Modification available, it is
161+ requested that the Recipient inform Government Agency at the web site provided above how to access the
162+ Modification.
163+
164+ G. Each Contributor represents that that its Modification does not violate any existing agreements,
165+ regulations, statutes or rules, and further that Contributor has sufficient rights to grant the rights
166+ conveyed by this Agreement.
167+
168+ H. A Recipient may choose to offer, and to charge a fee for, warranty, support, indemnity and/or
169+ liability obligations to one or more other Recipients of the Subject Software. A Recipient may do so,
170+ however, only on its own behalf and not on behalf of Government Agency or any other Recipient. Such a
171+ Recipient must make it absolutely clear that any such warranty, support, indemnity and/or liability
172+ obligation is offered by that Recipient alone. Further, such Recipient agrees to indemnify Government
173+ Agency and every other Recipient for any liability incurred by them as a result of warranty, support,
174+ indemnity and/or liability offered by such Recipient.
175+
176+ I. A Recipient may create a Larger Work by combining Subject Software with separate software not
177+ governed by the terms of this agreement and distribute the Larger Work as a single product. In such
178+ case, the Recipient must make sure Subject Software, or portions thereof, included in the Larger Work
179+ is subject to this Agreement.
180+
181+ J. Notwithstanding any provisions contained herein, Recipient is hereby put on notice that export of
182+ any goods or technical data from the United States may require some form of export license from the
183+ U.S. Government. Failure to obtain necessary export licenses may result in criminal liability under
184+ U.S. laws. Government Agency neither represents that a license shall not be required nor that, if
185+ required, it shall be issued. Nothing granted herein provides any such export license.
186+
187+ 4. DISCLAIMER OF WARRANTIES AND LIABILITIES; WAIVER AND INDEMNIFICATION
188+
189+ A. No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY KIND, EITHER
190+ EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY THAT THE SUBJECT
191+ SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
192+ PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE ERROR
193+ FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. THIS
194+ AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR
195+ RECIPIENT OF ANY RESULTS, RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS
196+ RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY DISCLAIMS ALL WARRANTIES AND
197+ LIABILITIES REGARDING THIRD-PARTY SOFTWARE, IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT
198+ "AS IS."
199+
200+ B. Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST GOVERNMENT AGENCY, ITS
201+ AGENTS, EMPLOYEES, CONTRACTORS AND SUBCONTRACTORS, AS WELL AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE
202+ OF THE SUBJECT SOFTWARE RESULTS IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM
203+ SUCH USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, RECIPIENT'S USE OF THE
204+ SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD HARMLESS GOVERNMENT AGENCY, ITS AGENTS,
205+ EMPLOYEES, CONTRACTORS AND SUBCONTRACTORS, AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY
206+ LAW. THE FOREGOING RELEASE AND INDEMNIFICATION SHALL APPLY EVEN IF THE LIABILITIES, DEMANDS, DAMAGES,
207+ EXPENSES OR LOSSES ARE CAUSED, OCCASIONED, OR CONTRIBUTED TO BY THE NEGLIGENCE, SOLE OR CONCURRENT, OF
208+ GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT. RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE
209+ IMMEDIATE, UNILATERAL TERMINATION OF THIS AGREEMENT.
210+
211+ 5. GENERAL TERMS
212+
213+ A. Termination: This Agreement and the rights granted hereunder will terminate automatically if a
214+ Recipient fails to comply with these terms and conditions, and fails to cure such noncompliance within
215+ thirty (30) days of becoming aware of such noncompliance. Upon termination, a Recipient agrees to
216+ immediately cease use and distribution of the Subject Software. All sublicenses to the Subject
217+ Software properly granted by the breaching Recipient shall survive any such termination of this
218+ Agreement.
219+
220+ B. Severability: If any provision of this Agreement is invalid or unenforceable under applicable law,
221+ it shall not affect the validity or enforceability of the remainder of the terms of this Agreement.
222+
223+ C. Applicable Law: This Agreement shall be subject to United States federal law only for all purposes,
224+ including, but not limited to, determining the validity of this Agreement, the meaning of its
225+ provisions and the rights, obligations and remedies of the parties.
226+
227+ D. Entire Understanding: This Agreement constitutes the entire understanding and agreement of the
228+ parties relating to release of the Subject Software and may not be superseded, modified or amended
229+ except by further written agreement duly executed by the parties.
230+
231+ E. Binding Authority: By accepting and using the Subject Software under this Agreement, a Recipient
232+ affirms its authority to bind the Recipient to all terms and conditions of this Agreement and that
233+ Recipient hereby agrees to all terms and conditions herein.
234+
235+ F. Point of Contact: Any Recipient contact with Government Agency is to be directed to the designated
236+ representative as follows: J. Ritchie Carroll <mailto:jrcarrol@tva.gov>.
237+
238+*/
239+#endregion
240+
241+#region [ Contributor License Agreements ]
242+
243+//******************************************************************************************************
244+//
245+// Copyright © 2011, Grid Protection Alliance. All Rights Reserved.
246+//
247+// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may
248+// not use this file except in compliance with the License. You may obtain a copy of the License at:
249+//
250+// http://www.opensource.org/licenses/eclipse-1.0.php
251+//
252+// Unless agreed to in writing, the subject software distributed under the License is distributed on an
253+// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
254+// License for the specific language governing permissions and limitations.
255+//
256+//******************************************************************************************************
257+
258+#endregion
259+
260+#pragma warning disable 0809
261+
262+using GSF.Collections;
263+using System;
264+using System.Collections.Concurrent;
265+using System.Collections.Generic;
266+using System.ComponentModel;
267+using System.Text;
268+using System.Threading;
269+
270+namespace GSF.Parsing
271+{
272+ /// <summary>
273+ /// This class defines a basic implementation of parsing functionality suitable for automating the parsing of multiple
274+ /// binary data streams, each represented as frames with common headers and returning the parsed data via an event.
275+ /// </summary>
276+ /// <remarks>
277+ /// <para>
278+ /// This parser is designed as a write-only stream such that data can come from any source.
279+ /// </para>
280+ /// <para>
281+ /// This class is more specific than the <see cref="BinaryImageParserBase"/> in that it can automate the parsing of a
282+ /// particular protocol that is formatted as a series of frames that have a common method of identification.
283+ /// Automation of type creation occurs by loading implementations of common types that implement the
284+ /// <see cref="ISupportSourceIdentifiableFrameImage{TSourceIdentifier,TTypeIdentifier}"/> interface. The common method of
285+ /// identification is handled by creating a class derived from the <see cref="ICommonHeader{TTypeIdentifier}"/> which primarily
286+ /// includes a TypeID property, but also should include any state information needed to parse a particular frame if necessary.
287+ /// Derived classes override the <see cref="FrameImageParserBase{TTypeIdentifier, TOutputType}.ParseCommonHeader"/>
288+ /// method in order to parse the <see cref="ICommonHeader{TTypeIdentifier}"/> from a provided binary image.
289+ /// </para>
290+ /// </remarks>
291+ /// <typeparam name="TSourceIdentifier">Type of identifier for the data source.</typeparam>
292+ /// <typeparam name="TTypeIdentifier">Type of identifier used to distinguish output types.</typeparam>
293+ /// <typeparam name="TOutputType">Type of the interface or class used to represent outputs.</typeparam>
294+ public abstract class MultiSourceFrameImageParserBase<TSourceIdentifier, TTypeIdentifier, TOutputType> : FrameImageParserBase<TTypeIdentifier, TOutputType> where TOutputType : ISupportSourceIdentifiableFrameImage<TSourceIdentifier, TTypeIdentifier>
295+ {
296+ #region [ Members ]
297+
298+ // Nested Types
299+
300+ /// <summary>
301+ /// Represents a source identifiable buffer.
302+ /// </summary>
303+ /// <remarks>
304+ /// This class implements <see cref="ISupportLifecycle"/> such that it will support
305+ /// automatic object pool handling, e.g., returning object to pool when disposed.
306+ /// </remarks>
307+ public class SourceIdentifiableBuffer : ISupportLifecycle
308+ {
309+ #region [ Members ]
310+
311+ // Events
312+
313+ /// <summary>
314+ /// Occurs when <see cref="SourceIdentifiableBuffer"/> is disposed.
315+ /// </summary>
316+ public event EventHandler Disposed;
317+
318+ // Fields
319+
320+ /// <summary>
321+ /// Defines the source identifier of the <see cref="Buffer"/>.
322+ /// </summary>
323+ public TSourceIdentifier Source;
324+
325+ /// <summary>
326+ /// Defines the buffer which is identifiable by its associated <see cref="Source"/>.
327+ /// </summary>
328+ public byte[] Buffer;
329+
330+ private int m_count;
331+ private bool m_disposed;
332+
333+ #endregion
334+
335+ #region [ Constructors ]
336+
337+ /// <summary>
338+ /// Releases the unmanaged resources before the <see cref="SourceIdentifiableBuffer"/> object is reclaimed by <see cref="GC"/>.
339+ /// </summary>
340+ ~SourceIdentifiableBuffer()
341+ {
342+ Dispose(false);
343+ }
344+
345+ #endregion
346+
347+ #region [ Properties ]
348+
349+ /// <summary>
350+ /// Gets or sets enabled state of <see cref="SourceIdentifiableBuffer"/>.
351+ /// </summary>
352+ public bool Enabled
353+ {
354+ get;
355+ set;
356+ }
357+
358+ /// <summary>
359+ /// Gets or sets valid number of bytes within the <see cref="Buffer"/>.
360+ /// </summary>
361+ /// <remarks>
362+ /// This property will automatically initialize buffer. Set to zero to release buffer.
363+ /// </remarks>
364+ public int Count
365+ {
366+ get
367+ {
368+ return m_count;
369+ }
370+ set
371+ {
372+ m_count = value;
373+
374+ if ((object)Buffer != null)
375+ BufferPool.ReturnBuffer(Buffer);
376+
377+ if (m_count > 0)
378+ Buffer = BufferPool.TakeBuffer(m_count);
379+ else
380+ Buffer = null;
381+ }
382+ }
383+
384+ #endregion
385+
386+ #region [ Methods ]
387+
388+ /// <summary>
389+ /// Releases all the resources used by the <see cref="SourceIdentifiableBuffer"/> object.
390+ /// </summary>
391+ public void Dispose()
392+ {
393+ Dispose(true);
394+ GC.SuppressFinalize(this);
395+ }
396+
397+ /// <summary>
398+ /// Releases the unmanaged resources used by the <see cref="SourceIdentifiableBuffer"/> object and optionally releases the managed resources.
399+ /// </summary>
400+ /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
401+ protected virtual void Dispose(bool disposing)
402+ {
403+ if (!m_disposed)
404+ {
405+ try
406+ {
407+ // Return any existing buffer to the pool
408+ Count = 0;
409+ }
410+ finally
411+ {
412+ m_disposed = true; // Prevent duplicate dispose.
413+
414+ if (Disposed != null)
415+ Disposed(this, EventArgs.Empty);
416+ }
417+ }
418+ }
419+
420+ /// <summary>
421+ /// Initializes (or reinitializes) <see cref="SourceIdentifiableBuffer"/> state.
422+ /// </summary>
423+ public void Initialize()
424+ {
425+ // Undispose class instance if it is being reused
426+ if (m_disposed)
427+ {
428+ m_disposed = false;
429+ GC.ReRegisterForFinalize(this);
430+ }
431+ }
432+
433+ #endregion
434+ }
435+
436+ // Fields
437+ private ProcessQueue<SourceIdentifiableBuffer> m_bufferQueue;
438+ private readonly ConcurrentDictionary<TSourceIdentifier, bool> m_sourceInitialized;
439+ private readonly ConcurrentDictionary<TSourceIdentifier, byte[]> m_unparsedBuffers;
440+ private TSourceIdentifier m_source;
441+ private bool m_disposed;
442+
443+ #endregion
444+
445+ #region [ Constructors ]
446+
447+ /// <summary>
448+ /// Creates a new instance of the <see cref="MultiSourceFrameImageParserBase{TSourceIdentifier,TTypeIdentifier,TOutputType}"/> class.
449+ /// </summary>
450+ protected MultiSourceFrameImageParserBase()
451+ {
452+ m_bufferQueue = CreateBufferQueue();
453+ m_bufferQueue.ProcessException += ProcessExceptionHandler;
454+
455+ if (ProtocolUsesSyncBytes)
456+ m_sourceInitialized = new ConcurrentDictionary<TSourceIdentifier, bool>();
457+
458+ m_unparsedBuffers = new ConcurrentDictionary<TSourceIdentifier, byte[]>();
459+ }
460+
461+ #endregion
462+
463+ #region [ Properties ]
464+
465+ /// <summary>
466+ /// Gets the total number of buffers that are currently queued for processing, if any.
467+ /// </summary>
468+ public virtual int QueuedBuffers
469+ {
470+ get
471+ {
472+ if ((object)m_bufferQueue != null)
473+ return m_bufferQueue.Count;
474+
475+ return 0;
476+ }
477+ }
478+
479+ /// <summary>
480+ /// Gets the current run-time statistics of the <see cref="MultiSourceFrameImageParserBase{TSourceIdentifier,TTypeIdentifier,TOutputType}"/>.
481+ /// </summary>
482+ public virtual ProcessQueueStatistics CurrentStatistics
483+ {
484+ get
485+ {
486+ return m_bufferQueue.CurrentStatistics;
487+ }
488+ }
489+
490+ /// <summary>
491+ /// Gets current status of <see cref="MultiSourceFrameImageParserBase{TSourceIdentifier,TTypeIdentifier,TOutputType}"/>.
492+ /// </summary>
493+ public override string Status
494+ {
495+ get
496+ {
497+ StringBuilder status = new StringBuilder();
498+
499+ status.Append(base.Status);
500+ status.Append(m_bufferQueue.Status);
501+
502+ return status.ToString();
503+ }
504+ }
505+
506+ #endregion
507+
508+ #region [ Methods ]
509+
510+ /// <summary>
511+ /// Releases the unmanaged resources used by the <see cref="MultiSourceFrameImageParserBase{TSourceIdentifier,TTypeIdentifier,TOutputType}"/> object and optionally releases the managed resources.
512+ /// </summary>
513+ /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
514+ protected override void Dispose(bool disposing)
515+ {
516+ if (!m_disposed)
517+ {
518+ try
519+ {
520+ if (disposing)
521+ {
522+ if ((object)m_bufferQueue != null)
523+ {
524+ m_bufferQueue.ProcessException -= ProcessExceptionHandler;
525+ m_bufferQueue.Dispose();
526+ }
527+ m_bufferQueue = null;
528+ }
529+ }
530+ finally
531+ {
532+ m_disposed = true; // Prevent duplicate dispose.
533+ base.Dispose(disposing); // Call base class Dispose().
534+ }
535+ }
536+ }
537+
538+ /// <summary>
539+ /// Start the streaming data parser.
540+ /// </summary>
541+ public override void Start()
542+ {
543+ base.Start();
544+
545+ if ((object)m_sourceInitialized != null)
546+ m_sourceInitialized.Clear();
547+
548+ m_unparsedBuffers.Clear();
549+ m_bufferQueue.Start();
550+ }
551+
552+ /// <summary>
553+ /// Starts the data parser given the specified type implementations.
554+ /// </summary>
555+ /// <param name="implementations">Output type implementations to establish for the parser.</param>
556+ public override void Start(IEnumerable<Type> implementations)
557+ {
558+ base.Start(implementations);
559+
560+ if ((object)m_sourceInitialized != null)
561+ m_sourceInitialized.Clear();
562+
563+ m_unparsedBuffers.Clear();
564+ m_bufferQueue.Start();
565+ }
566+
567+ /// <summary>
568+ /// Stops the streaming data parser.
569+ /// </summary>
570+ public override void Stop()
571+ {
572+ m_bufferQueue.Stop();
573+ base.Stop();
574+ }
575+
576+ /// <summary>
577+ /// Queues a sequence of bytes, from the specified data source, onto the stream for parsing.
578+ /// </summary>
579+ /// <param name="source">Identifier of the data source.</param>
580+ /// <param name="buffer">An array of bytes to queue for parsing</param>
581+ public virtual void Parse(TSourceIdentifier source, byte[] buffer)
582+ {
583+ if ((object)buffer == null)
584+ throw new ArgumentNullException("buffer");
585+
586+ Parse(source, buffer, 0, buffer.Length);
587+ }
588+
589+ /// <summary>
590+ /// Queues a sequence of bytes, from the specified data source, onto the stream for parsing.
591+ /// </summary>
592+ /// <param name="source">Identifier of the data source.</param>
593+ /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the queue.</param>
594+ /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current stream.</param>
595+ /// <param name="count">The number of bytes to be written to the current stream.</param>
596+ /// <remarks>
597+ /// This method associates a buffer with its data source identifier.
598+ /// </remarks>
599+ public virtual void Parse(TSourceIdentifier source, byte[] buffer, int offset, int count)
600+ {
601+ SourceIdentifiableBuffer identifiableBuffer = null;
602+
603+ buffer.ValidateParameters(offset, count);
604+
605+ try
606+ {
607+ // Get an identifiable buffer object
608+ identifiableBuffer = ReusableObjectPool<SourceIdentifiableBuffer>.Default.TakeObject();
609+ identifiableBuffer.Source = source;
610+ identifiableBuffer.Count = count;
611+
612+ // Copy buffer data for processing (destination buffer preallocated from buffer pool)
613+ Buffer.BlockCopy(buffer, offset, identifiableBuffer.Buffer, 0, count);
614+
615+ // Add buffer to the queue for parsing
616+ m_bufferQueue.Add(identifiableBuffer);
617+ }
618+ catch
619+ {
620+ // Return source buffer to object pool if we failed to queue it for processing
621+ if ((object)identifiableBuffer != null)
622+ identifiableBuffer.Dispose();
623+
624+ throw;
625+ }
626+ }
627+
628+ /// <summary>
629+ /// Queues the object implementing the <see cref="ISupportBinaryImage"/> interface, from the specified data source, onto the stream for parsing.
630+ /// </summary>
631+ /// <param name="source">Identifier of the data source.</param>
632+ /// <param name="image">Object to be parsed that implements the <see cref="ISupportBinaryImage"/> interface.</param>
633+ /// <remarks>
634+ /// This method takes the binary image from <see cref="ISupportBinaryImage"/> and writes the buffer to the <see cref="BinaryImageParserBase"/> stream for parsing.
635+ /// </remarks>
636+ public virtual void Parse(TSourceIdentifier source, ISupportBinaryImage image)
637+ {
638+ Parse(source, image.BinaryImage());
639+ }
640+
641+ /// <summary>
642+ /// Clears the internal buffer of unparsed data received from the specified <paramref name="source"/>.
643+ /// </summary>
644+ /// <param name="source">Identifier of the data source.</param>
645+ /// <remarks>
646+ /// This method can be used to ensure that partial data received from the <paramref name="source"/> is not kept in memory indefinitely.
647+ /// </remarks>
648+ public virtual void PurgeBuffer(TSourceIdentifier source)
649+ {
650+ byte[] buffer;
651+ m_unparsedBuffers.TryRemove(source, out buffer);
652+ }
653+
654+ /// <summary>
655+ /// Not implemented. Consumers should call the <see cref="Parse(TSourceIdentifier,ISupportBinaryImage)"/> method instead to make sure data source source ID gets tracked with data buffer.
656+ /// </summary>
657+ /// <exception cref="NotImplementedException">This method should not be called directly.</exception>
658+ /// <param name="image">A <see cref="ISupportBinaryImage"/>.</param>
659+ [EditorBrowsable(EditorBrowsableState.Never), Obsolete("MultiSourceFrameImageParserBase requires consumers call Parse overload that takes data source identifier as an argument", true)]
660+ public override void Parse(ISupportBinaryImage image)
661+ {
662+ throw new NotImplementedException("This method should not be called directly, call the Parse(TSourceIdentifier,ISupportBinaryImage) method to queue data for parsing instead.");
663+ }
664+
665+ /// <summary>
666+ /// Not implemented. Consumers should call the <see cref="Parse(TSourceIdentifier,byte[],int,int)"/> method instead to make sure data source source ID gets tracked with data buffer.
667+ /// </summary>
668+ /// <exception cref="NotImplementedException">This method should not be called directly.</exception>
669+ /// <param name="buffer">A <see cref="Byte"/> array.</param>
670+ /// <param name="count">An <see cref="Int32"/> for the offset.</param>
671+ /// <param name="offset">An <see cref="Int32"/> for the count.</param>
672+ [EditorBrowsable(EditorBrowsableState.Never), Obsolete("MultiSourceFrameImageParserBase requires consumers call Parse overload that takes data source identifier as an argument", true)]
673+ public override void Write(byte[] buffer, int offset, int count)
674+ {
675+ throw new NotImplementedException("This method should not be called directly, call the Parse(TSourceIdentifier,byte[],int,int) method to queue data for parsing instead.");
676+ }
677+
678+ /// <summary>
679+ /// Clears all buffers for this stream and causes any buffered data to be parsed immediately.
680+ /// </summary>
681+ /// <remarks>
682+ /// <para>
683+ /// If the user has called <see cref="Start()"/> method, this method will process all remaining buffers on the calling thread until all
684+ /// queued buffers have been parsed - the <see cref="MultiSourceFrameImageParserBase{TSourceIdentifier,TTypeIdentifier,TOutputType}"/>
685+ /// will then be automatically stopped. This method is typically called on shutdown to make sure any remaining queued buffers get
686+ /// parsed before the class instance is destructed.
687+ /// </para>
688+ /// <para>
689+ /// It is possible for items to be queued while the flush is executing. The flush will continue to parse buffers as quickly
690+ /// as possible until the internal buffer queue is empty. Unless the user stops queueing data to be parsed (i.e. calling the
691+ /// <see cref="Parse(TSourceIdentifier,byte[])"/> method), the flush call may never return (not a happy situtation on shutdown).
692+ /// </para>
693+ /// <para>
694+ /// The <see cref="MultiSourceFrameImageParserBase{TSourceIdentifier,TTypeIdentifier,TOutputType}"/> does not clear queue prior to destruction.
695+ /// If the user fails to call this method before the class is destructed, there may be data that remains unparsed in the internal buffer.
696+ /// </para>
697+ /// </remarks>
698+ public override void Flush()
699+ {
700+ m_bufferQueue.Flush();
701+ }
702+
703+ /// <summary>
704+ /// Creates the internal buffer queue.
705+ /// </summary>
706+ /// <remarks>
707+ /// <para>
708+ /// This method is virtual to allow derived classes to customize the style of processing queue used when consumers
709+ /// choose to implement an internal buffer queue. Default type is a real-time queue with the default settings.
710+ /// When overriding, use the <see cref="ParseQueuedBuffers"/> method for the <see cref="ProcessQueue{T}"/>) item
711+ /// processing delegate.
712+ /// </para>
713+ /// <para>
714+ /// Note that current design only supports serial processing - consumer overriding this method to return an asynchronous
715+ /// process queue to process multiple items at once on separate threads will need to redesign the processing delegate.
716+ /// </para>
717+ /// </remarks>
718+ /// <returns>New internal buffer processing queue (i.e., a new <see cref="ProcessQueue{T}"/>).</returns>
719+ protected virtual ProcessQueue<SourceIdentifiableBuffer> CreateBufferQueue()
720+ {
721+ return ProcessQueue<SourceIdentifiableBuffer>.CreateRealTimeQueue(ParseQueuedBuffers);
722+ }
723+
724+ /// <summary>
725+ /// This method is used by the internal <see cref="ProcessQueue{T}"/> to process all queued data buffers.
726+ /// </summary>
727+ /// <param name="buffers">Identifiable buffers to process.</param>
728+ /// <remarks>
729+ /// This is the <see cref="SourceIdentifiableBuffer"/> processing delegate to use when overriding the <see cref="CreateBufferQueue"/> method.
730+ /// </remarks>
731+ protected virtual void ParseQueuedBuffers(SourceIdentifiableBuffer[] buffers)
732+ {
733+ // Process all queued data buffers...
734+ foreach (SourceIdentifiableBuffer buffer in buffers)
735+ {
736+ // Track current buffer source
737+ m_source = buffer.Source;
738+
739+ // Check to see if this data source has been initialized
740+ if ((object)m_sourceInitialized != null)
741+ StreamInitialized = m_sourceInitialized.GetOrAdd(m_source, true);
742+
743+ // Restore any unparsed buffers for this data source, if any
744+ UnparsedBuffer = m_unparsedBuffers.GetOrAdd(m_source, (byte[])null);
745+
746+ // Start parsing sequence for this buffer - this will begin publication of new parsed outputs
747+ base.Write(buffer.Buffer, 0, buffer.Count);
748+
749+ // Track last unparsed buffer for this data source
750+ m_unparsedBuffers[m_source] = UnparsedBuffer;
751+ }
752+
753+ // Dispose of source buffers - no rush
754+ ThreadPool.QueueUserWorkItem(DisposeSourceBuffers, buffers);
755+ }
756+
757+ // Handle disposing of source buffers (this will return items to the resuable object pool)
758+ private void DisposeSourceBuffers(object state)
759+ {
760+ SourceIdentifiableBuffer[] buffers = state as SourceIdentifiableBuffer[];
761+
762+ if ((object)buffers != null)
763+ {
764+ foreach (SourceIdentifiableBuffer buffer in buffers)
765+ {
766+ if ((object)buffer != null)
767+ buffer.Dispose();
768+ }
769+ }
770+ }
771+
772+ /// <summary>
773+ /// Raises the <see cref="FrameImageParserBase{TTypeIdentifier, TOutputType}.DataParsed"/> event.
774+ /// </summary>
775+ /// <param name="output">The object that was deserialized from binary image.</param>
776+ protected override void OnDataParsed(TOutputType output)
777+ {
778+ // Make sure output gets associated with its data source prior to publication
779+ output.Source = m_source;
780+
781+ base.OnDataParsed(output);
782+ }
783+
784+ /// <summary>
785+ /// Raises the <see cref="BinaryImageParserBase.DataDiscarded"/> event.
786+ /// </summary>
787+ /// <param name="buffer">Source buffer that contains output that failed to parse.</param>
788+ protected override void OnDataDiscarded(byte[] buffer)
789+ {
790+ // If an error occurs during parsing from a data source, we reset its initialization state
791+ if ((object)m_sourceInitialized != null)
792+ m_sourceInitialized[m_source] = false;
793+
794+ base.OnDataDiscarded(buffer);
795+ }
796+
797+ // We just bubble any exceptions captured in process queue out to parsing exception event...
798+ private void ProcessExceptionHandler(object sender, EventArgs<Exception> e)
799+ {
800+ OnParsingException(e.Argument);
801+ }
802+
803+ #endregion
804+ }
805+}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t