Changeset 163:19d7bbecc1fb in finroc_plugins_runtime_construction


Ignore:
Timestamp:
15.04.2021 12:02:43 (4 weeks ago)
Author:
Max Reichardt <max.reichardt@…>
Branch:
17.03
Phase:
public
Tags:
tip
Message:

Improves handling of connectors loaded from XML files with no referenced port present at loading time.

Files:
2 edited

Legend:

Unmodified
Added
Removed
  • tFinstructable.cpp

    r162 r163  
    154154} 
    155155 
     156class tOnFullInitialization : public core::tAnnotation 
     157{ 
     158public: 
     159  tOnFullInitialization(tFinstructable& finstructable, bool& fully_initialized) : 
     160    finstructable(finstructable), 
     161    fully_initialized(fully_initialized) 
     162  {} 
     163 
     164private: 
     165  virtual void OnInitialization() override 
     166  { 
     167    FINROC_LOG_PRINT_STATIC(DEBUG_VERBOSE_1, "Fully initialized", *GetAnnotated<core::tFrameworkElement>()); 
     168    finstructable.CheckPendingConnectors(true); 
     169    fully_initialized = true; 
     170  } 
     171 
     172  tFinstructable& finstructable; 
     173  bool& fully_initialized; 
     174}; 
     175 
    156176} 
    157177 
     
    182202  { 
    183203    AddDependency(tSharedLibrary(shared_library_string)); 
     204  } 
     205} 
     206 
     207void tFinstructable::CheckPendingConnectors(bool print_warning_messages) 
     208{ 
     209  if (pending_connectors.size()) 
     210  { 
     211    core::tPath path_to_this = GetFrameworkElement()->GetPath(); 
     212    std::vector<tConnectorData> pending_connectors_copy; 
     213    std::swap(pending_connectors_copy, pending_connectors); 
     214    assert(pending_connectors.empty()); 
     215    for (auto & connector_data : pending_connectors_copy) 
     216    { 
     217      connector_data.status = InstantiateConnector(connector_data, path_to_this); 
     218      if (connector_data.status.length()) 
     219      { 
     220        pending_connectors.push_back(connector_data); 
     221        if (print_warning_messages) 
     222        { 
     223          FINROC_LOG_PRINT(WARNING, "Creating connector from ", connector_data.source, " to ", connector_data.destination, " failed. Reason: ", connector_data.status); 
     224        } 
     225      } 
     226    } 
    184227  } 
    185228} 
     
    556599        else if (name == "edge") 
    557600        { 
    558           std::string source_string = node->GetStringAttribute("src"); 
    559           std::string destination_string = node->GetStringAttribute("dest"); 
    560           rrlib::uri::tURI source_uri(source_string); 
    561           rrlib::uri::tURI destination_uri(destination_string); 
     601          tConnectorData connector_data; 
     602          connector_data.source = node->GetStringAttribute("src"); 
     603          connector_data.destination = node->GetStringAttribute("dest"); 
     604          connector_data.structure_file_version = version; 
     605          connector_data.top_level_composite_component = this_is_outermost_composite_component; 
    562606 
    563607          try 
    564608          { 
    565             rrlib::uri::tURIElements source_uri_parsed; 
    566             rrlib::uri::tURIElements destination_uri_parsed; 
    567             if (version) 
    568             { 
    569               source_uri.Parse(source_uri_parsed); 
    570               destination_uri.Parse(destination_uri_parsed); 
    571             } 
    572             else 
    573             { 
    574               source_uri_parsed.path = rrlib::uri::tPath(source_string); 
    575               destination_uri_parsed.path = rrlib::uri::tPath(destination_string); 
    576             } 
    577             core::tUriConnectOptions connect_options; 
    578             connect_options.flags.Set(core::tConnectionFlag::FINSTRUCTED, !static_cast<bool>(include_instance));  // TODO attach origin data to connectors also 
     609            core::tUriConnectOptions& connect_options = connector_data.connect_options; 
     610            connector_data.connect_options.flags.Set(core::tConnectionFlag::FINSTRUCTED, !static_cast<bool>(include_instance));  // TODO attach origin data to connectors also 
    579611            if (node->HasAttribute("flags")) 
    580612            { 
     
    619651            } 
    620652 
    621             if (source_uri_parsed.scheme.length() == 0 && destination_uri_parsed.scheme.length() == 0) 
    622             { 
    623               core::tAbstractPort* source_port = GetChildPort(source_uri_parsed.path); 
    624               core::tAbstractPort* destination_port = GetChildPort(destination_uri_parsed.path); 
    625  
    626               // Backward-compatibility: Check whether this a connector between service interfaces now 
    627               if (version == 0 && source_port == nullptr && destination_port == nullptr) 
     653            // read parameters 
     654            for (rrlib::xml::tNode::const_iterator parameter_node = node->ChildrenBegin(); parameter_node != node->ChildrenEnd(); ++parameter_node) 
     655            { 
     656              if (parameter_node->Name() == "parameter") 
    628657              { 
    629                 core::tAbstractPort* service_source_port = GetChildPort(ReplaceInterfaceInPath(source_uri_parsed.path, "Services")); 
    630                 core::tAbstractPort* service_destination_port = GetChildPort(ReplaceInterfaceInPath(destination_uri_parsed.path, "Services")); 
    631                 if (service_source_port && service_destination_port && service_source_port->GetDataType().GetTypeClassification() == rrlib::rtti::tTypeClassification::RPC_TYPE) 
    632                 { 
    633                   FINROC_LOG_PRINT(WARNING, "Adjusted connector's interfaces to service interfaces (auto-update loading legacy files): now connects '", *service_source_port, "' and '", *service_destination_port, "'"); 
    634                   source_port = service_source_port; 
    635                   destination_port = service_destination_port; 
    636                 } 
     658                connect_options.parameters.emplace(parameter_node->GetStringAttribute("name"), parameter_node->GetTextContent()); 
    637659              } 
    638               else if (version == 0 && source_port && source_port->GetDataType().GetTypeClassification() == rrlib::rtti::tTypeClassification::RPC_TYPE && destination_port == nullptr) 
     660            } 
     661 
     662            connector_data.status = InstantiateConnector(connector_data, path_to_this); 
     663            if (connector_data.status.length()) 
     664            { 
     665              this->pending_connectors.push_back(connector_data); 
     666              if (this->fully_initialized) 
    639667              { 
    640                 core::tAbstractPort* service_destination_port = GetChildPort(ReplaceInterfaceInPath(destination_uri_parsed.path, "Services")); 
    641                 if (service_destination_port && service_destination_port->GetDataType() == source_port->GetDataType()) 
    642                 { 
    643                   FINROC_LOG_PRINT(WARNING, "Adjusted connector's interfaces to service interfaces (auto-update loading legacy files): now connects '", *source_port, "' and '", *service_destination_port, "'"); 
    644                   destination_port = service_destination_port; 
    645                 } 
     668                FINROC_LOG_PRINT(WARNING, "Creating connector from ", connector_data.source, " to ", connector_data.destination, " failed. Reason: ", connector_data.status); 
    646669              } 
    647               else if (version == 0 && destination_port && destination_port->GetDataType().GetTypeClassification() == rrlib::rtti::tTypeClassification::RPC_TYPE && source_port == nullptr) 
    648               { 
    649                 core::tAbstractPort* service_source_port = GetChildPort(ReplaceInterfaceInPath(source_uri_parsed.path, "Services")); 
    650                 if (service_source_port && service_source_port->GetDataType() == destination_port->GetDataType()) 
    651                 { 
    652                   FINROC_LOG_PRINT(WARNING, "Adjusted connector's interfaces to service interfaces (auto-update loading legacy files): now connects '", *service_source_port, "' and '", *destination_port, "'"); 
    653                   source_port = service_source_port; 
    654                 } 
    655               } 
    656  
    657               if (source_port == nullptr && destination_port == nullptr) 
    658               { 
    659                 FINROC_LOG_PRINT(WARNING, "Cannot create connector because neither port is available: '", source_uri_parsed.path, "' and '", destination_uri_parsed.path, "'"); 
    660               } 
    661               else if (source_port == nullptr || source_port->GetFlag(tFlag::VOLATILE)) 
    662               { 
    663                 if (source_uri_parsed.path.IsAbsolute() && this_is_outermost_composite_component && version == 0) 
    664                 { 
    665                   FINROC_LOG_PRINT(WARNING, "Interpreting absolute connector source path (", source_uri_parsed.path, ") as legacy TCP connection"); 
    666                   destination_port->ConnectTo(rrlib::uri::tURI("tcp:" + rrlib::uri::tURI(source_uri_parsed.path).ToString()), core::tConnectionFlag::FINSTRUCTED); 
    667                 } 
    668                 else 
    669                 { 
    670                   destination_port->ConnectTo(source_uri_parsed.path.IsAbsolute() ? source_uri_parsed.path : path_to_this.Append(source_uri_parsed.path), connect_options); 
    671                 } 
    672               } 
    673               else if (destination_port == nullptr || destination_port->GetFlag(tFlag::VOLATILE)) 
    674               { 
    675                 if (destination_uri_parsed.path.IsAbsolute() && this_is_outermost_composite_component && version == 0) 
    676                 { 
    677                   FINROC_LOG_PRINT(WARNING, "Interpreting absolute connector destination path (", destination_uri_parsed.path, ") as legacy TCP connection"); 
    678                   source_port->ConnectTo(rrlib::uri::tURI("tcp:" + rrlib::uri::tURI(destination_uri_parsed.path).ToString()), core::tConnectionFlag::FINSTRUCTED); 
    679                 } 
    680                 else 
    681                 { 
    682                   source_port->ConnectTo(destination_uri_parsed.path.IsAbsolute() ? destination_uri_parsed.path : path_to_this.Append(destination_uri_parsed.path), connect_options); 
    683                 } 
    684               } 
    685               else 
    686               { 
    687                 source_port->ConnectTo(*destination_port, connect_options); 
    688               } 
    689             } 
    690             else 
    691             { 
    692               // Create URI connector 
    693               if (source_uri_parsed.scheme.length() && destination_uri_parsed.scheme.length()) 
    694               { 
    695                 throw std::runtime_error("Only one port may have an address with an URI scheme"); 
    696               } 
    697               core::tAbstractPort* source_port = GetChildPort(source_uri_parsed.scheme.length() == 0 ? source_uri_parsed.path : destination_uri_parsed.path); 
    698               if (!source_port) 
    699               { 
    700                 std::stringstream message; 
    701                 message << "Cannot create connector because port is not available: " << (source_uri_parsed.scheme.length() == 0 ? source_uri_parsed.path : destination_uri_parsed.path); 
    702                 throw std::runtime_error(message.str()); 
    703               } 
    704               const core::tURI& scheme_uri = source_uri_parsed.scheme.length() != 0 ? source_uri : destination_uri; 
    705  
    706               // read parameters 
    707               for (rrlib::xml::tNode::const_iterator parameter_node = node->ChildrenBegin(); parameter_node != node->ChildrenEnd(); ++parameter_node) 
    708               { 
    709                 if (parameter_node->Name() == "parameter") 
    710                 { 
    711                   connect_options.parameters.emplace(parameter_node->GetStringAttribute("name"), parameter_node->GetTextContent()); 
    712                 } 
    713               } 
    714  
    715               core::tUriConnector::Create(*source_port, scheme_uri, connect_options); 
    716670            } 
    717671          } 
    718672          catch (const std::exception& e) 
    719673          { 
    720             FINROC_LOG_PRINT(WARNING, "Creating connector from ", source_uri.ToString(), " to ", destination_uri.ToString(), " failed. Reason: ", e.what()); 
     674            FINROC_LOG_PRINT(WARNING, "Creating connector from ", connector_data.source, " to ", connector_data.destination, " failed. Reason: ", e.what()); 
    721675          } 
    722676        } 
     
    762716} 
    763717 
     718std::string tFinstructable::InstantiateConnector(const tConnectorData& connector_data, const core::tPath& path_to_this) 
     719{ 
     720  auto version = connector_data.structure_file_version; 
     721  try 
     722  { 
     723    rrlib::uri::tURI source_uri(connector_data.source); 
     724    rrlib::uri::tURI destination_uri(connector_data.destination); 
     725 
     726    rrlib::uri::tURIElements source_uri_parsed; 
     727    rrlib::uri::tURIElements destination_uri_parsed; 
     728    if (version) 
     729    { 
     730      source_uri.Parse(source_uri_parsed); 
     731      destination_uri.Parse(destination_uri_parsed); 
     732    } 
     733    else 
     734    { 
     735      source_uri_parsed.path = rrlib::uri::tPath(connector_data.source); 
     736      destination_uri_parsed.path = rrlib::uri::tPath(connector_data.destination); 
     737    } 
     738 
     739    if (source_uri_parsed.scheme.length() == 0 && destination_uri_parsed.scheme.length() == 0) 
     740    { 
     741      core::tAbstractPort* source_port = GetChildPort(source_uri_parsed.path); 
     742      core::tAbstractPort* destination_port = GetChildPort(destination_uri_parsed.path); 
     743 
     744      // Backward-compatibility: Check whether this a connector between service interfaces now 
     745      if (version == 0 && source_port == nullptr && destination_port == nullptr) 
     746      { 
     747        core::tAbstractPort* service_source_port = GetChildPort(ReplaceInterfaceInPath(source_uri_parsed.path, "Services")); 
     748        core::tAbstractPort* service_destination_port = GetChildPort(ReplaceInterfaceInPath(destination_uri_parsed.path, "Services")); 
     749        if (service_source_port && service_destination_port && service_source_port->GetDataType().GetTypeClassification() == rrlib::rtti::tTypeClassification::RPC_TYPE) 
     750        { 
     751          FINROC_LOG_PRINT(WARNING, "Adjusted connector's interfaces to service interfaces (auto-update loading legacy files): now connects '", *service_source_port, "' and '", *service_destination_port, "'"); 
     752          source_port = service_source_port; 
     753          destination_port = service_destination_port; 
     754        } 
     755      } 
     756      else if (version == 0 && source_port && source_port->GetDataType().GetTypeClassification() == rrlib::rtti::tTypeClassification::RPC_TYPE && destination_port == nullptr) 
     757      { 
     758        core::tAbstractPort* service_destination_port = GetChildPort(ReplaceInterfaceInPath(destination_uri_parsed.path, "Services")); 
     759        if (service_destination_port && service_destination_port->GetDataType() == source_port->GetDataType()) 
     760        { 
     761          FINROC_LOG_PRINT(WARNING, "Adjusted connector's interfaces to service interfaces (auto-update loading legacy files): now connects '", *source_port, "' and '", *service_destination_port, "'"); 
     762          destination_port = service_destination_port; 
     763        } 
     764      } 
     765      else if (version == 0 && destination_port && destination_port->GetDataType().GetTypeClassification() == rrlib::rtti::tTypeClassification::RPC_TYPE && source_port == nullptr) 
     766      { 
     767        core::tAbstractPort* service_source_port = GetChildPort(ReplaceInterfaceInPath(source_uri_parsed.path, "Services")); 
     768        if (service_source_port && service_source_port->GetDataType() == destination_port->GetDataType()) 
     769        { 
     770          FINROC_LOG_PRINT(WARNING, "Adjusted connector's interfaces to service interfaces (auto-update loading legacy files): now connects '", *service_source_port, "' and '", *destination_port, "'"); 
     771          source_port = service_source_port; 
     772        } 
     773      } 
     774 
     775      if (source_port == nullptr && destination_port == nullptr) 
     776      { 
     777        std::stringstream error_message; 
     778        error_message << "Cannot create connector because neither port is available: '" << source_uri_parsed.path << "' and '" << destination_uri_parsed.path << "'"; 
     779        throw std::runtime_error(error_message.str()); 
     780      } 
     781      else if (source_port == nullptr || source_port->GetFlag(tFlag::VOLATILE)) 
     782      { 
     783        if (source_uri_parsed.path.IsAbsolute() && connector_data.top_level_composite_component && version == 0) 
     784        { 
     785          FINROC_LOG_PRINT(WARNING, "Interpreting absolute connector source path (", source_uri_parsed.path, ") as legacy TCP connection"); 
     786          destination_port->ConnectTo(rrlib::uri::tURI("tcp:" + rrlib::uri::tURI(source_uri_parsed.path).ToString()), core::tConnectionFlag::FINSTRUCTED); 
     787        } 
     788        else 
     789        { 
     790          destination_port->ConnectTo(source_uri_parsed.path.IsAbsolute() ? source_uri_parsed.path : path_to_this.Append(source_uri_parsed.path), connector_data.connect_options); 
     791        } 
     792      } 
     793      else if (destination_port == nullptr || destination_port->GetFlag(tFlag::VOLATILE)) 
     794      { 
     795        if (destination_uri_parsed.path.IsAbsolute() && connector_data.top_level_composite_component && version == 0) 
     796        { 
     797          FINROC_LOG_PRINT(WARNING, "Interpreting absolute connector destination path (", destination_uri_parsed.path, ") as legacy TCP connection"); 
     798          source_port->ConnectTo(rrlib::uri::tURI("tcp:" + rrlib::uri::tURI(destination_uri_parsed.path).ToString()), core::tConnectionFlag::FINSTRUCTED); 
     799        } 
     800        else 
     801        { 
     802          source_port->ConnectTo(destination_uri_parsed.path.IsAbsolute() ? destination_uri_parsed.path : path_to_this.Append(destination_uri_parsed.path), connector_data.connect_options); 
     803        } 
     804      } 
     805      else 
     806      { 
     807        source_port->ConnectTo(*destination_port, connector_data.connect_options); 
     808      } 
     809    } 
     810    else 
     811    { 
     812      // Create URI connector 
     813      if (source_uri_parsed.scheme.length() && destination_uri_parsed.scheme.length()) 
     814      { 
     815        throw std::runtime_error("Only one port may have an address with an URI scheme"); 
     816      } 
     817      core::tAbstractPort* source_port = GetChildPort(source_uri_parsed.scheme.length() == 0 ? source_uri_parsed.path : destination_uri_parsed.path); 
     818      if (!source_port) 
     819      { 
     820        std::stringstream message; 
     821        message << "Cannot create connector because port is not available: " << (source_uri_parsed.scheme.length() == 0 ? source_uri_parsed.path : destination_uri_parsed.path); 
     822        throw std::runtime_error(message.str()); 
     823      } 
     824      const core::tURI& scheme_uri = source_uri_parsed.scheme.length() != 0 ? source_uri : destination_uri; 
     825 
     826      core::tUriConnector::Create(*source_port, scheme_uri, connector_data.connect_options); 
     827    } 
     828  } 
     829  catch (const std::exception& e) 
     830  { 
     831    return e.what(); 
     832  } 
     833  return ""; 
     834} 
     835 
    764836void tFinstructable::OnInitialization() 
    765837{ 
     
    767839  { 
    768840    throw std::logic_error("Any class using tFinstructable must set tFlag::FINSTRUCTABLE_GROUP in constructor"); 
     841  } 
     842 
     843  if (pending_connectors.empty()) 
     844  { 
     845    fully_initialized = true; 
     846  } 
     847  else 
     848  { 
     849    GetAnnotated<core::tFrameworkElement>()->EmplaceAnnotation<tOnFullInitialization>(*this, fully_initialized); 
    769850  } 
    770851} 
  • tFinstructable.h

    r140 r163  
    113113  static void AddDependency(const rrlib::rtti::tType& dt); 
    114114 
     115  /*! 
     116   * Evaluates connectors loaded from XML that could not be created again 
     117   * 
     118   * \param print_warning_messages Whether to print warning messages for all connectors that cannot be instantiated 
     119   */ 
     120  void CheckPendingConnectors(bool print_warning_messages); 
     121 
    115122  /*! for rrlib_logging */ 
    116123  std::string GetLogDescription() const; 
     
    181188  const std::string& xml_file; 
    182189 
     190  /*! Connector data containing all relevant data loaded from XML */ 
     191  struct tConnectorData 
     192  { 
     193    std::string source, destination; 
     194    core::tUriConnectOptions connect_options; 
     195    uint structure_file_version = 0; 
     196    std::string status; 
     197    bool top_level_composite_component = false; 
     198  }; 
     199 
     200  /*! connectors as loaded from XML file that could not be created (yet) */ 
     201  std::vector<tConnectorData> pending_connectors; 
     202 
     203  /*! Whether composite component initialization is complete */ 
     204  bool fully_initialized = false; 
    183205 
    184206  /*! 
     
    230252 
    231253  /*! 
     254   * Intantiate connector 
     255   * 
     256   * \param connector_data Data of connector 
     257   * \param path_to_this Path to this composite component 
     258   * \return Error message if connector could not (yet) be instantiated. 
     259   */ 
     260  std::string InstantiateConnector(const tConnectorData& connector_data, const core::tPath& path_to_this); 
     261 
     262  /*! 
    232263   * Is this finstructable group the one responsible for saving parameter's config entry? 
    233264   * 
Note: See TracChangeset for help on using the changeset viewer.