OSVR Framework (Internal Development Docs)  0.6-1962-g59773924
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
ProcessDeviceDescriptor.cpp
Go to the documentation of this file.
1 
11 // Copyright 2015 Sensics, Inc.
12 //
13 // Licensed under the Apache License, Version 2.0 (the "License");
14 // you may not use this file except in compliance with the License.
15 // You may obtain a copy of the License at
16 //
17 // http://www.apache.org/licenses/LICENSE-2.0
18 //
19 // Unless required by applicable law or agreed to in writing, software
20 // distributed under the License is distributed on an "AS IS" BASIS,
21 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22 // See the License for the specific language governing permissions and
23 // limitations under the License.
24 
25 #undef OSVR_DEV_VERBOSE_DISABLE
26 
27 // Internal Includes
29 #include <osvr/Common/PathTree.h>
30 #include <osvr/Common/PathNode.h>
33 #include <osvr/Util/Flag.h>
34 #include <osvr/Util/Verbosity.h>
38 
39 #include "PathParseAndRetrieve.h"
40 
41 // Library/third-party includes
42 #include <json/value.h>
43 #include <json/reader.h>
44 #include <boost/noncopyable.hpp>
45 #include <boost/variant/get.hpp>
46 #include <boost/algorithm/string/predicate.hpp>
47 #include <boost/algorithm/string/erase.hpp>
48 
49 // Standard includes
50 #include <utility>
51 #include <tuple>
52 
53 namespace osvr {
54 namespace common {
55  static const char INTERFACES_KEY[] = "interfaces";
56 
57  static inline util::Flag
58  processInterfacesFromDescriptor(PathNode &devNode,
59  Json::Value const &desc) {
60  util::Flag changed;
61  if (!desc.isMember(INTERFACES_KEY)) {
62  // No interfaces member
63  return changed;
64  }
65 
66  Json::Value const &ifaces = desc[INTERFACES_KEY];
67  if (!ifaces.isObject()) {
68  // Interfaces member isn't an object
69  return changed;
70  }
71  for (auto const &iface : ifaces.getMemberNames()) {
72 
73  auto &ifaceNode = treePathRetrieve(devNode, iface);
74  if (elements::isNull(ifaceNode.value())) {
75  ifaceNode.value() = elements::InterfaceElement();
76  changed.set();
77  }
78  }
79  return changed;
80  }
81 
82  static const char TARGET_KEY[] = "$target";
83  static const char SEMANTIC_KEY[] = "semantic";
84  static const char AUTOMATIC_KEY[] = "automaticAliases";
85  namespace {
86  class SemanticRecursion : boost::noncopyable {
87  public:
88  SemanticRecursion(PathNode &devNode) : m_devNode(devNode) {}
89 
90  util::Flag operator()(Json::Value const &semanticObject) {
91  m_recurse(semanticObject, SEMANTIC_KEY);
92  return m_flag;
93  }
94 
95  private:
96  bool m_add(Json::Value const &currentLevel,
97  std::string const &relativeSemanticPath) {
99  m_devNode, currentLevel.toStyledString(),
100  relativeSemanticPath, ALIASPRIORITY_SEMANTICROUTE);
101  }
102  void m_recurse(Json::Value const &currentLevel,
103  std::string const &relativeSemanticPath) {
104  if (currentLevel.isString()) {
105  m_flag += m_add(currentLevel, relativeSemanticPath);
106  return;
107  }
108  if (currentLevel.isObject()) {
109  Json::Value target = currentLevel[TARGET_KEY];
110  if (!target.isNull()) {
111  m_flag += m_add(target, relativeSemanticPath);
112  }
113 
114  for (auto const &memberName :
115  currentLevel.getMemberNames()) {
116  if (TARGET_KEY == memberName) {
117  continue;
118  }
119  m_recurse(currentLevel[memberName],
120  relativeSemanticPath + getPathSeparator() +
121  memberName);
122  }
123  }
124  }
125  PathNode &m_devNode;
126  util::Flag m_flag;
127  };
128 
129  } // namespace
130 
131  static inline util::Flag
132  processSemanticFromDescriptor(PathNode &devNode, Json::Value const &desc) {
133  util::Flag changed;
134  Json::Value const &sem = desc[SEMANTIC_KEY];
135  if (!sem.isObject()) {
136  // Semantic member isn't an object or isn't a member
137  return changed;
138  }
139  SemanticRecursion f{devNode};
140  changed += f(sem);
141  return changed;
142  }
143  static inline bool processAutomaticFromDescriptor(PathNode &devNode,
144  Json::Value const &desc) {
145  Json::Value const &automatic = desc[AUTOMATIC_KEY];
146  return AliasProcessor{}
147  .setDefaultPriority(ALIASPRIORITY_AUTOMATIC)
148  .enableRelativePath()
149  .enableRelativeSource()
150  .enableWildcard()
151  .process(devNode, automatic);
152  }
153 
156  static inline std::pair<std::string, std::string>
157  getDevHost(std::string const &deviceName, std::string const &host) {
158 
159  auto atLocation = deviceName.find('@');
160  if (std::string::npos == atLocation) {
161  // No at-symbol - we append our hostname.
162  return std::make_pair(deviceName, host);
163  }
164 
165  // Split host from device
166  std::string devName(deviceName);
167  devName.resize(atLocation);
168  return std::make_pair(devName, devName.substr(atLocation + 1));
169  }
170 
172  std::string const &deviceName,
173  std::string const &jsonDescriptor,
174  int listenPort,
175  std::string const &host) {
176  std::string devName{deviceName};
177  if (getPathSeparatorCharacter() == devName.at(0)) {
178  // Leading slash, which we'll need to drop from the device name
179  devName.erase(begin(devName));
180  }
181  util::Flag changed;
182 
184  auto &devNode = tree.getNodeByPath(getPathSeparator() + devName);
185  auto devElt = boost::get<elements::DeviceElement>(&devNode.value());
186  if (nullptr == devElt) {
187  std::string dev;
188  std::string devHost;
189 
190  // Split host from device, or use the default host and port.
191  std::tie(dev, devHost) = getDevHost(devName, host);
192  devNode.value() =
193  elements::DeviceElement::createDeviceElement(dev, devHost, listenPort);
194  devElt = boost::get<elements::DeviceElement>(&devNode.value());
195  changed.set();
196  }
197 
199  const std::string normalizedDescriptor =
200  normalizeDeviceDescriptor(jsonDescriptor);
201 
203  Json::Value descriptor;
204  {
205  Json::Reader reader;
206  if (!reader.parse(normalizedDescriptor, descriptor)) {
208  return changed.get();
209  }
210  }
211  if (descriptor == devElt->getDescriptor() && !changed) {
213  return changed.get();
214  }
215  devElt->getDescriptor() = descriptor;
216 
217  changed += processDeviceDescriptorFromExistingDevice(devNode, *devElt);
218 
219  return changed.get();
220  }
221 
223  PathNode &devNode, elements::DeviceElement const &devElt) {
224  util::Flag changed;
225 
226  changed +=
227  processInterfacesFromDescriptor(devNode, devElt.getDescriptor());
228 
229  changed +=
230  processSemanticFromDescriptor(devNode, devElt.getDescriptor());
231 
232  changed +=
233  processAutomaticFromDescriptor(devNode, devElt.getDescriptor());
234 
235  return changed.get();
236  }
237 
238 } // namespace common
239 } // namespace osvr
A tree representation, with path/url syntax, of the known OSVR system.
Definition: PathTree.h:43
std::string normalizeDeviceDescriptor(std::string const &jsonDescriptor)
"Normalizes" a device descriptor by parsing it and adding implied interfaces to the existing device d...
::osvr::util::TreeNode< PathElement > PathNode
The specific tree node type that contains a path element.
Definition: PathNode_fwd.h:42
util::TreeNode< ValueType > & treePathRetrieve(util::TreeNode< ValueType > &node, std::string path, bool permitParent=false)
Internal method for parsing a path and getting or creating the nodes along it.
static DeviceElement createDeviceElement(std::string const &deviceName, std::string const &server, int port=util::UseDefaultPort)
The element type corresponding to a device, which implements 0 or more interfaces.
bool get() const
Get the value of the flag as a bool.
Definition: Flag.h:52
PathNode & getNodeByPath(std::string const &path)
Returns the node indicated by the path, which must be absolute (begin with a /). Any non-existent nod...
Definition: PathTree.cpp:47
bool isNull(PathElement const &elt)
Returns true if the path element provided is a NullElement.
bool processDeviceDescriptorForPathTree(PathTree &tree, std::string const &deviceName, std::string const &jsonDescriptor, int listenPort, std::string const &host)
Set up a path tree based on a device descriptor.
Header.
Header.
The element type corresponding to an interface, which often may have one or more sensors.
Internal, configured header file for verbosity macros.
const char * getPathSeparator()
Gets the path separator - a slash - as a null-terminated string.
bool addAliasFromSourceAndRelativeDest(PathNode &node, std::string const &source, std::string const &dest, AliasPriority priority=ALIASPRIORITY_MANUAL)
Definition: PathTree.cpp:135
void set()
Set the flag to true.
Definition: Flag.h:55
Header.
A class that lightly wraps a bool, in order to provide easier maintenance of a "dirty" flag...
Definition: Flag.h:43
bool processDeviceDescriptorFromExistingDevice(PathNode &devNode, elements::DeviceElement const &devElt)
Set up a path tree based on a device descriptor from an existing DeviceElement node.