xml_address_space_loader.cpp
Go to the documentation of this file.
00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 // TODO Add EventNotifier Attribute to all requred nodes.
00012 
00013 #include "xml_address_space_loader.h"
00014 #include "xml_processor.h"
00015 
00016 #include <opc/ua/server/address_space.h>
00017 
00018 #include <libxml2/libxml/xmlmemory.h>
00019 #include <libxml2/libxml/parser.h>
00020 
00021 #include <iostream>
00022 #include <map>
00023 #include <stdexcept>
00024 #include <sstream>
00025 #include <string.h>
00026 
00027 namespace
00028 {
00029   using namespace OpcUa;
00030 
00031   ReferenceId GetReferenceId(const std::string& referenceName)
00032   {
00033     if (referenceName == "organizes")
00034       return ReferenceId::Organizes;
00035     if (referenceName == "references_to")
00036       return ReferenceId::References;
00037     if (referenceName == "has_child")
00038       return ReferenceId::HasChild;
00039     if (referenceName == "has_event_source")
00040       return ReferenceId::HasEventSource;
00041     if (referenceName == "has_modelling_rule")
00042       return ReferenceId::HasModellingRule;
00043     if (referenceName == "has_encoding")
00044       return ReferenceId::HasEncoding;
00045     if (referenceName == "has_description")
00046       return ReferenceId::HasDescription;
00047     if (referenceName == "has_type_definition")
00048       return ReferenceId::HasTypeDefinition;
00049     if (referenceName == "generates_event")
00050       return ReferenceId::GeneratesEvent;
00051     if (referenceName == "aggregates")
00052       return ReferenceId::Aggregates;
00053     if (referenceName == "has_subtype")
00054       return ReferenceId::HasSubtype;
00055     if (referenceName == "has_property")
00056       return ReferenceId::HasProperty;
00057     if (referenceName == "has_component")
00058       return ReferenceId::HasComponent;
00059     if (referenceName == "has_notifier")
00060       return ReferenceId::HasNotifier;
00061     if (referenceName == "has_ordered_component")
00062       return ReferenceId::HasOrderedComponent;
00063     if (referenceName == "has_model_parent")
00064       return ReferenceId::HasModelParent;
00065     if (referenceName == "from_state")
00066       return ReferenceId::FromState;
00067     if (referenceName == "to_state")
00068       return ReferenceId::ToState;
00069     if (referenceName == "has_clause")
00070       return ReferenceId::HasCause;
00071     if (referenceName == "has_effect")
00072       return ReferenceId::HasEffect;
00073     if (referenceName == "has_historical_configuration")
00074       return ReferenceId::HasHistoricalConfiguration;
00075     if (referenceName == "has_historical_event_configuration")
00076       return ReferenceId::HasHistoricalEventConfiguration;
00077     if (referenceName == "has_substate_machine")
00078       return ReferenceId::HasSubStateMachine;
00079     if (referenceName == "has_event_history")
00080       return ReferenceId::HasEventHistory;
00081     if (referenceName == "always_generates_event")
00082       return ReferenceId::AlwaysGeneratesEvent;
00083     if (referenceName == "has_true_substate")
00084       return ReferenceId::HasTrueSubState;
00085     if (referenceName == "has_false_substate")
00086       return ReferenceId::HasFalseSubState;
00087     if (referenceName == "has_condition")
00088       return ReferenceId::HasCondition;
00089     if (referenceName == "non_hierarchical_references")
00090       return ReferenceId::NonHierarchicalReferences;
00091     if (referenceName == "hierarchical_references")
00092       return ReferenceId::HierarchicalReferences;
00093     if (referenceName == "has_cause")
00094       return ReferenceId::HasCause;
00095     if (referenceName == "has_sub_state_machine")
00096       return ReferenceId::HasSubStateMachine;
00097     if (referenceName == "has_true_sub_state")
00098       return ReferenceId::HasTrueSubState;
00099     if (referenceName == "has_false_sub_state")
00100       return ReferenceId::HasFalseSubState;
00101 
00102     throw std::logic_error(std::string("Unknown reference name '") + referenceName + std::string(referenceName));
00103   }
00104 
00105   struct Reference
00106   {
00107     ReferenceId Id;
00108     NodeId TargetNode;
00109     bool IsForward;
00110     NodeClass TargetClass;
00111     QualifiedName TargetBrowseName;
00112     LocalizedText TargetDisplayName;
00113     NodeId TargetType;
00114 
00115     Reference()
00116       : Id(ReferenceId::Unknown)
00117       , IsForward(true)
00118       , TargetClass(NodeClass::Unspecified)
00119     {
00120     }
00121   };
00122 
00123   struct Attribute
00124   {
00125     AttributeId Id;
00126     Variant Value;
00127     Attribute()
00128       : Id(AttributeId::Unknown)
00129     {
00130     }
00131 
00132     Attribute(AttributeId id, Variant value)
00133       : Id(id)
00134       , Value(value)
00135     {
00136     }
00137   };
00138 
00139   struct INode
00140   {
00141     NodeId Id;
00142     std::map<AttributeId, Variant> Attributes;
00143     std::vector<Reference> References;
00144     bool IsExternal;
00145 
00146     INode()
00147       : IsExternal(false)
00148     {
00149     }
00150   };
00151 
00152   struct XmlDocDeleter
00153   {
00154     void operator() (xmlDocPtr doc)
00155     {
00156       xmlFreeDoc(doc);
00157     }
00158   };
00159 
00160   struct LibXmlFree
00161   {
00162     void operator() (void* ptr)
00163     {
00164       xmlFree(ptr);
00165     }
00166   };
00167 
00168   int xmlStrcmp(const xmlChar* xmlStr, const char* str)
00169   {
00170     return ::xmlStrcmp(xmlStr, (const xmlChar*)str);
00171   }
00172 
00173   bool IsXmlNode(const xmlNode& node)
00174   {
00175     return node.type == XML_ELEMENT_NODE;
00176   }
00177 
00178   bool IsXmlNode(const xmlNode& node, const char* name, bool debug = false)
00179   {
00180     if (node.type != XML_ELEMENT_NODE)
00181     {
00182       return false;
00183     }
00184 
00185     if (xmlStrcmp(node.name, name))
00186     {
00187       return false;
00188     }
00189     return true;
00190   }
00191 
00192   std::string GetNodeName(xmlNode& node)
00193   {
00194     if (!node.name)
00195     {
00196       return std::string();
00197     }
00198     return (const char*)node.name;
00199   }
00200 
00201   std::string GetProperty(xmlNode& node, const char* propName)
00202   {
00203     std::unique_ptr<xmlChar, LibXmlFree> attrValue(xmlGetProp(&node, (const xmlChar*)propName), LibXmlFree());
00204     const xmlChar* propValue = attrValue.get();
00205     if (propValue)
00206     {
00207       return (const char*)propValue;
00208     }
00209     return std::string();
00210   }
00211 
00212   std::string GetNodeValue(xmlNode& node)
00213   {
00214     const std::string nodeValue = GetProperty(node, "value");
00215     if (!nodeValue.empty())
00216     {
00217       return nodeValue;
00218     }
00219 
00220     std::unique_ptr<xmlChar, LibXmlFree> content(xmlNodeGetContent(&node));
00221     if (!content)
00222     {
00223       return std::string();
00224     }
00225     return (const char*)content.get();
00226   }
00227 
00228   ObjectId GetObjectIdOfType(const std::string& nodeValue)
00229   {
00230     if (nodeValue == "bool")
00231     {
00232       return ObjectId::Boolean;
00233     }
00234     if (nodeValue == "sbyte")
00235     {
00236       return ObjectId::SByte;
00237     }
00238     if (nodeValue == "byte")
00239     {
00240       return ObjectId::Byte;
00241     }
00242     if (nodeValue == "int16")
00243     {
00244       return ObjectId::Int16;
00245     }
00246     if (nodeValue == "uint16")
00247     {
00248       return ObjectId::UInt16;
00249     }
00250     if (nodeValue == "int32")
00251     {
00252       return ObjectId::Int32;
00253     }
00254     if (nodeValue == "uint32")
00255     {
00256       return ObjectId::UInt32;
00257     }
00258     if (nodeValue == "string")
00259     {
00260       return ObjectId::String;
00261     }
00262     if (nodeValue == "enum")
00263     {
00264       return ObjectId::Enumeration;
00265     }
00266     if (nodeValue == "int")
00267     {
00268       return ObjectId::Integer;
00269     }
00270     if (nodeValue == "byte_string")
00271     {
00272       return ObjectId::ByteString;
00273     }
00274     if (nodeValue == "guid")
00275     {
00276       return ObjectId::Guid;
00277     }
00278     if (nodeValue == "date_time")
00279     {
00280       return ObjectId::DateTime;
00281     }
00282 
00283     std::stringstream stream;
00284     stream << "Unknown data type '" << nodeValue << "'.";
00285     throw std::logic_error(stream.str());
00286   }
00287 
00288   inline ObjectId GetObjectIdOfType(xmlNode& node)
00289   {
00290     return GetObjectIdOfType(GetNodeValue(node));
00291   }
00292 
00293   inline VariantType ConvertToVariantType(ObjectId id)
00294   {
00295     switch (id)
00296     {
00297       case ObjectId::Null:        return VariantType::NUL;
00298       case ObjectId::Boolean:     return VariantType::BOOLEAN;
00299       case ObjectId::SByte:       return VariantType::SBYTE;
00300       case ObjectId::Byte:        return VariantType::BYTE;
00301       case ObjectId::Int16:       return VariantType::INT16;
00302       case ObjectId::UInt16:      return VariantType::UINT16;
00303 
00304       case ObjectId::Integer:
00305       case ObjectId::Enumeration:
00306       case ObjectId::Int32:       return VariantType::INT32;
00307 
00308       case ObjectId::UInt32:      return VariantType::UINT32;
00309       case ObjectId::Int64:       return VariantType::INT64;
00310       case ObjectId::UInt64:      return VariantType::UINT64;
00311       case ObjectId::Float:       return VariantType::FLOAT;
00312       case ObjectId::Double:      return VariantType::DOUBLE;
00313       case ObjectId::String:      return VariantType::STRING;
00314       case ObjectId::ByteString:  return VariantType::BYTE_STRING;
00315       case ObjectId::DateTime:    return VariantType::DATE_TIME;
00316       case ObjectId::Guid:        return VariantType::GUId;
00317 
00318       default:
00319         std::stringstream stream;
00320         stream << "Cannot convert ObjectId '" << (unsigned)id << "' to VariantType.";
00321         throw std::logic_error(stream.str());
00322     }
00323   }
00324 
00325   inline ObjectId ConvertToObjectId(VariantType type)
00326   {
00327     switch (type)
00328     {
00329       case VariantType::NUL:         return ObjectId::Null;
00330       case VariantType::BOOLEAN:     return ObjectId::Boolean;
00331       case VariantType::SBYTE:       return ObjectId::SByte;
00332       case VariantType::BYTE:        return ObjectId::Byte;
00333       case VariantType::INT16:       return ObjectId::Int16;
00334       case VariantType::UINT16:      return ObjectId::UInt16;
00335       case VariantType::INT32:       return ObjectId::Int32;
00336       case VariantType::UINT32:      return ObjectId::UInt32;
00337       case VariantType::INT64:       return ObjectId::Int64;
00338       case VariantType::UINT64:      return ObjectId::UInt64;
00339       case VariantType::FLOAT:       return ObjectId::Float;
00340       case VariantType::DOUBLE:      return ObjectId::Double;
00341       case VariantType::STRING:      return ObjectId::String;
00342       case VariantType::BYTE_STRING: return ObjectId::ByteString;
00343       case VariantType::DATE_TIME:   return ObjectId::DateTime;
00344       case VariantType::GUId:        return ObjectId::Guid;
00345 
00346       default:
00347         std::stringstream stream;
00348         stream << "Cannot convert VariantType '"<< (unsigned)type << "' to ObjectId.";
00349         throw std::logic_error(stream.str());
00350     }
00351   }
00352 
00353   inline VariantType GetVariantType(xmlNode& node)
00354   {
00355     const ObjectId typeId = GetObjectIdOfType(GetProperty(node, "type"));
00356     return ConvertToVariantType(typeId);
00357   }
00358 
00359   NodeClass GetNodeClass(xmlNode& node)
00360   {
00361     const std::string nodeValue = GetNodeValue(node);
00362     if (nodeValue == "object")
00363     {
00364       return NodeClass::Object;
00365     }
00366     if (nodeValue == "variable")
00367     {
00368       return NodeClass::Variable;
00369     }
00370     if (nodeValue == "method")
00371     {
00372       return NodeClass::Method;
00373     }
00374     if (nodeValue == "object_type")
00375     {
00376       return NodeClass::ObjectType;
00377     }
00378     if (nodeValue == "variable_type")
00379     {
00380       return NodeClass::VariableType;
00381     }
00382     if (nodeValue == "reference_type")
00383     {
00384       return NodeClass::ReferenceType;
00385     }
00386     if (nodeValue == "data_type")
00387     {
00388       return NodeClass::DataType;
00389     }
00390     if (nodeValue == "data_type")
00391     {
00392       return NodeClass::View;
00393     }
00394     std::stringstream stream;
00395     stream << "Unknown node class '" << nodeValue << "'. Line " << node.line << ".";
00396     throw std::logic_error(stream.str());
00397   }
00398 
00399   bool IsNumericNodeType(xmlNode& node)
00400   {
00401     const std::string propValue = GetProperty(node, "type");
00402     return propValue == "numeric";
00403   }
00404 
00405   uint32_t GetNamespaceIndex(xmlNode& node)
00406   {
00407     const std::string propValue = GetProperty(node, "ns");
00408     return atoi(propValue.c_str());
00409   }
00410 
00411   NodeId GetNodeId(xmlNode& node)
00412   {
00413     std::string nodeValue = GetNodeValue(node);
00414     if (nodeValue.empty())
00415     {
00416       std::stringstream stream;
00417       stream << "Empty node id. Line " << node.line << ".";
00418       throw std::logic_error(stream.str());
00419     }
00420     uint32_t nsIndex = GetNamespaceIndex(node);
00421     if (IsNumericNodeType(node))
00422     {
00423       return NumericNodeId(atoi(nodeValue.c_str()), nsIndex);
00424     }
00425     return StringNodeId(nodeValue, nsIndex);
00426   }
00427 
00428   bool GetBool(std::string str)
00429   {
00430     if (!str.empty() && (str == "false" || str == "0"))
00431     {
00432       return false;
00433     }
00434     return !str.empty();
00435   }
00436 
00437   std::string GetText(xmlNode& node)
00438   {
00439     const std::string nodeValue = GetNodeValue(node);
00440     if (nodeValue.empty())
00441     {
00442       std::stringstream stream;
00443       stream << "Empty browse name. Line " << node.line << ".";
00444       throw std::logic_error(stream.str());
00445     }
00446     return nodeValue;
00447   }
00448 
00449 
00450   QualifiedName GetQualifiedName(xmlNode& node)
00451   {
00452     return QualifiedName(GetNamespaceIndex(node), GetText(node));
00453   }
00454 
00455   LocalizedText GetLocalizedText(xmlNode& node)
00456   {
00457     const std::string nodeValue = GetNodeValue(node);
00458     if (nodeValue.empty())
00459     {
00460       std::stringstream stream;
00461       stream << "Empty browse name. Line " << node.line << ".";
00462       throw std::logic_error(stream.str());
00463     }
00464     return LocalizedText(nodeValue);
00465   }
00466 
00467   uint32_t GetUInt32(xmlNode& node)
00468   {
00469     const std::string nodeValue = GetNodeValue(node);
00470     if (nodeValue.empty())
00471     {
00472       std::stringstream stream;
00473       stream << "Empty opcua attribute value. Line " << node.line << ".";
00474       throw std::logic_error(stream.str());
00475     }
00476     return atoi(nodeValue.c_str());
00477   }
00478 
00479   int32_t GetInt32(xmlNode& node)
00480   {
00481     const std::string nodeValue = GetNodeValue(node);
00482     if (nodeValue.empty())
00483     {
00484       std::stringstream stream;
00485       stream << "Empty opcua attribute value. Line " << node.line << ".";
00486       throw std::logic_error(stream.str());
00487     }
00488     return atoi(nodeValue.c_str());
00489   }
00490 
00491 
00492   bool GetBool(xmlNode& node)
00493   {
00494     const std::string nodeValue = GetNodeValue(node);
00495     return GetBool(nodeValue);
00496   }
00497 
00498   Variant GetVariantValue(OpcUa::VariantType type, xmlNode& node)
00499   {
00500     const std::string nodeValue = GetNodeValue(node);
00501     switch (type)
00502     {
00503       case VariantType::SBYTE:
00504         return Variant((int8_t)strtol(nodeValue.c_str(), nullptr, 0));
00505       case VariantType::BYTE:
00506         return Variant((uint8_t)strtol(nodeValue.c_str(), nullptr, 0));
00507       case VariantType::INT16:
00508         return Variant((int16_t)strtol(nodeValue.c_str(), nullptr, 0));
00509       case VariantType::UINT16:
00510         return Variant((uint16_t)strtol(nodeValue.c_str(), nullptr, 0));
00511       case VariantType::INT32:
00512         return Variant((int32_t)strtol(nodeValue.c_str(), nullptr, 0));
00513       case VariantType::UINT32:
00514         return Variant((uint32_t)strtol(nodeValue.c_str(), nullptr, 0));
00515       case VariantType::INT64:
00516         return Variant((int64_t)strtoll(nodeValue.c_str(), nullptr, 0));
00517       case VariantType::UINT64:
00518         return Variant((int64_t)strtoll(nodeValue.c_str(), nullptr, 0));
00519       case VariantType::FLOAT:
00520         return Variant(strtof(nodeValue.c_str(), nullptr));
00521       case VariantType::DOUBLE:
00522         return Variant(strtod(nodeValue.c_str(), nullptr));
00523       // TODO check for other types.
00524       case VariantType::NUL:
00525         return Variant();
00526 
00527       case VariantType::STRING:
00528       default:
00529         break;
00530     }
00531     return Variant(nodeValue);
00532   }
00533 
00534   OpcUa::AttributeId GetAttributeId(xmlNode& node)
00535   {
00536     if (IsXmlNode(node, "id"))
00537       return AttributeId::NodeId;
00538     else if (IsXmlNode(node, "class"))
00539       return AttributeId::NodeClass;
00540     else if (IsXmlNode(node, "browse_name"))
00541       return AttributeId::BrowseName;
00542     else if (IsXmlNode(node, "display_name"))
00543       return AttributeId::DisplayName;
00544     else if (IsXmlNode(node, "description"))
00545       return AttributeId::Description;
00546     else if (IsXmlNode(node, "write_mask"))
00547       return AttributeId::WriteMask;
00548     else if (IsXmlNode(node, "user_write_mask"))
00549       return AttributeId::UserWriteMask;
00550     else if (IsXmlNode(node, "is_abstract"))
00551       return AttributeId::IsAbstract;
00552     else if (IsXmlNode(node, "symmetric"))
00553       return AttributeId::Symmetric;
00554     else if (IsXmlNode(node, "inverse_name"))
00555       return AttributeId::InverseName;
00556     else if (IsXmlNode(node, "contains_no_loops"))
00557       return AttributeId::ContainsNoLoops;
00558     else if (IsXmlNode(node, "event_notifier"))
00559       return AttributeId::EventNotifier;
00560     else if (IsXmlNode(node, "value"))
00561       return AttributeId::Value;
00562     else if (IsXmlNode(node, "value_rank"))
00563       return AttributeId::ValueRank;
00564     else if (IsXmlNode(node, "data_type"))
00565       return AttributeId::DataType;
00566     else if (IsXmlNode(node, "array_dimensions"))
00567       return AttributeId::ArrayDimensions;
00568     else if (IsXmlNode(node, "access_level"))
00569       return AttributeId::AccessLevel;
00570     else if (IsXmlNode(node, "user_access_level"))
00571       return AttributeId::UserAccessLevel;
00572     else if (IsXmlNode(node, "minimum_sampling_interval"))
00573       return AttributeId::MinimumSamplingInterval;
00574     else if (IsXmlNode(node, "historizing"))
00575       return AttributeId::Historizing;
00576     else if (IsXmlNode(node, "executable"))
00577       return AttributeId::Executable;
00578     else if (IsXmlNode(node, "user_executable"))
00579       return AttributeId::UserExecutable;
00580 
00581     return AttributeId::Unknown;
00582   }
00583 
00584   Variant GetAttributeValue(OpcUa::AttributeId id, xmlNode& node)
00585   {
00586     switch (id)
00587     {
00588       case AttributeId::NodeId:
00589         return Variant(GetNodeId(node));
00590 
00591       case AttributeId::NodeClass:
00592         return Variant((int32_t)GetNodeClass(node));
00593 
00594       case AttributeId::DisplayName:
00595         return Variant(GetLocalizedText(node));
00596 
00597       case AttributeId::BrowseName:
00598         return Variant(GetQualifiedName(node));
00599 
00600       case AttributeId::Description:
00601       case AttributeId::InverseName:
00602         return Variant(GetText(node));
00603 
00604       case AttributeId::EventNotifier:
00605         return Variant(std::vector<uint8_t>{0});
00606 
00607       case AttributeId::ValueRank:
00608         return Variant(GetInt32(node));
00609 
00610       case AttributeId::WriteMask:
00611       case AttributeId::UserWriteMask:
00612       case AttributeId::ArrayDimensions:
00613       case AttributeId::AccessLevel:
00614       case AttributeId::UserAccessLevel:
00615       case AttributeId::MinimumSamplingInterval:
00616         return Variant(GetUInt32(node));
00617 
00618       case AttributeId::IsAbstract:
00619       case AttributeId::Symmetric:
00620       case AttributeId::ContainsNoLoops:
00621       case AttributeId::Historizing:
00622       case AttributeId::Executable:
00623       case AttributeId::UserExecutable:
00624         return Variant(GetBool(node));
00625 
00626       case AttributeId::Value:
00627         break;
00628 
00629       case AttributeId::DataType:
00630         return Variant(GetObjectIdOfType(node));
00631 
00632       default:
00633         return Variant(GetText(node));
00634     }
00635     const VariantType type = GetVariantType(node);
00636     return GetVariantValue(type, node);
00637   }
00638 
00639   class AttributesCollector : private Internal::XmlProcessor
00640   {
00641   public:
00642     AttributesCollector(INode& node, bool debug)
00643       : OpcUaNode(node)
00644       , Debug(debug)
00645     {
00646     }
00647 
00648     virtual void Process(xmlNode& node)
00649     {
00650       for (xmlNodePtr subNode = node.children; subNode; subNode = subNode->next)
00651       {
00652         if (!IsXmlNode(*subNode))
00653         {
00654           continue;
00655         }
00656         const AttributeId attribute = GetAttributeId(*subNode);
00657         if (attribute == AttributeId::NodeId)
00658         {
00659           OpcUaNode.Id = GetNodeId(*subNode);
00660           continue;
00661         }
00662 
00663         const Variant value = GetAttributeValue(attribute, *subNode);
00664         AddAttribute(attribute, value);
00665       }
00666 
00667       // If tag 'data_type' is absent in the xml then need to add data type which will be based on type of value.
00668       if (!HasAttribute(AttributeId::DataType) && HasAttribute(AttributeId::Value))
00669       {
00670         AddAttribute(AttributeId::DataType, GetDataType(AttributeId::Value));
00671       }
00672     }
00673 
00674   private:
00675     bool IsAttributes(const xmlNode& node) const
00676     {
00677       return IsXmlNode(node, "attributes");
00678     }
00679 
00680     template <typename T>
00681     void AddAttribute(AttributeId attr, const T& value)
00682     {
00683       OpcUaNode.Attributes.insert(std::make_pair(attr, Variant(value)));
00684     }
00685 
00686     bool HasAttribute(AttributeId attr) const
00687     {
00688       return OpcUaNode.Attributes.find(AttributeId::DataType) != OpcUaNode.Attributes.end();
00689     }
00690 
00691     ObjectId GetDataType(AttributeId attr) const
00692     {
00693       auto attrPos = OpcUaNode.Attributes.find(attr);
00694       if (attrPos == OpcUaNode.Attributes.end())
00695       {
00696         return ObjectId::Null;
00697       }
00698       return ConvertToObjectId(attrPos->second.Type());
00699     }
00700 
00701   private:
00702     INode& OpcUaNode;
00703     const bool Debug;
00704   };
00705 
00706   class ReferencesCollector : private Internal::XmlProcessor
00707   {
00708   public:
00709     ReferencesCollector(INode& node, bool debug)
00710       : OpcUaNode(node)
00711       , Debug(debug)
00712     {
00713     }
00714 
00715     virtual void Process(xmlNode& node)
00716     {
00717       for (xmlNodePtr refNode = node.children; refNode; refNode = refNode->next)
00718       {
00719         if (!IsXmlNode(*refNode))
00720         {
00721           continue;
00722         }
00723 
00724         try
00725         {
00726           AddReferenceToNode(*refNode);
00727         }
00728         catch (const std::exception& exc)
00729         {
00730           std::cerr << exc.what() << std::endl;
00731         }
00732       }
00733     }
00734 
00735   private:
00736     void AddReferenceToNode(xmlNode& refNode)
00737     {
00738       const std::string refName = GetNodeName(refNode);
00739       const NodeId targetNode = GetNodeId(refNode);
00740       Reference reference;
00741       reference.Id = GetReferenceId(refName);
00742 
00743       for (xmlNodePtr subNode = refNode.children; subNode; subNode = subNode->next)
00744       {
00745         if (!IsXmlNode(*subNode))
00746         {
00747           continue;
00748         }
00749 
00750         const std::string& nodeName = GetNodeName(*subNode);
00751         if (nodeName == "id")
00752         {
00753           reference.TargetNode = GetNodeId(*subNode);
00754         }
00755         else if (nodeName == "class")
00756         {
00757           reference.TargetClass = GetNodeClass(*subNode);
00758         }
00759         else if (nodeName == "browse_name")
00760         {
00761           reference.TargetBrowseName = GetQualifiedName(*subNode);
00762         }
00763         else if (nodeName == "display_name")
00764         {
00765           reference.TargetDisplayName = GetLocalizedText(*subNode);
00766         }
00767         else if (nodeName == "is_forward")
00768         {
00769           reference.IsForward = GetBool(GetNodeValue(*subNode));
00770         }
00771         else if (nodeName == "type_definition")
00772         {
00773           reference.TargetType = GetNodeId(*subNode);
00774         }
00775       }
00776 
00777       EnsureValid(reference, refNode.line);
00778       OpcUaNode.References.push_back(reference);
00779     }
00780 
00781   private:
00782     void EnsureValid(const Reference& ref, int lineNum) const
00783     {
00784       std::stringstream stream;
00785       if (ref.Id == ReferenceId::Unknown)
00786       {
00787         stream << "Unknown reference type. line" << lineNum << ".";
00788         throw std::logic_error(stream.str());
00789       }
00790       if (ref.TargetNode == NodeId())
00791       {
00792         stream << "Empty target node Id. line" << lineNum << ".";
00793         throw std::logic_error(stream.str());
00794       }
00795     }
00796 
00797   private:
00798     INode& OpcUaNode;
00799     const bool Debug;
00800   };
00801 
00802   class NodesCollector : private Internal::XmlProcessor
00803   {
00804   public:
00805     NodesCollector(std::map<NodeId, INode>& nodes, bool debug)
00806       : Nodes(nodes)
00807       , Debug(debug)
00808     {
00809     }
00810 
00811     virtual void Process(xmlNode& node)
00812     {
00813       if (!IsXmlNode(node))
00814       {
00815         return;
00816       }
00817 
00818       INode opcuaNode;
00819       if (IsXmlNode(node, "node"))
00820       {
00821         opcuaNode.IsExternal = false;
00822       }
00823       else if (IsXmlNode(node, "external"))
00824       {
00825         opcuaNode.IsExternal = true;
00826       }
00827       else
00828       {
00829         if (Debug)
00830         {
00831           std::cerr << "Unknown node '" << node.name << "' at line " << node.line <<  "." << std::endl;
00832         }
00833         return;
00834       }
00835 
00836       FillNode(node, opcuaNode);
00837       EnsureNodeIsValid(opcuaNode, node);
00838       Nodes.insert(std::make_pair(opcuaNode.Id, opcuaNode));
00839     }
00840 
00841   private:
00842     void EnsureNodeIsValid(const INode& opcuaNode, const xmlNode& node) const
00843     {
00844       if (opcuaNode.Id == NodeId())
00845       {
00846         std::stringstream stream;
00847         stream << "INode at line '" << node.line << "' has no Id.";
00848         throw std::logic_error(stream.str());
00849       }
00850     }
00851 
00852     void FillNode(const xmlNode& node, INode& opcuaNode) const
00853     {
00854       AttributesCollector attributeCollector(opcuaNode, Debug);
00855       ReferencesCollector referencCollector(opcuaNode, Debug);
00856 
00857       for (xmlNodePtr subNode = node.children; subNode; subNode = subNode->next)
00858       {
00859         if (IsXmlNode(*subNode, "attributes"))
00860         {
00861           attributeCollector.Process(*subNode);
00862           continue;
00863         }
00864         else if (IsXmlNode(*subNode, "references"))
00865         {
00866           referencCollector.Process(*subNode);
00867         }
00868         else if (Debug)
00869         {
00870           std::cerr << "Unknown node '" << subNode->name << "' at line " << subNode->line <<  "." << std::endl;
00871         }
00872       }
00873     }
00874 
00875   private:
00876     std::map<NodeId, INode>& Nodes;
00877     const bool Debug;
00878   };
00879 
00880 
00881   class ConfigurationProcessor
00882   {
00883   public:
00884     ConfigurationProcessor(bool debug)
00885       : Debug(debug)
00886     {
00887 
00888     }
00889 
00890     std::map<NodeId, INode> Process(xmlDoc& doc)
00891     {
00892       xmlNodePtr rootNode = xmlDocGetRootElement(&doc);
00893       EnsureRootNodeValid(*rootNode);
00894 
00895       std::map<NodeId, INode> nodes;
00896       NodesCollector nodesBuilder(nodes, Debug);
00897       for (xmlNodePtr cur = rootNode->children; cur; cur = cur->next)
00898       {
00899         nodesBuilder.Process(*cur);
00900       }
00901 
00902       return nodes;
00903     }
00904 
00905   private:
00906     void EnsureRootNodeValid(xmlNode& rootNode)
00907     {
00908       if (rootNode.type != XML_ELEMENT_NODE)
00909       {
00910         throw std::logic_error("Root element is not a node.'");
00911       }
00912       if (xmlStrcmp(rootNode.name, "address_space"))
00913       {
00914         throw std::logic_error(std::string("Invalid root element '") + (const char*)rootNode.name + std::string("'."));
00915       }
00916       std::unique_ptr<xmlChar, LibXmlFree> versionBuf(xmlGetProp(&rootNode, (const xmlChar*)"version"), LibXmlFree());
00917       const xmlChar* version = versionBuf.get();
00918       if (!version)
00919       {
00920         throw std::logic_error("Address space element has no 'version' attribute.");
00921       }
00922       if (xmlStrcmp(version, "1"))
00923       {
00924         throw std::logic_error(std::string("Unknown version '") + (const char*)version + std::string("'of address space."));
00925       }
00926     }
00927 
00928   private:
00929     const bool Debug;
00930   };
00931 
00932   std::map<NodeId, INode> ParseConfig(const char* configPath, bool debug)
00933   {
00934     std::unique_ptr<xmlDoc, XmlDocDeleter> doc(xmlParseFile(configPath), XmlDocDeleter());
00935     if (!doc)
00936     {
00937       throw std::logic_error(std::string("Cannot load file '") + std::string(configPath) + std::string("'"));
00938     }
00939     ConfigurationProcessor xmlConfiguration(debug);
00940     return xmlConfiguration.Process(*doc);
00941   }
00942 
00943 
00944   class NodesRegistrator
00945   {
00946   public:
00947     NodesRegistrator(OpcUa::NodeManagementServices& registry, bool debug)
00948       : Registry(registry)
00949       , Debug(debug)
00950     {
00951     }
00952 
00953     void RegisterNodes(const std::map<NodeId, INode>& nodes)
00954     {
00955       for (const auto& node : nodes)
00956       {
00957         if (!node.second.IsExternal)
00958         {
00959           RegisterNode(node.second);
00960         }
00961         AddReferences(node.second);
00962       }
00963     }
00964 
00965   private:
00966     void RegisterNode(const INode& node)
00967     {
00968       //Registry.AddAttribute(node.Id, AttributeId::NodeId, Variant(node.Id));
00969       for (const std::pair<AttributeId, Variant>& attr : node.Attributes)
00970       {
00971         //Registry.AddAttribute(node.Id, attr.first, attr.second);
00972       }
00973     }
00974 
00975     void AddReferences(const INode& node)
00976     {
00977       for (const Reference& ref : node.References)
00978       {
00979         ReferenceDescription desc;
00980         desc.BrowseName = ref.TargetBrowseName;
00981         desc.DisplayName = ref.TargetDisplayName;
00982         desc.IsForward = ref.IsForward;
00983         desc.ReferenceTypeId = ref.Id;
00984         desc.TargetNodeClass = ref.TargetClass;
00985         desc.TargetNodeId = ref.TargetNode;
00986         desc.TargetNodeTypeDefinition = ref.TargetType;
00987         //Registry.AddReference(node.Id, desc);
00988       }
00989     }
00990 
00991   private:
00992     OpcUa::NodeManagementServices& Registry;
00993     const bool Debug;
00994   };
00995 } // namespace
00996 
00997 namespace OpcUa
00998 {
00999   namespace Internal
01000   {
01001 
01002     XmlAddressSpaceLoader::XmlAddressSpaceLoader(OpcUa::NodeManagementServices& registry, bool debug)
01003       : Registry(registry)
01004       , Debug(debug)
01005     {
01006     }
01007 
01008     void XmlAddressSpaceLoader::Load(const char* fileName)
01009     {
01010       std::map<NodeId, INode> nodes = ParseConfig(fileName, Debug);
01011       NodesRegistrator reg(Registry, Debug);
01012       reg.RegisterNodes(nodes);
01013     }
01014 
01015   } // namespace Internal
01016 } // namespace OpcUa


ros_opcua_impl_freeopcua
Author(s): Denis Štogl
autogenerated on Sat Jun 8 2019 18:24:57