00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include "address_space_internal.h"
00012
00013
00014 namespace OpcUa
00015 {
00016 namespace Internal
00017 {
00018 typedef std::map <IntegerId, std::shared_ptr<InternalSubscription>> SubscriptionsIdMap;
00019
00020
00021 struct AttSubscription
00022 {
00023 IntegerId SubscriptionId;
00024 IntegerId MonitoredItemId;
00025 MonitoringParameters Parameters;
00026 };
00027
00028 AddressSpaceInMemory::AddressSpaceInMemory(bool debug)
00029 : Debug(debug)
00030 , DataChangeCallbackHandle(0)
00031 {
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045 }
00046
00047 AddressSpaceInMemory::~AddressSpaceInMemory()
00048 {
00049 }
00050
00051 std::vector<AddNodesResult> AddressSpaceInMemory::AddNodes(const std::vector<AddNodesItem>& items)
00052 {
00053 boost::unique_lock<boost::shared_mutex> lock(DbMutex);
00054
00055 std::vector<AddNodesResult> results;
00056 for (const AddNodesItem& item: items)
00057 {
00058 results.push_back(AddNode(item));
00059 }
00060 return results;
00061 }
00062
00063 std::vector<StatusCode> AddressSpaceInMemory::AddReferences(const std::vector<AddReferencesItem>& items)
00064 {
00065 boost::unique_lock<boost::shared_mutex> lock(DbMutex);
00066
00067 std::vector<StatusCode> results;
00068 for (const auto& item : items)
00069 {
00070 results.push_back(AddReference(item));
00071 }
00072 return results;
00073 }
00074
00075 std::vector<BrowsePathResult> AddressSpaceInMemory::TranslateBrowsePathsToNodeIds(const TranslateBrowsePathsParameters& params) const
00076 {
00077 boost::shared_lock<boost::shared_mutex> lock(DbMutex);
00078
00079 std::vector<BrowsePathResult> results;
00080 for (BrowsePath browsepath : params.BrowsePaths )
00081 {
00082 BrowsePathResult result = TranslateBrowsePath(browsepath);
00083 results.push_back(result);
00084 }
00085 return results;
00086 }
00087
00088 std::vector<BrowseResult> AddressSpaceInMemory::Browse(const OpcUa::NodesQuery& query) const
00089 {
00090 boost::shared_lock<boost::shared_mutex> lock(DbMutex);
00091
00092 if (Debug) std::cout << "AddressSpaceInternal | Browsing." << std::endl;
00093 std::vector<BrowseResult> results;
00094 for ( BrowseDescription browseDescription: query.NodesToBrowse)
00095 {
00096 BrowseResult result;
00097 if(Debug)
00098 {
00099 std::cout << "AddressSpaceInternal | Browsing ";
00100 std::cout << " NodeId: '" << browseDescription.NodeToBrowse << "'";
00101 std::cout << ", ReferenceId: '" << browseDescription.ReferenceTypeId << "'";
00102 std::cout << ", Direction: " << browseDescription.Direction;
00103 std::cout << ", NodeClasses: 0x" << std::hex << (unsigned)browseDescription.NodeClasses;
00104 std::cout << ", ResultMask: '0x" << std::hex << (unsigned)browseDescription.ResultMask << std::endl;
00105 }
00106
00107 NodesMap::const_iterator node_it = Nodes.find(browseDescription.NodeToBrowse);
00108 if ( node_it == Nodes.end() )
00109 {
00110 if (Debug) std::cout << "AddressSpaceInternal | Node '" << OpcUa::ToString(browseDescription.NodeToBrowse) << "' not found in the address space." << std::endl;
00111 continue;
00112 }
00113
00114 std::copy_if(node_it->second.References.begin(), node_it->second.References.end(), std::back_inserter(result.Referencies),
00115 std::bind(&AddressSpaceInMemory::IsSuitableReference, this, std::cref(browseDescription), std::placeholders::_1)
00116 );
00117 results.push_back(result);
00118 }
00119 return results;
00120 }
00121
00122 std::vector<BrowseResult> AddressSpaceInMemory::BrowseNext() const
00123 {
00124 boost::shared_lock<boost::shared_mutex> lock(DbMutex);
00125
00126 return std::vector<BrowseResult>();
00127 }
00128
00129 std::vector<NodeId> AddressSpaceInMemory::RegisterNodes(const std::vector<NodeId>& params) const
00130 {
00131 boost::shared_lock<boost::shared_mutex> lock(DbMutex);
00132
00133 return params;
00134 }
00135
00136 void AddressSpaceInMemory::UnregisterNodes(const std::vector<NodeId>& params) const
00137 {
00138 boost::shared_lock<boost::shared_mutex> lock(DbMutex);
00139
00140 return;
00141 }
00142
00143 std::vector<DataValue> AddressSpaceInMemory::Read(const ReadParameters& params) const
00144 {
00145 boost::shared_lock<boost::shared_mutex> lock(DbMutex);
00146
00147 std::vector<DataValue> values;
00148 for (const ReadValueId& attribute : params.AttributesToRead)
00149 {
00150 values.push_back(GetValue(attribute.NodeId, attribute.AttributeId));
00151 }
00152 return values;
00153 }
00154
00155 std::vector<StatusCode> AddressSpaceInMemory::Write(const std::vector<OpcUa::WriteValue>& values)
00156 {
00157 boost::unique_lock<boost::shared_mutex> lock(DbMutex);
00158
00159 std::vector<StatusCode> statuses;
00160 for (WriteValue value : values)
00161 {
00162 if (value.Value.Encoding & DATA_VALUE)
00163 {
00164 statuses.push_back(SetValue(value.NodeId, value.AttributeId, value.Value));
00165 continue;
00166 }
00167 statuses.push_back(StatusCode::BadNotWritable);
00168 }
00169 return statuses;
00170 }
00171
00172 std::tuple<bool, NodeId> AddressSpaceInMemory::FindElementInNode(const NodeId& nodeid, const RelativePathElement& element) const
00173 {
00174 NodesMap::const_iterator nodeit = Nodes.find(nodeid);
00175 if ( nodeit != Nodes.end() )
00176 {
00177 for (auto reference : nodeit->second.References)
00178 {
00179
00180 if (reference.BrowseName == element.TargetName)
00181 {
00182 return std::make_tuple(true, reference.TargetNodeId);
00183 }
00184 }
00185 }
00186 return std::make_tuple(false, NodeId());
00187 }
00188
00189 BrowsePathResult AddressSpaceInMemory::TranslateBrowsePath(const BrowsePath& browsepath) const
00190 {
00191 NodeId current = browsepath.StartingNode;
00192 BrowsePathResult result;
00193
00194 for (RelativePathElement element : browsepath.Path.Elements)
00195 {
00196 auto res = FindElementInNode(current, element);
00197 if ( std::get<0>(res) == false )
00198 {
00199 result.Status = OpcUa::StatusCode::BadNoMatch;
00200 return result;
00201 }
00202 current = std::get<1>(res);
00203 }
00204
00205 result.Status = OpcUa::StatusCode::Good;
00206 std::vector<BrowsePathTarget> targets;
00207 BrowsePathTarget target;
00208 target.Node = current;
00209 target.RemainingPathIndex = std::numeric_limits<uint32_t>::max();
00210 targets.push_back(target);
00211 result.Targets = targets;
00212 return result;
00213 }
00214
00215 DataValue AddressSpaceInMemory::GetValue(const NodeId& node, AttributeId attribute) const
00216 {
00217 NodesMap::const_iterator nodeit = Nodes.find(node);
00218 if ( nodeit == Nodes.end() )
00219 {
00220 if (Debug) std::cout << "AddressSpaceInternal | Bad node not found: " << node << std::endl;
00221 }
00222 else
00223 {
00224 AttributesMap::const_iterator attrit = nodeit->second.Attributes.find(attribute);
00225 if ( attrit == nodeit->second.Attributes.end() )
00226 {
00227 if (Debug) std::cout << "AddressSpaceInternal | node " << node << " has not attribute: " << (uint32_t)attribute << std::endl;
00228 }
00229 else
00230 {
00231 if ( attrit->second.GetValueCallback )
00232 {
00233 if (Debug) std::cout << "AddressSpaceInternal | A callback is set for this value, calling callback" << std::endl;
00234 return attrit->second.GetValueCallback();
00235 }
00236 if (Debug) std::cout << "AddressSpaceInternal | No callback is set for this value returning stored value" << std::endl;
00237 return attrit->second.Value;
00238 }
00239 }
00240 DataValue value;
00241 value.Encoding = DATA_VALUE_STATUS_CODE;
00242 value.Status = StatusCode::BadNotReadable;
00243 return value;
00244 }
00245
00246 uint32_t AddressSpaceInMemory::AddDataChangeCallback(const NodeId& node, AttributeId attribute, std::function<Server::DataChangeCallback> callback)
00247 {
00248 if (Debug) std::cout << "AddressSpaceInternal| Set data changes callback for node " << node
00249 << " and attribute " << (unsigned)attribute << std::endl;
00250 NodesMap::iterator it = Nodes.find(node);
00251 if ( it == Nodes.end() )
00252 {
00253 if (Debug) std::cout << "AddressSpaceInternal| Node '" << node << "' not found." << std::endl;
00254 throw std::runtime_error("AddressSpaceInternal | NodeId not found");
00255 }
00256 AttributesMap::iterator ait = it->second.Attributes.find(attribute);
00257 if ( ait == it->second.Attributes.end() )
00258 {
00259 if (Debug) std::cout << "address_space| Attribute " << (unsigned)attribute << " of node '" << node << "' not found." << std::endl;
00260 throw std::runtime_error("Attribute not found");
00261 }
00262
00263 uint32_t handle = ++DataChangeCallbackHandle;
00264 DataChangeCallbackData data;
00265 data.Callback = callback;
00266 ait->second.DataChangeCallbacks[handle] = data;
00267 ClientIdToAttributeMap[handle] = NodeAttribute(node, attribute);
00268 return handle;
00269 }
00270
00271 void AddressSpaceInMemory::DeleteDataChangeCallback(uint32_t serverhandle )
00272 {
00273 if (Debug) std::cout << "AddressSpaceInternal | Deleting callback with client id. " << serverhandle << std::endl;
00274
00275 ClientIdToAttributeMapType::iterator it = ClientIdToAttributeMap.find(serverhandle);
00276 if ( it == ClientIdToAttributeMap.end() )
00277 {
00278 std::cout << "AddressSpaceInternal | Error, request to delete a callback using unknown handle: " << serverhandle << std::endl;
00279 return;
00280 }
00281
00282 NodesMap::iterator nodeit = Nodes.find(it->second.Node);
00283 if ( nodeit != Nodes.end() )
00284 {
00285 AttributesMap::iterator ait = nodeit->second.Attributes.find(it->second.Attribute);
00286 if ( ait != nodeit->second.Attributes.end() )
00287 {
00288 size_t nb = ait->second.DataChangeCallbacks.erase(serverhandle);
00289 if (Debug) std::cout << "AddressSpaceInternal | deleted " << nb << " callbacks" << std::endl;
00290 ClientIdToAttributeMap.erase(serverhandle);
00291 return;
00292 }
00293 }
00294 throw std::runtime_error("AddressSpaceInternal | NodeId or attribute nor found");
00295 }
00296
00297 StatusCode AddressSpaceInMemory::SetValueCallback(const NodeId& node, AttributeId attribute, std::function<DataValue(void)> callback)
00298 {
00299 NodesMap::iterator it = Nodes.find(node);
00300 if ( it != Nodes.end() )
00301 {
00302 AttributesMap::iterator ait = it->second.Attributes.find(attribute);
00303 if ( ait != it->second.Attributes.end() )
00304 {
00305 ait->second.GetValueCallback = callback;
00306 return StatusCode::Good;
00307 }
00308 }
00309 return StatusCode::BadAttributeIdInvalid;
00310 }
00311
00312 void AddressSpaceInMemory::SetMethod(const NodeId& node, std::function<std::vector<OpcUa::Variant> (std::vector<OpcUa::Variant> arguments)> callback)
00313 {
00314 NodesMap::iterator it = Nodes.find(node);
00315 if ( it != Nodes.end() )
00316 {
00317 it->second.Method = callback;
00318 }
00319 throw std::runtime_error("While setting node callback: node does not exist.");
00320 }
00321
00322 std::vector<OpcUa::CallMethodResult> AddressSpaceInMemory::Call(std::vector<OpcUa::CallMethodRequest> methodsToCall)
00323 {
00324 std::vector<OpcUa::CallMethodResult> results;
00325 for (auto method : methodsToCall)
00326 {
00327 results.push_back(CallMethod(method));
00328 }
00329 return results;
00330 }
00331
00332 CallMethodResult AddressSpaceInMemory::CallMethod(CallMethodRequest request)
00333 {
00334 boost::shared_lock<boost::shared_mutex> lock(DbMutex);
00335
00336 CallMethodResult result;
00337 NodesMap::iterator node_it = Nodes.find(request.ObjectId);
00338 if ( node_it == Nodes.end() )
00339 {
00340 result.Status = StatusCode::BadNodeIdUnknown;
00341 return result;
00342 }
00343 NodesMap::iterator method_it = Nodes.find(request.MethodId);
00344 if ( method_it == Nodes.end() )
00345 {
00346 result.Status = StatusCode::BadNodeIdUnknown;
00347 return result;
00348 }
00349 if ( ! method_it->second.Method )
00350 {
00351 result.Status = StatusCode::BadNothingToDo;
00352 return result;
00353 }
00354
00355 try
00356 {
00357 result.OutputArguments = method_it->second.Method(request.InputArguments);
00358 }
00359 catch (std::exception& ex)
00360 {
00361 std::cout << "Exception whil calling method" << request.MethodId << ": " << ex.what() << std::endl;
00362 result.Status = StatusCode::BadUnexpectedError;
00363 return result;
00364 }
00365 for (auto var : request.InputArguments)
00366 {
00367 result.InputArgumentResults.push_back(StatusCode::Good);
00368 }
00369 return result;
00370 }
00371
00372 StatusCode AddressSpaceInMemory::SetValue(const NodeId& node, AttributeId attribute, const DataValue& data)
00373 {
00374 NodesMap::iterator it = Nodes.find(node);
00375 if ( it != Nodes.end() )
00376 {
00377 AttributesMap::iterator ait = it->second.Attributes.find(attribute);
00378 if ( ait != it->second.Attributes.end() )
00379 {
00380 DataValue value(data);
00381 value.SetServerTimestamp(DateTime::Current());
00382 ait->second.Value = value;
00383
00384 for (auto pair : ait->second.DataChangeCallbacks)
00385 {
00386 pair.second.Callback(it->first, ait->first, ait->second.Value);
00387 }
00388 return StatusCode::Good;
00389 }
00390 }
00391 return StatusCode::BadAttributeIdInvalid;
00392 }
00393
00394 bool AddressSpaceInMemory::IsSuitableReference(const BrowseDescription& desc, const ReferenceDescription& reference) const
00395 {
00396 if (Debug) std::cout << "AddressSpaceInternal | Checking reference '" << reference.ReferenceTypeId << "' to the node '" << reference.TargetNodeId << "' (" << reference.BrowseName << ") which must fit ref: " << desc.ReferenceTypeId << " with include subtype: " << desc.IncludeSubtypes << std::endl;
00397
00398 if ((desc.Direction == BrowseDirection::Forward && !reference.IsForward) || (desc.Direction == BrowseDirection::Inverse && reference.IsForward))
00399 {
00400 if (Debug) std::cout << "AddressSpaceInternal | Reference in different direction." << std::endl;
00401 return false;
00402 }
00403 if (desc.ReferenceTypeId != ObjectId::Null && !IsSuitableReferenceType(reference, desc.ReferenceTypeId, desc.IncludeSubtypes))
00404 {
00405 if (Debug) std::cout << "AddressSpaceInternal | Reference has wrong type." << std::endl;
00406 return false;
00407 }
00408 if (desc.NodeClasses != NodeClass::Unspecified && (desc.NodeClasses & reference.TargetNodeClass) == NodeClass::Unspecified)
00409 {
00410 if (Debug) std::cout << "AddressSpaceInternal | Reference has wrong class." << std::endl;
00411 return false;
00412 }
00413 if (Debug) std::cout << "AddressSpaceInternal | Reference suitable." << std::endl;
00414 return true;
00415 }
00416
00417 bool AddressSpaceInMemory::IsSuitableReferenceType(const ReferenceDescription& reference, const NodeId& typeId, bool includeSubtypes) const
00418 {
00419 if (!includeSubtypes)
00420 {
00421 return reference.ReferenceTypeId == typeId;
00422 }
00423 const std::vector<NodeId> suitableTypes = SelectNodesHierarchy(std::vector<NodeId>(1, typeId));
00424 const auto resultIt = std::find(suitableTypes.begin(), suitableTypes.end(), reference.ReferenceTypeId);\
00425 return resultIt != suitableTypes.end();
00426 }
00427
00428 std::vector<NodeId> AddressSpaceInMemory::SelectNodesHierarchy(std::vector<NodeId> sourceNodes) const
00429 {
00430 std::vector<NodeId> subNodes;
00431 for ( NodeId nodeid: sourceNodes )
00432 {
00433 NodesMap::const_iterator node_it = Nodes.find(nodeid);
00434 if ( node_it != Nodes.end() )
00435 {
00436 for (auto& ref: node_it->second.References )
00437 {
00438 subNodes.push_back(ref.TargetNodeId);
00439 }
00440 }
00441 }
00442 if (subNodes.empty())
00443 {
00444 return sourceNodes;
00445 }
00446
00447 const std::vector<NodeId> allChilds = SelectNodesHierarchy(subNodes);
00448 sourceNodes.insert(sourceNodes.end(), allChilds.begin(), allChilds.end());
00449 return sourceNodes;
00450 }
00451
00452 AddNodesResult AddressSpaceInMemory::AddNode( const AddNodesItem& item )
00453 {
00454 AddNodesResult result;
00455 if (Debug) std::cout << "AddressSpaceInternal | address_space| Adding new node id='" << item.RequestedNewNodeId << "' name=" << item.BrowseName.Name << std::endl;
00456
00457 const NodeId resultId = GetNewNodeId(item.RequestedNewNodeId);
00458
00459 if (!Nodes.empty() && resultId != ObjectId::Null && Nodes.find(resultId) != Nodes.end())
00460 {
00461 std::cerr << "AddressSpaceInternal | Error: NodeId '"<< resultId << "' allready exist: " << std::endl;
00462 result.Status = StatusCode::BadNodeIdExists;
00463 return result;
00464 }
00465
00466 NodesMap::iterator parent_node_it = Nodes.end();
00467 if (item.ParentNodeId != NodeId())
00468 {
00469 parent_node_it = Nodes.find(item.ParentNodeId);
00470 if ( parent_node_it == Nodes.end() )
00471 {
00472 if (Debug) std::cout << "AddressSpaceInternal | Error: Parent node '"<< item.ParentNodeId << "'does not exist" << std::endl;
00473 result.Status = StatusCode::BadParentNodeIdInvalid;
00474 return result;
00475 }
00476 }
00477
00478 NodeStruct nodestruct;
00479
00480 nodestruct.Attributes[AttributeId::NodeId].Value = resultId;
00481 nodestruct.Attributes[AttributeId::BrowseName].Value = item.BrowseName;
00482 nodestruct.Attributes[AttributeId::NodeClass].Value = static_cast<int32_t>(item.Class);
00483
00484
00485 for (const auto& attr: item.Attributes.Attributes)
00486 {
00487 AttributeValue attval;
00488 attval.Value = attr.second;
00489
00490 nodestruct.Attributes.insert(std::make_pair(attr.first, attval));
00491 }
00492
00493 Nodes.insert(std::make_pair(resultId, nodestruct));
00494
00495 if (parent_node_it != Nodes.end())
00496 {
00497
00498 ReferenceDescription desc;
00499 desc.ReferenceTypeId = item.ReferenceTypeId;
00500 desc.TargetNodeId = resultId;
00501 desc.TargetNodeClass = item.Class;
00502 desc.BrowseName = item.BrowseName;
00503 desc.DisplayName = LocalizedText(item.BrowseName.Name);
00504 desc.TargetNodeTypeDefinition = item.TypeDefinition;
00505 desc.IsForward = true;
00506
00507 parent_node_it->second.References.push_back(desc);
00508 }
00509
00510 if (item.TypeDefinition != ObjectId::Null)
00511 {
00512
00513 AddReferencesItem typeRef;
00514 typeRef.SourceNodeId = resultId;
00515 typeRef.IsForward = true;
00516 typeRef.ReferenceTypeId = ObjectId::HasTypeDefinition;
00517 typeRef.TargetNodeId = item.TypeDefinition;
00518 typeRef.TargetNodeClass = NodeClass::DataType;
00519 AddReference(typeRef);
00520 }
00521
00522 result.Status = StatusCode::Good;
00523 result.AddedNodeId = resultId;
00524 if (Debug) std::cout << "AddressSpaceInternal | node added." << std::endl;
00525 return result;
00526 }
00527
00528 StatusCode AddressSpaceInMemory::AddReference(const AddReferencesItem& item)
00529 {
00530 NodesMap::iterator node_it = Nodes.find(item.SourceNodeId);
00531 if ( node_it == Nodes.end() )
00532 {
00533 return StatusCode::BadSourceNodeIdInvalid;
00534 }
00535 NodesMap::iterator targetnode_it = Nodes.find(item.TargetNodeId);
00536 if ( targetnode_it == Nodes.end() )
00537 {
00538 return StatusCode::BadTargetNodeIdInvalid;
00539 }
00540 ReferenceDescription desc;
00541 desc.ReferenceTypeId = item.ReferenceTypeId;
00542 desc.IsForward = item.IsForward;
00543 desc.TargetNodeId = item.TargetNodeId;
00544 desc.TargetNodeClass = item.TargetNodeClass;
00545 DataValue dv = GetValue(item.TargetNodeId, AttributeId::BrowseName);
00546 if (dv.Status == StatusCode::Good)
00547 {
00548 desc.BrowseName = dv.Value.As<QualifiedName>();
00549 }
00550 else
00551 {
00552 desc.BrowseName = QualifiedName("NONAME", 0);
00553 }
00554 dv = GetValue(item.TargetNodeId, AttributeId::DisplayName);
00555 if (dv.Status == StatusCode::Good)
00556 {
00557 desc.DisplayName = dv.Value.As<LocalizedText>();
00558 }
00559 else
00560 {
00561 desc.DisplayName = LocalizedText(desc.BrowseName.Name);
00562 }
00563 node_it->second.References.push_back(desc);
00564 return StatusCode::Good;
00565 }
00566
00567 NodeId AddressSpaceInMemory::GetNewNodeId(const NodeId& id)
00568 {
00569 if (id == ObjectId::Null || id.IsNull())
00570 {
00571 return OpcUa::NumericNodeId(++MaxNodeIdNum, DefaultIdx);
00572 }
00573
00574 if (id.HasNullIdentifier())
00575 {
00576 return OpcUa::NumericNodeId(++MaxNodeIdNum, id.GetNamespaceIndex());
00577 }
00578
00579 return id;
00580 }
00581 }
00582
00583 namespace Server
00584 {
00585 AddressSpace::UniquePtr CreateAddressSpace(bool debug)
00586 {
00587 return AddressSpace::UniquePtr(new Internal::AddressSpaceInMemory(debug));
00588 }
00589 }
00590 }