Example #1
0
        /// <summary>
        /// Disposes a temporal <see cref="IaonSession"/> created using <see cref="CreateTemporalSession"/>.
        /// </summary>
        /// <param name="adapter"><see cref="IClientSubscription"/> source instance.</param>
        /// <param name="session"><see cref="IaonSession"/> instance to dispose.</param>
        public static void DisposeTemporalSession(this IClientSubscription adapter, ref IaonSession session)
        {
            if ((object)session != null)
            {
                EventHandler <EventArgs <string, UpdateType> > statusMessageFunction;
                EventHandler <EventArgs <Exception> >          processExceptionFunction;
                EventHandler processingCompletedFunction;

                // Remove and detach from event handlers
                if (s_statusMessageHandlers.TryRemove(adapter, out statusMessageFunction))
                {
                    session.StatusMessage -= statusMessageFunction;
                }

                if (s_processExceptionHandlers.TryRemove(adapter, out processExceptionFunction))
                {
                    session.ProcessException -= processExceptionFunction;
                }

                if (s_processingCompletedHandlers.TryRemove(adapter, out processingCompletedFunction))
                {
                    session.ProcessingComplete -= processingCompletedFunction;
                }

                session.Dispose();
            }

            session = null;
        }
        /// <summary>
        /// Initializes <see cref="SynchronizedClientSubscription"/>.
        /// </summary>
        public override void Initialize()
        {
            MeasurementKey[] inputMeasurementKeys;
            string           setting;

            if (Settings.TryGetValue("inputMeasurementKeys", out setting))
            {
                // IMPORTANT: The allowSelect argument of ParseInputMeasurementKeys must be null
                //            in order to prevent SQL injection via the subscription filter expression
                inputMeasurementKeys   = AdapterBase.ParseInputMeasurementKeys(DataSource, false, setting);
                m_requestedInputFilter = setting;

                // IMPORTANT: We need to remove the setting before calling base.Initialize()
                //            or else we will still be subject to SQL injection
                Settings.Remove("inputMeasurementKeys");
            }
            else
            {
                inputMeasurementKeys   = new MeasurementKey[0];
                m_requestedInputFilter = null;
            }

            base.Initialize();

            // Set the InputMeasurementKeys and UsePrecisionTimer properties after calling
            // base.Initialize() so that the base class does not overwrite our settings
            InputMeasurementKeys = inputMeasurementKeys;
            UsePrecisionTimer    = false;

            if (Settings.TryGetValue("bufferBlockRetransmissionTimeout", out setting))
            {
                m_bufferBlockRetransmissionTimeout = double.Parse(setting);
            }
            else
            {
                m_bufferBlockRetransmissionTimeout = 5.0D;
            }

            if (Settings.TryGetValue("requestNaNValueFilter", out setting))
            {
                m_isNaNFiltered = m_parent.AllowNaNValueFilter && setting.ParseBoolean();
            }
            else
            {
                m_isNaNFiltered = false;
            }

            m_bufferBlockRetransmissionTimer           = Common.TimerScheduler.CreateTimer((int)(m_bufferBlockRetransmissionTimeout * 1000.0D));
            m_bufferBlockRetransmissionTimer.AutoReset = false;
            m_bufferBlockRetransmissionTimer.Elapsed  += BufferBlockRetransmissionTimer_Elapsed;

            // Handle temporal session initialization
            if (this.TemporalConstraintIsDefined())
            {
                m_iaonSession = this.CreateTemporalSession();
            }
        }
Example #3
0
        /// <summary>
        /// Initializes <see cref="UnsynchronizedClientSubscription"/>.
        /// </summary>
        public override void Initialize()
        {
            base.Initialize();

            string setting;

            if (Settings.TryGetValue("inputMeasurementKeys", out setting))
            {
                m_requestedInputFilter = setting;
            }
            else
            {
                m_requestedInputFilter = null;
            }

            if (Settings.TryGetValue("publishInterval", out setting))
            {
                m_publishInterval = int.Parse(setting);
            }
            else
            {
                m_publishInterval = -1;
            }

            if (Settings.TryGetValue("includeTime", out setting))
            {
                m_includeTime = setting.ParseBoolean();
            }
            else
            {
                m_includeTime = true;
            }

            if (Settings.TryGetValue("useMillisecondResolution", out setting))
            {
                m_useMillisecondResolution = setting.ParseBoolean();
            }
            else
            {
                m_useMillisecondResolution = false;
            }

            if (m_parent.UseBaseTimeOffsets && m_includeTime)
            {
                m_baseTimeRotationTimer           = new System.Timers.Timer();
                m_baseTimeRotationTimer.Interval  = m_useMillisecondResolution ? 60000 : 420000;
                m_baseTimeRotationTimer.AutoReset = true;
                m_baseTimeRotationTimer.Elapsed  += BaseTimeRotationTimer_Elapsed;
            }

            // Handle temporal session intialization
            if (this.TemporalConstraintIsDefined())
            {
                m_iaonSession = this.CreateTemporalSession();
            }
        }
Example #4
0
        /// <summary>
        /// Initializes <see cref="SynchronizedClientSubscription"/>.
        /// </summary>
        public override void Initialize()
        {
            base.Initialize();
            base.UsePrecisionTimer = false;

            if (!Settings.TryGetValue("inputMeasurementKeys", out m_requestedInputFilter))
            {
                m_requestedInputFilter = null;
            }

            // Handle temporal session intialization
            if (this.TemporalConstraintIsDefined())
            {
                m_iaonSession = this.CreateTemporalSession();
            }
        }
Example #5
0
        /// <summary>
        /// Initializes <see cref="SynchronizedClientSubscription"/>.
        /// </summary>
        public override void Initialize()
        {
            string setting;

            base.Initialize();
            base.UsePrecisionTimer = false;

            if (!Settings.TryGetValue("inputMeasurementKeys", out m_requestedInputFilter))
            {
                m_requestedInputFilter = null;
            }

            if (Settings.TryGetValue("bufferBlockRetransmissionTimeout", out setting))
            {
                m_bufferBlockRetransmissionTimeout = double.Parse(setting);
            }
            else
            {
                m_bufferBlockRetransmissionTimeout = 5.0D;
            }

            if (Settings.TryGetValue("requestNaNValueFiltering", out setting))
            {
                m_isNaNFiltered = m_parent.AllowNaNValueFilter && setting.ParseBoolean();
            }
            else
            {
                m_isNaNFiltered = false;
            }

            m_bufferBlockRetransmissionTimer           = new Timer();
            m_bufferBlockRetransmissionTimer.AutoReset = false;
            m_bufferBlockRetransmissionTimer.Interval  = m_bufferBlockRetransmissionTimeout * 1000.0D;
            m_bufferBlockRetransmissionTimer.Elapsed  += BufferBlockRetransmissionTimer_Elapsed;

            // Handle temporal session initialization
            if (this.TemporalConstraintIsDefined())
            {
                m_iaonSession = this.CreateTemporalSession();
            }
        }
Example #6
0
        /// <summary>
        /// Returns a new temporal <see cref="IaonSession"/> for a <see cref="IClientSubscription"/>.
        /// </summary>
        /// <param name="clientSubscription"><see cref="IClientSubscription"/> instance to create temporal <see cref="IaonSession"/> for.</param>
        /// <returns>New temporal <see cref="IaonSession"/> for a <see cref="IClientSubscription"/>.</returns>
        public static IaonSession CreateTemporalSession(this IClientSubscription clientSubscription)
        {
            IaonSession session;

            // Cache the specified input measurement keys requested by the remote subscription
            // internally since these will only be needed in the private Iaon session
            MeasurementKey[] inputMeasurementKeys = clientSubscription.InputMeasurementKeys;
            IMeasurement[]   outputMeasurements   = clientSubscription.OutputMeasurements;

            // Since historical data is requested, we "turn off" interaction with the outside real-time world
            // by removing the client subscription adapter from external routes. To accomplish this we expose
            // I/O demands for an undefined measurement as assigning to null would mean "broadcast" is desired.
            clientSubscription.InputMeasurementKeys = new[] { MeasurementKey.Undefined };
            clientSubscription.OutputMeasurements   = new IMeasurement[] { Measurement.Undefined };

            // Create a new Iaon session
            session      = new IaonSession();
            session.Name = "<" + clientSubscription.HostName.ToNonNullString("unavailable") + ">@" + clientSubscription.StartTimeConstraint.ToString("yyyy-MM-dd HH:mm:ss");

            // Assign requested input measurement keys as a routing restriction
            session.InputMeasurementKeysRestriction = inputMeasurementKeys;

            // Setup default bubbling event handlers associated with the client session adapter
            EventHandler <EventArgs <string, UpdateType> > statusMessageHandler = (sender, e) =>
            {
                if (e.Argument2 == UpdateType.Information)
                {
                    clientSubscription.OnStatusMessage(e.Argument1);
                }
                else
                {
                    clientSubscription.OnStatusMessage("0x" + (int)e.Argument2 + e.Argument1);
                }
            };
            EventHandler <EventArgs <Exception> > processExceptionHandler = (sender, e) => clientSubscription.OnProcessException(e.Argument);
            EventHandler processingCompletedHandler = clientSubscription.OnProcessingCompleted;

            // Cache dynamic event handlers so they can be detached later
            s_statusMessageHandlers[clientSubscription]       = statusMessageHandler;
            s_processExceptionHandlers[clientSubscription]    = processExceptionHandler;
            s_processingCompletedHandlers[clientSubscription] = processingCompletedHandler;

            // Attach handlers to new session - this will proxy all temporal session messages through the client session adapter
            session.StatusMessage      += statusMessageHandler;
            session.ProcessException   += processExceptionHandler;
            session.ProcessingComplete += processingCompletedHandler;

            // Send the first message indicating a new temporal session is being established
            statusMessageHandler(null, new EventArgs <string, UpdateType>(
                                     string.Format("Initializing temporal session for host \"{0}\" spanning {1} to {2} processing data {3}...",
                                                   clientSubscription.HostName.ToNonNullString("unknown"),
                                                   clientSubscription.StartTimeConstraint.ToString("yyyy-MM-dd HH:mm:ss.fff"),
                                                   clientSubscription.StopTimeConstraint.ToString("yyyy-MM-dd HH:mm:ss.fff"),
                                                   clientSubscription.ProcessingInterval == 0 ? "as fast as possible" :
                                                   clientSubscription.ProcessingInterval == -1 ? "at the default rate" : "at " + clientSubscription.ProcessingInterval + "ms intervals"),
                                     UpdateType.Information));

            // Duplicate current real-time session configuration for adapters that report temporal support
            session.DataSource = IaonSession.ExtractTemporalConfiguration(clientSubscription.DataSource);

            // Initialize temporal session adapters without starting them
            session.Initialize(false);

            // Define an in-situ action adapter for the temporal Iaon session used to proxy data back to the client subscription. Note
            // to enable adapters that are connect-on-demand in the temporal session, we must make sure the proxy adapter is setup to
            // respect input demands. The proxy adapter produces no points into the temporal session - all received points are simply
            // internally proxied out to the parent client subscription outside the purview of the Iaon session; from the perspective
            // of the Iaon session, points seem to dead-end in the proxy adapter. The proxy adapter is an action adapter and action
            // adapters typically produce measurements, as such, actions default to respecting output demands not input demands. Using
            // the default settings of not respecting input demands and the proxy adapter not producing any points, the Iaon session
            // would ignore the adapter's input needs. In this case we want Iaon session to recognize the inputs of the proxy adapter
            // as important to the connect-on-demand dependency chain, so we request respect for the input demands.
            TemporalClientSubscriptionProxy proxyAdapter = new TemporalClientSubscriptionProxy
            {
                // Assign critical adapter properties
                ID                   = 0,
                Name                 = "PROXY!SERVICES",
                ConnectionString     = "",
                DataSource           = session.DataSource,
                RespectInputDemands  = true,
                InputMeasurementKeys = inputMeasurementKeys,
                OutputMeasurements   = outputMeasurements,
                Parent               = clientSubscription,
                Initialized          = true
            };

            // Add new proxy adapter to temporal session action adapter collection - this will start adapter
            session.ActionAdapters.Add(proxyAdapter);

            // Load current temporal constraint parameters
            Dictionary <string, string> settings = clientSubscription.Settings;
            string startTime, stopTime, parameters;

            settings.TryGetValue("startTimeConstraint", out startTime);
            settings.TryGetValue("stopTimeConstraint", out stopTime);
            settings.TryGetValue("timeConstraintParameters", out parameters);

            // Assign requested temporal constraints to all private session adapters
            session.AllAdapters.SetTemporalConstraint(startTime, stopTime, parameters);
            session.AllAdapters.ProcessingInterval = clientSubscription.ProcessingInterval;

            // Start temporal session adapters
            session.AllAdapters.Start();

            // Recalculate routing tables to accommodate addition of proxy adapter and handle
            // input measurement keys restriction
            session.RecalculateRoutingTables();

            return(session);
        }
Example #7
0
        /// <summary>
        /// Initializes <see cref="UnsynchronizedClientSubscription"/>.
        /// </summary>
        public override void Initialize()
        {
            base.Initialize();

            string setting;

            if (Settings.TryGetValue("inputMeasurementKeys", out setting))
            {
                m_requestedInputFilter = setting;
            }
            else
            {
                m_requestedInputFilter = null;
            }

            if (Settings.TryGetValue("publishInterval", out setting))
            {
                m_publishInterval = int.Parse(setting);
            }
            else
            {
                m_publishInterval = -1;
            }

            if (Settings.TryGetValue("includeTime", out setting))
            {
                m_includeTime = setting.ParseBoolean();
            }
            else
            {
                m_includeTime = true;
            }

            if (Settings.TryGetValue("useMillisecondResolution", out setting))
            {
                m_useMillisecondResolution = setting.ParseBoolean();
            }
            else
            {
                m_useMillisecondResolution = false;
            }

            if (Settings.TryGetValue("requestNaNValueFilter", out setting))
            {
                m_isNaNFiltered = m_parent.AllowNaNValueFilter && setting.ParseBoolean();
            }
            else
            {
                m_isNaNFiltered = false;
            }

            if (Settings.TryGetValue("bufferBlockRetransmissionTimeout", out setting))
            {
                m_bufferBlockRetransmissionTimeout = double.Parse(setting);
            }
            else
            {
                m_bufferBlockRetransmissionTimeout = 5.0D;
            }

            if (m_parent.UseBaseTimeOffsets && m_includeTime)
            {
                m_baseTimeRotationTimer           = new Timer();
                m_baseTimeRotationTimer.Interval  = m_useMillisecondResolution ? 60000 : 420000;
                m_baseTimeRotationTimer.AutoReset = true;
                m_baseTimeRotationTimer.Elapsed  += BaseTimeRotationTimer_Elapsed;
            }

            m_bufferBlockRetransmissionTimer           = new Timer();
            m_bufferBlockRetransmissionTimer.AutoReset = false;
            m_bufferBlockRetransmissionTimer.Interval  = m_bufferBlockRetransmissionTimeout * 1000.0D;
            m_bufferBlockRetransmissionTimer.Elapsed  += BufferBlockRetransmissionTimer_Elapsed;

            // Handle temporal session initialization
            if (this.TemporalConstraintIsDefined())
            {
                m_iaonSession = this.CreateTemporalSession();
            }
        }
        /// <summary>
        /// Initializes <see cref="UnsynchronizedClientSubscription"/>.
        /// </summary>
        public override void Initialize()
        {
            MeasurementKey[] inputMeasurementKeys;
            string           setting;

            if (Settings.TryGetValue("inputMeasurementKeys", out setting))
            {
                // IMPORTANT: The allowSelect argument of ParseInputMeasurementKeys must be null
                //            in order to prevent SQL injection via the subscription filter expression
                inputMeasurementKeys   = ParseInputMeasurementKeys(DataSource, false, setting);
                m_requestedInputFilter = setting;

                // IMPORTANT: We need to remove the setting before calling base.Initialize()
                //            or else we will still be subject to SQL injection
                Settings.Remove("inputMeasurementKeys");
            }
            else
            {
                inputMeasurementKeys   = new MeasurementKey[0];
                m_requestedInputFilter = null;
            }

            base.Initialize();

            // Set the InputMeasurementKeys property after calling base.Initialize()
            // so that the base class does not overwrite our setting
            InputMeasurementKeys = inputMeasurementKeys;

            if (!Settings.TryGetValue("publishInterval", out setting) || !double.TryParse(setting, out m_publishInterval))
            {
                m_publishInterval = -1;
            }

            if (Settings.TryGetValue("includeTime", out setting))
            {
                m_includeTime = setting.ParseBoolean();
            }
            else
            {
                m_includeTime = true;
            }

            if (Settings.TryGetValue("useMillisecondResolution", out setting))
            {
                m_useMillisecondResolution = setting.ParseBoolean();
            }
            else
            {
                m_useMillisecondResolution = false;
            }

            if (Settings.TryGetValue("requestNaNValueFilter", out setting))
            {
                m_isNaNFiltered = m_parent.AllowNaNValueFilter && setting.ParseBoolean();
            }
            else
            {
                m_isNaNFiltered = false;
            }

            if (Settings.TryGetValue("bufferBlockRetransmissionTimeout", out setting))
            {
                m_bufferBlockRetransmissionTimeout = double.Parse(setting);
            }
            else
            {
                m_bufferBlockRetransmissionTimeout = 5.0D;
            }

            if (m_parent.UseBaseTimeOffsets && m_includeTime)
            {
                m_baseTimeRotationTimer           = Common.TimerScheduler.CreateTimer(m_useMillisecondResolution ? 60000 : 420000);
                m_baseTimeRotationTimer.AutoReset = true;
                m_baseTimeRotationTimer.Elapsed  += BaseTimeRotationTimer_Elapsed;
            }

            m_bufferBlockRetransmissionTimer           = Common.TimerScheduler.CreateTimer((int)(m_bufferBlockRetransmissionTimeout * 1000.0D));
            m_bufferBlockRetransmissionTimer.AutoReset = false;
            m_bufferBlockRetransmissionTimer.Elapsed  += BufferBlockRetransmissionTimer_Elapsed;

            // Handle temporal session initialization
            if (this.TemporalConstraintIsDefined())
            {
                m_iaonSession = this.CreateTemporalSession();
            }
        }
Example #9
0
        /// <summary>
        /// Returns a new temporal <see cref="IaonSession"/> for a <see cref="IClientSubscription"/>.
        /// </summary>
        /// <param name="clientSubscription"><see cref="IClientSubscription"/> instance to create temporal <see cref="IaonSession"/> for.</param>
        /// <returns>New temporal <see cref="IaonSession"/> for a <see cref="IClientSubscription"/>.</returns>
        public static IaonSession CreateTemporalSession(this IClientSubscription clientSubscription)
        {
            IaonSession session;

            // Cache the specified input measurement keys requested by the remote subscription
            // internally since these will only be needed in the private Iaon session
            MeasurementKey[] inputMeasurementKeys = clientSubscription.InputMeasurementKeys;
            IMeasurement[]   outputMeasurements   = clientSubscription.OutputMeasurements;

            // Since historical data is requested, we "turn off" interaction with the outside real-time world
            // by removing this adapter from external routes. To accomplish this we expose I/O demands for an
            // undefined measurement. Note: assigning to null would mean "broadcast" of all data is desired.
            clientSubscription.InputMeasurementKeys = new MeasurementKey[] { MeasurementKey.Undefined };
            clientSubscription.OutputMeasurements   = new IMeasurement[] { Measurement.Undefined };

            // Create a new Iaon session
            session      = new IaonSession();
            session.Name = "<" + clientSubscription.HostName.ToNonNullString("unavailable") + ">@" + clientSubscription.StartTimeConstraint.ToString("yyyy-MM-dd HH:mm:ss");

            // Assign requested input measurement keys as a routing restriction
            session.InputMeasurementKeysRestriction = inputMeasurementKeys;

            // Setup default bubbling event handlers associated with the client session adapter
            EventHandler <EventArgs <string, UpdateType> > statusMessageHandler = (sender, e) =>
            {
                if (e.Argument2 == UpdateType.Information)
                {
                    clientSubscription.OnStatusMessage(e.Argument1);
                }
                else
                {
                    clientSubscription.OnStatusMessage("0x" + (int)e.Argument2 + e.Argument1);
                }
            };
            EventHandler <EventArgs <Exception> > processExceptionHandler = (sender, e) => clientSubscription.OnProcessException(e.Argument);
            EventHandler processingCompletedHandler = (sender, e) => clientSubscription.OnProcessingCompleted(sender, e);

            // Cache dynamic event handlers so they can be detached later
            s_statusMessageHandlers[clientSubscription]       = statusMessageHandler;
            s_processExceptionHandlers[clientSubscription]    = processExceptionHandler;
            s_processingCompletedHandlers[clientSubscription] = processingCompletedHandler;

            // Attach handlers to new session - this will proxy all temporal session messages through the client session adapter
            session.StatusMessage      += statusMessageHandler;
            session.ProcessException   += processExceptionHandler;
            session.ProcessingComplete += processingCompletedHandler;

            // Send the first message indicating a new temporal session is being established
            statusMessageHandler(null, new EventArgs <string, UpdateType>(
                                     string.Format("Initializing temporal session for host \"{0}\" spanning {1} to {2} processing data {3}...",
                                                   clientSubscription.HostName.ToNonNullString("unknown"),
                                                   clientSubscription.StartTimeConstraint.ToString("yyyy-MM-dd HH:mm:ss.fff"),
                                                   clientSubscription.StopTimeConstraint.ToString("yyyy-MM-dd HH:mm:ss.fff"),
                                                   clientSubscription.ProcessingInterval == 0 ? "as fast as possible" :
                                                   clientSubscription.ProcessingInterval == -1 ? "at the default rate" : "at " + clientSubscription.ProcessingInterval + "ms intervals"),
                                     UpdateType.Information));

            // Duplicate current real-time session configuration for adapters that report temporal support
            session.DataSource = IaonSession.ExtractTemporalConfiguration(clientSubscription.DataSource);

            // Define an in-situ action adapter for the temporal Iaon session used to proxy data back to the client subscription
            DataTable actionAdapters  = session.DataSource.Tables["ActionAdapters"];
            DataRow   proxyAdapterRow = actionAdapters.NewRow();

            // Define connection string for proxy adapter based on original inputs and ouputs as requested by client subscription
            StringBuilder connectionString = new StringBuilder();

            if (inputMeasurementKeys != null && inputMeasurementKeys.Length > 0)
            {
                connectionString.AppendFormat("inputMeasurementKeys={{{0}}}", inputMeasurementKeys.Select(key => key.SignalID).ToDelimitedString(";"));
            }

            if (outputMeasurements != null && outputMeasurements.Length > 0)
            {
                if (connectionString.Length > 0)
                {
                    connectionString.Append("; ");
                }

                connectionString.AppendFormat("outputMeasurements={{{0}}}", outputMeasurements.Select(m => m.ID).ToDelimitedString(";"));
            }

            // Assign critical adapter properties
            proxyAdapterRow["ID"]               = 0;
            proxyAdapterRow["AdapterName"]      = "PROXY!SERVICES";
            proxyAdapterRow["AssemblyName"]     = "GSF.TimeSeries.dll";
            proxyAdapterRow["TypeName"]         = "GSF.TimeSeries.Transport.TemporalClientSubscriptionProxy";
            proxyAdapterRow["ConnectionString"] = connectionString.ToString();

            // Add proxy row to Iaon action adapter definitions
            actionAdapters.Rows.Add(proxyAdapterRow);

            // Initialize temporal session adapters without starting them
            session.Initialize(false);

            // Get reference to temporal session proxy adapter to it can be associated with the client subscription
            TemporalClientSubscriptionProxy proxyAdapter = null;
            IActionAdapter adapter0;

            // Lookup proxy adapter defined with reserved ID zero
            if (session.ActionAdapters.TryGetAdapterByID(0, out adapter0))
            {
                proxyAdapter = adapter0 as TemporalClientSubscriptionProxy;
            }

            if ((object)proxyAdapter == null)
            {
                throw new InvalidOperationException("Failed to define temporal subscription proxy adapter - cannot complete temporal session initialization.");
            }

            // Associate proxy with client subscription
            proxyAdapter.Parent = clientSubscription;

            // Load current temporal constraint parameters
            Dictionary <string, string> settings = clientSubscription.Settings;
            string startTime, stopTime, parameters;

            settings.TryGetValue("startTimeConstraint", out startTime);
            settings.TryGetValue("stopTimeConstraint", out stopTime);
            settings.TryGetValue("timeConstraintParameters", out parameters);

            // Assign requested temporal constraints to all private session adapters
            session.AllAdapters.SetTemporalConstraint(startTime, stopTime, parameters);
            session.AllAdapters.ProcessingInterval = clientSubscription.ProcessingInterval;

            // Start temporal session adapters
            session.AllAdapters.Start();

            // Recalculate routing tables to accomodate addtion of proxy adapter and handle
            // input measurement keys restriction
            session.RecalculateRoutingTables();

            return(session);
        }