ua_pubsub_ns0.c 41 KB

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