|
@@ -4,42 +4,33 @@ import { UAReference } from "./UAReference";
|
|
|
import { assert } from "@/util/assert";
|
|
|
import { XMLElem, type IToXML } from "@/util/XmlElem";
|
|
|
import { UARolePermission } from "./UARolePermission";
|
|
|
-import { UAExtension } from "./UAExtension";
|
|
|
-import { UAUserWriteMask } from "./UAUserWriteMask";
|
|
|
-import { UAWriteMask } from "./UAWriteMask";
|
|
|
-import { UAAccessRestriction } from "./UAAccessRestriction";
|
|
|
import { type IAddressSpace } from "./IAddressSpace";
|
|
|
import { ReferenceTypeIds } from "./opcua_node_ids";
|
|
|
+import { UALocalizedText } from "./UALocalizedText";
|
|
|
export class UABaseNode implements IToXML{
|
|
|
|
|
|
public static nullBaseNode=new UABaseNode({browseName: "", addressSpace: {} as IAddressSpace, nodeId: NodeId.nullNodeId});
|
|
|
|
|
|
-
|
|
|
- public nodeId: NodeId;
|
|
|
+ //Default values from xsd
|
|
|
+ public nodeId!: NodeId;
|
|
|
public nodeClass="UABaseNode";
|
|
|
- public browseName: string;
|
|
|
- public addressSpace: IAddressSpace
|
|
|
- public displayName?: string; //LocText
|
|
|
- public description?: string; //LocText
|
|
|
- public symbolicName?: string; //SymbolicName
|
|
|
- public releaseStatus?: string; //ReleaseStatus
|
|
|
- public hasNoPermissions?: boolean;
|
|
|
- public writeMask?: UAWriteMask;
|
|
|
- public userWriteMask?: UAUserWriteMask;
|
|
|
- public category?: string;
|
|
|
+ public browseName!: string;
|
|
|
+ public addressSpace!: IAddressSpace
|
|
|
+ public displayName: UALocalizedText[]=[];
|
|
|
+ public description: UALocalizedText[]=[];
|
|
|
+ public symbolicName?: string;
|
|
|
+ public releaseStatus: string="Released";
|
|
|
+ public hasNoPermissions: boolean=false;
|
|
|
+ public writeMask: number=0;
|
|
|
+ public userWriteMask: number=0;
|
|
|
+ public category: string[]=[];
|
|
|
public documentation?: string;
|
|
|
- public accessRestriction?: UAAccessRestriction;
|
|
|
+ public accessRestriction?: number;
|
|
|
public rolePermissions: UARolePermission[]=[];
|
|
|
- public extensions: UAExtension[]=[];
|
|
|
public references: UAReference[]=[];
|
|
|
- public opts: string[]=[];
|
|
|
|
|
|
constructor(options: UABaseNodeOptions) {
|
|
|
- this.nodeId=options.nodeId;
|
|
|
- this.browseName=options.browseName;
|
|
|
- this.addressSpace=options.addressSpace;
|
|
|
- this.displayName=options.displayName;
|
|
|
- this.references=options.references||[];
|
|
|
+ Object.assign(this, options);
|
|
|
}
|
|
|
|
|
|
|
|
@@ -130,7 +121,7 @@ export class UABaseNode implements IToXML{
|
|
|
getModellingRule(): string|undefined{
|
|
|
this.references.forEach((ref)=>{
|
|
|
if(ref.referenceType == "HasModellingRule"){
|
|
|
- return ref.toNode.displayName;
|
|
|
+ return ref.toNode.browseName;
|
|
|
}
|
|
|
});
|
|
|
return undefined;
|
|
@@ -154,28 +145,77 @@ export class UABaseNode implements IToXML{
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-
|
|
|
-
|
|
|
static fromXML(xmlObject: any, addressSpace: IAddressSpace): UABaseNode{
|
|
|
- const xmlReferences=xmlObject['References']||[];
|
|
|
const references:UAReference[]=[];
|
|
|
const nodeId=coerceNodeId(xmlObject['@_NodeId']);
|
|
|
- for(const xmlref of xmlReferences.Reference||[]) {
|
|
|
+ for(const xmlref of xmlObject['References']?.['Reference']||[]) {
|
|
|
references.push(UAReference.fromXML(xmlref, nodeId));
|
|
|
}
|
|
|
- const ua=new UABaseNode({nodeId: nodeId,
|
|
|
+ const displayNames:UALocalizedText[]=[];
|
|
|
+ for(const xmldn of xmlObject['DisplayName']||[]) {
|
|
|
+ displayNames.push(UALocalizedText.fromXML("DisplayName", xmldn));
|
|
|
+ }
|
|
|
+ const descriptions:UALocalizedText[]=[];
|
|
|
+ for(const desc of xmlObject['Description']||[]) {
|
|
|
+ descriptions.push(UALocalizedText.fromXML("Description", desc));
|
|
|
+ }
|
|
|
+ const permissions:UARolePermission[]=[];
|
|
|
+ for(const perm of xmlObject['RolePermissions']?.['RolePermission']||[]) {
|
|
|
+ permissions.push(UARolePermission.fromXML(perm));
|
|
|
+ }
|
|
|
+ const ua=new UABaseNode({addressSpace: addressSpace,
|
|
|
+ nodeId: nodeId,
|
|
|
browseName: xmlObject['@_BrowseName'],
|
|
|
- displayName: xmlObject['DisplayName']['#text'],
|
|
|
+ writeMask: Number(xmlObject['@_WriteMask']||0),
|
|
|
+ userWriteMask: Number(xmlObject['@_UserWriteMask']||0),
|
|
|
+ accessRestriction: xmlObject['@_AccessRestrictions'],
|
|
|
+ hasNoPermissions: xmlObject['@_HasNoPermissions']||false,
|
|
|
+ symbolicName: xmlObject['@_SymbolicName'],
|
|
|
+ releaseStatus: xmlObject['@_ReleaseStatus']||"Released",
|
|
|
+ displayName: displayNames,
|
|
|
+ description: descriptions,
|
|
|
+ category: xmlObject['Category'],
|
|
|
+ documentation: xmlObject['Documentation']?.['#text'],
|
|
|
references: references,
|
|
|
- addressSpace: addressSpace
|
|
|
- });
|
|
|
-
|
|
|
-
|
|
|
+ rolePermissions: permissions,
|
|
|
+ });
|
|
|
return ua;
|
|
|
}
|
|
|
|
|
|
- toXML(_lnst: NamespaceTable, _gnst: NamespaceTable): XMLElem {
|
|
|
- throw new Error("UABaseNode has no xml rep; implement in subtype.");
|
|
|
+
|
|
|
+ toXML(lnst: NamespaceTable, gnst: NamespaceTable): XMLElem {
|
|
|
+ const nid=UABaseNode.localNodeId(this.nodeId, lnst, gnst);
|
|
|
+ const elem =new XMLElem('UAVariable');
|
|
|
+ elem.attr('NodeId', nid.toString())
|
|
|
+ .attr('BrowseName', this.browseName)
|
|
|
+ .attr('WriteMask', this.writeMask.toString())
|
|
|
+ .attr('UserWriteMask', this.userWriteMask.toString())
|
|
|
+ .attr('AccessRestriction', this.accessRestriction?.toString())
|
|
|
+ .attr('HasNoPermissions', this.hasNoPermissions)
|
|
|
+ .attr('SymbolicName', this.symbolicName)
|
|
|
+ .attr('ReleaseStatus',this.releaseStatus)
|
|
|
+ .attr('Documentation', this.documentation);
|
|
|
+
|
|
|
+ for(const c in this.category) {
|
|
|
+ elem.attr('Category', c);
|
|
|
+ }
|
|
|
+ const refs=new XMLElem('References');
|
|
|
+ for(const ref of this.references) {
|
|
|
+ if(ref.fromNode.nodeId.toString()==this.nodeId.toString()) //on load resolveReferences() duplicates references to both sides. skip them for export
|
|
|
+ refs.add(ref.toXML(lnst, gnst));
|
|
|
+ }
|
|
|
+ if(refs.elements.length>0)
|
|
|
+ elem.add(refs);
|
|
|
+ for(const dn of this.displayName)
|
|
|
+ elem.add(dn.toXML());
|
|
|
+ for(const desc of this.description)
|
|
|
+ elem.add(desc.toXML());
|
|
|
+ const perms=new XMLElem('RolePermissions')
|
|
|
+ for(const perm of this.rolePermissions)
|
|
|
+ perms.add(perm.toXML());
|
|
|
+ if(perms.elements.length>0)
|
|
|
+ elem.add(perms);
|
|
|
+ return elem;
|
|
|
}
|
|
|
|
|
|
static localNodeId(nodeId: NodeId, lnst: NamespaceTable, gnst: NamespaceTable) {
|
|
@@ -191,11 +231,19 @@ export class UABaseNode implements IToXML{
|
|
|
|
|
|
|
|
|
export interface UABaseNodeOptions {
|
|
|
- browseName: string;
|
|
|
+ addressSpace: IAddressSpace;
|
|
|
nodeId: NodeId;
|
|
|
- namespace?: string;
|
|
|
+ browseName: string;
|
|
|
+ writeMask?: number;
|
|
|
+ userWriteMask?: number;
|
|
|
+ accessRestriction?: number;
|
|
|
+ hasNoPermissions?: boolean;
|
|
|
+ symbolicName?: string;
|
|
|
+ releaseStatus?: string;
|
|
|
+ displayName?: UALocalizedText[];
|
|
|
+ description?: UALocalizedText[];
|
|
|
+ category?: string[];
|
|
|
+ documentation?: string;
|
|
|
references?: UAReference[];
|
|
|
- displayName?: string;
|
|
|
- description?: string;
|
|
|
- addressSpace: IAddressSpace;
|
|
|
+ rolePermissions?: UARolePermission[];
|
|
|
}
|