ua_pubsub_ns0.c 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  4. *
  5. * Copyright (c) 2017-2018 Fraunhofer IOSB (Author: Andreas Ebner)
  6. */
  7. #include "ua_server_pubsub.h"
  8. #include "src_generated/ua_types_generated.h"
  9. #include "ua_server_pubsub.h"
  10. #include "ua_types.h"
  11. #include "ua_types.h"
  12. #include "ua_pubsub_ns0.h"
  13. #include "ua_pubsub.h"
  14. #include "src_generated/ua_types_generated_encoding_binary.h"
  15. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL /* conditional compilation */
  16. typedef struct{
  17. UA_NodeId parentNodeId;
  18. UA_UInt32 parentCalssifier;
  19. UA_UInt32 elementClassiefier;
  20. } UA_NodePropertyContext;
  21. //Prototypes
  22. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  23. static UA_StatusCode addWriterGroupAction(UA_Server *server,
  24. const UA_NodeId *sessionId, void *sessionHandle,
  25. const UA_NodeId *methodId, void *methodContext,
  26. const UA_NodeId *objectId, void *objectContext,
  27. size_t inputSize, const UA_Variant *input,
  28. size_t outputSize, UA_Variant *output);
  29. static UA_StatusCode removeGroupAction(UA_Server *server,
  30. const UA_NodeId *sessionId, void *sessionHandle,
  31. const UA_NodeId *methodId, void *methodContext,
  32. const UA_NodeId *objectId, void *objectContext,
  33. size_t inputSize, const UA_Variant *input,
  34. size_t outputSize, UA_Variant *output);
  35. #endif
  36. static UA_StatusCode
  37. addPubSubObjectNode(UA_Server *server, char* name, UA_UInt32 objectid,
  38. UA_UInt32 parentid, UA_UInt32 referenceid, UA_UInt32 type_id) {
  39. UA_ObjectAttributes object_attr = UA_ObjectAttributes_default;
  40. object_attr.displayName = UA_LOCALIZEDTEXT("", name);
  41. return UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(0, objectid),
  42. UA_NODEID_NUMERIC(0, parentid),
  43. UA_NODEID_NUMERIC(0, referenceid),
  44. UA_QUALIFIEDNAME(0, name),
  45. UA_NODEID_NUMERIC(0, type_id),
  46. object_attr, NULL, NULL);
  47. }
  48. static UA_StatusCode
  49. writePubSubNs0VariableArray(UA_Server *server, UA_UInt32 id, void *v,
  50. size_t length, const UA_DataType *type) {
  51. UA_Variant var;
  52. UA_Variant_init(&var);
  53. UA_Variant_setArray(&var, v, length, type);
  54. return UA_Server_writeValue(server, UA_NODEID_NUMERIC(0, id), var);
  55. }
  56. static UA_NodeId
  57. findSingleChildNode(UA_Server *server, UA_QualifiedName targetName,
  58. UA_NodeId referenceTypeId, UA_NodeId startingNode){
  59. UA_NodeId resultNodeId;
  60. UA_RelativePathElement rpe;
  61. UA_RelativePathElement_init(&rpe);
  62. rpe.referenceTypeId = referenceTypeId;
  63. rpe.isInverse = false;
  64. rpe.includeSubtypes = false;
  65. rpe.targetName = targetName;
  66. UA_BrowsePath bp;
  67. UA_BrowsePath_init(&bp);
  68. bp.startingNode = startingNode;
  69. bp.relativePath.elementsSize = 1;
  70. bp.relativePath.elements = &rpe;
  71. UA_BrowsePathResult bpr =
  72. UA_Server_translateBrowsePathToNodeIds(server, &bp);
  73. if(bpr.statusCode != UA_STATUSCODE_GOOD ||
  74. bpr.targetsSize < 1)
  75. return UA_NODEID_NULL;
  76. if(UA_NodeId_copy(&bpr.targets[0].targetId.nodeId, &resultNodeId) != UA_STATUSCODE_GOOD){
  77. UA_BrowsePathResult_deleteMembers(&bpr);
  78. return UA_NODEID_NULL;
  79. }
  80. UA_BrowsePathResult_deleteMembers(&bpr);
  81. return resultNodeId;
  82. }
  83. static void
  84. onRead(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
  85. const UA_NodeId *nodeid, void *nodeContext,
  86. const UA_NumericRange *range, const UA_DataValue *data) {
  87. UA_Variant value;
  88. UA_Variant_init(&value);
  89. UA_NodeId myNodeId;
  90. UA_WriterGroup *writerGroup = NULL;
  91. UA_PubSubConnection *pubSubConnection = NULL;
  92. switch(((UA_NodePropertyContext *) nodeContext)->parentCalssifier){
  93. case UA_NS0ID_PUBSUBCONNECTIONTYPE:
  94. myNodeId = ((UA_NodePropertyContext *) nodeContext)->parentNodeId;
  95. pubSubConnection = UA_PubSubConnection_findConnectionbyId(server, myNodeId);
  96. switch(((UA_NodePropertyContext *) nodeContext)->elementClassiefier) {
  97. case UA_NS0ID_PUBSUBCONNECTIONTYPE_PUBLISHERID:
  98. if(pubSubConnection->config->publisherIdType == UA_PUBSUB_PUBLISHERID_STRING) {
  99. UA_Variant_setScalar(&value, &pubSubConnection->config->publisherId.numeric,
  100. &UA_TYPES[UA_TYPES_STRING]);
  101. }else
  102. UA_Variant_setScalar(&value, &pubSubConnection->config->publisherId.numeric, &UA_TYPES[UA_TYPES_UINT32]);
  103. break;
  104. default:
  105. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  106. "Read error! Unknown property.");
  107. }
  108. break;
  109. case UA_NS0ID_WRITERGROUPTYPE:
  110. myNodeId = ((UA_NodePropertyContext *) nodeContext)->parentNodeId;
  111. writerGroup = UA_WriterGroup_findWGbyId(server, myNodeId);
  112. if(!writerGroup)
  113. return;
  114. switch(((UA_NodePropertyContext *) nodeContext)->elementClassiefier){
  115. case UA_NS0ID_WRITERGROUPTYPE_PUBLISHINGINTERVAL:
  116. UA_Variant_setScalar(&value, &writerGroup->config.publishingInterval, &UA_TYPES[UA_TYPES_DURATION]);
  117. break;
  118. default:
  119. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  120. "Read error! Unknown property.");
  121. }
  122. break;
  123. default:
  124. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  125. "Read error! Unknown parent element.");
  126. }
  127. UA_Server_writeValue(server, *nodeid, value);
  128. }
  129. static void
  130. onWrite(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
  131. const UA_NodeId *nodeId, void *nodeContext,
  132. const UA_NumericRange *range, const UA_DataValue *data){
  133. UA_Variant value;
  134. UA_NodeId myNodeId;
  135. UA_WriterGroup *writerGroup = NULL;
  136. switch(((UA_NodePropertyContext *) nodeContext)->parentCalssifier){
  137. case UA_NS0ID_PUBSUBCONNECTIONTYPE:
  138. //no runtime writable attributes
  139. break;
  140. case UA_NS0ID_WRITERGROUPTYPE:
  141. myNodeId = ((UA_NodePropertyContext *) nodeContext)->parentNodeId;
  142. writerGroup = UA_WriterGroup_findWGbyId(server, myNodeId);
  143. UA_WriterGroupConfig writerGroupConfig;
  144. memset(&writerGroupConfig, 0, sizeof(writerGroupConfig));
  145. if(!writerGroup)
  146. return;
  147. switch(((UA_NodePropertyContext *) nodeContext)->elementClassiefier){
  148. case UA_NS0ID_WRITERGROUPTYPE_PUBLISHINGINTERVAL:
  149. UA_Server_getWriterGroupConfig(server, writerGroup->identifier, &writerGroupConfig);
  150. writerGroupConfig.publishingInterval = *((UA_Duration *) data->value.data);
  151. UA_Server_updateWriterGroupConfig(server, writerGroup->identifier, &writerGroupConfig);
  152. UA_Variant_setScalar(&value, data->value.data, &UA_TYPES[UA_TYPES_DURATION]);
  153. UA_WriterGroupConfig_deleteMembers(&writerGroupConfig);
  154. break;
  155. default:
  156. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  157. "Write error! Unknown property element.");
  158. }
  159. break;
  160. default:
  161. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  162. "Read error! Unknown parent element.");
  163. }
  164. }
  165. static UA_StatusCode
  166. addVariableValueSource(UA_Server *server, UA_ValueCallback valueCallback,
  167. UA_NodeId node, UA_NodePropertyContext *context){
  168. UA_Server_setNodeContext(server, node, context);
  169. return UA_Server_setVariableNode_valueCallback(server, node, valueCallback);
  170. }
  171. /*************************************************/
  172. /* PubSubConnection */
  173. /*************************************************/
  174. UA_StatusCode
  175. addPubSubConnectionRepresentation(UA_Server *server, UA_PubSubConnection *connection){
  176. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  177. if(connection->config->name.length > 512)
  178. return UA_STATUSCODE_BADOUTOFMEMORY;
  179. UA_STACKARRAY(char, connectionName, sizeof(char) * connection->config->name.length +1);
  180. memcpy(connectionName, connection->config->name.data, connection->config->name.length);
  181. connectionName[connection->config->name.length] = '\0';
  182. //This code block must use a lock
  183. UA_Nodestore_remove(server, &connection->identifier);
  184. UA_NodeId pubSubConnectionNodeId;
  185. UA_ObjectAttributes attr = UA_ObjectAttributes_default;
  186. attr.displayName = UA_LOCALIZEDTEXT("de-DE", connectionName);
  187. retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT, UA_NODEID_NUMERIC(0, connection->identifier.identifier.numeric),
  188. UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE), UA_NODEID_NUMERIC(0, UA_NS0ID_HASPUBSUBCONNECTION),
  189. UA_QUALIFIEDNAME(0, connectionName), UA_NODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES], NULL, &pubSubConnectionNodeId);
  190. addPubSubObjectNode(server, "Address", connection->identifier.identifier.numeric+1, pubSubConnectionNodeId.identifier.numeric, UA_NS0ID_HASCOMPONENT, UA_NS0ID_NETWORKADDRESSURLTYPE);
  191. UA_Server_addNode_finish(server, pubSubConnectionNodeId);
  192. //End lock zone
  193. UA_NodeId addressNode, urlNode, interfaceNode, publisherIdNode, connectionPropertieNode, transportProfileUri;
  194. addressNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "Address"),
  195. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
  196. UA_NODEID_NUMERIC(0, connection->identifier.identifier.numeric));
  197. urlNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "Url"),
  198. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), addressNode);
  199. interfaceNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "NetworkInterface"),
  200. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), addressNode);
  201. publisherIdNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "PublisherId"),
  202. UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
  203. UA_NODEID_NUMERIC(0, connection->identifier.identifier.numeric));
  204. connectionPropertieNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "ConnectionProperties"),
  205. UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
  206. UA_NODEID_NUMERIC(0, connection->identifier.identifier.numeric));
  207. transportProfileUri = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "TransportProfileUri"),
  208. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
  209. UA_NODEID_NUMERIC(0, connection->identifier.identifier.numeric));
  210. retVal |= writePubSubNs0VariableArray(server, connectionPropertieNode.identifier.numeric,
  211. connection->config->connectionProperties,
  212. connection->config->connectionPropertiesSize,
  213. &UA_TYPES[UA_TYPES_KEYVALUEPAIR]);
  214. UA_NetworkAddressUrlDataType *networkAddressUrlDataType = ((UA_NetworkAddressUrlDataType *) connection->config->address.data);
  215. UA_Variant value;
  216. UA_Variant_init(&value);
  217. UA_Variant_setScalar(&value, &networkAddressUrlDataType->url, &UA_TYPES[UA_TYPES_STRING]);
  218. UA_Server_writeValue(server, urlNode, value);
  219. UA_Variant_setScalar(&value, &networkAddressUrlDataType->networkInterface, &UA_TYPES[UA_TYPES_STRING]);
  220. UA_Server_writeValue(server, interfaceNode, value);
  221. UA_Variant_setScalar(&value, &connection->config->transportProfileUri, &UA_TYPES[UA_TYPES_STRING]);
  222. UA_Server_writeValue(server, transportProfileUri, value);
  223. UA_NodePropertyContext *connectionPublisherIdContext = (UA_NodePropertyContext *) UA_malloc(sizeof(UA_NodePropertyContext));
  224. connectionPublisherIdContext->parentNodeId = connection->identifier;
  225. connectionPublisherIdContext->parentCalssifier = UA_NS0ID_PUBSUBCONNECTIONTYPE;
  226. connectionPublisherIdContext->elementClassiefier = UA_NS0ID_PUBSUBCONNECTIONTYPE_PUBLISHERID;
  227. UA_ValueCallback valueCallback;
  228. valueCallback.onRead = onRead;
  229. valueCallback.onWrite = NULL;
  230. retVal |= addVariableValueSource(server, valueCallback, publisherIdNode, connectionPublisherIdContext);
  231. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  232. retVal |= UA_Server_addReference(server, connection->identifier,
  233. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
  234. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_ADDWRITERGROUP), true);
  235. retVal |= UA_Server_addReference(server, connection->identifier,
  236. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
  237. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_ADDREADERGROUP), true);
  238. retVal |= UA_Server_addReference(server, connection->identifier,
  239. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
  240. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_REMOVEGROUP), true);
  241. #endif
  242. return retVal;
  243. }
  244. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  245. static UA_StatusCode
  246. addPubSubConnectionAction(UA_Server *server,
  247. const UA_NodeId *sessionId, void *sessionHandle,
  248. const UA_NodeId *methodId, void *methodContext,
  249. const UA_NodeId *objectId, void *objectContext,
  250. size_t inputSize, const UA_Variant *input,
  251. size_t outputSize, UA_Variant *output){
  252. UA_PubSubConnectionDataType pubSubConnectionDataType = *((UA_PubSubConnectionDataType *) input[0].data);
  253. UA_NetworkAddressUrlDataType networkAddressUrlDataType;
  254. memset(&networkAddressUrlDataType, 0, sizeof(networkAddressUrlDataType));
  255. UA_ExtensionObject eo = pubSubConnectionDataType.address;
  256. if(eo.encoding == UA_EXTENSIONOBJECT_ENCODED_BYTESTRING){
  257. size_t offset = 0;
  258. UA_NetworkAddressUrlDataType_decodeBinary(&eo.content.encoded.body, &offset, &networkAddressUrlDataType);
  259. if(networkAddressUrlDataType.url.length > 512)
  260. return UA_STATUSCODE_BADOUTOFMEMORY;
  261. UA_STACKARRAY(char, buffer, sizeof(char) * networkAddressUrlDataType.url.length +1);
  262. memcpy(buffer, networkAddressUrlDataType.url.data, networkAddressUrlDataType.url.length);
  263. buffer[networkAddressUrlDataType.url.length] = '\0';
  264. printf("%s\n", buffer);
  265. }
  266. UA_PubSubConnectionConfig connectionConfig;
  267. memset(&connectionConfig, 0, sizeof(UA_PubSubConnectionConfig));
  268. connectionConfig.transportProfileUri = UA_STRING("http://opcfoundation.org/UA-Profile/Transport/pubsub-udp-uadp");
  269. connectionConfig.name = pubSubConnectionDataType.name;
  270. UA_Variant_setScalar(&connectionConfig.address, &networkAddressUrlDataType,
  271. &UA_TYPES[UA_TYPES_NETWORKADDRESSURLDATATYPE]);
  272. if(pubSubConnectionDataType.publisherId.type == &UA_TYPES[UA_TYPES_UINT32]){
  273. connectionConfig.publisherId.numeric = * ((UA_UInt32 *) pubSubConnectionDataType.publisherId.data);
  274. } else {
  275. connectionConfig.publisherIdType = UA_PUBSUB_PUBLISHERID_STRING;
  276. connectionConfig.publisherId.string = * ((UA_String *) pubSubConnectionDataType.publisherId.data);
  277. }
  278. //call API function and create the connection
  279. UA_NodeId connectionId;
  280. if(UA_Server_addPubSubConnection(server, &connectionConfig, &connectionId) != UA_STATUSCODE_GOOD){
  281. //error handling
  282. };
  283. for(size_t i = 0; i < pubSubConnectionDataType.writerGroupsSize; i++){
  284. //UA_PubSubConnection_addWriterGroup(server, UA_NODEID_NULL, NULL, NULL);
  285. };
  286. for(size_t i = 0; i < pubSubConnectionDataType.readerGroupsSize; i++){
  287. //UA_PubSubConnection_addReaderGroup(server, NULL, NULL, NULL);
  288. };
  289. UA_NetworkAddressUrlDataType_deleteMembers(&networkAddressUrlDataType);
  290. //set ouput value
  291. UA_Variant_setScalarCopy(output, &connectionId, &UA_TYPES[UA_TYPES_NODEID]);
  292. return UA_STATUSCODE_GOOD;
  293. }
  294. #endif
  295. UA_StatusCode
  296. removePubSubConnectionRepresentation(UA_Server *server, UA_PubSubConnection *connection){
  297. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  298. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  299. retVal |= UA_Server_deleteReference(server, connection->identifier, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), true,
  300. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_ADDWRITERGROUP),
  301. false);
  302. retVal |= UA_Server_deleteReference(server, connection->identifier, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), true,
  303. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_ADDREADERGROUP),
  304. false);
  305. retVal |= UA_Server_deleteReference(server, connection->identifier, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), true,
  306. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_REMOVEGROUP),
  307. false);
  308. #endif
  309. retVal |= UA_Server_deleteNode(server, connection->identifier, true);
  310. return retVal;
  311. }
  312. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  313. static UA_StatusCode
  314. removeConnectionAction(UA_Server *server,
  315. const UA_NodeId *sessionId, void *sessionHandle,
  316. const UA_NodeId *methodId, void *methodContext,
  317. const UA_NodeId *objectId, void *objectContext,
  318. size_t inputSize, const UA_Variant *input,
  319. size_t outputSize, UA_Variant *output){
  320. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  321. UA_NodeId nodeToRemove = *((UA_NodeId *) input[0].data);
  322. retVal |= UA_Server_removePubSubConnection(server, nodeToRemove);
  323. if(retVal == UA_STATUSCODE_BADNOTFOUND)
  324. retVal = UA_STATUSCODE_BADNODEIDUNKNOWN;
  325. return retVal;
  326. }
  327. #endif
  328. /*************************************************/
  329. /* PublishedDataSet */
  330. /*************************************************/
  331. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  332. static UA_StatusCode
  333. addDataSetFolderAction(UA_Server *server,
  334. const UA_NodeId *sessionId, void *sessionHandle,
  335. const UA_NodeId *methodId, void *methodContext,
  336. const UA_NodeId *objectId, void *objectContext,
  337. size_t inputSize, const UA_Variant *input,
  338. size_t outputSize, UA_Variant *output){
  339. /* defined in R 1.04 9.1.4.5.7 */
  340. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  341. UA_String newFolderName = *((UA_String *) input[0].data);
  342. UA_NodeId generatedId;
  343. UA_ObjectAttributes objectAttributes = UA_ObjectAttributes_default;
  344. UA_LocalizedText name = {UA_STRING("en-US"), newFolderName};
  345. objectAttributes.displayName = name;
  346. retVal |= UA_Server_addObjectNode(server, UA_NODEID_NULL, *objectId, UA_NODEID_NUMERIC(0,UA_NS0ID_ORGANIZES),
  347. UA_QUALIFIEDNAME(0, "DataSetFolder"), UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE),
  348. objectAttributes, NULL, &generatedId);
  349. UA_Variant_setScalarCopy(output, &generatedId, &UA_TYPES[UA_TYPES_NODEID]);
  350. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  351. retVal |= UA_Server_addReference(server, generatedId,
  352. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
  353. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_ADDPUBLISHEDDATAITEMS), true);
  354. retVal |= UA_Server_addReference(server, generatedId,
  355. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
  356. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_REMOVEPUBLISHEDDATASET), true);
  357. retVal |= UA_Server_addReference(server, generatedId,
  358. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
  359. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_ADDDATASETFOLDER), true);
  360. retVal |= UA_Server_addReference(server, generatedId,
  361. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
  362. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_REMOVEDATASETFOLDER), true);
  363. #endif
  364. return retVal;
  365. }
  366. #endif
  367. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  368. static UA_StatusCode
  369. removeDataSetFolderAction(UA_Server *server,
  370. const UA_NodeId *sessionId, void *sessionHandle,
  371. const UA_NodeId *methodId, void *methodContext,
  372. const UA_NodeId *objectId, void *objectContext,
  373. size_t inputSize, const UA_Variant *input,
  374. size_t outputSize, UA_Variant *output){
  375. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  376. UA_NodeId nodeToRemove = *((UA_NodeId *) input[0].data);
  377. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  378. retVal |= UA_Server_deleteReference(server, nodeToRemove, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), true,
  379. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_ADDPUBLISHEDDATAITEMS),
  380. false);
  381. retVal |= UA_Server_deleteReference(server, nodeToRemove, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), true,
  382. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_REMOVEPUBLISHEDDATASET),
  383. false);
  384. retVal |= UA_Server_deleteReference(server, nodeToRemove, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), true,
  385. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_ADDDATASETFOLDER),
  386. false);
  387. retVal |= UA_Server_deleteReference(server, nodeToRemove, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), true,
  388. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_REMOVEDATASETFOLDER),
  389. false);
  390. #endif
  391. retVal |= UA_Server_deleteNode(server, nodeToRemove, false);
  392. return retVal;
  393. }
  394. #endif
  395. UA_StatusCode
  396. addPublishedDataItemsRepresentation(UA_Server *server, UA_PublishedDataSet *publishedDataSet){
  397. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  398. if(publishedDataSet->config.name.length > 512)
  399. return UA_STATUSCODE_BADOUTOFMEMORY;
  400. UA_STACKARRAY(char, pdsName, sizeof(char) * publishedDataSet->config.name.length +1);
  401. memcpy(pdsName, publishedDataSet->config.name.data, publishedDataSet->config.name.length);
  402. pdsName[publishedDataSet->config.name.length] = '\0';
  403. //This code block must use a lock
  404. UA_Nodestore_remove(server, &publishedDataSet->identifier);
  405. retVal |= addPubSubObjectNode(server, pdsName, publishedDataSet->identifier.identifier.numeric, UA_NS0ID_PUBLISHSUBSCRIBE_PUBLISHEDDATASETS,
  406. UA_NS0ID_HASPROPERTY, UA_NS0ID_PUBLISHEDDATAITEMSTYPE);
  407. //End lock zone
  408. UA_NodeId configurationVersionNode;
  409. configurationVersionNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "ConfigurationVersion"),
  410. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
  411. UA_NODEID_NUMERIC(0, publishedDataSet->identifier.identifier.numeric));
  412. UA_Variant value;
  413. UA_Variant_init(&value);
  414. UA_Variant_setScalar(&value, &publishedDataSet->dataSetMetaData.configurationVersion, &UA_TYPES[UA_TYPES_CONFIGURATIONVERSIONDATATYPE]);
  415. UA_Server_writeValue(server, configurationVersionNode, value);
  416. return retVal;
  417. }
  418. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  419. static UA_StatusCode
  420. addPublishedDataItemsAction(UA_Server *server,
  421. const UA_NodeId *sessionId, void *sessionHandle,
  422. const UA_NodeId *methodId, void *methodContext,
  423. const UA_NodeId *objectId, void *objectContext,
  424. size_t inputSize, const UA_Variant *input,
  425. size_t outputSize, UA_Variant *output){
  426. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  427. size_t fieldNameAliasesSize = input[1].arrayLength;
  428. UA_String * fieldNameAliases = (UA_String *) input[1].data;
  429. size_t fieldFlagsSize = input[2].arrayLength;
  430. UA_DataSetFieldFlags * fieldFlags = (UA_DataSetFieldFlags *) input[2].data;
  431. size_t variablesToAddSize = input[3].arrayLength;
  432. UA_PublishedVariableDataType *variablesToAdd = (UA_PublishedVariableDataType *) input[3].data;
  433. if(!(fieldNameAliasesSize == fieldFlagsSize || fieldFlagsSize == variablesToAddSize))
  434. return UA_STATUSCODE_BADINVALIDARGUMENT;
  435. UA_PublishedDataSetConfig publishedDataSetConfig;
  436. memset(&publishedDataSetConfig, 0, sizeof(publishedDataSetConfig));
  437. publishedDataSetConfig.name = *((UA_String *) input[0].data);
  438. publishedDataSetConfig.publishedDataSetType = UA_PUBSUB_DATASET_PUBLISHEDITEMS;
  439. UA_NodeId dataSetItemsNodeId;
  440. retVal |= UA_Server_addPublishedDataSet(server, &publishedDataSetConfig, &dataSetItemsNodeId).addResult;
  441. UA_DataSetFieldConfig dataSetFieldConfig;
  442. for (size_t j = 0; j < variablesToAddSize; ++j) {
  443. memset(&dataSetFieldConfig, 0, sizeof(dataSetFieldConfig));
  444. dataSetFieldConfig.dataSetFieldType = UA_PUBSUB_DATASETFIELD_VARIABLE;
  445. dataSetFieldConfig.field.variable.fieldNameAlias = fieldNameAliases[j];
  446. if(fieldFlags[j] == UA_DATASETFIELDFLAGS_PROMOTEDFIELD){
  447. dataSetFieldConfig.field.variable.promotedField = UA_TRUE;
  448. }
  449. dataSetFieldConfig.field.variable.publishParameters = variablesToAdd[j];
  450. UA_Server_addDataSetField(server, dataSetItemsNodeId, &dataSetFieldConfig, NULL);
  451. }
  452. return retVal;
  453. }
  454. #endif
  455. UA_StatusCode
  456. removePublishedDataSetRepresentation(UA_Server *server, UA_PublishedDataSet *publishedDataSet){
  457. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  458. retVal |= UA_Server_deleteNode(server, publishedDataSet->identifier, false);
  459. return retVal;
  460. }
  461. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  462. static UA_StatusCode
  463. removePublishedDataSetAction(UA_Server *server,
  464. const UA_NodeId *sessionId, void *sessionHandle,
  465. const UA_NodeId *methodId, void *methodContext,
  466. const UA_NodeId *objectId, void *objectContext,
  467. size_t inputSize, const UA_Variant *input,
  468. size_t outputSize, UA_Variant *output){
  469. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  470. UA_NodeId nodeToRemove = *((UA_NodeId *) input[0].data);
  471. retVal |= UA_Server_removePublishedDataSet(server, nodeToRemove);
  472. return retVal;
  473. }
  474. #endif
  475. /**********************************************/
  476. /* WriterGroup */
  477. /**********************************************/
  478. UA_StatusCode
  479. addWriterGroupRepresentation(UA_Server *server, UA_WriterGroup *writerGroup){
  480. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  481. if(writerGroup->config.name.length > 512)
  482. return UA_STATUSCODE_BADOUTOFMEMORY;
  483. UA_STACKARRAY(char, wgName, sizeof(char) * writerGroup->config.name.length + 1);
  484. memcpy(wgName, writerGroup->config.name.data, writerGroup->config.name.length);
  485. wgName[writerGroup->config.name.length] = '\0';
  486. //This code block must use a lock
  487. UA_Nodestore_remove(server, &writerGroup->identifier);
  488. retVal |= addPubSubObjectNode(server, wgName, writerGroup->identifier.identifier.numeric, writerGroup->linkedConnection.identifier.numeric,
  489. UA_NS0ID_HASCOMPONENT, UA_NS0ID_WRITERGROUPTYPE);
  490. //End lock zone
  491. UA_NodeId keepAliveNode, publishingIntervalNode, priorityNode, writerGroupIdNode;
  492. keepAliveNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "KeepAliveTime"),
  493. UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
  494. UA_NODEID_NUMERIC(0, writerGroup->identifier.identifier.numeric));
  495. publishingIntervalNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "PublishingInterval"),
  496. UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
  497. UA_NODEID_NUMERIC(0, writerGroup->identifier.identifier.numeric));
  498. UA_NodePropertyContext * publishingIntervalContext = (UA_NodePropertyContext *) UA_malloc(sizeof(UA_NodePropertyContext));
  499. publishingIntervalContext->parentNodeId = writerGroup->identifier;
  500. publishingIntervalContext->parentCalssifier = UA_NS0ID_WRITERGROUPTYPE;
  501. publishingIntervalContext->elementClassiefier = UA_NS0ID_WRITERGROUPTYPE_PUBLISHINGINTERVAL;
  502. UA_ValueCallback valueCallback;
  503. valueCallback.onRead = onRead;
  504. valueCallback.onWrite = onWrite;
  505. retVal |= addVariableValueSource(server, valueCallback, publishingIntervalNode, publishingIntervalContext);
  506. UA_Server_writeAccessLevel(server, publishingIntervalNode, (UA_ACCESSLEVELMASK_READ ^ UA_ACCESSLEVELMASK_WRITE));
  507. priorityNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "Priority"),
  508. UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
  509. UA_NODEID_NUMERIC(0, writerGroup->identifier.identifier.numeric));
  510. writerGroupIdNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "WriterGroupId"),
  511. UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
  512. UA_NODEID_NUMERIC(0, writerGroup->identifier.identifier.numeric));
  513. UA_Variant value;
  514. UA_Variant_init(&value);
  515. UA_Variant_setScalar(&value, &writerGroup->config.publishingInterval, &UA_TYPES[UA_TYPES_DURATION]);
  516. UA_Server_writeValue(server, publishingIntervalNode, value);
  517. UA_Variant_setScalar(&value, &writerGroup->config.keepAliveTime, &UA_TYPES[UA_TYPES_DURATION]);
  518. UA_Server_writeValue(server, keepAliveNode, value);
  519. UA_Variant_setScalar(&value, &writerGroup->config.priority, &UA_TYPES[UA_TYPES_BYTE]);
  520. UA_Server_writeValue(server, priorityNode, value);
  521. UA_Variant_setScalar(&value, &writerGroup->config.writerGroupId, &UA_TYPES[UA_TYPES_UINT16]);
  522. UA_Server_writeValue(server, writerGroupIdNode, value);
  523. return retVal;
  524. }
  525. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  526. static UA_StatusCode
  527. addWriterGroupAction(UA_Server *server,
  528. const UA_NodeId *sessionId, void *sessionHandle,
  529. const UA_NodeId *methodId, void *methodContext,
  530. const UA_NodeId *objectId, void *objectContext,
  531. size_t inputSize, const UA_Variant *input,
  532. size_t outputSize, UA_Variant *output){
  533. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  534. UA_WriterGroupDataType *writerGroupDataType = ((UA_WriterGroupDataType *) input[0].data);
  535. UA_NodeId generatedId;
  536. UA_WriterGroupConfig writerGroupConfig;
  537. memset(&writerGroupConfig, 0, sizeof(UA_WriterGroupConfig));
  538. writerGroupConfig.name = writerGroupDataType->name;
  539. writerGroupConfig.publishingInterval = writerGroupDataType->publishingInterval;
  540. writerGroupConfig.writerGroupId = writerGroupDataType->writerGroupId;
  541. writerGroupConfig.enabled = writerGroupDataType->enabled;
  542. writerGroupConfig.priority = writerGroupDataType->priority;
  543. //ToDo transfer all arguments to internal WGConfiguration
  544. retVal |= UA_Server_addWriterGroup(server, *objectId, &writerGroupConfig, &generatedId);
  545. UA_Variant_setScalarCopy(output, &generatedId, &UA_TYPES[UA_TYPES_NODEID]);
  546. return retVal;
  547. }
  548. #endif
  549. UA_StatusCode
  550. removeGroupRepresentation(UA_Server *server, UA_WriterGroup *writerGroup) {
  551. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  552. retVal |= UA_Server_deleteNode(server, writerGroup->identifier, false);
  553. return retVal;
  554. }
  555. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  556. static UA_StatusCode
  557. removeGroupAction(UA_Server *server,
  558. const UA_NodeId *sessionId, void *sessionHandle,
  559. const UA_NodeId *methodId, void *methodContext,
  560. const UA_NodeId *objectId, void *objectContext,
  561. size_t inputSize, const UA_Variant *input,
  562. size_t outputSize, UA_Variant *output){
  563. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  564. UA_NodeId nodeToRemove = *((UA_NodeId *) input[0].data);
  565. if(UA_WriterGroup_findWGbyId(server, nodeToRemove) != NULL)
  566. retVal |= UA_Server_removeWriterGroup(server, nodeToRemove);
  567. //else
  568. //retVal |= UA_Server_removeReaderGroup(server, nodeToRemve);
  569. return retVal;
  570. }
  571. #endif
  572. /**********************************************/
  573. /* DataSetWriter */
  574. /**********************************************/
  575. UA_StatusCode
  576. addDataSetWriterRepresentation(UA_Server *server, UA_DataSetWriter *dataSetWriter){
  577. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  578. if(dataSetWriter->config.name.length > 512)
  579. return UA_STATUSCODE_BADOUTOFMEMORY;
  580. UA_STACKARRAY(char, dswName, sizeof(char) * dataSetWriter->config.name.length + 1);
  581. memcpy(dswName, dataSetWriter->config.name.data, dataSetWriter->config.name.length);
  582. dswName[dataSetWriter->config.name.length] = '\0';
  583. //This code block must use a lock
  584. UA_Nodestore_remove(server, &dataSetWriter->identifier);
  585. retVal |= addPubSubObjectNode(server, dswName, dataSetWriter->identifier.identifier.numeric, dataSetWriter->linkedWriterGroup.identifier.numeric,
  586. UA_NS0ID_HASDATASETWRITER, UA_NS0ID_DATASETWRITERTYPE);
  587. //End lock zone
  588. retVal |= UA_Server_addReference(server, dataSetWriter->connectedDataSet,
  589. UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETTOWRITER),
  590. UA_EXPANDEDNODEID_NUMERIC(0, dataSetWriter->identifier.identifier.numeric), true);
  591. return retVal;
  592. }
  593. UA_StatusCode
  594. removeDataSetWriterRepresentation(UA_Server *server, UA_DataSetWriter *dataSetWriter) {
  595. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  596. retVal |= UA_Server_deleteNode(server, dataSetWriter->identifier, false);
  597. return retVal;
  598. }
  599. /**********************************************/
  600. /* Destructors */
  601. /**********************************************/
  602. static void
  603. connectionTypeDestructor(UA_Server *server,
  604. const UA_NodeId *sessionId, void *sessionContext,
  605. const UA_NodeId *typeId, void *typeContext,
  606. const UA_NodeId *nodeId, void **nodeContext) {
  607. UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_USERLAND, "Connection destructor called!");
  608. UA_NodeId publisherIdNode;
  609. publisherIdNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "PublisherId"),
  610. UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), *nodeId);
  611. UA_NodePropertyContext *internalConnectionContext;
  612. UA_Server_getNodeContext(server, publisherIdNode, (void **) &internalConnectionContext);
  613. if(!UA_NodeId_equal(&UA_NODEID_NULL , &publisherIdNode)){
  614. UA_free(internalConnectionContext);
  615. }
  616. }
  617. static void
  618. writerGroupTypeDestructor(UA_Server *server,
  619. const UA_NodeId *sessionId, void *sessionContext,
  620. const UA_NodeId *typeId, void *typeContext,
  621. const UA_NodeId *nodeId, void **nodeContext) {
  622. UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_USERLAND, "WriterGroup destructor called!");
  623. UA_NodeId intervalNode;
  624. intervalNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "PublishingInterval"),
  625. UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), *nodeId);
  626. UA_NodePropertyContext *internalConnectionContext;
  627. UA_Server_getNodeContext(server, intervalNode, (void **) &internalConnectionContext);
  628. if(!UA_NodeId_equal(&UA_NODEID_NULL , &intervalNode)){
  629. UA_free(internalConnectionContext);
  630. }
  631. }
  632. static void
  633. dataSetWriterTypeDestructor(UA_Server *server,
  634. const UA_NodeId *sessionId, void *sessionContext,
  635. const UA_NodeId *typeId, void *typeContext,
  636. const UA_NodeId *nodeId, void **nodeContext) {
  637. UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_USERLAND, "DataSetWriter destructor called!");
  638. }
  639. UA_StatusCode
  640. UA_Server_initPubSubNS0(UA_Server *server) {
  641. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  642. UA_String profileArray[1];
  643. profileArray[0] = UA_STRING("http://opcfoundation.org/UA-Profile/Transport/pubsub-udp-uadp");
  644. retVal |= writePubSubNs0VariableArray(server, UA_NS0ID_PUBLISHSUBSCRIBE_SUPPORTEDTRANSPORTPROFILES,
  645. profileArray,
  646. 1, &UA_TYPES[UA_TYPES_STRING]);
  647. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  648. retVal |= UA_Server_setMethodNode_callback(server,
  649. UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_ADDCONNECTION), addPubSubConnectionAction);
  650. retVal |= UA_Server_setMethodNode_callback(server,
  651. UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_REMOVECONNECTION), removeConnectionAction);
  652. retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_PUBLISHEDDATASETS),
  653. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
  654. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_ADDDATASETFOLDER), true);
  655. retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_PUBLISHEDDATASETS),
  656. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
  657. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_ADDPUBLISHEDDATAITEMS), true);
  658. retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_PUBLISHEDDATASETS),
  659. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
  660. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_REMOVEPUBLISHEDDATASET), true);
  661. retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_PUBLISHEDDATASETS),
  662. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
  663. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_REMOVEDATASETFOLDER), true);
  664. retVal |= UA_Server_setMethodNode_callback(server,
  665. UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_ADDDATASETFOLDER), addDataSetFolderAction);
  666. retVal |= UA_Server_setMethodNode_callback(server,
  667. UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_REMOVEDATASETFOLDER), removeDataSetFolderAction);
  668. retVal |= UA_Server_setMethodNode_callback(server,
  669. UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_ADDPUBLISHEDDATAITEMS), addPublishedDataItemsAction);
  670. retVal |= UA_Server_setMethodNode_callback(server,
  671. UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_REMOVEPUBLISHEDDATASET), removePublishedDataSetAction);
  672. retVal |= UA_Server_setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_ADDWRITERGROUP), addWriterGroupAction);
  673. retVal |= UA_Server_setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_REMOVEGROUP), removeGroupAction);
  674. #else
  675. retVal |= UA_Server_deleteReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE), UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), true,
  676. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_ADDCONNECTION),
  677. false);
  678. retVal |= UA_Server_deleteReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE), UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), true,
  679. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_REMOVECONNECTION),
  680. false);
  681. #endif
  682. UA_NodeTypeLifecycle liveCycle;
  683. liveCycle.constructor = NULL;
  684. liveCycle.destructor = connectionTypeDestructor;
  685. UA_Server_setNodeTypeLifecycle(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE), liveCycle);
  686. liveCycle.destructor = writerGroupTypeDestructor;
  687. UA_Server_setNodeTypeLifecycle(server, UA_NODEID_NUMERIC(0, UA_NS0ID_WRITERGROUPTYPE), liveCycle);
  688. liveCycle.destructor = dataSetWriterTypeDestructor;
  689. UA_Server_setNodeTypeLifecycle(server, UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETWRITERDATATYPE), liveCycle);
  690. return retVal;
  691. }
  692. #endif /* UA_ENABLE_PUBSUB_INFORMATIONMODEL */