//******************************************************************************************************// AdapterCollectionBase.cs - Gbtc//// Copyright © 2010, Grid Protection Alliance. All Rights Reserved.//// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See// the NOTICE file distributed with this work for additional information regarding copyright ownership.// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may// not use this file except in compliance with the License. You may obtain a copy of the License at://// http://www.opensource.org/licenses/eclipse-1.0.php//// Unless agreed to in writing, the subject software distributed under the License is distributed on an// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the// License for the specific language governing permissions and limitations.//// Code Modification History:// ----------------------------------------------------------------------------------------------------// 09/02/2010 - J. Ritchie Carroll// Generated original version of source code.////****************************************************************************************************** using GSF.IO;using GSF.Units;using System;using System.Collections.Concurrent;using System.Collections.Generic;using System.Collections.ObjectModel;using System.ComponentModel;using System.Data;using System.IO;using System.Linq;using System.Reflection;using System.Text;using System.Threading; namespace GSF.TimeSeries.Adapters{ /// <summary> /// Represents a collection of <see cref="IAdapter"/> implementations. /// </summary> /// <typeparam name="T">Type of <see cref="IAdapter"/> this collection contains.</typeparam> [EditorBrowsable(EditorBrowsableState.Never)] public abstract class AdapterCollectionBase<T> : Collection<T>, IAdapterCollection where T : IAdapter { #region [ Members ] // Events /// <summary> /// Provides status messages to consumer. /// </summary> /// <remarks> /// <see cref="EventArgs{T}.Argument"/> is new status message. /// </remarks> public event EventHandler<EventArgs<string>> StatusMessage; /// <summary> /// Event is raised when there is an exception encountered while processing. /// </summary> /// <remarks> /// <see cref="EventArgs{T}.Argument"/> is the exception that was thrown. /// </remarks> public event EventHandler<EventArgs<Exception>> ProcessException; /// <summary> /// Event is raised when <see cref="InputMeasurementKeys"/> are updated. /// </summary> public event EventHandler InputMeasurementKeysUpdated; /// <summary> /// Event is raised when <see cref="OutputMeasurements"/> are updated. /// </summary> public event EventHandler OutputMeasurementsUpdated; /// <summary> /// Event is raised when this <see cref="AdapterCollectionBase{T}"/> is disposed or an <see cref="IAdapter"/> in the collection is disposed. /// </summary> public event EventHandler Disposed; // Fields private string m_name; private uint m_id; private bool m_initialized; private string m_connectionString; private IAdapterCollection m_parent; private Dictionary<string, string> m_settings; private DataSet m_dataSource; private string m_dataMember; private int m_initializationTimeout; private bool m_autoStart; private bool m_processMeasurementFilter; private IMeasurement[] m_outputMeasurements; private MeasurementKey[] m_inputMeasurementKeys; private string[] m_inputSourceIDs; private string[] m_outputSourceIDs; private MeasurementKey[] m_requestedInputMeasurementKeys; private MeasurementKey[] m_requestedOutputMeasurementKeys; private ConcurrentDictionary<string, AutoResetEvent> m_waitHandles; private Ticks m_lastProcessTime; private Time m_totalProcessTime; private long m_processedMeasurements; private DateTime m_startTimeConstraint; private DateTime m_stopTimeConstraint; private int m_processingInterval; private System.Timers.Timer m_monitorTimer; private bool m_monitorTimerEnabled; private bool m_enabled; private bool m_disposed; #endregion #region [ Constructors ] /// <summary> /// Constructs a new instance of the <see cref="AdapterCollectionBase{T}"/>. /// </summary> /// <param name="waitHandles">Wait handle dictionary.</param> protected AdapterCollectionBase(ConcurrentDictionary<string, AutoResetEvent> waitHandles) { m_name = this.GetType().Name; m_settings = new Dictionary<string, string>(); m_startTimeConstraint = DateTime.MinValue; m_stopTimeConstraint = DateTime.MaxValue; m_processingInterval = -1; m_initializationTimeout = AdapterBase.DefaultInitializationTimeout; m_waitHandles = waitHandles; m_autoStart = true; m_monitorTimer = new System.Timers.Timer(); m_monitorTimer.Elapsed += m_monitorTimer_Elapsed; // We monitor total number of processed measurements every minute m_monitorTimer.Interval = 60000; m_monitorTimer.AutoReset = true; m_monitorTimer.Enabled = false; } /// <summary> /// Releases the unmanaged resources before the <see cref="AdapterCollectionBase{T}"/> object is reclaimed by <see cref="GC"/>. /// </summary> ~AdapterCollectionBase() { Dispose(false); } #endregion #region [ Properties ] /// <summary> /// Gets or sets the name of this <see cref="AdapterCollectionBase{T}"/>. /// </summary> public virtual string Name { get { return m_name; } set { m_name = value; } } /// <summary> /// Gets or sets numeric ID associated with this <see cref="AdapterCollectionBase{T}"/>. /// </summary> public virtual uint ID { get { return m_id; } set { m_id = value; } } /// <summary> /// Gets or sets flag indicating if the adapter collection has been initialized successfully. /// </summary> public virtual bool Initialized { get { return m_initialized; } set { m_initialized = value; } } /// <summary> /// Gets or sets key/value pair connection information specific to this <see cref="AdapterCollectionBase{T}"/>. /// </summary> public virtual string ConnectionString { get { return m_connectionString; } set { m_connectionString = value; // Preparse settings upon connection string assignment if (m_connectionString.IsNullOrWhiteSpace()) m_settings = new Dictionary<string, string>(); else m_settings = m_connectionString.ParseKeyValuePairs(); } } /// <summary> /// Gets a read-only reference to the collection that contains this <see cref="AdapterCollectionBase{T}"/>, if any. /// </summary> public ReadOnlyCollection<IAdapter> Parent { get { return new ReadOnlyCollection<IAdapter>(m_parent); } } /// <summary> /// Gets or sets <see cref="DataSet"/> based data source used to load each <see cref="IAdapter"/>. /// Updates to this property will cascade to all items in this <see cref="AdapterCollectionBase{T}"/>. /// </summary> /// <remarks> /// Table name specified in <see cref="DataMember"/> from <see cref="DataSource"/> is expected /// to have the following table column names:<br/> /// ID, AdapterName, AssemblyName, TypeName, ConnectionString<br/> /// ID column type should be integer based, all other column types are expected to be string based. /// </remarks> public virtual DataSet DataSource { get { return m_dataSource; } set { m_dataSource = value; // Update data source for items in this collection lock (this) { foreach (T item in this) { item.DataSource = m_dataSource; } } } } /// <summary> /// Gets or sets specific data member (e.g., table name) in <see cref="DataSource"/> used to <see cref="Initialize"/> this <see cref="AdapterCollectionBase{T}"/>. /// </summary> /// <remarks> /// Table name specified in <see cref="DataMember"/> from <see cref="DataSource"/> is expected /// to have the following table column names:<br/> /// ID, AdapterName, AssemblyName, TypeName, ConnectionString<br/> /// ID column type should be integer based, all other column types are expected to be string based. /// </remarks> public virtual string DataMember { get { return m_dataMember; } set { m_dataMember = value; } } /// <summary> /// Gets or sets the default adapter time that represents the maximum time system will wait during <see cref="Start"/> for initialization. /// </summary> /// <remarks> /// Set to <see cref="Timeout.Infinite"/> to wait indefinitely. /// </remarks> public virtual int InitializationTimeout { get { return m_initializationTimeout; } set { m_initializationTimeout = value; } } /// <summary> /// Gets or sets flag indicating if adapter collection should automatically start items when <see cref="AutoInitialize"/> is <c>false</c>. /// </summary> public virtual bool AutoStart { get { return m_autoStart; } set { m_autoStart = value; } } /// <summary> /// Gets or sets flag that determines if measurements being queued for processing should be tested to see if they are in the <see cref="InputMeasurementKeys"/>. /// </summary> public virtual bool ProcessMeasurementFilter { get { return m_processMeasurementFilter; } set { m_processMeasurementFilter = value; // Update this flag for items in this collection lock (this) { foreach (T item in this) { item.ProcessMeasurementFilter = m_processMeasurementFilter; } } } } /// <summary> /// Gets or sets primary keys of input measurements the <see cref="AdapterCollectionBase{T}"/> expects, if any. /// </summary> public virtual MeasurementKey[] InputMeasurementKeys { get { // If a specific set of input measurement keys has been assigned, use that set if (m_inputMeasurementKeys != null) return m_inputMeasurementKeys; List<MeasurementKey> cumulativeKeys = new List<MeasurementKey>(); // Otherwise return cumulative results of all child adapters lock (this) { foreach (T adapter in this) { if ((object)adapter != null) { MeasurementKey[] inputMeasurementKeys = adapter.InputMeasurementKeys; // If any of the children expects all measurements (i.e., null InputMeasurementKeys) // then the parent collection must expect all measurements if (inputMeasurementKeys == null) return null; if (inputMeasurementKeys.Length > 0) cumulativeKeys.AddRange(inputMeasurementKeys); } } } return cumulativeKeys.Distinct().ToArray(); } set { m_inputMeasurementKeys = value; OnInputMeasurementKeysUpdated(); } } /// <summary> /// Gets or sets output measurements that the <see cref="AdapterCollectionBase{T}"/> will produce, if any. /// </summary> public virtual IMeasurement[] OutputMeasurements { get { // If a specific set of output measurements has been assigned, use that set if (m_outputMeasurements != null) return m_outputMeasurements; // Otherwise return cumulative results of all child adapters List<IMeasurement> cumulativeMeasurements = new List<IMeasurement>(); // Otherwise return cumulative results of all child adapters lock (this) { foreach (T adapter in this) { if ((object)adapter != null) { IMeasurement[] outputMeasurements = adapter.OutputMeasurements; if (outputMeasurements != null && outputMeasurements.Length > 0) cumulativeMeasurements.AddRange(outputMeasurements); } } } return cumulativeMeasurements.Distinct().ToArray(); } set { m_outputMeasurements = value; OnOutputMeasurementsUpdated(); } } /// <summary> /// Gets or sets <see cref="MeasurementKey.Source"/> values used to filter input measurement keys. /// </summary> /// <remarks> /// The collection classes simply track this value if assigned, no automatic action is taken. /// </remarks> public virtual string[] InputSourceIDs { get { return m_inputSourceIDs; } set { m_inputSourceIDs = value; } } /// <summary> /// Gets or sets <see cref="MeasurementKey.Source"/> values used to filter output measurements. /// </summary> /// <remarks> /// The collection classes simply track this value if assigned, no automatic action is taken. /// </remarks> public virtual string[] OutputSourceIDs { get { return m_outputSourceIDs; } set { m_outputSourceIDs = value; } } /// <summary> /// Gets or sets input measurement keys that are requested by other adapters based on what adapter says it can provide. /// </summary> public virtual MeasurementKey[] RequestedInputMeasurementKeys { get { // If a specific set of input measurement keys has been assigned, use that set if (m_requestedInputMeasurementKeys != null) return m_requestedInputMeasurementKeys; // Otherwise return cumulative results of all child adapters lock (this) { if (typeof(T) is IActionAdapter) return this.Cast<IActionAdapter>().Where(item => item.RequestedInputMeasurementKeys != null).SelectMany(item => item.RequestedInputMeasurementKeys).Distinct().ToArray(); if (typeof(T) is IOutputAdapter) return this.Cast<IOutputAdapter>().Where(item => item.RequestedInputMeasurementKeys != null).SelectMany(item => item.RequestedInputMeasurementKeys).Distinct().ToArray(); } return null; } set { m_requestedInputMeasurementKeys = value; } } /// <summary> /// Gets or sets output measurement keys that are requested by other adapters based on what adapter says it can provide. /// </summary> public virtual MeasurementKey[] RequestedOutputMeasurementKeys { get { // If a specific set of output measurement keys has been assigned, use that set if (m_requestedOutputMeasurementKeys != null) return m_requestedOutputMeasurementKeys; // Otherwise return cumulative results of all child adapters lock (this) { if (typeof(T) is IActionAdapter) return this.Cast<IActionAdapter>().Where(item => item.RequestedOutputMeasurementKeys != null).SelectMany(item => item.RequestedOutputMeasurementKeys).Distinct().ToArray(); if (typeof(T) is IInputAdapter)Lines 1–500 of 1773. Load more
//****************************************************************************************************** // AdapterCollectionBase.cs - Gbtc // // Copyright © 2010, Grid Protection Alliance. All Rights Reserved. // // Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See // the NOTICE file distributed with this work for additional information regarding copyright ownership. // The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may // not use this file except in compliance with the License. You may obtain a copy of the License at: // // http://www.opensource.org/licenses/eclipse-1.0.php // // Unless agreed to in writing, the subject software distributed under the License is distributed on an // "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the // License for the specific language governing permissions and limitations. // // Code Modification History: // ---------------------------------------------------------------------------------------------------- // 09/02/2010 - J. Ritchie Carroll // Generated original version of source code. // //****************************************************************************************************** using GSF.IO; using GSF.Units; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Data; using System.IO; using System.Linq; using System.Reflection; using System.Text; using System.Threading; namespace GSF.TimeSeries.Adapters { /// <summary> /// Represents a collection of <see cref="IAdapter"/> implementations. /// </summary> /// <typeparam name="T">Type of <see cref="IAdapter"/> this collection contains.</typeparam> [EditorBrowsable(EditorBrowsableState.Never)] public abstract class AdapterCollectionBase<T> : Collection<T>, IAdapterCollection where T : IAdapter { #region [ Members ] // Events /// <summary> /// Provides status messages to consumer. /// </summary> /// <remarks> /// <see cref="EventArgs{T}.Argument"/> is new status message. /// </remarks> public event EventHandler<EventArgs<string>> StatusMessage; /// <summary> /// Event is raised when there is an exception encountered while processing. /// </summary> /// <remarks> /// <see cref="EventArgs{T}.Argument"/> is the exception that was thrown. /// </remarks> public event EventHandler<EventArgs<Exception>> ProcessException; /// <summary> /// Event is raised when <see cref="InputMeasurementKeys"/> are updated. /// </summary> public event EventHandler InputMeasurementKeysUpdated; /// <summary> /// Event is raised when <see cref="OutputMeasurements"/> are updated. /// </summary> public event EventHandler OutputMeasurementsUpdated; /// <summary> /// Event is raised when this <see cref="AdapterCollectionBase{T}"/> is disposed or an <see cref="IAdapter"/> in the collection is disposed. /// </summary> public event EventHandler Disposed; // Fields private string m_name; private uint m_id; private bool m_initialized; private string m_connectionString; private IAdapterCollection m_parent; private Dictionary<string, string> m_settings; private DataSet m_dataSource; private string m_dataMember; private int m_initializationTimeout; private bool m_autoStart; private bool m_processMeasurementFilter; private IMeasurement[] m_outputMeasurements; private MeasurementKey[] m_inputMeasurementKeys; private string[] m_inputSourceIDs; private string[] m_outputSourceIDs; private MeasurementKey[] m_requestedInputMeasurementKeys; private MeasurementKey[] m_requestedOutputMeasurementKeys; private ConcurrentDictionary<string, AutoResetEvent> m_waitHandles; private Ticks m_lastProcessTime; private Time m_totalProcessTime; private long m_processedMeasurements; private DateTime m_startTimeConstraint; private DateTime m_stopTimeConstraint; private int m_processingInterval; private System.Timers.Timer m_monitorTimer; private bool m_monitorTimerEnabled; private bool m_enabled; private bool m_disposed; #endregion #region [ Constructors ] /// <summary> /// Constructs a new instance of the <see cref="AdapterCollectionBase{T}"/>. /// </summary> /// <param name="waitHandles">Wait handle dictionary.</param> protected AdapterCollectionBase(ConcurrentDictionary<string, AutoResetEvent> waitHandles) { m_name = this.GetType().Name; m_settings = new Dictionary<string, string>(); m_startTimeConstraint = DateTime.MinValue; m_stopTimeConstraint = DateTime.MaxValue; m_processingInterval = -1; m_initializationTimeout = AdapterBase.DefaultInitializationTimeout; m_waitHandles = waitHandles; m_autoStart = true; m_monitorTimer = new System.Timers.Timer(); m_monitorTimer.Elapsed += m_monitorTimer_Elapsed; // We monitor total number of processed measurements every minute m_monitorTimer.Interval = 60000; m_monitorTimer.AutoReset = true; m_monitorTimer.Enabled = false; } /// <summary> /// Releases the unmanaged resources before the <see cref="AdapterCollectionBase{T}"/> object is reclaimed by <see cref="GC"/>. /// </summary> ~AdapterCollectionBase() { Dispose(false); } #endregion #region [ Properties ] /// <summary> /// Gets or sets the name of this <see cref="AdapterCollectionBase{T}"/>. /// </summary> public virtual string Name { get { return m_name; } set { m_name = value; } } /// <summary> /// Gets or sets numeric ID associated with this <see cref="AdapterCollectionBase{T}"/>. /// </summary> public virtual uint ID { get { return m_id; } set { m_id = value; } } /// <summary> /// Gets or sets flag indicating if the adapter collection has been initialized successfully. /// </summary> public virtual bool Initialized { get { return m_initialized; } set { m_initialized = value; } } /// <summary> /// Gets or sets key/value pair connection information specific to this <see cref="AdapterCollectionBase{T}"/>. /// </summary> public virtual string ConnectionString { get { return m_connectionString; } set { m_connectionString = value; // Preparse settings upon connection string assignment if (m_connectionString.IsNullOrWhiteSpace()) m_settings = new Dictionary<string, string>(); else m_settings = m_connectionString.ParseKeyValuePairs(); } } /// <summary> /// Gets a read-only reference to the collection that contains this <see cref="AdapterCollectionBase{T}"/>, if any. /// </summary> public ReadOnlyCollection<IAdapter> Parent { get { return new ReadOnlyCollection<IAdapter>(m_parent); } } /// <summary> /// Gets or sets <see cref="DataSet"/> based data source used to load each <see cref="IAdapter"/>. /// Updates to this property will cascade to all items in this <see cref="AdapterCollectionBase{T}"/>. /// </summary> /// <remarks> /// Table name specified in <see cref="DataMember"/> from <see cref="DataSource"/> is expected /// to have the following table column names:<br/> /// ID, AdapterName, AssemblyName, TypeName, ConnectionString<br/> /// ID column type should be integer based, all other column types are expected to be string based. /// </remarks> public virtual DataSet DataSource { get { return m_dataSource; } set { m_dataSource = value; // Update data source for items in this collection lock (this) { foreach (T item in this) { item.DataSource = m_dataSource; } } } } /// <summary> /// Gets or sets specific data member (e.g., table name) in <see cref="DataSource"/> used to <see cref="Initialize"/> this <see cref="AdapterCollectionBase{T}"/>. /// </summary> /// <remarks> /// Table name specified in <see cref="DataMember"/> from <see cref="DataSource"/> is expected /// to have the following table column names:<br/> /// ID, AdapterName, AssemblyName, TypeName, ConnectionString<br/> /// ID column type should be integer based, all other column types are expected to be string based. /// </remarks> public virtual string DataMember { get { return m_dataMember; } set { m_dataMember = value; } } /// <summary> /// Gets or sets the default adapter time that represents the maximum time system will wait during <see cref="Start"/> for initialization. /// </summary> /// <remarks> /// Set to <see cref="Timeout.Infinite"/> to wait indefinitely. /// </remarks> public virtual int InitializationTimeout { get { return m_initializationTimeout; } set { m_initializationTimeout = value; } } /// <summary> /// Gets or sets flag indicating if adapter collection should automatically start items when <see cref="AutoInitialize"/> is <c>false</c>. /// </summary> public virtual bool AutoStart { get { return m_autoStart; } set { m_autoStart = value; } } /// <summary> /// Gets or sets flag that determines if measurements being queued for processing should be tested to see if they are in the <see cref="InputMeasurementKeys"/>. /// </summary> public virtual bool ProcessMeasurementFilter { get { return m_processMeasurementFilter; } set { m_processMeasurementFilter = value; // Update this flag for items in this collection lock (this) { foreach (T item in this) { item.ProcessMeasurementFilter = m_processMeasurementFilter; } } } } /// <summary> /// Gets or sets primary keys of input measurements the <see cref="AdapterCollectionBase{T}"/> expects, if any. /// </summary> public virtual MeasurementKey[] InputMeasurementKeys { get { // If a specific set of input measurement keys has been assigned, use that set if (m_inputMeasurementKeys != null) return m_inputMeasurementKeys; List<MeasurementKey> cumulativeKeys = new List<MeasurementKey>(); // Otherwise return cumulative results of all child adapters lock (this) { foreach (T adapter in this) { if ((object)adapter != null) { MeasurementKey[] inputMeasurementKeys = adapter.InputMeasurementKeys; // If any of the children expects all measurements (i.e., null InputMeasurementKeys) // then the parent collection must expect all measurements if (inputMeasurementKeys == null) return null; if (inputMeasurementKeys.Length > 0) cumulativeKeys.AddRange(inputMeasurementKeys); } } } return cumulativeKeys.Distinct().ToArray(); } set { m_inputMeasurementKeys = value; OnInputMeasurementKeysUpdated(); } } /// <summary> /// Gets or sets output measurements that the <see cref="AdapterCollectionBase{T}"/> will produce, if any. /// </summary> public virtual IMeasurement[] OutputMeasurements { get { // If a specific set of output measurements has been assigned, use that set if (m_outputMeasurements != null) return m_outputMeasurements; // Otherwise return cumulative results of all child adapters List<IMeasurement> cumulativeMeasurements = new List<IMeasurement>(); // Otherwise return cumulative results of all child adapters lock (this) { foreach (T adapter in this) { if ((object)adapter != null) { IMeasurement[] outputMeasurements = adapter.OutputMeasurements; if (outputMeasurements != null && outputMeasurements.Length > 0) cumulativeMeasurements.AddRange(outputMeasurements); } } } return cumulativeMeasurements.Distinct().ToArray(); } set { m_outputMeasurements = value; OnOutputMeasurementsUpdated(); } } /// <summary> /// Gets or sets <see cref="MeasurementKey.Source"/> values used to filter input measurement keys. /// </summary> /// <remarks> /// The collection classes simply track this value if assigned, no automatic action is taken. /// </remarks> public virtual string[] InputSourceIDs { get { return m_inputSourceIDs; } set { m_inputSourceIDs = value; } } /// <summary> /// Gets or sets <see cref="MeasurementKey.Source"/> values used to filter output measurements. /// </summary> /// <remarks> /// The collection classes simply track this value if assigned, no automatic action is taken. /// </remarks> public virtual string[] OutputSourceIDs { get { return m_outputSourceIDs; } set { m_outputSourceIDs = value; } } /// <summary> /// Gets or sets input measurement keys that are requested by other adapters based on what adapter says it can provide. /// </summary> public virtual MeasurementKey[] RequestedInputMeasurementKeys { get { // If a specific set of input measurement keys has been assigned, use that set if (m_requestedInputMeasurementKeys != null) return m_requestedInputMeasurementKeys; // Otherwise return cumulative results of all child adapters lock (this) { if (typeof(T) is IActionAdapter) return this.Cast<IActionAdapter>().Where(item => item.RequestedInputMeasurementKeys != null).SelectMany(item => item.RequestedInputMeasurementKeys).Distinct().ToArray(); if (typeof(T) is IOutputAdapter) return this.Cast<IOutputAdapter>().Where(item => item.RequestedInputMeasurementKeys != null).SelectMany(item => item.RequestedInputMeasurementKeys).Distinct().ToArray(); } return null; } set { m_requestedInputMeasurementKeys = value; } } /// <summary> /// Gets or sets output measurement keys that are requested by other adapters based on what adapter says it can provide. /// </summary> public virtual MeasurementKey[] RequestedOutputMeasurementKeys { get { // If a specific set of output measurement keys has been assigned, use that set if (m_requestedOutputMeasurementKeys != null) return m_requestedOutputMeasurementKeys; // Otherwise return cumulative results of all child adapters lock (this) { if (typeof(T) is IActionAdapter) return this.Cast<IActionAdapter>().Where(item => item.RequestedOutputMeasurementKeys != null).SelectMany(item => item.RequestedOutputMeasurementKeys).Distinct().ToArray(); if (typeof(T) is IInputAdapter)