00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "model_impl.h"
00021
00022 #include <opc/ua/model.h>
00023
00024 namespace OpcUa
00025 {
00026 namespace Model
00027 {
00028
00029 Object::Object(NodeId objectId, Services::SharedPtr services)
00030 : Node(services)
00031 {
00032 Id = objectId;
00033 ReadParameters attrs;
00034 attrs.AttributesToRead.push_back(ToReadValueId(objectId, AttributeId::DisplayName));
00035 attrs.AttributesToRead.push_back(ToReadValueId(objectId, AttributeId::BrowseName));
00036 std::vector<DataValue> values = services->Attributes()->Read(attrs);
00037 DisplayName = values[0].Value.As<LocalizedText>();
00038 BrowseName = values[1].Value.As<QualifiedName>();
00039 }
00040
00041 Object::Object(Object&& object)
00042 : Node(std::move(object.OpcUaServices))
00043 {
00044 Id = std::move(object.Id);
00045 DisplayName = std::move(object.DisplayName);
00046 BrowseName = std::move(object.BrowseName);
00047 }
00048
00049 Object::Object(const Object& object)
00050 : Node(object.OpcUaServices)
00051 {
00052 Id = object.Id;
00053 DisplayName = object.DisplayName;
00054 BrowseName = object.BrowseName;
00055 }
00056
00057 Object::Object(Services::SharedPtr services)
00058 : Node(services)
00059 {
00060 }
00061
00062 ObjectType Object::GetType() const
00063 {
00064 return ObjectType(ObjectId::Null, GetServices());
00065 }
00066
00067 std::vector<Variable> Object::GetVariables() const
00068 {
00069 return Browse<Variable>(GetId(), NodeClass::Variable, GetServices());
00070 }
00071
00072 Variable Object::GetVariable(const QualifiedName& name) const
00073 {
00074 OpcUa::RelativePathElement element;
00075 element.ReferenceTypeId = OpcUa::ObjectId::HierarchicalReferences;
00076 element.IncludeSubtypes = true;
00077 element.TargetName = name;
00078
00079 OpcUa::RelativePath path;
00080 path.Elements.push_back(element);
00081 return GetVariable(path);
00082 }
00083
00084 Variable Object::GetVariable(const RelativePath& relativePath) const
00085 {
00086 OpcUa::BrowsePath browsePath;
00087 browsePath.StartingNode = GetId();
00088 browsePath.Path = relativePath;
00089 OpcUa::TranslateBrowsePathsParameters params;
00090 params.BrowsePaths.push_back(browsePath);
00091 const std::vector<OpcUa::BrowsePathResult>& result = GetServices()->Views()->TranslateBrowsePathsToNodeIds(params);
00092 if (result.size() != 1)
00093 throw std::runtime_error("object_model| Server returned more than one browse paths on TranslateBrowsePathsToNodeIds request.");
00094
00095 const OpcUa::BrowsePathResult& resultPath = result.back();
00096 OpcUa::CheckStatusCode(resultPath.Status);
00097 if (resultPath.Targets.size() != 1)
00098 throw std::runtime_error("object_model| Server returned too many target elements on TranslateBrowsePathsToNodeIds request.");
00099
00100 return Variable(resultPath.Targets.back().Node, GetServices());
00101 }
00102
00103
00104 std::vector<Object> Object::GetObjects() const
00105 {
00106 return Browse<Object>(GetId(), NodeClass::Object, GetServices());
00107 }
00108
00109 Object Object::GetObject(const QualifiedName& name) const
00110 {
00111 return Object(ObjectId::Null, GetServices());
00112 }
00113
00114 Object Object::GetObject(const RelativePath& name) const
00115 {
00116 return Object(ObjectId::Null, GetServices());
00117 }
00118
00119 Object Object::CreateObject(const ObjectType& type, const QualifiedName& browseName)
00120 {
00121 return CreateObject(NodeId(), type, browseName);
00122 }
00123
00124 Object Object::CreateObject(const NodeId& newNodeId, const ObjectType& nodeType, const QualifiedName& browseName)
00125 {
00126 return CreateObject(newNodeId, GetId(), nodeType.GetId(), browseName, browseName.Name);
00127 }
00128
00129 Object Object::CreateObject(const ObjectType& type, const QualifiedName& browseName, const std::string& displayName)
00130 {
00131 return CreateObject(NodeId(), GetId(), type.GetId(), browseName, displayName);
00132 }
00133
00134 Object Object::CreateObject(const NodeId& newNodeId, const NodeId& parentNode, const NodeId& typeId, const QualifiedName& browseName, const std::string& displayName)
00135 {
00136 Object object(GetServices());
00137 object.Id = InstantiateType(newNodeId, parentNode, typeId, NodeClass::Object, browseName, displayName);
00138 object.BrowseName = browseName;
00139 object.DisplayName = LocalizedText(displayName);
00140 return object;
00141
00142 }
00143
00144 NodeId Object::InstantiateType(const NodeId& newNodeId, const NodeId& parentNode, const NodeId& typeId, NodeClass nodeClass, const QualifiedName& browseName, const std::string& displayName)
00145 {
00146
00147 AddNodesItem newNodeRequest;
00148 newNodeRequest.BrowseName = browseName;
00149 newNodeRequest.RequestedNewNodeId = newNodeId;
00150 newNodeRequest.Class = nodeClass;
00151 newNodeRequest.ParentNodeId = parentNode;
00152 newNodeRequest.ReferenceTypeId = nodeClass == NodeClass::Object ? ObjectId::HasComponent : ObjectId::HasProperty;
00153 newNodeRequest.TypeDefinition = typeId;
00154 ObjectAttributes attrs;
00155 attrs.Description = LocalizedText(displayName);
00156 attrs.DisplayName = LocalizedText(displayName);
00157 newNodeRequest.Attributes = attrs;
00158
00159 NodeManagementServices::SharedPtr nodes = GetServices()->NodeManagement();
00160 std::vector<AddNodesResult> newObjectNode = nodes->AddNodes({newNodeRequest});
00161 if (newObjectNode.size() != 1)
00162 {
00163 throw std::runtime_error("opcua_model| Server returned wrong number new nodes results.");
00164 }
00165
00166 OpcUa::CheckStatusCode(newObjectNode[0].Status);
00167
00168 std::map<NodeId, std::vector<ReferenceDescription>> nextRefs;
00169 nextRefs.insert({newObjectNode[0].AddedNodeId, BrowseObjectsAndVariables(typeId)});
00170 while(!nextRefs.empty())
00171 {
00172 std::map<NodeId, std::vector<ReferenceDescription>> newRefs;
00173 for (auto idRefs : nextRefs)
00174 {
00175 std::map<NodeId, std::vector<ReferenceDescription>> tmpRefs = CopyObjectsAndVariables(idRefs.first, idRefs.second);
00176 newRefs.insert(tmpRefs.begin(), tmpRefs.end());
00177 }
00178 nextRefs = std::move(newRefs);
00179 }
00180 return newObjectNode[0].AddedNodeId;
00181 }
00182
00183 std::vector<ReferenceDescription> Object::BrowseObjectsAndVariables(const NodeId& id)
00184 {
00185
00186 BrowseDescription desc;
00187 desc.Direction = BrowseDirection::Forward;
00188 desc.IncludeSubtypes = true;
00189 desc.NodeClasses = NodeClass::Object | NodeClass::Variable | NodeClass::Method;
00190 desc.ReferenceTypeId = ObjectId::HierarchicalReferences;
00191 desc.NodeToBrowse = id;
00192 desc.ResultMask = BrowseResultMask::NodeClass | BrowseResultMask::TypeDefinition | BrowseResultMask::BrowseName | BrowseResultMask::DisplayName;
00193
00194
00195 NodesQuery query;
00196 query.NodesToBrowse.push_back(desc);
00197 ViewServices::SharedPtr views = GetServices()->Views();
00198 return views->Browse(query)[0].Referencies;
00199 }
00200
00201 std::map<NodeId, std::vector<ReferenceDescription>> Object::CopyObjectsAndVariables(const NodeId& targetNode, const std::vector<ReferenceDescription>& refs)
00202 {
00203 std::map<NodeId, std::vector<ReferenceDescription>> nextCopyData;
00204 for (const ReferenceDescription& ref : refs)
00205 {
00206 std::vector<AddNodesResult> result;
00207 std::vector<AddNodesItem> newNodeRequest;
00208 switch (ref.TargetNodeClass)
00209 {
00210 case NodeClass::Object:
00211 {
00212 if (ref.TargetNodeTypeDefinition !=ObjectId::Null)
00213 {
00214 InstantiateType(NodeId(), targetNode, ref.TargetNodeTypeDefinition, NodeClass::Object, ref.BrowseName, ref.DisplayName.Text);
00215 }
00216 else
00217 {
00218 newNodeRequest = {CreateObjectCopy(targetNode, ref)};
00219 }
00220 break;
00221 }
00222 case NodeClass::Variable:
00223 {
00224 newNodeRequest = {CreateVariableCopy(targetNode, ref)};
00225 break;
00226 }
00227 default:
00228 {
00229 continue;
00230 }
00231 }
00232 if (newNodeRequest.empty())
00233 {
00234 continue;
00235 }
00236 result = GetServices()->NodeManagement()->AddNodes(newNodeRequest);
00237 std::vector<ReferenceDescription> newRefs = BrowseObjectsAndVariables(ref.TargetNodeId);
00238 nextCopyData.insert({result[0].AddedNodeId, newRefs});
00239 }
00240 return nextCopyData;
00241 }
00242
00243 Variable Object::CreateVariable(const QualifiedName& browseName, const Variant& value)
00244 {
00245 return CreateVariable(NodeId(), browseName, value);
00246 }
00247
00248 Variable Object::CreateVariable(const NodeId& newVariableId, const QualifiedName& browseName, const Variant& value)
00249 {
00250
00251 AddNodesItem newNodeRequest;
00252 newNodeRequest.BrowseName = browseName;
00253 newNodeRequest.RequestedNewNodeId = newVariableId;
00254 newNodeRequest.Class = NodeClass::Variable;
00255 newNodeRequest.ParentNodeId = GetId();
00256 newNodeRequest.ReferenceTypeId = ObjectId::HasProperty;
00257 newNodeRequest.TypeDefinition = NodeId();
00258 VariableAttributes attrs;
00259 attrs.Description = LocalizedText(browseName.Name);
00260 attrs.DisplayName = LocalizedText(browseName.Name);
00261 attrs.Value = value;
00262 attrs.Type = OpcUa::VariantTypeToDataType(value.Type());
00263 newNodeRequest.Attributes = attrs;
00264
00265 NodeManagementServices::SharedPtr nodes = GetServices()->NodeManagement();
00266 std::vector<AddNodesResult> newNode = nodes->AddNodes({newNodeRequest});
00267 if (newNode.size() != 1)
00268 {
00269 throw std::runtime_error("opcua_model| Server returned wrong number new nodes results.");
00270 }
00271
00272 OpcUa::CheckStatusCode(newNode[0].Status);
00273 Variable newVariable(GetServices());
00274 newVariable.Id = newNode[0].AddedNodeId;
00275 newVariable.BrowseName = browseName;
00276 newVariable.DisplayName = attrs.Description;
00277 newVariable.DataType = value.Type();
00278 newVariable.TypeId = newNodeRequest.TypeDefinition;
00279 return newVariable;
00280 }
00281
00282 Variable Object::CreateVariable(const QualifiedName& browseName, const VariableType& type)
00283 {
00284 return Variable(GetServices());
00285 }
00286
00287 Variable Object::CreateVariable(const NodeId& newVariableId, const QualifiedName& browseName, const VariableType& type)
00288 {
00289 return Variable(GetServices());
00290 }
00291
00292 AddNodesItem Object::CreateVariableCopy(const NodeId& parentId, const ReferenceDescription& ref)
00293 {
00294 const NodeId& nodeId = ref.TargetNodeId;
00295
00296 ReadParameters readParams;
00297 readParams.AttributesToRead.push_back(ToReadValueId(nodeId, AttributeId::DisplayName));
00298 readParams.AttributesToRead.push_back(ToReadValueId(nodeId, AttributeId::Description));
00299 readParams.AttributesToRead.push_back(ToReadValueId(nodeId, AttributeId::Value));
00300 readParams.AttributesToRead.push_back(ToReadValueId(nodeId, AttributeId::DataType));
00301 readParams.AttributesToRead.push_back(ToReadValueId(nodeId, AttributeId::ValueRank));
00302 readParams.AttributesToRead.push_back(ToReadValueId(nodeId, AttributeId::ArrayDimensions));
00303 readParams.AttributesToRead.push_back(ToReadValueId(nodeId, AttributeId::AccessLevel));
00304 readParams.AttributesToRead.push_back(ToReadValueId(nodeId, AttributeId::UserAccessLevel));
00305 readParams.AttributesToRead.push_back(ToReadValueId(nodeId, AttributeId::MinimumSamplingInterval));
00306 readParams.AttributesToRead.push_back(ToReadValueId(nodeId, AttributeId::Historizing));
00307 readParams.AttributesToRead.push_back(ToReadValueId(nodeId, AttributeId::WriteMask));
00308 readParams.AttributesToRead.push_back(ToReadValueId(nodeId, AttributeId::UserWriteMask));
00309 readParams.AttributesToRead.push_back(ToReadValueId(nodeId, AttributeId::BrowseName));
00310 std::vector<DataValue> values = GetServices()->Attributes()->Read(readParams);
00311
00312 VariableAttributes attrs;
00313 attrs.DisplayName = values[0].Value.As<LocalizedText>();
00314 attrs.Description = values[1].Value.As<LocalizedText>();
00315 attrs.Value = values[2].Value;
00316 attrs.Type = values[3].Value.As<NodeId>();
00317 attrs.Rank = values[4].Value.As<int32_t>();
00318 attrs.Dimensions = values[5].Value.As<std::vector<uint32_t>>();
00319 attrs.AccessLevel = static_cast<VariableAccessLevel>(values[6].Value.As<uint8_t>());
00320 attrs.UserAccessLevel = static_cast<VariableAccessLevel>(values[7].Value.As<uint8_t>());
00321 attrs.MinimumSamplingInterval = values[8].Value.As<Duration>();
00322 attrs.Historizing = values[9].Value.As<bool>();
00323 attrs.WriteMask = values[10].Value.As<uint32_t>();
00324 attrs.UserWriteMask = values[11].Value.As<uint32_t>();
00325
00326 AddNodesItem newNode;
00327 newNode.BrowseName = values[12].Value.As<QualifiedName>();
00328 newNode.Class = NodeClass::Variable;
00329 newNode.ParentNodeId = parentId;
00330 newNode.ReferenceTypeId = ref.ReferenceTypeId;
00331 newNode.TypeDefinition = ref.TargetNodeTypeDefinition;
00332 newNode.Attributes = attrs;
00333 return newNode;
00334 }
00335
00336 AddNodesItem Object::CreateObjectCopy(const NodeId& parentId, const ReferenceDescription& ref)
00337 {
00338 const NodeId& nodeId = ref.TargetNodeId;
00339
00340 ReadParameters readParams;
00341 readParams.AttributesToRead.push_back(ToReadValueId(nodeId, AttributeId::DisplayName));
00342 readParams.AttributesToRead.push_back(ToReadValueId(nodeId, AttributeId::Description));
00343 readParams.AttributesToRead.push_back(ToReadValueId(nodeId, AttributeId::WriteMask));
00344 readParams.AttributesToRead.push_back(ToReadValueId(nodeId, AttributeId::UserWriteMask));
00345 readParams.AttributesToRead.push_back(ToReadValueId(nodeId, AttributeId::BrowseName));
00346 std::vector<DataValue> values = GetServices()->Attributes()->Read(readParams);
00347
00348 ObjectAttributes attrs;
00349 attrs.DisplayName = values[0].Value.As<LocalizedText>();
00350 attrs.Description = values[1].Value.As<LocalizedText>();
00351 attrs.WriteMask = values[2].Value.As<uint32_t>();
00352 attrs.UserWriteMask = values[3].Value.As<uint32_t>();
00353
00354 AddNodesItem newNode;
00355 newNode.BrowseName = values[4].Value.As<QualifiedName>();
00356 newNode.Class = NodeClass::Object;
00357 newNode.ParentNodeId = parentId;
00358 newNode.ReferenceTypeId = ref.ReferenceTypeId;
00359 newNode.TypeDefinition = ref.TargetNodeTypeDefinition;
00360 newNode.Attributes = attrs;
00361 return newNode;
00362 }
00363
00364 }
00365 }