nodes.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. #!/usr/bin/env/python
  2. # -*- coding: utf-8 -*-
  3. ###
  4. ### Author: Chris Iatrou (ichrispa@core-vector.net)
  5. ### Version: rev 13
  6. ###
  7. ### This program was created for educational purposes and has been
  8. ### contributed to the open62541 project by the author. All licensing
  9. ### terms for this source is inherited by the terms and conditions
  10. ### specified for by the open62541 project (see the projects readme
  11. ### file for more information on the LGPL terms and restrictions).
  12. ###
  13. ### This program is not meant to be used in a production environment. The
  14. ### author is not liable for any complications arising due to the use of
  15. ### this program.
  16. ###
  17. import sys
  18. import logging
  19. from sets import Set
  20. from datatypes import *
  21. from constants import *
  22. logger = logging.getLogger(__name__)
  23. if sys.version_info[0] >= 3:
  24. # strings are already parsed to unicode
  25. def unicode(s):
  26. return s
  27. class Reference(object):
  28. # all either nodeids or strings with an alias
  29. def __init__(self, source, referenceType, target, isForward = True, hidden = False):
  30. self.source = source
  31. self.referenceType = referenceType
  32. self.target = target
  33. self.isForward = isForward
  34. self.hidden = hidden # the reference is part of a nodeset that already exists
  35. def __str__(self):
  36. retval = str(self.source)
  37. if not self.isForward:
  38. retval = retval + "<"
  39. retval = retval + "--[" + str(self.referenceType) + "]--"
  40. if self.isForward:
  41. retval = retval + ">"
  42. return retval + str(self.target)
  43. def __repr__(self):
  44. return str(self)
  45. def __eq__(self, other):
  46. return str(self) == str(other)
  47. def __hash__(self):
  48. return hash(str(self))
  49. class Node(object):
  50. def __init__(self):
  51. self.id = NodeId()
  52. self.nodeClass = NODE_CLASS_GENERERIC
  53. self.browseName = QualifiedName()
  54. self.displayName = LocalizedText()
  55. self.description = LocalizedText()
  56. self.writeMask = 0
  57. self.userWriteMask = 0
  58. self.references = Set()
  59. self.inverseReferences = Set()
  60. self.hidden = False
  61. def __str__(self):
  62. return self.__class__.__name__ + "(" + str(self.id) + ")"
  63. def __repr__(self):
  64. return str(self)
  65. def sanitize(self):
  66. pass
  67. def parseXML(self, xmlelement):
  68. for idname in ['NodeId', 'NodeID', 'nodeid']:
  69. if xmlelement.hasAttribute(idname):
  70. self.id = NodeId(xmlelement.getAttribute(idname))
  71. for (at, av) in xmlelement.attributes.items():
  72. if at == "BrowseName":
  73. self.browseName = QualifiedName(av)
  74. elif at == "DisplayName":
  75. self.displayName = LocalizedText(av)
  76. elif at == "Description":
  77. self.description = LocalizedText(av)
  78. elif at == "WriteMask":
  79. self.writeMask = int(av)
  80. elif at == "UserWriteMask":
  81. self.userWriteMask = int(av)
  82. elif at == "EventNotifier":
  83. self.eventNotifier = int(av)
  84. for x in xmlelement.childNodes:
  85. if x.nodeType != x.ELEMENT_NODE:
  86. continue
  87. if x.firstChild:
  88. if x.tagName == "BrowseName":
  89. self.browseName = QualifiedName(x.firstChild.data)
  90. elif x.tagName == "DisplayName":
  91. self.displayName = LocalizedText(x.firstChild.data)
  92. elif x.tagName == "Description":
  93. self.description = LocalizedText(x.firstChild.data)
  94. elif x.tagName == "WriteMask":
  95. self.writeMask = int(unicode(x.firstChild.data))
  96. elif x.tagName == "UserWriteMask":
  97. self.userWriteMask = int(unicode(x.firstChild.data))
  98. if x.tagName == "References":
  99. self.parseXMLReferences(x)
  100. def parseXMLReferences(self, xmlelement):
  101. for ref in xmlelement.childNodes:
  102. if ref.nodeType != ref.ELEMENT_NODE:
  103. continue
  104. source = NodeId(str(self.id)) # deep-copy of the nodeid
  105. target = NodeId(ref.firstChild.data)
  106. reftype = None
  107. forward = True
  108. for (at, av) in ref.attributes.items():
  109. if at == "ReferenceType":
  110. if '=' in av:
  111. reftype = NodeId(av)
  112. else:
  113. reftype = av # alias, such as "HasSubType"
  114. elif at == "IsForward":
  115. forward = not "false" in av.lower()
  116. if forward:
  117. self.references.add(Reference(source, reftype, target, forward))
  118. else:
  119. self.inverseReferences.add(Reference(source, reftype, target, forward))
  120. def replaceAliases(self, aliases):
  121. if str(self.id) in aliases:
  122. self.id = NodeId(aliases[self.id])
  123. new_refs = set()
  124. for ref in self.references:
  125. if str(ref.source) in aliases:
  126. ref.source = NodeId(aliases[ref.source])
  127. if str(ref.target) in aliases:
  128. ref.target = NodeId(aliases[ref.target])
  129. if str(ref.referenceType) in aliases:
  130. ref.referenceType = NodeId(aliases[ref.referenceType])
  131. new_refs.add(ref)
  132. self.references = new_refs
  133. new_inv_refs = set()
  134. for ref in self.inverseReferences:
  135. if str(ref.source) in aliases:
  136. ref.source = NodeId(aliases[ref.source])
  137. if str(ref.target) in aliases:
  138. ref.target = NodeId(aliases[ref.target])
  139. if str(ref.referenceType) in aliases:
  140. ref.referenceType = NodeId(aliases[ref.referenceType])
  141. new_inv_refs.add(ref)
  142. self.inverseReferences = new_inv_refs
  143. def replaceNamespaces(self, nsMapping):
  144. self.id.ns = nsMapping[self.id.ns]
  145. self.browseName.ns = nsMapping[self.browseName.ns]
  146. new_refs = set()
  147. for ref in self.references:
  148. ref.source.ns = nsMapping[ref.source.ns]
  149. ref.target.ns = nsMapping[ref.target.ns]
  150. ref.referenceType.ns = nsMapping[ref.referenceType.ns]
  151. new_refs.add(ref)
  152. self.references = new_refs
  153. new_inv_refs = set()
  154. for ref in self.inverseReferences:
  155. ref.source.ns = nsMapping[ref.source.ns]
  156. ref.target.ns = nsMapping[ref.target.ns]
  157. ref.referenceType.ns = nsMapping[ref.referenceType.ns]
  158. new_inv_refs.add(ref)
  159. self.inverseReferences = new_inv_refs
  160. class ReferenceTypeNode(Node):
  161. def __init__(self, xmlelement = None):
  162. Node.__init__(self)
  163. self.nodeClass = NODE_CLASS_REFERENCETYPE
  164. self.isAbstract = False
  165. self.symmetric = False
  166. self.inverseName = ""
  167. if xmlelement:
  168. self.parseXML(xmlelement)
  169. def parseXML(self, xmlelement):
  170. Node.parseXML(self, xmlelement)
  171. for (at, av) in xmlelement.attributes.items():
  172. if at == "Symmetric":
  173. self.symmetric = "false" not in av.lower()
  174. elif at == "InverseName":
  175. self.inverseName = str(av)
  176. elif at == "IsAbstract":
  177. self.isAbstract = "false" not in av.lower()
  178. for x in xmlelement.childNodes:
  179. if x.nodeType == x.ELEMENT_NODE:
  180. if x.tagName == "InverseName" and x.firstChild:
  181. self.inverseName = str(unicode(x.firstChild.data))
  182. class ObjectNode(Node):
  183. def __init__(self, xmlelement = None):
  184. Node.__init__(self)
  185. self.nodeClass = NODE_CLASS_OBJECT
  186. self.eventNotifier = 0
  187. if xmlelement:
  188. self.parseXML(xmlelement)
  189. def parseXML(self, xmlelement):
  190. Node.parseXML(self, xmlelement)
  191. for (at, av) in xmlelement.attributes.items():
  192. if at == "EventNotifier":
  193. self.eventNotifier = int(av)
  194. class VariableNode(Node):
  195. def __init__(self, xmlelement = None):
  196. Node.__init__(self)
  197. self.nodeClass = NODE_CLASS_VARIABLE
  198. self.dataType = NodeId()
  199. self.valueRank = -1
  200. self.arrayDimensions = []
  201. self.accessLevel = 0
  202. self.userAccessLevel = 0
  203. self.minimumSamplingInterval = 0.0
  204. self.historizing = False
  205. self.value = None
  206. self.xmlValueDef = None
  207. if xmlelement:
  208. self.parseXML(xmlelement)
  209. def parseXML(self, xmlelement):
  210. Node.parseXML(self, xmlelement)
  211. for (at, av) in xmlelement.attributes.items():
  212. if at == "ValueRank":
  213. self.valueRank = int(av)
  214. elif at == "AccessLevel":
  215. self.accessLevel = int(av)
  216. elif at == "UserAccessLevel":
  217. self.userAccessLevel = int(av)
  218. elif at == "MinimumSamplingInterval":
  219. self.minimumSamplingInterval = float(av)
  220. elif at == "DataType":
  221. if "=" in av:
  222. self.dataType = NodeId(av)
  223. else:
  224. self.dataType = av
  225. for x in xmlelement.childNodes:
  226. if x.nodeType != x.ELEMENT_NODE:
  227. continue
  228. if x.tagName == "Value":
  229. self.__xmlValueDef__ = x
  230. elif x.tagName == "DataType":
  231. self.dataType = NodeId(str(x))
  232. elif x.tagName == "ValueRank":
  233. self.valueRank = int(unicode(x.firstChild.data))
  234. elif x.tagName == "ArrayDimensions":
  235. self.arrayDimensions = int(unicode(x.firstChild.data))
  236. elif x.tagName == "AccessLevel":
  237. self.accessLevel = int(unicode(x.firstChild.data))
  238. elif x.tagName == "UserAccessLevel":
  239. self.userAccessLevel = int(unicode(x.firstChild.data))
  240. elif x.tagName == "MinimumSamplingInterval":
  241. self.minimumSamplingInterval = float(unicode(x.firstChild.data))
  242. elif x.tagName == "Historizing":
  243. self.historizing = "false" not in x.lower()
  244. class VariableTypeNode(VariableNode):
  245. def __init__(self, xmlelement = None):
  246. VariableNode.__init__(self)
  247. self.nodeClass = NODE_CLASS_VARIABLETYPE
  248. if xmlelement:
  249. self.parseXML(xmlelement)
  250. class MethodNode(Node):
  251. def __init__(self, xmlelement = None):
  252. Node.__init__(self)
  253. self.nodeClass = NODE_CLASS_METHOD
  254. self.executable = True
  255. self.userExecutable = True
  256. self.methodDecalaration = None
  257. if xmlelement:
  258. self.parseXML(xmlelement)
  259. def parseXML(self, xmlelement):
  260. Node.parseXML(self, xmlelement)
  261. for (at, av) in xmlelement.attributes.items():
  262. if at == "Executable":
  263. self.executable = "false" not in av.lower()
  264. if at == "UserExecutable":
  265. self.userExecutable = "false" not in av.lower()
  266. if at == "MethodDeclarationId":
  267. self.methodDeclaration = str(av)
  268. class ObjectTypeNode(Node):
  269. def __init__(self, xmlelement = None):
  270. Node.__init__(self)
  271. self.nodeClass = NODE_CLASS_OBJECTTYPE
  272. self.isAbstract = False
  273. if xmlelement:
  274. self.parseXML(xmlelement)
  275. def parseXML(self, xmlelement):
  276. Node.parseXML(self, xmlelement)
  277. for (at, av) in xmlelement.attributes.items():
  278. if at == "IsAbstract":
  279. self.isAbstract = "false" not in av.lower()
  280. class DataTypeNode(Node):
  281. def __init__(self, xmlelement = None):
  282. Node.__init__(self)
  283. self.nodeClass = NODE_CLASS_DATATYPE
  284. self.isAbstract = False
  285. if xmlelement:
  286. self.parseXML(xmlelement)
  287. def parseXML(self, xmlelement):
  288. Node.parseXML(self, xmlelement)
  289. for (at, av) in xmlelement.attributes.items():
  290. if at == "IsAbstract":
  291. self.isAbstract = "false" not in av.lower()
  292. class ViewNode(Node):
  293. def __init__(self, xmlelement = None):
  294. Node.__init__(self)
  295. self.nodeClass = NODE_CLASS_VIEW
  296. self.containsNoLoops == False
  297. self.eventNotifier == False
  298. if xmlelement:
  299. self.parseXML(xmlelement)
  300. def parseXML(self, xmlelement):
  301. Node.parseXML(self, xmlelement)
  302. for (at, av) in xmlelement.attributes.items():
  303. if at == "ContainsNoLoops":
  304. self.containsNoLoops = "false" not in av.lower()
  305. if at == "eventNotifier":
  306. self.eventNotifier = "false" not in av.lower()