Skip to content

Commit

Permalink
Merge branch 'dynamic_sessions' of github.com:martinadams/quickfixn i…
Browse files Browse the repository at this point in the history
…nto 314

Conflicts:
	QuickFIXn/IApplicationExt.cs
	UnitTests/SessionTest.cs
  • Loading branch information
gbirchmeier committed Jun 9, 2015
2 parents 33dd7b0 + 43b73f6 commit b132023
Show file tree
Hide file tree
Showing 12 changed files with 690 additions and 34 deletions.
98 changes: 81 additions & 17 deletions QuickFIXn/AbstractInitiator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public abstract class AbstractInitiator : IInitiator
private HashSet<SessionID> disconnected_ = new HashSet<SessionID>();
private bool isStopped_ = true;
private Thread thread_;
private SessionFactory sessionFactory_ = null;

#region Properties

Expand Down Expand Up @@ -59,18 +60,11 @@ public void Start()
throw new System.ObjectDisposedException(this.GetType().Name);

// create all sessions
SessionFactory factory = new SessionFactory(_app, _storeFactory, _logFactory, _msgFactory);
sessionFactory_ = new SessionFactory(_app, _storeFactory, _logFactory, _msgFactory);
foreach (SessionID sessionID in _settings.GetSessions())
{
Dictionary dict = _settings.Get(sessionID);
string connectionType = dict.GetString(SessionSettings.CONNECTION_TYPE);

if ("initiator".Equals(connectionType))
{
sessionIDs_.Add(sessionID);
sessions_[sessionID] = factory.Create(sessionID, dict);
SetDisconnected(sessionID);
}
AddSession(sessionID, dict);
}

if (0 == sessions_.Count)
Expand All @@ -83,6 +77,65 @@ public void Start()
thread_.Start();
}

/// <summary>
/// Add new session, either at start-up or as an ad-hoc operation
/// </summary>
/// <param name="sessionID">ID of new session<param>
/// <param name="dict">config settings for new session</param></param>
/// <returns>true if session added succesfully, false if session already exists or is of wrong type</returns>
public bool AddSession(SessionID sessionID, Dictionary dict)
{
if (dict.GetString(SessionSettings.CONNECTION_TYPE) == "initiator" && !sessionIDs_.Contains(sessionID))
{
Session session = sessionFactory_.Create(sessionID, dict);
lock (sync_)
{
if (!_settings.Has(sessionID)) // session won't be in settings if ad-hoc creation after startup
_settings.Set(sessionID, dict);
sessionIDs_.Add(sessionID);
sessions_[sessionID] = session;
SetDisconnected(sessionID);
}
return true;
}
return false;
}

/// <summary>
/// Ad-hoc removal of an existing sssion
/// </summary>
/// <param name="sessionID">ID of session to be removed</param>
/// <param name="terminateActiveSession">true if sesion to be removed even if it has an active connection</param>
/// <returns>true if session removed or was already not present, false if could not be removed because of active connection</returns>
public bool RemoveSession(SessionID sessionID, bool terminateActiveSession)
{
Session session = null;
bool disconnectRequired = false;
lock (sync_)
{
if (sessionIDs_.Contains(sessionID))
{
session = sessions_[sessionID];
if (session.IsLoggedOn && !terminateActiveSession)
return false;

sessions_.Remove(sessionID);
_settings.Remove(sessionID);
disconnectRequired = IsConnected(sessionID) || IsPending(sessionID);
if (disconnectRequired)
SetDisconnected(sessionID);
disconnected_.Remove(sessionID);
sessionIDs_.Remove(sessionID);
OnRemove(sessionID);
}
}
if (disconnectRequired)
session.Disconnect("Removed dynamically");
if (session != null)
session.Dispose();
return true;
}

/// <summary>
/// Logout existing session and close connection. Attempt graceful disconnect first.
/// </summary>
Expand Down Expand Up @@ -144,12 +197,13 @@ public void Stop(bool force)
{
foreach (Session s in sessions_.Values)
s.Dispose();

sessions_.Clear();
sessionIDs_.Clear();
pending_.Clear();
connected_.Clear();
disconnected_.Clear();
}
sessions_.Clear();
sessionIDs_.Clear();
pending_.Clear();
connected_.Clear();
disconnected_.Clear();
}

public bool IsLoggedOn
Expand Down Expand Up @@ -178,6 +232,13 @@ public bool IsLoggedOn
protected virtual void OnConfigure(SessionSettings settings)
{ }

/// <summary>
/// Override this to handle ad-hoc session removal
/// </summary>
/// <param name="sessionID">ID of session being remvoed</param>
protected virtual void OnRemove(SessionID sessionID)
{ }

[System.Obsolete("This method's intended purpose is unclear. Don't use it.")]
protected virtual void OnInitialize(SessionSettings settings)
{ }
Expand Down Expand Up @@ -254,9 +315,12 @@ protected void SetDisconnected(SessionID sessionID)
{
lock (sync_)
{
pending_.Remove(sessionID);
connected_.Remove(sessionID);
disconnected_.Add(sessionID);
if (sessionIDs_.Contains(sessionID))
{
pending_.Remove(sessionID);
connected_.Remove(sessionID);
disconnected_.Add(sessionID);
}
}
}

Expand Down
49 changes: 48 additions & 1 deletion QuickFIXn/Dictionary.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System;
using System.Linq;
using System.Collections.Generic;
using System.Globalization;

namespace QuickFix
Expand Down Expand Up @@ -37,7 +39,8 @@ public int Size
}

#endregion


#region Public Methods
public Dictionary()
{ }

Expand Down Expand Up @@ -195,6 +198,50 @@ public void Merge(Dictionary toMerge)
if(!data_.ContainsKey(entry.Key))
data_[entry.Key] = entry.Value;
}
#endregion

#region Public Overrides
/// <summary>
/// Test Dictionary objects for equality.
/// Dictionaries are deemed to be equal if their names and dictionary contents are the same
/// </summary>
/// <param name="other">Dictionary to compare against</param>
/// <returns>true if the two Dictionary objects are the same in terms of contents, else false</returns>
public override bool Equals(object other)
{
//Check whether the compared objects reference the same data.
if (Object.ReferenceEquals(this, other))
return true;

//Check whether the compared object is null.
if (Object.ReferenceEquals(other, null))
return false;

//Check whether the names and dictionary contents are the same
var otherDict = (Dictionary)other;
if (Name != otherDict.Name || Count != otherDict.Count)
return false;

// Could use LINQ query here, but this is probably faster!
string otherDictValue = null;
foreach (var kvp in data_)
if (!otherDict.data_.TryGetValue(kvp.Key, out otherDictValue) || otherDictValue != kvp.Value)
return false;
return true;
}

/// <summary>
/// Generate hash code for the Dictionary.
/// If Equals() returns true for a compared object,
/// then GetHashCode() must return the same value for this object and the compared object.
/// </summary>
/// <returns>hash code</returns>
public override int GetHashCode()
{
int nameHash = Object.ReferenceEquals(Name, null) ? 1 : Name.GetHashCode();
return nameHash + 100 * Count;
}
#endregion

#region IEnumerable Members

Expand Down
16 changes: 16 additions & 0 deletions QuickFIXn/IAcceptor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,22 @@ public interface IAcceptor
/// </summary>
/// <returns>a map of SessionIDs to EndPoints</returns>
Dictionary<SessionID,IPEndPoint> GetAcceptorAddresses();

/// <summary>
/// Add a new session after acceptor has been started
/// </summary>
/// <param name="sessionID">ID of session to be added</param>
/// <param name="dict">session settings</param>
/// <returns>>true if session added succesfully, false if session already exists or is of wrong type</returns>
bool AddSession(SessionID sessionID, QuickFix.Dictionary dict);

/// <summary>
/// Remove an existing session after acceptor has been started
/// </summary>
/// <param name="sessionID">ID of session to be removed</param>
/// <param name="terminateActiveSession">true if sesion to be removed even if it has an active connection</param>
/// <returns>true if session removed or was already not present, false if could not be removed because of active connection</returns>
bool RemoveSession(SessionID sessionID, bool terminateActiveSession);
}

/// <summary>
Expand Down
16 changes: 16 additions & 0 deletions QuickFIXn/IInitiator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,22 @@ public interface IInitiator : IDisposable
/// </summary>
/// <returns>the SessionIDs for the sessions managed by this initiator</returns>
HashSet<SessionID> GetSessionIDs();

/// <summary>
/// Add a new session after initiator has been started
/// </summary>
/// <param name="sessionID">ID of session to be added</param>
/// <param name="dict">session settings</param>
/// <returns>>true if session added succesfully, false if session already exists or is of wrong type</returns>
bool AddSession(SessionID sessionID, QuickFix.Dictionary dict);

/// <summary>
/// Remove an existing session after initiator has been started
/// </summary>
/// <param name="sessionID">ID of session to be removed</param>
/// <param name="terminateActiveSession">true if sesion to be removed even if it has an active connection</param>
/// <returns>true if session removed or was already not present, false if could not be removed because of active connection</returns>
bool RemoveSession(SessionID sessionID, bool terminateActiveSession);
}

/// <summary>
Expand Down
2 changes: 1 addition & 1 deletion QuickFIXn/QuickFix.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -142,4 +142,4 @@
<Target Name="AfterBuild">
</Target>
-->
</Project>
</Project>
7 changes: 6 additions & 1 deletion QuickFIXn/Session.cs
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ public Session(
this.DataDictionaryProvider = new DataDictionaryProvider(dataDictProvider);
this.schedule_ = sessionSchedule;
this.msgFactory_ = msgFactory;
appDoesEarlyIntercept_ = app is IApplicationExt;
this.appDoesEarlyIntercept_ = app is IApplicationExt;

this.SenderDefaultApplVerID = senderDefaultApplVerID;

Expand Down Expand Up @@ -1625,6 +1625,11 @@ protected bool SendRaw(Message message, int seqNum)
public void Dispose()
{
if (state_ != null) { state_.Dispose(); }
lock (sessions_)
{
sessions_.Remove(this.SessionID);
}

}
}
}
15 changes: 15 additions & 0 deletions QuickFIXn/SessionSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,21 @@ public void Set(QuickFix.Dictionary defaults)
entry.Value.Merge(defaults_);
}

/// <summary>
/// Remove existing session config from the settings
/// </summary>
/// <param name="sessionID">ID of session for which config to be removed</param>
/// <returns>true if removed, false if config for the session does not exist</returns>
public bool Remove(SessionID sessionID)
{
return settings_.Remove(sessionID);
}

/// <summary>
/// Add new session config
/// </summary>
/// <param name="sessionID">ID of session for which to add config</param>
/// <param name="settings">session config</param>
public void Set(SessionID sessionID, QuickFix.Dictionary settings)
{
if (Has(sessionID))
Expand Down
Loading

0 comments on commit b132023

Please sign in to comment.