source: finroc_core/port/tUriConnector.cpp @ 427:0a7e413412e9

17.03
Last change on this file since 427:0a7e413412e9 was 427:0a7e413412e9, checked in by Max Reichardt <mreichardt@…>, 3 years ago

Unifies and optimizes serialization of tConnectOptions and tUriConnectOptions (for uniform handling on Java side). Makes sure that auto-set flags erroneously set by user are ignored.

File size: 9.0 KB
Line 
1//
2// You received this file as part of Finroc
3// A framework for intelligent robot control
4//
5// Copyright (C) Finroc GbR (finroc.org)
6//
7// This program is free software; you can redistribute it and/or modify
8// it under the terms of the GNU General Public License as published by
9// the Free Software Foundation; either version 2 of the License, or
10// (at your option) any later version.
11//
12// This program is distributed in the hope that it will be useful,
13// but WITHOUT ANY WARRANTY; without even the implied warranty of
14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15// GNU General Public License for more details.
16//
17// You should have received a copy of the GNU General Public License along
18// with this program; if not, write to the Free Software Foundation, Inc.,
19// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20//
21//----------------------------------------------------------------------
22/*!\file    core/port/tUriConnector.cpp
23 *
24 * \author  Max Reichardt
25 *
26 * \date    2017-01-16
27 *
28 */
29//----------------------------------------------------------------------
30#include "core/port/tUriConnector.h"
31
32//----------------------------------------------------------------------
33// External includes (system with <>, local with "")
34//----------------------------------------------------------------------
35
36//----------------------------------------------------------------------
37// Internal includes with ""
38//----------------------------------------------------------------------
39#include "core/tRuntimeEnvironment.h"
40#include "core/internal/tLocalUriConnector.h"
41#include "core/port/tAbstractPort.h"
42
43//----------------------------------------------------------------------
44// Debugging
45//----------------------------------------------------------------------
46#include <cassert>
47
48//----------------------------------------------------------------------
49// Namespace usage
50//----------------------------------------------------------------------
51
52//----------------------------------------------------------------------
53// Namespace declaration
54//----------------------------------------------------------------------
55namespace finroc
56{
57namespace core
58{
59
60//----------------------------------------------------------------------
61// Forward declarations / typedefs / enums
62//----------------------------------------------------------------------
63
64//----------------------------------------------------------------------
65// Const values
66//----------------------------------------------------------------------
67const std::vector<std::unique_ptr<tUriConnector>> tUriConnector::tOwner::cEMPTY_CONNECTOR_LIST;
68
69//----------------------------------------------------------------------
70// Implementation
71//----------------------------------------------------------------------
72
73namespace internal
74{
75/*!
76 * \return List with available scheme handlers
77 */
78static tUriConnector::tSchemeHandlerRegister& SchemeHandlers()
79{
80  static tUriConnector::tSchemeHandlerRegister scheme_handlers;
81  return scheme_handlers;
82}
83}
84
85tUriConnector::tUriConnector(tOwner& owner, const tURI& uri, const tConnectOptions& connect_options, const tSchemeHandler& scheme_handler) :
86  flags(tConnectOptions::UnsetAutoFlags(connect_options.flags) | (connect_options.conversion_operations.Size() ? tFlags(tFlag::CONVERSION) : tFlags())),
87  owner(owner),
88  conversion_operations(connect_options.conversion_operations),
89  uri(uri),
90  scheme_handler(scheme_handler),
91  status(tStatus::DISCONNECTED)
92{
93  if (!owner.connectors)
94  {
95    owner.connectors.reset(new std::vector<std::unique_ptr<tUriConnector>>());
96  }
97
98  for (auto & connector_entry : (*owner.connectors))
99  {
100    if (!connector_entry)
101    {
102      connector_entry.reset(this);
103      return;
104    }
105  }
106  owner.connectors->emplace_back(this);
107}
108
109tUriConnector::~tUriConnector()
110{}
111
112bool tUriConnector::Create(core::tAbstractPort& owner_port, const tURI& uri, const tUriConnectOptions& connect_options)
113{
114  rrlib::uri::tURIElements uri_elements;
115  uri.Parse(uri_elements);
116  if (uri_elements.scheme.length() == 0)
117  {
118    return internal::tLocalUriConnector::Create(owner_port, uri_elements.path, connect_options, owner_port);
119  }
120
121  for (tSchemeHandler * handler : internal::SchemeHandlers())
122  {
123    if (uri_elements.scheme == handler->scheme_name)
124    {
125      return handler->Create(owner_port, uri, uri_elements, connect_options);
126    }
127  }
128  throw std::runtime_error("No scheme handler for scheme '" + uri_elements.scheme + "' registered.");
129}
130
131void tUriConnector::Publish()
132{
133  rrlib::thread::tLock lock(tRuntimeEnvironment::GetInstance().GetStructureMutex());
134  if (!flags.Get(tFlag::PUBLISHED))
135  {
136    flags.Set(tFlag::PUBLISHED);
137    auto& runtime = tRuntimeEnvironment::GetInstance();
138    for (auto it = runtime.runtime_listeners.Begin(); it != runtime.runtime_listeners.End(); ++it)
139    {
140      (*it)->OnUriConnectorChange(tRuntimeListener::tEvent::ADD, *this);
141    }
142  }
143}
144
145const tUriConnector::tSchemeHandlerRegister& tUriConnector::GetSchemeHandlerRegister()
146{
147  return internal::SchemeHandlers();
148}
149
150bool tUriConnector::SetParameter(size_t index, const rrlib::rtti::tTypedConstPointer& new_value)
151{
152  auto parameter_definitions = scheme_handler.GetParameterDefinitions();
153  if (static_cast<long int>(index) >= (parameter_definitions.End() - parameter_definitions.Begin()))
154  {
155    FINROC_LOG_PRINT(WARNING, "Index out of bounds");
156    return false;
157  }
158  const rrlib::rtti::tParameterDefinition* parameter_definition = parameter_definitions.Begin() + index;
159  if (parameter_definition->IsStatic())
160  {
161    FINROC_LOG_PRINT(WARNING, "Static parameter cannot be changed");
162    return false;
163  }
164  auto parameter_value = GetParameterValues().Begin() + index;
165  if (parameter_value->GetType() != new_value.GetType())
166  {
167    FINROC_LOG_PRINT(WARNING, "New parameter value has incompatible type");
168    return false;
169  }
170
171  bool equals = new_value.Equals(*parameter_value);
172  if (!equals)
173  {
174    rrlib::rtti::tTypedPointer writable_parameter(const_cast<void*>(parameter_value->GetRawDataPointer()), parameter_value->GetType());
175    writable_parameter.DeepCopyFrom(new_value);
176  }
177  return (!equals);
178}
179
180void tUriConnector::SetParametersInConstructor(const core::tUriConnectOptions& connect_options)
181{
182  auto parameter_definitions = scheme_handler.GetParameterDefinitions();
183  for (auto & parameter : connect_options.parameters)
184  {
185    bool found = false;
186    for (auto it = parameter_definitions.begin(); it != parameter_definitions.end(); ++it)
187    {
188      if (parameter.first == it->GetName())
189      {
190        try
191        {
192          rrlib::serialization::tStringInputStream stream(parameter.second);
193          auto parameter_value = GetParameterValues().Begin() + (it - parameter_definitions.begin());
194          rrlib::rtti::tTypedPointer writable_parameter(const_cast<void*>(parameter_value->GetRawDataPointer()), parameter_value->GetType());
195          writable_parameter.Deserialize(stream);
196        }
197        catch (const std::exception& e)
198        {
199          FINROC_LOG_PRINT(WARNING, "Failed setting parameter '", parameter.first, "' to '", parameter.second, "': ", e);
200        }
201        found = true;
202        break;
203      }
204    }
205    if (!found)
206    {
207      FINROC_LOG_PRINT(WARNING, "Unknown parameter ", parameter.first, ". Ignoring.");
208    }
209  }
210}
211
212void tUriConnector::SetStatus(tStatus new_status)
213{
214  rrlib::thread::tLock lock(tRuntimeEnvironment::GetInstance().GetStructureMutex());
215  if (new_status != status)
216  {
217    status = new_status;
218    assert(flags.Get(tFlag::PUBLISHED));
219    auto& runtime = tRuntimeEnvironment::GetInstance();
220    for (auto it = runtime.runtime_listeners.Begin(); it != runtime.runtime_listeners.End(); ++it)
221    {
222      (*it)->OnUriConnectorChange(tRuntimeListener::tEvent::CHANGE, *this);
223    }
224  }
225}
226
227tUriConnector::tOwner::~tOwner()
228{
229  ClearUriConnectors();
230}
231
232void tUriConnector::tOwner::ClearUriConnectors()
233{
234  if (connectors)
235  {
236    for (auto & connector : (*connectors))
237    {
238      connector->OnDisconnect();
239    }
240    connectors.reset();
241  }
242}
243
244
245void tUriConnector::tOwner::Disconnect(tUriConnector& connector)
246{
247  rrlib::thread::tLock lock(tRuntimeEnvironment::GetInstance().GetStructureMutex());
248  connector.OnDisconnect();
249
250  if (connectors)
251  {
252    for (auto & connector_entry : (*connectors))
253    {
254      if (connector_entry.get() == &connector)
255      {
256        connector_entry.reset();
257        return;
258      }
259    }
260  }
261
262  assert(connector.Flags().Get(tUriConnector::tFlag::PUBLISHED));
263  auto& runtime = tRuntimeEnvironment::GetInstance();
264  for (auto it = runtime.runtime_listeners.Begin(); it != runtime.runtime_listeners.End(); ++it)
265  {
266    (*it)->OnUriConnectorChange(tRuntimeListener::tEvent::REMOVE, connector);
267  }
268}
269
270tUriConnector::tSchemeHandler::tSchemeHandler(const char* scheme_name, const tConstParameterDefinitionRange& parameter_definitions) :
271  scheme_name(scheme_name),
272  parameter_definitions(parameter_definitions),
273  handle(static_cast<uint8_t>(internal::SchemeHandlers().Add(this)))
274{
275}
276
277//----------------------------------------------------------------------
278// End of namespace declaration
279//----------------------------------------------------------------------
280}
281}
Note: See TracBrowser for help on using the repository browser.