150
g_dbus_method_invocation_return_dbus_error(invocation, unity::DBUS_BUS_NAME,
154
g_dbus_method_invocation_return_dbus_error(invocation,
155
unity::DBUS_BUS_NAME.c_str(),
151
156
"Failed to find method");
156
GetState(const gchar* pieceName)
161
GVariant* GetState(std::string const& query)
158
std::queue<Introspectable*> queue;
159
queue.push(_parent_introspectable);
161
// Since the empty string won't really match the name of the parent (Unity),
162
// we make sure that we're able to accept a blank string and just define it to
163
// mean the top level.
164
Introspectable* piece = g_strcmp0(pieceName, "") == 0
165
? _parent_introspectable
166
: FindPieceToIntrospect(queue, pieceName);
168
// FIXME this might not work, make sure it does.
172
return piece->Introspect(true);
163
// process the XPath query:
164
std::list<Introspectable*> parts = GetIntrospectableNodesFromQuery(query, _parent_introspectable);
165
GVariantBuilder builder;
166
g_variant_builder_init(&builder, G_VARIANT_TYPE("aa{sv}"));
168
for (Introspectable *node : parts)
170
g_variant_builder_add_value(&builder, node->Introspect());
173
return g_variant_new("(aa{sv})", &builder);
176
* Do a breadth-first search of the introspectable tree.
177
* Do a breadth-first search of the introspection tree and find all nodes that match the
179
FindPieceToIntrospect(std::queue<Introspectable*> queue, const gchar* pieceName)
180
std::list<Introspectable*> GetIntrospectableNodesFromQuery(std::string const& query, Introspectable* tree_root)
181
Introspectable* piece;
183
while (!queue.empty())
185
piece = queue.front();
188
if (g_strcmp0 (piece->GetName(), pieceName) == 0)
193
for (auto it = piece->GetIntrospectableChildren().begin(), last = piece->GetIntrospectableChildren().end(); it != last; it++)
182
std::list<Introspectable*> start_points;
183
std::string sanitised_query;
184
// Allow user to be lazy when specifying root node.
185
if (query == "" || query == "/")
187
sanitised_query = "/" + tree_root->GetName();
191
sanitised_query = query;
193
// split query into parts
194
std::list<XPathQueryPart> query_parts;
197
std::list<std::string> query_strings;
198
boost::algorithm::split(query_strings, sanitised_query, boost::algorithm::is_any_of("/"));
199
// Boost's split() implementation does not match it's documentation! According to the
200
// docs, it's not supposed to add empty strings, but it does, which is a PITA. This
201
// next line removes them:
202
query_strings.erase( std::remove_if( query_strings.begin(),
204
boost::bind( &std::string::empty, _1 ) ),
205
query_strings.end());
206
foreach(std::string part, query_strings)
208
query_parts.push_back(XPathQueryPart(part));
212
// absolute or relative query string?
213
if (sanitised_query.at(0) == '/' && sanitised_query.at(1) != '/')
215
// absolute query - start point is tree root node.
216
if (query_parts.front().Matches(tree_root))
218
start_points.push_back(tree_root);
223
// relative - need to do a depth first tree search for all nodes that match the
224
// first node in the query.
226
// warn about malformed queries (all queries must start with '/')
227
if (sanitised_query.at(0) != '/')
229
LOG_WARNING(logger) << "Malformed relative introspection query: '" << query << "'.";
232
// non-recursive BFS traversal to find starting points:
233
std::queue<Introspectable*> queue;
234
queue.push(tree_root);
235
while (!queue.empty())
237
Introspectable *node = queue.front();
239
if (query_parts.front().Matches(node))
241
// found one. We keep going deeper, as there may be another node beneath this one
242
// with the same node name.
243
start_points.push_back(node);
245
// Add all children of current node to queue.
246
foreach(Introspectable* child, node->GetIntrospectableChildren())
253
// now we have the tree start points, process them:
254
query_parts.pop_front();
255
typedef std::pair<Introspectable*, std::list<XPathQueryPart>::iterator> node_match_pair;
257
std::queue<node_match_pair> traverse_queue;
258
foreach(Introspectable *node, start_points)
260
traverse_queue.push(node_match_pair(node, query_parts.begin()));
262
start_points.clear();
264
while (!traverse_queue.empty())
266
node_match_pair p = traverse_queue.front();
267
traverse_queue.pop();
269
Introspectable *node = p.first;
270
auto query_it = p.second;
272
if (query_it == query_parts.end())
275
start_points.push_back(node);
279
// push all children of current node to start of queue, advance search iterator, and loop again.
280
foreach (Introspectable *child, node->GetIntrospectableChildren())
282
if (query_it->Matches(child))
284
auto it_copy(query_it);
286
traverse_queue.push(node_match_pair(child, it_copy));