4using System.Threading.Tasks;
23 [CollectionName(
"Output")]
27 [Index(
"ParentId",
"NodeId")]
30 private Guid objectId = Guid.Empty;
31 private Guid parentId = Guid.Empty;
33 private string nodeId =
string.Empty;
34 private string oldId =
null;
36 private List<OutputNode> children =
null;
37 private int siblingOrdinal = 0;
38 private bool childrenLoaded =
false;
39 private readonly
object synchObject =
new object();
40 private DateTime created = DateTime.Now;
41 private DateTime updated = DateTime.MinValue;
59 return Node.thingReference;
67 public override bool Equals(
object obj)
72 return this.nodeId == Ref.NodeId && this.SourceId == Ref.SourceId && this.Partition == Ref.Partition;
81 return this.nodeId.GetHashCode() ^
93 set => this.objectId = value;
101 get => this.parentId;
102 set => this.parentId = value;
111 set => this.created = value;
117 [DefaultValueDateTimeMinValue]
121 set => this.updated = value;
130 get => this.siblingOrdinal;
131 set => this.siblingOrdinal = value;
137 [Header(14,
"ID:", 0)]
138 [Page(15,
"Output", 0)]
139 [ToolTip(16,
"Output identity in the collection of output.")]
147 this.thingReference =
null;
149 if (this.oldId is
null && !
string.IsNullOrEmpty(value))
169 StringBuilder sb =
new StringBuilder();
172 sb.Append(this.nodeId);
185 return sb.ToString();
263 if (this.objectId == Guid.Empty)
274 Message.Updated = DateTime.Now;
296 if (this.state <
NodeState.ErrorUnsigned)
300 await this.RaiseUpdate();
305 if (this.state <
NodeState.WarningUnsigned)
309 await this.RaiseUpdate();
318 await this.RaiseUpdate();
338 await this.NodeStateChanged();
341 internal async Task NodeStateChanged()
350 Timestamp = DateTime.UtcNow
421 if (this.objectId == Guid.Empty)
424 bool Removed =
false;
447 bool ErrorsFound =
false;
448 bool WarningsFound =
false;
449 bool InformationFound =
false;
460 WarningsFound =
true;
464 InformationFound =
true;
475 NewStateUnsigned =
NodeState.ErrorUnsigned;
477 else if (WarningsFound)
479 NewStateSigned =
NodeState.WarningSigned;
480 NewStateUnsigned =
NodeState.WarningUnsigned;
482 else if (InformationFound)
485 NewStateUnsigned =
NodeState.Information;
497 if (this.state != NewStateSigned)
499 this.state = NewStateSigned;
501 await this.RaiseUpdate();
506 if (this.state != NewStateUnsigned)
508 this.state = NewStateUnsigned;
510 await this.RaiseUpdate();
515 await this.NodeStateChanged();
526 internal Task RaiseUpdate()
528 return this.OnUpdate.Raise(
this, EventArgs.Empty);
539 string Suffix =
string.Empty;
552 Suffix =
" (" + i.ToString() +
")";
585 if (!this.childrenLoaded)
586 this.LoadChildren().Wait();
588 return !(this.children is
null) && this.children.Count > 0;
619 [Obsolete(
"Use the asynchronous GetParent() method instead.")]
629 if (!(this.parent is
null))
632 if (this.parentId == Guid.Empty)
635 this.parent = await this.LoadParent();
636 if (this.parent is
null)
637 throw new Exception(
"Parent not found.");
651 while (!(Loop is
null))
653 if (Loop is T Ancestor)
672 if (this.updated == DateTime.MinValue)
686 set => this.state = value;
697 return this.GetChildNodes();
701 private async Task<IEnumerable<INode>> GetChildNodes()
703 if (!this.childrenLoaded)
704 await this.LoadChildren();
706 lock (this.synchObject)
708 if (this.children is
null)
709 return Array.Empty<
INode>();
711 return this.children.ToArray();
715 private async Task LoadChildren()
717 List<OutputNode> Children =
new List<OutputNode>();
726 lock (this.synchObject)
728 this.children =
null;
730 if (Children.Count > 0)
736 this.children = Children;
739 this.childrenLoaded =
true;
742 if (!(ToUpdate is
null))
753 if (this.ChildrenOrdered)
755 Children.Sort((n1, n2) => n1.siblingOrdinal.CompareTo(n2.siblingOrdinal));
760 Children.Sort((n1, n2) => n1.nodeId.CompareTo(n2.nodeId));
772 if (this.ChildrenOrdered)
783 Child.siblingOrdinal = Expected;
788 return ToUpdate?.ToArray();
794 internal async Task<OutputNode> LoadParent()
796 if (!(this.parent is
null))
799 if (this.parentId == Guid.Empty)
859 LinkedList<Parameter> Result =
new LinkedList<Parameter>();
863 if (!(this.parent is
null))
866 if (!this.childrenLoaded)
867 await this.LoadChildren();
869 if (!(this.children is
null))
873 lock (this.synchObject)
875 i = this.children.Count;
881 string s = this.state
switch
891 if (!
string.IsNullOrEmpty(s))
896 if (this.updated != DateTime.MinValue)
923 LinkedList<Message> Result =
new LinkedList<Message>();
937 List<Message> Result =
new List<Message>();
942 return Result.ToArray();
979 if (!this.ChildrenOrdered)
982 if (!this.childrenLoaded)
983 await this.LoadChildren();
985 if (this.children is
null)
995 int i = this.children.IndexOf(Child);
999 Child2 = this.children[i - 1];
1001 this.children.RemoveAt(i);
1002 this.children.Insert(i - 1, Child);
1004 i = Child.siblingOrdinal;
1005 Child.siblingOrdinal = Child2.siblingOrdinal;
1006 Child2.siblingOrdinal = i;
1016 Timestamp = DateTime.UtcNow
1030 if (!this.ChildrenOrdered)
1033 if (!this.childrenLoaded)
1034 await this.LoadChildren();
1036 if (this.children is
null)
1044 lock (this.children)
1046 int c = this.children.Count;
1047 int i = this.children.IndexOf(Child);
1048 if (i < 0 || i + 1 >= c)
1051 Child2 = this.children[i + 1];
1053 this.children.RemoveAt(i);
1054 this.children.Insert(i + 1, Child);
1056 i = Child.siblingOrdinal;
1057 Child.siblingOrdinal = Child2.siblingOrdinal;
1058 Child2.siblingOrdinal = i;
1068 Timestamp = DateTime.UtcNow
1095 throw new Exception(
"Child must be an output node.");
1097 if (this.objectId == Guid.Empty)
1098 throw new Exception(
"Parent node must be persisted before you can add nodes to it.");
1100 if (!this.childrenLoaded)
1101 await this.LoadChildren();
1103 Node.parentId = this.objectId;
1109 lock (this.synchObject)
1111 if (this.children is
null)
1112 this.children =
new List<OutputNode>();
1113 else if ((c = this.children.Count) > 0)
1114 After = this.children[c - 1];
1118 Node.siblingOrdinal = this.children.Count;
1121 this.children.Add(Node);
1124 if (!(ToUpdate is
null))
1127 if (Node.objectId == Guid.Empty)
1136 NodeType = Node.GetType().FullName,
1138 DisplayName = await Node.GetTypeNameAsync(
Language),
1153 Timestamp = DateTime.UtcNow
1156 if (this.ChildrenOrdered && !(After is
null))
1158 Event.AfterNodeId = After.nodeId;
1165 await Node.NodeUpdated();
1167 await this.RaiseUpdate();
1175 this.updated = DateTime.Now;
1187 ParentPartition = this.Partition,
1196 Timestamp = DateTime.UtcNow
1199 if (this.oldId != this.nodeId)
1202 this.oldId = this.nodeId;
1211 if (this.objectId != Guid.Empty)
1214 await this.RaiseUpdate();
1225 throw new Exception(
"Child must be an output node.");
1227 if (!this.childrenLoaded)
1228 await this.LoadChildren();
1233 lock (this.synchObject)
1235 if (!(this.children is
null))
1237 i = this.children.IndexOf(Node);
1240 this.children.RemoveAt(i);
1241 if (i == 0 && this.children.Count == 0)
1242 this.children =
null;
1251 if (!(ToUpdate is
null))
1254 Node.parentId = Guid.Empty;
1257 if (Node.objectId != Guid.Empty)
1260 await this.RaiseUpdate();
1267 Timestamp = DateTime.UtcNow
1281 if (this.parent.childrenLoaded)
1285 lock (this.parent.synchObject)
1287 if (!(this.parent.children is
null))
1289 if (this.parent.children.Remove(
this))
1291 if (this.parent.children.Count == 0)
1292 this.parent.children =
null;
1299 if (!(ToUpdate is
null))
1304 if (!this.childrenLoaded)
1305 await this.LoadChildren();
1307 if (!(this.children is
null))
1309 List<OutputNode> Children = this.children;
1310 this.children =
null;
1314 Child.parent =
null;
1315 Child.parentId = Guid.Empty;
1320 this.children =
null;
1323 if (this.objectId != Guid.Empty)
1326 this.objectId = Guid.Empty;
1340 return Task.FromResult<IEnumerable<ICommand>>(
new ICommand[]
Class representing an event.
Static class managing the application event log. Applications and services log events on this static ...
static void Warning(string Message, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, string StackTrace, params KeyValuePair< string, object >[] Tags)
Logs a warning event.
static void Error(string Message, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, string StackTrace, params KeyValuePair< string, object >[] Tags)
Logs an error event.
static void Informational(string Message, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, string StackTrace, params KeyValuePair< string, object >[] Tags)
Logs an informational event.
Clears all messages for an output.
Logs a message on an output.
Defines a message logged on an output node.
DateTime Created
When node was created.
MessageType Type
Message Type
string EventId
Optional Event ID.
Base class for all output nodes.
int SiblingOrdinal
Sibling ordinal, used to order siblings when ordered.
DateTime Updated
When node was last updated. If it has not been updated, value will be DateTime.MinValue.
virtual Task< bool > RemoveWarningAsync(string EventId)
Removes warning messages with a given event ID from the node.
bool HasChildren
If the source has any child sources.
async Task< Message[]> GetMessageArrayAsync(RequestOrigin Caller)
Gets messages logged on the node.
abstract Task< bool > AcceptsParentAsync(INode Parent)
If the node accepts a presumptive parent, i.e. can be added to that parent (if that parent accepts th...
async Task< T > GetAncestor< T >()
Tries to get an ancestor node of a given type, if one exists.
virtual Task< bool > CanViewAsync(RequestOrigin Caller)
If the node is visible to the caller.
virtual Task< bool > RemoveErrorAsync(string EventId)
Removes error messages with a given event ID from the node.
virtual string LocalId
If provided, an ID for the node, but unique locally between siblings. Can be null,...
INode Parent
Parent Node, or null if a root node.
Guid ParentId
Object ID of parent node in persistence layer.
async Task< INode > GetParent()
Gets the parent of the node.
override bool Equals(object obj)
Determines whether the specified object is equal to the current object.
virtual async Task< bool > MoveDownAsync(RequestOrigin Caller)
Tries to move the node down.
virtual Task< bool > RemoveWarningAsync()
Removes warning messages with an empty event ID from the node.
virtual Task< bool > CanAddAsync(RequestOrigin Caller)
If the node can be added to by the caller.
virtual Task LogWarningAsync(string EventId, string Body)
Logs an warning message on the node.
virtual Task< IEnumerable< ICommand > > Commands
Available command objects. If no commands are available, null is returned.
virtual async Task< bool > RemoveAsync(INode Child)
Removes a child from the node.
virtual Task< bool > CanDestroyAsync(RequestOrigin Caller)
If the node can be destroyed to by the caller.
virtual Task LogErrorAsync(string Body)
Logs an error message on the node.
virtual Task< bool > RemoveInformationAsync(string EventId)
Removes an informational message on the node.
virtual async Task< bool > MoveUpAsync(RequestOrigin Caller)
Tries to move the node up.
virtual bool HasCommands
If the node has registered commands or not.
EventHandlerAsync OnUpdate
Event raised when node has been updated.
virtual Task< bool > CanEditAsync(RequestOrigin Caller)
If the node can be edited by the caller.
abstract Task< bool > AcceptsChildAsync(INode Child)
If the node accepts a presumptive child, i.e. can receive as a child (if that child accepts the node ...
DateTime Created
When node was created.
virtual Task< bool > RemoveErrorAsync()
Removes error messages with an empty event ID from the node.
virtual Task LogErrorAsync(string EventId, string Body)
Logs an error message on the node.
virtual async Task< bool > MoveDownAsync(OutputNode Child, RequestOrigin Caller)
Tries to move the child node down.
Guid ObjectId
Object ID in persistence layer.
virtual async Task< IEnumerable< Parameter > > GetDisplayableParametersAsync(Language Language, RequestOrigin Caller)
Gets displayable parameters.
async Task< Parameter[]> GetDisplayableParameterAraryAsync(Language Language, RequestOrigin Caller)
Gets displayable parameters.
string SourceId
Optional ID of source containing node.
virtual bool IsReadable
If the node can be read.
virtual async Task< bool > RemoveMessageAsync(MessageType Type, string EventId)
Logs a message on the node.
virtual OutputNode[] CheckOrderLocked(List< OutputNode > Children)
Checks the ordering of children.
virtual bool ChildrenOrdered
If the children of the node have an intrinsic order (true), or if the order is not important (false).
virtual Task LogInformationAsync(string EventId, string Body)
Logs an informational message on the node.
virtual bool IsControllable
If the node can be controlled.
virtual async Task DestroyAsync()
Destroys the node. If it is a child to a parent node, it is removed from the parent first.
virtual Task< bool > RemoveInformationAsync()
Removes warning messages with an empty event ID from the node.
static async Task< string > GetUniqueNodeId(string OutputId)
Gets a Output ID, based on OutputId that is not already available in the database.
virtual async Task AddAsync(INode Child)
Adds a new child to the node.
virtual Task< bool > RemoveMessageAsync(MessageType Type)
Removes messages with empty event IDs from the node.
OutputNode()
Base class for all output nodes.
Task< IEnumerable< INode > > ChildNodes
Child nodes. If no child nodes are available, null is returned.
virtual async Task NodeUpdated()
Persists changes to the node, and generates a node updated event.
abstract Task< string > GetTypeNameAsync(Language Language)
Gets the type name of the node.
virtual async Task< bool > MoveUpAsync(OutputNode Child, RequestOrigin Caller)
Tries to move the child node up.
virtual Task LogInformationAsync(string Body)
Logs an informational message on the node.
override string ToString()
virtual OutputNode[] SortChildrenAfterLoadLocked(List< OutputNode > Children)
Method that allows the node to sort its children, after they have been loaded.
override int GetHashCode()
Serves as the default hash function.
NodeState State
Current overall state of the node.
DateTime LastChanged
When the node was last updated.
virtual Task LogMessageAsync(MessageType Type, string Body)
Logs a message on the node.
virtual async Task< IEnumerable< Message > > GetMessagesAsync(RequestOrigin Caller)
Gets messages logged on the node.
virtual async Task LogMessageAsync(MessageType Type, string EventId, string Body)
Logs a message on the node.
virtual string LogId
If provided, an ID for the node, as it would appear or be used in system logs. Can be null,...
string Partition
Optional partition in which the Node ID is unique.
virtual Task LogWarningAsync(string Body)
Logs an warning message on the node.
virtual async Task UpdateAsync()
Updates the node (in persisted storage).
Defines the Output data source. This data source contains a tree structure of output of nodes
const string SourceID
Source ID for the output data source.
Static interface for database persistence. In order to work, a database provider has to be assigned t...
static Task< IEnumerable< object > > FindDelete(string Collection, params string[] SortOrder)
Finds objects in a given collection and deletes them in the same atomic operation.
static async Task Update(object Object)
Updates an object in the database.
static async Task Delete(object Object)
Deletes an object in the database.
static async Task< object > LoadObject(string CollectionName, object ObjectId)
Loads an object given its Object ID ObjectId and its collection name CollectionName .
static Task< IEnumerable< object > > Find(string Collection, params string[] SortOrder)
Finds objects in a given collection.
static async Task Insert(object Object)
Inserts an object into the default collection of the database.
This filter selects objects that conform to all child-filters provided.
This filter selects objects that have a named field equal to a given value.
A chunked list is a linked list of chunks of objects of type T .
void AddRange(IEnumerable< T > Collection)
Adds a range of elements (last) to the list.
T[] ToArray()
Returns an array containing all elements of the collection.
Contains information about a language.
async Task< Namespace > GetNamespaceAsync(string Name)
Gets the namespace object, given its name, if available.
async Task< Namespace > CreateNamespaceAsync(string Name)
Creates a new language namespace, or updates an existing language namespace, if one exist with the sa...
Contains information about a namespace in a language.
Task< LanguageString > GetStringAsync(int Id)
Gets the string object, given its ID, if available.
Basic access point for runtime language localization.
static async Task< Language > GetDefaultLanguageAsync()
Gets the default language.
Represents a named semaphore, i.e. an object, identified by a name, that allows single concurrent wri...
Static class of application-wide semaphores that can be used to order access to editable objects.
static async Task< Semaphore > BeginWrite(string Key)
Waits until the semaphore identified by Key is ready for writing. Each call to BeginWrite must be fo...
DateTime-valued parameter.
Contains information about a message logged on a node.
Base class for all node parameters.
string Name
Parameter Name.
virtual object StringValue
String representation of parameter value
Tokens available in request.
static readonly RequestOrigin Empty
Empty request origin.
bool HasPrivilege(string Privilege)
If the origin has a given privilege.
static string EmptyIfSame(string Id1, string Id2)
Returns Id1 if different, string.Empty if the same.
Node status changed event.
Contains a reference to a thing
Base Interface for all output nodes.
Interface for actuator nodes.
Interface for nodes that are published through the concentrator interface.
Task< bool > MoveUpAsync(RequestOrigin Caller)
Tries to move the node up.
INode Parent
Parent Node, or null if a root node.
Task< bool > MoveDownAsync(RequestOrigin Caller)
Tries to move the node down.
Interface for sensor nodes.
Interface for thing references.
delegate Task EventHandlerAsync(object Sender, EventArgs e)
Asynchronous version of EventArgs.
TypeNameSerialization
How the type name should be serialized.
MessageType
Type of message.
NodeState
State of a node.