OSVR Framework (Internal Development Docs)  0.6-1962-g59773924
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
AliasProcessor.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 // Internal Includes
27 #include <osvr/Common/PathTree.h>
28 #include <osvr/Common/PathNode.h>
30 #include <osvr/Util/Flag.h>
32 #include <osvr/Util/Verbosity.h>
33 #include <osvr/Common/ParseAlias.h>
35 
36 #include "PathParseAndRetrieve.h"
37 
38 // Library/third-party includes
39 #include <boost/noncopyable.hpp>
40 #include <boost/algorithm/string/predicate.hpp>
41 #include <boost/algorithm/string/erase.hpp>
42 
43 // Standard includes
44 // - none
45 
46 namespace osvr {
47 namespace common {
48  namespace {
49  static const char PRIORITY_KEY[] = "$priority";
50  static const char WILDCARD_SUFFIX[] = "/*";
51  static const size_t WILDCARD_SUFFIX_LEN = sizeof(WILDCARD_SUFFIX) - 1;
52 
56  template <typename T>
57  inline void applyWildcard(PathNode &node,
58  std::string const &pathWithWildcard,
59  T functor) {
60  auto startingPath = pathWithWildcard;
61  boost::algorithm::erase_tail(startingPath, WILDCARD_SUFFIX_LEN);
62  auto &startingNode = treePathRetrieve(node, startingPath);
63  auto absoluteStartingPath = getFullPath(startingNode);
64  auto absoluteStartingPathLen = absoluteStartingPath.length();
65  util::traverseWith(startingNode, [&](PathNode &node) {
66  // Don't visit null nodes
67  if (elements::isNull(node.value())) {
68  return;
69  }
70  auto visitPath = getFullPath(node);
73  auto relPath = visitPath;
74  boost::algorithm::erase_head(relPath,
75  absoluteStartingPathLen + 1);
76  functor(node, relPath);
77  });
78  }
79 
81  inline bool doesPathContainWildcard(std::string const &path) {
82  return boost::algorithm::ends_with(path, WILDCARD_SUFFIX);
83  }
84 
86  class AutomaticAliases : boost::noncopyable {
87  public:
88  AutomaticAliases(PathNode &devNode,
89  detail::AliasProcessorOptions opts)
90  : m_devNode(devNode), m_opts(opts) {}
91 
96  util::Flag operator()(Json::Value const &val) {
97  if (val.isArray()) {
98  m_processArray(val);
99  } else if (val.isObject()) {
100  m_processObject(val);
101  }
102  return m_flag;
103  }
104 
105  private:
108  void m_processArray(Json::Value const &arr) {
109  for (auto const &elt : arr) {
110  if (elt.isObject()) {
111  m_processObject(elt);
112  }
113  }
114  }
115 
120  void m_processObject(Json::Value const &obj) {
121  AliasPriority priority{m_opts.defaultPriority};
122  if (obj.isMember(PRIORITY_KEY)) {
123  priority =
124  static_cast<AliasPriority>(obj[PRIORITY_KEY].asInt());
125  }
126  for (auto const &key : obj.getMemberNames()) {
127  if (PRIORITY_KEY == key) {
128  continue;
129  }
130  m_processEntry(key, obj[key], priority);
131  }
132  }
133 
137  void m_processEntry(std::string const &path,
138  Json::Value const &source,
139  AliasPriority priority) {
140  if (!m_opts.permitRelativePath && !isPathAbsolute(path)) {
141  OSVR_DEV_VERBOSE(
142  "Got a non-permitted relative path: " << path);
143  return;
144  }
145  ParsedAlias parsedSource(source);
146  auto leaf = parsedSource.getLeaf();
147  if (!m_opts.permitRelativeSource && !isPathAbsolute(leaf)) {
148  OSVR_DEV_VERBOSE(
149  "Got a non-permitted relative source leaf: " << leaf);
150  return;
151  }
152  if (!doesPathContainWildcard(leaf)) {
154  m_processSingleEntry(path, parsedSource.getAlias(),
155  priority);
156  return;
157  }
158 
160  if (!m_opts.permitWildcard) {
161  OSVR_DEV_VERBOSE(
162  "Got a non-permitted wildcard in the source leaf of: "
163  << parsedSource.getAlias());
164  }
165 
166  if (parsedSource.isSimple()) {
167  applyWildcard(
168  m_devNode, leaf,
169  [&](PathNode &node, std::string const &relPath) {
170  m_processSingleEntry(path + getPathSeparator() +
171  relPath,
172  getFullPath(node), priority);
173  });
174  return;
175  }
176 
177  applyWildcard(m_devNode, leaf, [&](PathNode &node,
178  std::string const &relPath) {
179  parsedSource.setLeaf(getFullPath(node));
180  m_processSingleEntry(path + getPathSeparator() + relPath,
181  parsedSource.getAlias(), priority);
182  });
183  }
184 
187  void m_processSingleEntry(std::string const &path,
188  std::string const &source,
189  AliasPriority priority) {
190  m_flag += addAliasFromSourceAndRelativeDest(m_devNode, source,
191  path, priority);
192  }
193 
194  PathNode &m_devNode;
195  detail::AliasProcessorOptions m_opts;
196  util::Flag m_flag;
197  };
198 
199  } // namespace
200 
201  bool AliasProcessor::process(PathNode &node, Json::Value const &val) {
202  AutomaticAliases processor{node, m_opts};
203  return processor(val).get();
204  }
205 
206  Json::Value createJSONAlias(std::string const &path,
207  Json::Value const &destination) {
208  Json::Value ret{Json::nullValue};
209  if (path.empty()) {
210  return ret;
211  }
212  if (destination.isNull()) {
213  return ret;
214  }
215  ret = Json::objectValue;
216  ret[path] = destination;
217  return ret;
218  }
219 
220  Json::Value convertRouteToAlias(Json::Value const &val) {
221  Json::Value ret{val};
222  if (!val.isObject()) {
223  // Can't be a route if it's not an object.
224  return ret;
225  }
226  if (val.isMember(routing_keys::destination()) &&
227  val.isMember(routing_keys::source())) {
228  // By golly this is an old-fashioned route.
229  ret = createJSONAlias(val[routing_keys::destination()].asString(),
230  val[routing_keys::source()]);
231  }
232  return ret;
233  }
234 
235  Json::Value applyPriorityToAlias(Json::Value const &alias,
236  AliasPriority priority) {
237  Json::Value ret{alias};
238  if (ret.isObject()) {
239  ret[PRIORITY_KEY] = priority;
240  }
241  return ret;
242  }
243 } // namespace common
244 } // namespace osvr
Header.
::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.
std::string getFullPath(PathNode const &node)
Gets the absolute path for the given node.
Definition: PathNode.cpp:42
Json::Value convertRouteToAlias(Json::Value const &val)
Given a single JSON object, if it's an old-fashioned "routing directive", convert it to a normal "ali...
void traverseWith(T &node, F &&functor)
A method to handle visiting every node in a tree with a lambda or other by-value function object...
bool isNull(PathElement const &elt)
Returns true if the path element provided is a NullElement.
Json::Value applyPriorityToAlias(Json::Value const &alias, AliasPriority priority)
Given a JSON object describing one or more aliases, set the priority of the alias(es).
Header.
Header.
Internal, configured header file for verbosity macros.
const char * getPathSeparator()
Gets the path separator - a slash - as a null-terminated string.
Json::Value createJSONAlias(std::string const &path, Json::Value const &destination)
Given a path and a destination, combine them into a JSON alias description.
bool addAliasFromSourceAndRelativeDest(PathNode &node, std::string const &source, std::string const &dest, AliasPriority priority=ALIASPRIORITY_MANUAL)
Definition: PathTree.cpp:135
Header.