2using System.Collections.Generic;
4using System.Threading.Tasks;
22 [CollectionName(
"MeteringTopology")]
26 [Index(
"ParentId",
"NodeId")]
29 private Guid objectId = Guid.Empty;
30 private Guid parentId = Guid.Empty;
32 private string nodeId =
string.Empty;
33 private string oldId =
null;
35 private List<MeteringNode> children =
null;
36 private bool childrenLoaded =
false;
37 private readonly
object synchObject =
new object();
38 private DateTime created = DateTime.Now;
39 private DateTime updated = DateTime.MinValue;
55 if (Node.thingReference is
null)
58 return Node.thingReference;
66 public override bool Equals(
object obj)
71 return this.nodeId == Ref.NodeId && this.SourceId == Ref.SourceId && this.Partition == Ref.Partition;
80 return this.nodeId.GetHashCode() ^
92 set => this.objectId = value;
100 get => this.parentId;
101 set => this.parentId = value;
110 set => this.created = value;
116 [DefaultValueDateTimeMinValue]
120 set => this.updated = value;
126 [Header(15,
"ID:", 0)]
127 [Page(16,
"Identity", 0)]
128 [ToolTip(17,
"Node identity on the network.")]
136 this.thingReference =
null;
138 if (this.oldId is
null && !
string.IsNullOrEmpty(value))
158 StringBuilder sb =
new StringBuilder();
161 sb.Append(this.nodeId);
174 return sb.ToString();
252 if (this.objectId == Guid.Empty)
263 Message.Updated = DateTime.Now;
285 if (this.state <
NodeState.ErrorUnsigned)
289 await this.RaiseUpdate();
294 if (this.state <
NodeState.WarningUnsigned)
298 await this.RaiseUpdate();
307 await this.RaiseUpdate();
327 await this.NodeStateChanged();
330 internal async Task NodeStateChanged()
339 Timestamp = DateTime.Now
410 if (this.objectId == Guid.Empty)
436 bool ErrorsFound =
false;
437 bool WarningsFound =
false;
438 bool InformationFound =
false;
449 WarningsFound =
true;
453 InformationFound =
true;
464 NewStateUnsigned =
NodeState.ErrorUnsigned;
466 else if (WarningsFound)
468 NewStateSigned =
NodeState.WarningSigned;
469 NewStateUnsigned =
NodeState.WarningUnsigned;
471 else if (InformationFound)
474 NewStateUnsigned =
NodeState.Information;
486 if (this.state != NewStateSigned)
488 this.state = NewStateSigned;
490 await this.RaiseUpdate();
495 if (this.state != NewStateUnsigned)
497 this.state = NewStateUnsigned;
499 await this.RaiseUpdate();
504 await this.NodeStateChanged();
515 internal Task RaiseUpdate()
517 return this.OnUpdate.Raise(
this, EventArgs.Empty);
527 string Suffix =
string.Empty;
545 Suffix =
" (" + i.ToString() +
")";
578 if (!this.childrenLoaded)
579 this.LoadChildren().Wait();
581 return !(this.children is
null) && this.children.Count > 0;
612 [Obsolete(
"Use the asynchronous GetParent() method instead.")]
622 if (!(this.parent is
null))
625 if (this.parentId == Guid.Empty)
628 this.parent = await this.LoadParent();
629 if (this.parent is
null)
630 throw new Exception(
"Parent not found.");
644 while (!(Loop is
null))
646 if (Loop is T Ancestor)
665 if (this.updated == DateTime.MinValue)
679 set => this.state = value;
690 return this.GetChildNodes();
694 private async Task<IEnumerable<INode>> GetChildNodes()
696 if (!this.childrenLoaded)
697 await this.LoadChildren();
699 lock (this.synchObject)
701 if (this.children is
null)
704 return this.children.ToArray();
708 private async Task LoadChildren()
711 LinkedList<MeteringNode> Children2 =
new LinkedList<MeteringNode>();
716 lock (this.synchObject)
718 this.children =
null;
722 if (this.children is
null)
723 this.children =
new List<MeteringNode>();
725 this.children.Add(Child);
730 this.childrenLoaded =
true;
743 internal async Task<MeteringNode> LoadParent()
745 if (!(this.parent is
null))
748 if (this.parentId == Guid.Empty)
764 return Task.FromResult(
true);
774 return Task.FromResult(
true);
784 return Task.FromResult(
true);
794 return Task.FromResult(
true);
808 LinkedList<Parameter> Result =
new LinkedList<Parameter>();
814 if (!(this.parent is
null))
817 if (!this.childrenLoaded)
818 await this.LoadChildren();
820 if (!(this.children is
null))
824 lock (this.synchObject)
826 i = this.children.Count;
860 if (!
string.IsNullOrEmpty(s))
865 if (this.updated != DateTime.MinValue)
879 List<Parameter> Result =
new List<Parameter>();
884 return Result.ToArray();
895 LinkedList<Message> Result =
new LinkedList<Message>();
909 List<Message> Result =
new List<Message>();
914 return Result.ToArray();
951 if (!this.ChildrenOrdered || this.children is
null)
959 int i = this.children.IndexOf(Child);
963 this.children.RemoveAt(i);
964 this.children.Insert(i - 1, Child);
972 Timestamp = DateTime.Now
986 if (!this.ChildrenOrdered || this.children is
null)
994 int c = this.children.Count;
995 int i = this.children.IndexOf(Child);
996 if (i < 0 || i + 1 >= c)
999 this.children.RemoveAt(i);
1000 this.children.Insert(i + 1, Child);
1008 Timestamp = DateTime.Now
1035 throw new Exception(
"Child must be a metering node.");
1037 if (this.objectId == Guid.Empty)
1038 throw new Exception(
"Parent node must be persisted before you can add nodes to it.");
1040 if (!this.childrenLoaded)
1041 await this.LoadChildren();
1043 Node.parentId = this.objectId;
1048 lock (this.synchObject)
1050 if (this.children is
null)
1051 this.children =
new List<MeteringNode>();
1052 else if ((c = this.children.Count) > 0)
1053 After = this.children[c - 1];
1055 this.children.Add(Node);
1059 if (Node.objectId == Guid.Empty)
1068 NodeType = Node.GetType().FullName,
1070 DisplayName = await Node.GetTypeNameAsync(
Language),
1085 Timestamp = DateTime.Now
1088 if (this.ChildrenOrdered && !(After is
null))
1090 Event.AfterNodeId = After.nodeId;
1097 await Node.NodeUpdated();
1099 await this.RaiseUpdate();
1107 this.updated = DateTime.Now;
1128 Timestamp = DateTime.Now
1131 if (this.oldId != this.nodeId)
1134 this.oldId = this.nodeId;
1143 if (this.objectId != Guid.Empty)
1146 await this.RaiseUpdate();
1157 throw new Exception(
"Child must be a metering node.");
1159 if (!this.childrenLoaded)
1160 await this.LoadChildren();
1164 lock (this.synchObject)
1166 if (!(this.children is
null))
1168 i = this.children.IndexOf(Node);
1171 this.children.RemoveAt(i);
1172 if (i == 0 && this.children.Count == 0)
1173 this.children =
null;
1180 Node.parentId = Guid.Empty;
1183 if (Node.objectId != Guid.Empty)
1186 await this.RaiseUpdate();
1193 Timestamp = DateTime.Now
1207 if (this.parent.childrenLoaded)
1209 lock (this.parent.synchObject)
1211 if (!(this.parent.children is
null))
1213 this.parent.children.Remove(
this);
1214 if (this.parent.children.Count == 0)
1215 this.parent.children =
null;
1221 if (!this.childrenLoaded)
1222 await this.LoadChildren();
1224 if (!(this.children is
null))
1228 Child.parent =
null;
1229 Child.parentId = Guid.Empty;
1234 this.children =
null;
1237 if (this.objectId != Guid.Empty)
1240 this.objectId = Guid.Empty;
1254 return Task.FromResult<IEnumerable<ICommand>>(
new ICommand[]
1268 public static async Task<IEnumerable<ICommand>>
Join(Task<IEnumerable<ICommand>>
Commands, params
ICommand[] Commands2)
1270 IEnumerable<ICommand> Commands1 = await
Commands;
1272 if (Commands1 is
null)
1275 if (!(Commands1 is List<ICommand> Result))
1277 Result =
new List<ICommand>();
1279 foreach (
ICommand Cmd
in Commands1)
1283 Result.AddRange(Commands2);
1290 #region ILifeCycleManagement
1300 public virtual string Owner =>
string.Empty;
1313 return Task.FromResult<KeyValuePair<string, object>[]>(
new KeyValuePair<string, object>[0]);
1323 throw new NotSupportedException();
1331 throw new NotSupportedException();
1339 throw new NotSupportedException();
1344 #region Momentary values
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.
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 InsertLazy(object Object)
Inserts an object into the database, if unlocked. If locked, object will be inserted at next opportun...
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.
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.
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
Clears all messages for a node.
Logs a message on a node.
Defines a message logged on a metering node.
MessageType Type
Message Type
DateTime Created
When node was created.
string EventId
Optional Event ID.
Base class for all metering nodes.
virtual bool IsControllable
If the node can be controlled.
virtual Task Claimed(string Owner, bool IsPublic)
Called when node has been claimed by an owner.
virtual Task< bool > RemoveMessageAsync(MessageType Type)
Removes messages with empty event IDs from the node.
virtual Task< IEnumerable< ICommand > > Commands
Available command objects. If no commands are available, null is returned.
virtual Task< bool > RemoveErrorAsync(string EventId)
Removes error messages with a given event ID from the node.
virtual Task< bool > RemoveWarningAsync()
Removes warning messages with an empty event ID from the node.
virtual async Task LogMessageAsync(MessageType Type, string EventId, string Body)
Logs a message on the node.
async Task< Parameter[]> GetDisplayableParameterAraryAsync(Language Language, RequestOrigin Caller)
Gets displayable parameters.
virtual bool IsReadable
If the node can be read.
bool HasChildren
If the source has any child sources.
virtual async Task NodeUpdated()
Persists changes to the node, and generates a node updated event.
virtual Task LogWarningAsync(string EventId, string Body)
Logs an warning message on the node.
NodeState State
Current overall state of the node.
virtual Task< bool > RemoveInformationAsync()
Removes warning messages with an empty event ID from the node.
abstract Task< string > GetTypeNameAsync(Language Language)
Gets the type name of 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,...
virtual Task< bool > RemoveInformationAsync(string EventId)
Removes an informational message on the node.
virtual async Task< bool > MoveUpAsync(MeteringNode Child, RequestOrigin Caller)
Tries to move the child node up.
DateTime LastChanged
When the node was last updated.
virtual Task< KeyValuePair< string, object >[]> GetMetaData()
Gets meta-data about the node.
virtual Task LogInformationAsync(string Body)
Logs an informational message on the node.
virtual string LocalId
If provided, an ID for the node, but unique locally between siblings. Can be null,...
virtual Task Removed()
Called when node has been removed from the registry.
virtual Task< bool > CanAddAsync(RequestOrigin Caller)
If the node can be added to by the caller.
virtual bool IsProvisioned
If node can be provisioned.
virtual bool HasCommands
If the node has registered commands or not.
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 LogErrorAsync(string Body)
Logs an error message on the node.
Guid ObjectId
Object ID in persistence layer.
virtual Task< bool > RemoveWarningAsync(string EventId)
Removes warning messages with a given event ID from the node.
static async Task< IEnumerable< ICommand > > Join(Task< IEnumerable< ICommand > > Commands, params ICommand[] Commands2)
Joins sets of commands.
DateTime Created
When node was created.
async Task< T > GetAncestor< T >()
Tries to get an ancestor node of a given type, if one exists.
DateTime Updated
When node was last updated. If it has not been updated, value will be DateTime.MinValue.
virtual Task< bool > CanEditAsync(RequestOrigin Caller)
If the node can be edited by the caller.
string SourceId
Optional ID of source containing node.
virtual Task Disowned()
Called when node has been disowned by its owner.
virtual bool IsPublic
If the node is public.
INode Parent
Parent Node, or null if a root node.
virtual async Task< bool > MoveDownAsync(MeteringNode Child, RequestOrigin Caller)
Tries to move the child node down.
MeteringNode()
Base class for all metering nodes.
virtual async Task< bool > RemoveMessageAsync(MessageType Type, string EventId)
Logs a message on the node.
void NewMomentaryValues(params Field[] Values)
Reports newly measured values.
static async Task< string > GetUniqueNodeId(string NodeId)
Gets a Node ID, based on NodeId that is not already available in the database.
Task< IEnumerable< INode > > ChildNodes
Child nodes. If no child nodes are available, null is returned.
void NewMomentaryValues(IEnumerable< Field > Values)
Reports newly measured values.
virtual void SortChildrenAfterLoadLocked(List< MeteringNode > Children)
Method that allows the node to sort its children, after they have been loaded.
EventHandlerAsync OnUpdate
Event raised when node has been updated.
async Task< INode > GetParent()
Gets the parent of the node.
virtual async Task UpdateAsync()
Updates the node (in persisted storage).
virtual async Task AddAsync(INode Child)
Adds a new child to 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...
virtual string Owner
Who the owner of the node is. The empty string means the node has no owner.
virtual async Task< IEnumerable< Parameter > > GetDisplayableParametersAsync(Language Language, RequestOrigin Caller)
Gets displayable parameters.
virtual Task< bool > RemoveErrorAsync()
Removes error messages with an empty event ID from the node.
virtual Task LogWarningAsync(string Body)
Logs an warning message on the node.
virtual async Task< IEnumerable< Message > > GetMessagesAsync(RequestOrigin Caller)
Gets messages logged on the node.
virtual Task< bool > CanViewAsync(RequestOrigin Caller)
If the node is visible to the caller.
virtual async Task< bool > MoveDownAsync(RequestOrigin Caller)
Tries to move the node down.
async Task< Message[]> GetMessageArrayAsync(RequestOrigin Caller)
Gets messages logged on the node.
override bool Equals(object obj)
Determines whether the specified object is equal to the current object.
override string ToString()
string Partition
Optional partition in which the Node ID is unique.
virtual Task LogErrorAsync(string EventId, string Body)
Logs an error message on the node.
virtual Task LogMessageAsync(MessageType Type, string Body)
Logs a message on 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 async Task< bool > MoveUpAsync(RequestOrigin Caller)
Tries to move the node up.
override int GetHashCode()
Serves as the default hash function.
Guid ParentId
Object ID of parent node in persistence layer.
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< bool > RemoveAsync(INode Child)
Removes a child from the node.
virtual Task LogInformationAsync(string EventId, string Body)
Logs an informational message on the node.
virtual Task< bool > CanDestroyAsync(RequestOrigin Caller)
If the node can be destroyed to by the caller.
Defines the Metering Topology data source. This data source contains a tree structure of persistent r...
static Task NewMomentaryValues(IThingReference Reference, IEnumerable< Field > Values)
Reports newly measured values.
const string SourceID
Source ID for the metering topology data source.
Tokens available in request.
static readonly RequestOrigin Empty
Empty request origin.
Base class for all sensor data fields.
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
Interface for observable classes implementing communication protocols.
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.
Base Interface for all metering nodes.
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.