#region Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
//-----------------------------------------------------------------------------
// Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
// Web: https://www.technosoftware.com
//
// The source code in this file is covered under a dual-license scenario:
// - Owner of a purchased license: SCLA 1.0
// - GPL V3: everybody else
//
// SCLA license terms accompanied with this source code.
// See SCLA 1.0: https://technosoftware.com/license/Source_Code_License_Agreement.pdf
//
// GNU General Public License as published by the Free Software Foundation;
// version 3 of the License are accompanied with this source code.
// See https://technosoftware.com/license/GPLv3License.txt
//
// This source code is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE.
//-----------------------------------------------------------------------------
#endregion Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
#region Using Directives
using System;
using System.Runtime.Serialization;
#endregion
namespace Technosoftware.DaAeHdaClient.Ae
{
///
/// An in-process object which provides access to AE server objects.
///
[Serializable]
public class TsCAeServer : OpcServer, ITsCAeServer
{
#region SubscriptionCollection Class
///
/// A read-only collection of subscriptions.
///
public class SubscriptionCollection : OpcReadOnlyCollection
{
#region Constructors, Destructor, Initialization
///
/// Creates an empty collection.
///
internal SubscriptionCollection() : base(new TsCAeSubscription[0]) { }
#endregion
#region Public Methods
///
/// An indexer for the collection.
///
public new TsCAeSubscription this[int index] => (TsCAeSubscription)Array.GetValue(index);
///
/// Returns a copy of the collection as an array.
///
public new TsCAeSubscription[] ToArray()
{
return (TsCAeSubscription[])Array;
}
///
/// Adds a subscription to the end of the collection.
///
internal void Add(TsCAeSubscription subscription)
{
var array = new TsCAeSubscription[Count + 1];
Array.CopyTo(array, 0);
array[Count] = subscription;
Array = array;
}
///
/// Removes a subscription to the from the collection.
///
internal void Remove(TsCAeSubscription subscription)
{
var array = new TsCAeSubscription[Count - 1];
var index = 0;
for (var ii = 0; ii < Array.Length; ii++)
{
var element = (TsCAeSubscription)Array.GetValue(ii);
if (subscription != element)
{
array[index++] = element;
}
}
Array = array;
}
#endregion
}
#endregion
#region Names Class
///
/// A set of names for fields used in serialization.
///
private class Names
{
internal const string Count = "CT";
internal const string Subscription = "SU";
}
#endregion
#region Fields
private int filters_;
private bool disposing_;
private SubscriptionCollection subscriptions_ = new SubscriptionCollection();
#endregion
#region Constructors, Destructor, Initialization
///
/// Initializes the object with a factory and a default OpcUrl.
///
/// The OpcFactory used to connect to remote servers.
/// The network address of a remote server.
public TsCAeServer(OpcFactory factory, OpcUrl url)
: base(factory, url)
{
}
///
/// Constructs a server by de-serializing its OpcUrl from the stream.
///
protected TsCAeServer(SerializationInfo info, StreamingContext context)
:
base(info, context)
{
var count = (int)info.GetValue(Names.Count, typeof(int));
subscriptions_ = new SubscriptionCollection();
for (var ii = 0; ii < count; ii++)
{
var subscription = (TsCAeSubscription)info.GetValue(Names.Subscription + ii, typeof(TsCAeSubscription));
subscriptions_.Add(subscription);
}
}
#endregion
#region Properties
///
/// The filters supported by the server.
///
// ReSharper disable once UnusedMember.Global
public int AvailableFilters => filters_;
///
/// The outstanding subscriptions for the server.
///
public SubscriptionCollection Subscriptions => subscriptions_;
#endregion
#region Public Methods
///
/// Connects to the server with the specified OpcUrl and credentials.
///
public override void Connect(OpcUrl url, OpcConnectData connectData)
{
LicenseHandler.ValidateFeatures(LicenseHandler.ProductFeature.AlarmsConditions);
// connect to server.
base.Connect(url, connectData);
// all done if no subscriptions.
if (subscriptions_.Count == 0)
{
return;
}
// create subscriptions (should only happen if server has been deserialized).
var subscriptions = new SubscriptionCollection();
foreach (TsCAeSubscription template in subscriptions_)
{
// create subscription for template.
try { subscriptions.Add(EstablishSubscription(template)); }
catch
{
// ignored
}
}
// save new set of subscriptions.
subscriptions_ = subscriptions;
}
///
/// Disconnects from the server and releases all network resources.
///
public override void Disconnect()
{
if (Server == null) throw new NotConnectedException();
// dispose of all subscriptions first.
disposing_ = true;
foreach (TsCAeSubscription subscription in subscriptions_)
{
subscription.Dispose();
}
disposing_ = false;
// disconnect from server.
base.Disconnect();
}
///
/// Returns the current server status.
///
/// The current server status.
public OpcServerStatus GetServerStatus()
{
LicenseHandler.ValidateFeatures(LicenseHandler.ProductFeature.AlarmsConditions);
if (Server == null) throw new NotConnectedException();
var status = ((ITsCAeServer)Server).GetServerStatus();
if (status != null)
{
if (status.StatusInfo == null)
{
status.StatusInfo = GetString($"serverState.{status.ServerState}");
}
}
else
{
if (Server == null) throw new NotConnectedException();
}
return status;
}
///
/// Creates a new event subscription.
///
/// The initial state for the subscription.
/// The new subscription object.
public ITsCAeSubscription CreateSubscription(TsCAeSubscriptionState state)
{
LicenseHandler.ValidateFeatures(LicenseHandler.ProductFeature.AlarmsConditions);
if (Server == null) throw new NotConnectedException();
// create remote object.
var subscription = ((ITsCAeServer)Server).CreateSubscription(state);
if (subscription != null)
{
// create wrapper.
var wrapper = new TsCAeSubscription(this, subscription, state);
subscriptions_.Add(wrapper);
return wrapper;
}
// should never happen.
return null;
}
///
/// Returns the event filters supported by the server.
///
/// A bit mask of all event filters supported by the server.
public int QueryAvailableFilters()
{
LicenseHandler.ValidateFeatures(LicenseHandler.ProductFeature.AlarmsConditions);
if (Server == null) throw new NotConnectedException();
filters_ = ((ITsCAeServer)Server).QueryAvailableFilters();
return filters_;
}
///
/// Returns the event categories supported by the server for the specified event types.
///
/// A bit mask for the event types of interest.
/// A collection of event categories.
public TsCAeCategory[] QueryEventCategories(int eventType)
{
LicenseHandler.ValidateFeatures(LicenseHandler.ProductFeature.AlarmsConditions);
if (Server == null) throw new NotConnectedException();
// fetch categories from server.
var categories = ((ITsCAeServer)Server).QueryEventCategories(eventType);
// return result.
return categories;
}
///
/// Returns the condition names supported by the server for the specified event categories.
///
/// A bit mask for the event categories of interest.
/// A list of condition names.
public string[] QueryConditionNames(int eventCategory)
{
LicenseHandler.ValidateFeatures(LicenseHandler.ProductFeature.AlarmsConditions);
if (Server == null) throw new NotConnectedException();
// fetch condition names from the server.
var conditions = ((ITsCAeServer)Server).QueryConditionNames(eventCategory);
// return result.
return conditions;
}
///
/// Returns the sub-condition names supported by the server for the specified event condition.
///
/// The name of the condition.
/// A list of sub-condition names.
public string[] QuerySubConditionNames(string conditionName)
{
LicenseHandler.ValidateFeatures(LicenseHandler.ProductFeature.AlarmsConditions);
if (Server == null) throw new NotConnectedException();
// fetch sub-condition names from the server.
var subConditions = ((ITsCAeServer)Server).QuerySubConditionNames(conditionName);
// return result.
return subConditions;
}
///
/// Returns the condition names supported by the server for the specified event source.
///
/// The name of the event source.
/// A list of condition names.
public string[] QueryConditionNames(string sourceName)
{
LicenseHandler.ValidateFeatures(LicenseHandler.ProductFeature.AlarmsConditions);
if (Server == null) throw new NotConnectedException();
// fetch condition names from the server.
var conditions = ((ITsCAeServer)Server).QueryConditionNames(sourceName);
// return result.
return conditions;
}
///
/// Returns the event attributes supported by the server for the specified event categories.
///
/// A bit mask for the event categories of interest.
/// A collection of event attributes.
public TsCAeAttribute[] QueryEventAttributes(int eventCategory)
{
LicenseHandler.ValidateFeatures(LicenseHandler.ProductFeature.AlarmsConditions);
if (Server == null) throw new NotConnectedException();
// fetch attributes from server.
var attributes = ((ITsCAeServer)Server).QueryEventAttributes(eventCategory);
// return result.
return attributes;
}
///
/// Returns the DA item ids for a set of attribute ids belonging to events which meet the specified filter criteria.
///
/// The event source of interest.
/// The id of the event category for the events of interest.
/// The name of a condition within the event category.
/// The name of a sub-condition within a multi-state condition.
/// The ids of the attributes to return item ids for.
/// A list of item urls for each specified attribute.
public TsCAeItemUrl[] TranslateToItemIDs(
string sourceName,
int eventCategory,
string conditionName,
string subConditionName,
int[] attributeIDs)
{
LicenseHandler.ValidateFeatures(LicenseHandler.ProductFeature.AlarmsConditions);
if (Server == null) throw new NotConnectedException();
var itemUrls = ((ITsCAeServer)Server).TranslateToItemIDs(
sourceName,
eventCategory,
conditionName,
subConditionName,
attributeIDs);
return itemUrls;
}
///
/// Returns the current state information for the condition instance corresponding to the source and condition name.
///
/// The source name
/// A condition name for the source.
/// The list of attributes to return with the condition state.
/// The current state of the connection.
public TsCAeCondition GetConditionState(
string sourceName,
string conditionName,
int[] attributeIDs)
{
LicenseHandler.ValidateFeatures(LicenseHandler.ProductFeature.AlarmsConditions);
if (Server == null) throw new NotConnectedException();
var condition = ((ITsCAeServer)Server).GetConditionState(sourceName, conditionName, attributeIDs);
return condition;
}
///
/// Places the specified process areas into the enabled state.
///
/// A list of fully qualified area names.
/// The results of the operation for each area.
public OpcResult[] EnableConditionByArea(string[] areas)
{
LicenseHandler.ValidateFeatures(LicenseHandler.ProductFeature.AlarmsConditions);
if (Server == null) throw new NotConnectedException();
var results = ((ITsCAeServer)Server).EnableConditionByArea(areas);
return results;
}
///
/// Places the specified process areas into the disabled state.
///
/// A list of fully qualified area names.
/// The results of the operation for each area.
public OpcResult[] DisableConditionByArea(string[] areas)
{
LicenseHandler.ValidateFeatures(LicenseHandler.ProductFeature.AlarmsConditions);
if (Server == null) throw new NotConnectedException();
var results = ((ITsCAeServer)Server).DisableConditionByArea(areas);
return results;
}
///
/// Places the specified process areas into the enabled state.
///
/// A list of fully qualified source names.
/// The results of the operation for each area.
public OpcResult[] EnableConditionBySource(string[] sources)
{
LicenseHandler.ValidateFeatures(LicenseHandler.ProductFeature.AlarmsConditions);
if (Server == null) throw new NotConnectedException();
var results = ((ITsCAeServer)Server).EnableConditionBySource(sources);
return results;
}
///
/// Places the specified process areas into the disabled state.
///
/// A list of fully qualified source names.
/// The results of the operation for each area.
public OpcResult[] DisableConditionBySource(string[] sources)
{
LicenseHandler.ValidateFeatures(LicenseHandler.ProductFeature.AlarmsConditions);
if (Server == null) throw new NotConnectedException();
var results = ((ITsCAeServer)Server).DisableConditionBySource(sources);
return results;
}
///
/// Returns the enabled state for the specified process areas.
///
/// A list of fully qualified area names.
public TsCAeEnabledStateResult[] GetEnableStateByArea(string[] areas)
{
LicenseHandler.ValidateFeatures(LicenseHandler.ProductFeature.AlarmsConditions);
if (Server == null) throw new NotConnectedException();
var results = ((ITsCAeServer)Server).GetEnableStateByArea(areas);
return results;
}
///
/// Returns the enabled state for the specified event sources.
///
/// A list of fully qualified source names.
public TsCAeEnabledStateResult[] GetEnableStateBySource(string[] sources)
{
LicenseHandler.ValidateFeatures(LicenseHandler.ProductFeature.AlarmsConditions);
if (Server == null) throw new NotConnectedException();
var results = ((ITsCAeServer)Server).GetEnableStateBySource(sources);
return results;
}
///
/// Used to acknowledge one or more conditions in the event server.
///
/// The identifier for who is acknowledging the condition.
/// A comment associated with the acknowledgment.
/// The conditions being acknowledged.
/// A list of result id indicating whether each condition was successfully acknowledged.
public OpcResult[] AcknowledgeCondition(
string acknowledgmentId,
string comment,
TsCAeEventAcknowledgement[] conditions)
{
LicenseHandler.ValidateFeatures(LicenseHandler.ProductFeature.AlarmsConditions);
if (Server == null) throw new NotConnectedException();
return ((ITsCAeServer)Server).AcknowledgeCondition(acknowledgmentId, comment, conditions);
}
///
/// Browses for all children of the specified area that meet the filter criteria.
///
/// The full-qualified id for the area.
/// The type of children to return.
/// The expression used to filter the names of children returned.
/// The set of elements that meet the filter criteria.
public TsCAeBrowseElement[] Browse(
string areaId,
TsCAeBrowseType browseType,
string browseFilter)
{
LicenseHandler.ValidateFeatures(LicenseHandler.ProductFeature.AlarmsConditions);
if (Server == null) throw new NotConnectedException();
return ((ITsCAeServer)Server).Browse(areaId, browseType, browseFilter);
}
///
/// Browses for all children of the specified area that meet the filter criteria.
///
/// The full-qualified id for the area.
/// The type of children to return.
/// The expression used to filter the names of children returned.
/// The maximum number of elements to return.
/// The object used to continue the browse if the number nodes exceeds the maximum specified.
/// The set of elements that meet the filter criteria.
public TsCAeBrowseElement[] Browse(
string areaId,
TsCAeBrowseType browseType,
string browseFilter,
int maxElements,
out IOpcBrowsePosition position)
{
LicenseHandler.ValidateFeatures(LicenseHandler.ProductFeature.AlarmsConditions);
if (Server == null) throw new NotConnectedException();
return ((ITsCAeServer)Server).Browse(areaId, browseType, browseFilter, maxElements, out position);
}
///
/// Continues browsing the server's address space at the specified position.
///
/// The maximum number of elements to return.
/// The position object used to continue a browse operation.
/// The set of elements that meet the filter criteria.
public TsCAeBrowseElement[] BrowseNext(int maxElements, ref IOpcBrowsePosition position)
{
LicenseHandler.ValidateFeatures(LicenseHandler.ProductFeature.AlarmsConditions);
if (Server == null) throw new NotConnectedException();
return ((ITsCAeServer)Server).BrowseNext(maxElements, ref position);
}
#endregion
#region ISerializable Members
///
/// Serializes a server into a stream.
///
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
info.AddValue(Names.Count, subscriptions_.Count);
for (var ii = 0; ii < subscriptions_.Count; ii++)
{
info.AddValue(Names.Subscription + ii, subscriptions_[ii]);
}
}
#endregion
#region Private Methods
///
/// Called when a subscription object is disposed.
///
///
internal void SubscriptionDisposed(TsCAeSubscription subscription)
{
if (!disposing_)
{
subscriptions_.Remove(subscription);
}
}
///
/// Establishes a subscription based on the template provided.
///
private TsCAeSubscription EstablishSubscription(TsCAeSubscription template)
{
ITsCAeSubscription remoteServer = null;
try
{
// create remote object.
remoteServer = ((ITsCAeServer)Server).CreateSubscription(template.State);
if (remoteServer == null)
{
return null;
}
// create wrapper.
var subscription = new TsCAeSubscription(this, remoteServer, template.State);
// set filters.
subscription.SetFilters(template.Filters);
// set attributes.
var enumerator = template.Attributes.GetEnumerator();
while (enumerator.MoveNext())
{
if (enumerator.Key != null)
subscription.SelectReturnedAttributes(
(int)enumerator.Key,
((TsCAeSubscription.AttributeCollection)enumerator.Value).ToArray());
}
// return new subscription
return subscription;
}
catch
{
if (remoteServer != null)
{
remoteServer.Dispose();
}
}
// return null.
return null;
}
#endregion
}
}