Skip to content

Commit

Permalink
[MDAPI-67] [.NET] Integrate IndexedEventTxModel
Browse files Browse the repository at this point in the history
  • Loading branch information
Konstantin Ivaschenko committed Jul 10, 2024
1 parent a775236 commit 0360931
Show file tree
Hide file tree
Showing 10 changed files with 607 additions and 1 deletion.
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@ dotnet_naming_symbols.stylecop_fields_must_be_private_group.applicable_accessibi
dotnet_naming_symbols.stylecop_fields_must_be_private_group.applicable_kinds = field
dotnet_naming_rule.stylecop_instance_fields_must_be_private_rule.symbols = stylecop_fields_must_be_private_group
dotnet_naming_rule.stylecop_instance_fields_must_be_private_rule.style = disallowed_style
dotnet_naming_rule.stylecop_instance_fields_must_be_private_rule.severity = error
dotnet_naming_rule.stylecop_instance_fields_must_be_private_rule.severity = none

# Private fields must be camelCase
# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1306.md
Expand Down
1 change: 1 addition & 0 deletions StyleCop.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@
<Rule Id="SA1649" Action="None"/><!-- FileNameMustMatchTypeName -->
<Rule Id="SA1310" Action="None"/><!-- FieldNamesMustNotContainUnderscore -->
<Rule Id="SA1629" Action="None"/><!-- DocumentationTextMustEndWithAPeriod -->
<Rule Id="SA1401" Action="None"/><!-- FieldsMustBePrivate -->
</Rules>
</RuleSet>
178 changes: 178 additions & 0 deletions src/DxFeed.Graal.Net/Models/AbstractTxModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
// <copyright file="AbstractTxModel.cs" company="Devexperts LLC">
// Copyright © 2024 Devexperts LLC. All rights reserved.
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
// </copyright>

using System;
using DxFeed.Graal.Net.Api;
using DxFeed.Graal.Net.Events;
using DxFeed.Graal.Net.Native.Model;

namespace DxFeed.Graal.Net.Models;

/// <summary>
/// Abstract base class for models that handle transactions of <see cref="IIndexedEvent"/>.
/// This class manages all snapshot and transaction logic, subscription handling, and listener notifications.
/// </summary>
/// <remarks>
/// This model is designed to handle incremental transactions. Users of this model only see the list
/// of events in a consistent state. This model delays incoming events that are part of an incomplete snapshot
/// or ongoing transaction until the snapshot is complete or the transaction has ended.
///
/// <h3>Configuration</h3>
/// This model must be configured using the <see cref="Builder{TB,TM}"/>. Specific implementations can add additional
/// configuration options as needed.
///
/// <h3>Resource management and closed models</h3>
/// Attached model is a potential memory leak. If the pointer to attached model is lost, then there is no way
/// to detach this model from the feed and the model will not be reclaimed by the garbage collector as long as the
/// corresponding feed is still used. Detached model can be reclaimed by the garbage collector, but detaching model
/// requires knowing the pointer to the feed at the place of the call, which is not always convenient.
///
/// The convenient way to detach model from the feed is to call its <see cref="Close"/> method. Closed model
/// becomes permanently detached from all feeds, removes all its listeners and is guaranteed to be reclaimable by
/// the garbage collector as soon as all external references to it are cleared.
///
/// <h3>Threads and locks</h3>
/// This class is thread-safe and can be used concurrently from multiple threads without external synchronization.
/// </remarks>
public abstract class AbstractTxModel
{
private protected readonly AbstractTxModelHandle handle;

private protected AbstractTxModel(AbstractTxModelHandle handle) =>
this.handle = handle;

/// <summary>
/// Gets whether batch processing is enabled.
/// See <see cref="Builder{TB,TM}.WithBatchProcessing(bool)"/>.
/// </summary>
/// <returns>
/// <c>true</c> if batch processing is enabled; otherwise, <c>false</c>.
/// </returns>
public bool IsBatchProcessing() =>
handle.IsBatchProcessing();

/// <summary>
/// Gets whether snapshot processing is enabled.
/// See <see cref="Builder{TB,TM}.WithSnapshotProcessing(bool)"/>.
/// </summary>
/// <returns>
/// <c>true</c> if snapshot processing is enabled; otherwise, <c>false</c>.
/// </returns>
public bool IsSnapshotProcessing() =>
handle.IsSnapshotProcessing();

/// <summary>
/// Closes this model and makes it <i>permanently detached</i>.
/// </summary>
/// <remarks>
/// This method clears installed listeners and ensures that the model
/// can be safely garbage-collected when all outside references to it are lost.
/// </remarks>
public void Close() =>
handle.Close();

/// <summary>
/// Abstract builder for building models inherited from <see cref="AbstractTxModel"/>.
/// Specific implementations can add additional configuration options to this builder.
/// </summary>
/// <remarks>
/// Inheritors of this class must override the abstract method <see cref="Build"/> to build a specific model.
/// </remarks>
/// <typeparam name="TB">The type of the builder subclass.</typeparam>
/// <typeparam name="TM">The type of the model subclass.</typeparam>
public abstract class Builder<TB, TM>
where TB : Builder<TB, TM>
where TM : AbstractTxModel
{
/// <summary>
/// Initializes a new instance of the <see cref="Builder{TB, TM}"/> class with the specified event type.
/// </summary>
/// <param name="eventType">The type of events processed by the model being created.</param>
protected Builder(Type eventType)
{
}

/// <summary>
/// Enables or disables batch processing. <b>This is enabled by default</b>.
/// </summary>
/// <remarks>
/// If batch processing is disabled, the model will notify the listener
/// <b>separately for each transaction</b> (even if it is represented by a single event);
/// otherwise, transactions can be combined in a single listener call.
///
/// <br/>A transaction may represent either a snapshot or update events that are received after a snapshot.
/// Whether this flag is set or not, the model will always notify listeners that a snapshot has been received
/// and will not combine multiple snapshots or a snapshot with another transaction
/// into a single listener notification.
/// </remarks>
/// <param name="isBatchProcessing"><c>true</c> to enable batch processing; <c>false</c> otherwise.</param>
/// <returns>The builder instance.</returns>
public TB WithBatchProcessing(bool isBatchProcessing)
{
return (TB)this;
}

/// <summary>
/// Enables or disables snapshot processing. <b>This is disabled by default</b>.
/// </summary>
/// <remarks>
/// If snapshot processing is enabled, transactions representing a snapshot will be processed as follows:
/// events that are marked for removal will be removed, repeated indexes will be merged, and
/// event flags of events are set to zero; otherwise, the user will see the snapshot in raw form,
/// with possible repeated indexes, events marked for removal, and event flags unchanged.
///
/// Whether this flag is set or not, in transactions that are not a snapshot, events that are marked
/// for removal will not be removed, repeated indexes will not be merged, and
/// event flags of events will not be changed.
/// This flag only affects the processing of transactions that are a snapshot.
/// </remarks>
/// <param name="isSnapshotProcessing"><c>true</c> to enable snapshot processing; <c>false</c> otherwise.</param>
/// <returns>The builder instance.</returns>
public TB WithSnapshotProcessing(bool isSnapshotProcessing)
{
return (TB)this;
}

/// <summary>
/// Sets the <see cref="DXFeed"/> for the model being created.
/// The feed cannot be attached after the model has been built.
/// </summary>
/// <param name="feed">The <see cref="DXFeed"/>.</param>
/// <returns>The builder instance.</returns>
public TB WithFeed(DXFeed feed)
{
return (TB)this;
}

/// <summary>
/// Sets the subscription symbol for the model being created.
/// The symbol cannot be added or changed after the model has been built.
/// </summary>
/// <param name="symbol">The subscription symbol.</param>
/// <returns>The builder instance.</returns>
public TB WithSymbol(object symbol)
{
return (TB)this;
}

/// <summary>
/// Sets the listener for transaction notifications.
/// The listener cannot be changed or added once the model has been built.
/// </summary>
/// <param name="listener">The transaction listener.</param>
/// <returns>The builder instance.</returns>
public TB WithListener(TxModelListener listener)
{
return (TB)this;
}

/// <summary>
/// Builds an instance of the model based on the provided parameters.
/// </summary>
/// <returns>The created model.</returns>
public abstract TM Build();
}
}
151 changes: 151 additions & 0 deletions src/DxFeed.Graal.Net/Models/IndexedTxModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
// <copyright file="IndexedTxModel.cs" company="Devexperts LLC">
// Copyright © 2024 Devexperts LLC. All rights reserved.
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
// </copyright>

using System;
using System.Collections.Generic;
using DxFeed.Graal.Net.Api;
using DxFeed.Graal.Net.Events;
using DxFeed.Graal.Net.Native.Model;

namespace DxFeed.Graal.Net.Models;

/// <summary>
/// An incremental model for indexed events.
/// This model manages all snapshot and transaction logic, subscription handling, and listener notifications.
/// </summary>
/// <remarks>
/// <para>
/// This model is designed to handle incremental transactions. Users of this model only see the list
/// of events in a consistent state. This model delays incoming events that are part of an incomplete snapshot
/// or ongoing transaction until the snapshot is complete or the transaction has ended. This model notifies
/// the user of received transactions through an installed <see cref="TxModelListener"/> listener.
/// </para>
/// <h3>Configuration</h3>
/// <para>
/// This model must be configured using the <see cref="Builder"/> class, as most configuration
/// settings cannot be changed once the model is built. This model requires configuration with
/// a <see cref="Builder.WithSymbol(object)"/> symbol and

Check warning on line 30 in src/DxFeed.Graal.Net/Models/IndexedTxModel.cs

View workflow job for this annotation

GitHub Actions / Build & Test on win-x64

XML comment has cref attribute 'WithSymbol(object)' that could not be resolved

Check warning on line 30 in src/DxFeed.Graal.Net/Models/IndexedTxModel.cs

View workflow job for this annotation

GitHub Actions / Build & Test on win-x64

XML comment has cref attribute 'WithSymbol(object)' that could not be resolved

Check warning on line 30 in src/DxFeed.Graal.Net/Models/IndexedTxModel.cs

View workflow job for this annotation

GitHub Actions / Build & Test on linux-x64

XML comment has cref attribute 'WithSymbol(object)' that could not be resolved

Check warning on line 30 in src/DxFeed.Graal.Net/Models/IndexedTxModel.cs

View workflow job for this annotation

GitHub Actions / Build & Test on linux-x64

XML comment has cref attribute 'WithSymbol(object)' that could not be resolved

Check warning on line 30 in src/DxFeed.Graal.Net/Models/IndexedTxModel.cs

View workflow job for this annotation

GitHub Actions / Build & Test on osx-arm64

XML comment has cref attribute 'WithSymbol(object)' that could not be resolved

Check warning on line 30 in src/DxFeed.Graal.Net/Models/IndexedTxModel.cs

View workflow job for this annotation

GitHub Actions / Build & Test on osx-arm64

XML comment has cref attribute 'WithSymbol(object)' that could not be resolved
/// a <see cref="Builder.WithSources(DxFeed.Graal.Net.Events.IndexedEventSource[])"/> sources
/// for subscription, and it must be <see cref="Builder.WithFeed(DXFeed)"/> attached to a <see cref="DXFeed"/>

Check warning on line 32 in src/DxFeed.Graal.Net/Models/IndexedTxModel.cs

View workflow job for this annotation

GitHub Actions / Build & Test on win-x64

XML comment has cref attribute 'WithFeed(DXFeed)' that could not be resolved

Check warning on line 32 in src/DxFeed.Graal.Net/Models/IndexedTxModel.cs

View workflow job for this annotation

GitHub Actions / Build & Test on win-x64

XML comment has cref attribute 'WithFeed(DXFeed)' that could not be resolved

Check warning on line 32 in src/DxFeed.Graal.Net/Models/IndexedTxModel.cs

View workflow job for this annotation

GitHub Actions / Build & Test on linux-x64

XML comment has cref attribute 'WithFeed(DXFeed)' that could not be resolved

Check warning on line 32 in src/DxFeed.Graal.Net/Models/IndexedTxModel.cs

View workflow job for this annotation

GitHub Actions / Build & Test on linux-x64

XML comment has cref attribute 'WithFeed(DXFeed)' that could not be resolved

Check warning on line 32 in src/DxFeed.Graal.Net/Models/IndexedTxModel.cs

View workflow job for this annotation

GitHub Actions / Build & Test on osx-arm64

XML comment has cref attribute 'WithFeed(DXFeed)' that could not be resolved

Check warning on line 32 in src/DxFeed.Graal.Net/Models/IndexedTxModel.cs

View workflow job for this annotation

GitHub Actions / Build & Test on osx-arm64

XML comment has cref attribute 'WithFeed(DXFeed)' that could not be resolved
/// instance to begin operation.
/// For ease of use, some of these configurations can be changed after the model is built, see
/// <see cref="SetSources(DxFeed.Graal.Net.Events.IndexedEventSource[])"/>.
/// </para>
/// <para>
/// This model only supports single symbol subscriptions; multiple symbols cannot be configured.
/// </para>
/// <h3>Resource management and closed models</h3>
/// <para>
/// Attached model is a potential memory leak. If the pointer to attached model is lost, then there is no way
/// to detach this model from the feed and the model will not be reclaimed by the garbage collector as long as the
/// corresponding feed is still used. Detached model can be reclaimed by the garbage collector, but detaching model
/// requires knowing the pointer to the feed at the place of the call, which is not always convenient.
/// </para>
/// <para>
/// The convenient way to detach model from the feed is to call its <see cref="AbstractTxModel.Close"/> method.
/// Closed model becomes permanently detached from all feeds, removes all its listeners and is guaranteed
/// to be reclaimable by the garbage collector as soon as all external references to it are cleared.
/// </para>
/// <h3>Threads and locks</h3>
/// <para>
/// This class is thread-safe and can be used concurrently from multiple threads without external synchronization.
/// </para>
/// </remarks>
public sealed class IndexedTxModel : AbstractTxModel
{
private IndexedTxModel(AbstractTxModelHandle handle)
: base(handle)
{
}

/// <summary>
/// Factory method to create a new builder for this model.
/// </summary>
/// <param name="eventType">The class type of the time series event.</param>
/// <returns>A new <see cref="Builder"/> instance.</returns>
public static Builder NewBuilder(Type eventType) =>
new(eventType);

/// <summary>
/// Returns the current set of sources.
/// If no sources have been set, an empty set is returned,
/// indicating that all possible sources have been subscribed to.
/// </summary>
/// <returns>The set of current sources.</returns>
public HashSet<IndexedEventSource> GetSources() =>
((IndexedTxModelHandle)handle).GetSources();

/// <summary>
/// Sets the sources from which to subscribe for indexed events.
/// If an empty list is provided, subscriptions will default to all available sources.
/// If these sources have already been set, nothing happens.
/// </summary>
/// <param name="sources">The specified sources.</param>
public void SetSources(params IndexedEventSource[] sources) =>
((IndexedTxModelHandle)handle).SetSources(sources);

/// <summary>
/// Sets the sources from which to subscribe for indexed events.
/// If an empty set is provided, subscriptions will default to all available sources.
/// If these sources have already been set, nothing happens.
/// </summary>
/// <param name="sources">The specified sources.</param>
public void SetSources(ICollection<IndexedEventSource> sources) =>
((IndexedTxModelHandle)handle).SetSources(sources);

/// <summary>
/// A builder class for creating an instance of <see cref="IndexedTxModel"/>.
/// </summary>
public class Builder : Builder<Builder, IndexedTxModel>
{
/// <summary>
/// Initializes a new instance of the <see cref="Builder"/> class with the specified event type.
/// </summary>
/// <param name="eventType">The type of events processed by the model being created.</param>
public Builder(Type eventType)
: base(eventType)
{
}

/// <summary>
/// Sets the sources from which to subscribe for indexed events.
/// If no sources have been set, subscriptions will default to all possible sources.
/// </summary>
/// <remarks>
/// The default value for this source is an empty set,
/// which means that this model subscribes to all available sources.
/// These sources can be changed later, after the model has been created,
/// by calling <see cref="SetSources(IndexedEventSource[])"/>.
/// </remarks>
/// <param name="sources">The specified sources.</param>
/// <returns>The builder instance.</returns>
public Builder WithSources(params IndexedEventSource[] sources)
{
return this;
}

/// <summary>
/// Sets the sources from which to subscribe for indexed events.
/// If no sources have been set, subscriptions will default to all possible sources.
/// </summary>
/// <remarks>
/// The default value for this source is an empty set,
/// which means that this model subscribes to all available sources.
/// These sources can be changed later, after the model has been created,
/// by calling <see cref="SetSources(IndexedEventSource[])"/>.
/// </remarks>
/// <param name="sources">The specified sources.</param>
/// <returns>The builder instance.</returns>
public Builder WithSources(ICollection<IndexedEventSource> sources)
{
return this;
}

/// <inheritdoc/>
public override IndexedTxModel Build() =>
throw new NotImplementedException();
}
}
Loading

0 comments on commit 0360931

Please sign in to comment.