4using System.Threading.Tasks;
24 [CollectionName(
"Jobs")]
28 [Index(
"ParentId",
"NodeId")]
31 private Guid objectId = Guid.Empty;
32 private Guid parentId = Guid.Empty;
34 private string nodeId =
string.Empty;
35 private string oldId =
null;
37 private List<JobNode> children =
null;
38 private int siblingOrdinal = 0;
39 private bool childrenLoaded =
false;
40 private readonly
object synchObject =
new object();
41 private DateTime created = DateTime.Now;
42 private DateTime updated = DateTime.MinValue;
60 return Node.thingReference;
68 public override bool Equals(
object obj)
73 return this.nodeId == Ref.NodeId && this.SourceId == Ref.SourceId && this.Partition == Ref.Partition;
82 return this.nodeId.GetHashCode() ^
94 set => this.objectId = value;
102 get => this.parentId;
103 set => this.parentId = value;
112 set => this.created = value;
118 [DefaultValueDateTimeMinValue]
122 set => this.updated = value;
131 get => this.siblingOrdinal;
132 set => this.siblingOrdinal = value;
138 [Header(2,
"Job ID:", 0)]
140 [ToolTip(4,
"Job identity in the collection of jobs.")]
148 this.thingReference =
null;
150 if (this.oldId is
null && !
string.IsNullOrEmpty(value))
170 StringBuilder sb =
new StringBuilder();
173 sb.Append(this.nodeId);
186 return sb.ToString();
264 if (this.objectId == Guid.Empty)
275 Message.Updated = DateTime.Now;
297 if (this.state <
NodeState.ErrorUnsigned)
301 await this.RaiseUpdate();
306 if (this.state <
NodeState.WarningUnsigned)
310 await this.RaiseUpdate();
319 await this.RaiseUpdate();
339 await this.NodeStateChanged();
342 internal async Task NodeStateChanged()
351 Timestamp = DateTime.UtcNow
422 if (this.objectId == Guid.Empty)
425 bool Removed =
false;
448 bool ErrorsFound =
false;
449 bool WarningsFound =
false;
450 bool InformationFound =
false;
461 WarningsFound =
true;
465 InformationFound =
true;
476 NewStateUnsigned =
NodeState.ErrorUnsigned;
478 else if (WarningsFound)
480 NewStateSigned =
NodeState.WarningSigned;
481 NewStateUnsigned =
NodeState.WarningUnsigned;
483 else if (InformationFound)
486 NewStateUnsigned =
NodeState.Information;
498 if (this.state != NewStateSigned)
500 this.state = NewStateSigned;
502 await this.RaiseUpdate();
507 if (this.state != NewStateUnsigned)
509 this.state = NewStateUnsigned;
511 await this.RaiseUpdate();
516 await this.NodeStateChanged();
527 internal Task RaiseUpdate()
529 return this.OnUpdate.Raise(
this, EventArgs.Empty);
540 string Suffix =
string.Empty;
553 Suffix =
" (" + i.ToString() +
")";
586 if (!this.childrenLoaded)
587 this.LoadChildren().Wait();
589 return !(this.children is
null) && this.children.Count > 0;
620 [Obsolete(
"Use the asynchronous GetParent() method instead.")]
630 if (!(this.parent is
null))
633 if (this.parentId == Guid.Empty)
636 this.parent = await this.LoadParent();
637 if (this.parent is
null)
638 throw new Exception(
"Parent not found.");
652 while (!(Loop is
null))
654 if (Loop is T Ancestor)
673 if (this.updated == DateTime.MinValue)
687 set => this.state = value;
698 return this.GetChildNodes();
702 private async Task<IEnumerable<INode>> GetChildNodes()
704 if (!this.childrenLoaded)
705 await this.LoadChildren();
707 lock (this.synchObject)
709 if (this.children is
null)
710 return Array.Empty<
INode>();
712 return this.children.ToArray();
716 private async Task LoadChildren()
718 List<JobNode> Children =
new List<JobNode>();
724 Children.Add(
JobSource.RegisterNode(Node));
727 lock (this.synchObject)
729 this.children =
null;
731 if (Children.Count > 0)
733 foreach (
JobNode Child
in Children)
737 this.children = Children;
740 this.childrenLoaded =
true;
743 if (!(ToUpdate is
null))
754 if (this.ChildrenOrdered)
756 Children.Sort((n1, n2) => n1.siblingOrdinal.CompareTo(n2.siblingOrdinal));
761 Children.Sort((n1, n2) => n1.nodeId.CompareTo(n2.nodeId));
773 if (this.ChildrenOrdered)
778 foreach (
JobNode Child
in Children)
784 Child.siblingOrdinal = Expected;
789 return ToUpdate?.ToArray();
795 internal async Task<JobNode> LoadParent()
797 if (!(this.parent is
null))
800 if (this.parentId == Guid.Empty)
860 LinkedList<Parameter> Result =
new LinkedList<Parameter>();
864 if (!(this.parent is
null))
867 if (!this.childrenLoaded)
868 await this.LoadChildren();
870 if (!(this.children is
null))
874 lock (this.synchObject)
876 i = this.children.Count;
882 string s = this.state
switch
892 if (!
string.IsNullOrEmpty(s))
897 if (this.updated != DateTime.MinValue)
924 LinkedList<Message> Result =
new LinkedList<Message>();
938 List<Message> Result =
new List<Message>();
943 return Result.ToArray();
980 if (!this.ChildrenOrdered)
983 if (!this.childrenLoaded)
984 await this.LoadChildren();
986 if (this.children is
null)
996 int i = this.children.IndexOf(Child);
1000 Child2 = this.children[i - 1];
1002 this.children.RemoveAt(i);
1003 this.children.Insert(i - 1, Child);
1005 i = Child.siblingOrdinal;
1006 Child.siblingOrdinal = Child2.siblingOrdinal;
1007 Child2.siblingOrdinal = i;
1017 Timestamp = DateTime.UtcNow
1031 if (!this.ChildrenOrdered)
1034 if (!this.childrenLoaded)
1035 await this.LoadChildren();
1037 if (this.children is
null)
1045 lock (this.children)
1047 int c = this.children.Count;
1048 int i = this.children.IndexOf(Child);
1049 if (i < 0 || i + 1 >= c)
1052 Child2 = this.children[i + 1];
1054 this.children.RemoveAt(i);
1055 this.children.Insert(i + 1, Child);
1057 i = Child.siblingOrdinal;
1058 Child.siblingOrdinal = Child2.siblingOrdinal;
1059 Child2.siblingOrdinal = i;
1069 Timestamp = DateTime.UtcNow
1096 throw new Exception(
"Child must be a job node.");
1098 if (this.objectId == Guid.Empty)
1099 throw new Exception(
"Parent node must be persisted before you can add nodes to it.");
1101 if (!this.childrenLoaded)
1102 await this.LoadChildren();
1104 Node.parentId = this.objectId;
1110 lock (this.synchObject)
1112 if (this.children is
null)
1113 this.children =
new List<JobNode>();
1114 else if ((c = this.children.Count) > 0)
1115 After = this.children[c - 1];
1119 Node.siblingOrdinal = this.children.Count;
1122 this.children.Add(Node);
1125 if (!(ToUpdate is
null))
1128 if (Node.objectId == Guid.Empty)
1137 NodeType = Node.GetType().FullName,
1139 DisplayName = await Node.GetTypeNameAsync(
Language),
1154 Timestamp = DateTime.UtcNow
1157 if (this.ChildrenOrdered && !(After is
null))
1159 Event.AfterNodeId = After.nodeId;
1166 await Node.NodeUpdated();
1168 await this.RaiseUpdate();
1176 this.updated = DateTime.Now;
1188 ParentPartition = this.Partition,
1197 Timestamp = DateTime.UtcNow
1200 if (this.oldId != this.nodeId)
1202 JobSource.RegisterNewNodeId(
this, this.oldId);
1203 this.oldId = this.nodeId;
1212 if (this.objectId != Guid.Empty)
1215 await this.RaiseUpdate();
1226 throw new Exception(
"Child must be a job node.");
1228 if (!this.childrenLoaded)
1229 await this.LoadChildren();
1234 lock (this.synchObject)
1236 if (!(this.children is
null))
1238 i = this.children.IndexOf(Node);
1241 this.children.RemoveAt(i);
1242 if (i == 0 && this.children.Count == 0)
1243 this.children =
null;
1252 if (!(ToUpdate is
null))
1255 Node.parentId = Guid.Empty;
1258 if (Node.objectId != Guid.Empty)
1261 await this.RaiseUpdate();
1268 Timestamp = DateTime.UtcNow
1282 if (this.parent.childrenLoaded)
1286 lock (this.parent.synchObject)
1288 if (!(this.parent.children is
null))
1290 if (this.parent.children.Remove(
this))
1292 if (this.parent.children.Count == 0)
1293 this.parent.children =
null;
1300 if (!(ToUpdate is
null))
1305 if (!this.childrenLoaded)
1306 await this.LoadChildren();
1308 if (!(this.children is
null))
1310 List<JobNode> Children = this.children;
1311 this.children =
null;
1313 foreach (
JobNode Child
in Children)
1315 Child.parent =
null;
1316 Child.parentId = Guid.Empty;
1321 this.children =
null;
1324 if (this.objectId != Guid.Empty)
1327 this.objectId = Guid.Empty;
1341 return Task.FromResult<IEnumerable<ICommand>>(
new ICommand[]
1357 return Task.CompletedTask;
1366 return Task.CompletedTask;
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 a job.
Defines a message logged on a job node.
string EventId
Optional Event ID.
DateTime Created
When node was created.
MessageType Type
Message Type
Base class for all job nodes.
INode Parent
Parent Node, or null if a root node.
virtual async Task UpdateAsync()
Updates the node (in persisted storage).
NodeState State
Current overall state of the node.
Task< IEnumerable< INode > > ChildNodes
Child nodes. If no child nodes are available, null is returned.
bool HasChildren
If the source has any child sources.
virtual string LocalId
If provided, an ID for the node, but unique locally between siblings. Can be null,...
virtual bool HasCommands
If the node has registered commands or not.
virtual bool IsReadable
If the node can be read.
virtual Task< bool > CanViewAsync(RequestOrigin Caller)
If the node is visible to the caller.
Guid ObjectId
Object ID in persistence layer.
abstract Task< string > GetTypeNameAsync(Language Language)
Gets the type name of the node.
virtual async Task NodeUpdated()
Persists changes to the node, and generates a node updated event.
virtual async Task< IEnumerable< Parameter > > GetDisplayableParametersAsync(Language Language, RequestOrigin Caller)
Gets displayable parameters.
string Partition
Optional partition in which the Node ID is unique.
virtual Task< bool > RemoveWarningAsync(string EventId)
Removes warning messages with a given event ID from the node.
DateTime Updated
When node was last updated. If it has not been updated, value will be DateTime.MinValue.
async Task< INode > GetParent()
Gets the parent of the node.
virtual async Task< bool > MoveUpAsync(RequestOrigin Caller)
Tries to move the node up.
virtual async Task AddAsync(INode Child)
Adds a new child to the node.
virtual Task< bool > RemoveErrorAsync(string EventId)
Removes error messages with a given event ID from the node.
virtual async Task< bool > RemoveAsync(INode Child)
Removes a child from the node.
string SourceId
Optional ID of source containing node.
static async Task< string > GetUniqueJobId(string JobId)
Gets a Job ID, based on JobId that is not already available in the database.
Guid ParentId
Object ID of parent node in persistence layer.
async Task< T > GetAncestor< T >()
Tries to get an ancestor node of a given type, if one exists.
virtual string LogId
If provided, an ID for the node, as it would appear or be used in system logs. Can be null,...
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(string EventId)
Removes an informational message on the node.
override string ToString()
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...
DateTime LastChanged
When the node was last updated.
virtual async Task< bool > MoveDownAsync(RequestOrigin Caller)
Tries to move the node down.
virtual Task LogMessageAsync(MessageType Type, string Body)
Logs a message on the node.
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 ...
virtual async Task LogMessageAsync(MessageType Type, string EventId, string Body)
Logs a message on the node.
virtual Task< IEnumerable< ICommand > > Commands
Available command objects. If no commands are available, null is returned.
virtual async Task< bool > MoveUpAsync(JobNode Child, RequestOrigin Caller)
Tries to move the child node up.
virtual Task RemovedFromRoot(Root Root)
Node has been removed from the root node.
virtual bool IsControllable
If the node can be controlled.
virtual Task LogWarningAsync(string Body)
Logs an warning message on the node.
virtual Task LogErrorAsync(string Body)
Logs an error message on the node.
virtual Task LogInformationAsync(string Body)
Logs an informational message on the node.
virtual Task LogErrorAsync(string EventId, string Body)
Logs an error message on the node.
virtual async Task< bool > RemoveMessageAsync(MessageType Type, string EventId)
Logs a message on the node.
virtual Task LogInformationAsync(string EventId, string Body)
Logs an informational message on the node.
DateTime Created
When node was created.
override int GetHashCode()
Serves as the default hash function.
virtual JobNode[] SortChildrenAfterLoadLocked(List< JobNode > Children)
Method that allows the node to sort its children, after they have been loaded.
virtual Task< bool > RemoveMessageAsync(MessageType Type)
Removes messages with empty event IDs from the node.
virtual Task< bool > CanEditAsync(RequestOrigin Caller)
If the node can be edited by the caller.
async Task< Message[]> GetMessageArrayAsync(RequestOrigin Caller)
Gets messages logged on the node.
JobNode()
Base class for all job nodes.
virtual Task< bool > CanAddAsync(RequestOrigin Caller)
If the node can be added to by the caller.
virtual async Task< bool > MoveDownAsync(JobNode Child, RequestOrigin Caller)
Tries to move the child node down.
override bool Equals(object obj)
Determines whether the specified object is equal to the current object.
virtual Task< bool > RemoveErrorAsync()
Removes error messages with an empty event ID from the node.
virtual bool ChildrenOrdered
If the children of the node have an intrinsic order (true), or if the order is not important (false).
virtual Task< bool > CanDestroyAsync(RequestOrigin Caller)
If the node can be destroyed to by the caller.
async Task< Parameter[]> GetDisplayableParameterAraryAsync(Language Language, RequestOrigin Caller)
Gets displayable parameters.
virtual Task LogWarningAsync(string EventId, string Body)
Logs an warning message on the node.
EventHandlerAsync OnUpdate
Event raised when node has been updated.
virtual async Task< IEnumerable< Message > > GetMessagesAsync(RequestOrigin Caller)
Gets messages logged on the node.
int SiblingOrdinal
Sibling ordinal, used to order siblings when ordered.
virtual Task AddedToRoot(Root Root)
Node has been added to the root node.
virtual Task< bool > RemoveWarningAsync()
Removes warning messages with an empty event ID from the node.
virtual JobNode[] CheckOrderLocked(List< JobNode > Children)
Checks the ordering of children.
virtual Task< bool > RemoveInformationAsync()
Removes warning messages with an empty event ID from the node.
Defines the Jobs data source. This data source contains a tree structure of jobs of nodes
const string SourceID
Source ID for the jobs data source.
Class for the root node of the Jobs 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 job 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.