unity.scopes.utility.BufferedResultForwarder

Base class for a client to receive and buffer the results of a query until another BufferedResultForwarder becomes ready. More...

Inheritance diagram for unity::scopes::utility::BufferedResultForwarder: src="https://assets.ubuntu.com/v1/dbf869d1-classunity_1_1scopes_1_1utility_1_1_buffered_result_forwarder__inherit__graph.png" border="0" alt="Inheritance graph"/>

Public Member Functions

 BufferedResultForwarder (unity::scopes::SearchReplyProxy const &upstream, BufferedResultForwarder::SPtr const &next_forwarder=BufferedResultForwarder::SPtr())
 Create a forwarder that sends (at least one) result to its upstream reply proxy before indicating that it is ready to its follower. More...
 
void push (CategorisedResult result) override
 Forwards a single result before calling set_ready(). More...
 
bool is_ready () const
 Check if this forwarder is ready. More...
 
src="https://assets.ubuntu.com/v1/c6607712-closed.png" alt="-"/> Public Member Functions inherited from unity::scopes::SearchListenerBase
virtual void push (Department::SCPtr const &parent)
 Called at most once by the scopes runtime for a tree of departments returned by a query. More...
 
virtual void push (experimental::Annotation annotation)
 Called once by the scopes runtime for each annotation that is returned by a query(). More...
 
virtual void push (Category::SCPtr const &category)
 Called once by the scopes runtime for each category that is returned by a query(). More...
 
virtual void push (Filters const &filters, FilterState const &filter_state)
 Called once by the scopes to send all the filters and their state. More...
 
src="https://assets.ubuntu.com/v1/c6607712-closed.png" alt="-"/> Public Member Functions inherited from unity::scopes::ListenerBase
virtual void info (OperationInfo const &op_info)
 Called by the scopes runtime each time a scope reports additional information about the reply to a query. More...
 

Protected Member Functions

void set_ready ()
 Mark this forwarder as ready. More...
 
unity::scopes::SearchReplyProxy upstream () const
 Get the upstream proxy. More...
 
void finished (CompletionDetails const &details) override
 Called once by the scopes runtime after the final result for a request was sent. More...
 

Detailed Description

Base class for a client to receive and buffer the results of a query until another BufferedResultForwarder becomes ready.

This class implements result buffering, useful for aggregator scopes that receive results from multiple child scopes and need to display categories in a specific order. The aggregator scope must create an instance of BufferedResultForwarder for every child scope it queries and chain the instances together in the desired order.

The default implementation of BufferedResultForwarder forwards the results it receives upstream and declares itself "ready" after receiving the first result. The results are then buffered until all prior forwarders have declared themselves ready. Buffering is very efficient—results are buffered only until proper order is guaranteed, and buffering is disabled for forwarders that do not need to wait for a predecessor to become ready. This means that results are pushed to the client (displayed) as early as possible.

The default implementation only pushes results and their categories, but ignores departments, filters, and annotations. If you wish to handle and forward these, you must to derive your own forwarder from BufferedResultForwarder and override the appropropriate methods of the SearchListenerBase class.

The default implementation buffers a single result before indicating to its follower that it is ready. This means that the first category from each child determines overall order. For example, if each child produces results for a single category, the chaining insures the correct order (results from child A followed by results from child B, or vice versa). However, if child A produces results for categories A1 and A2, and child B produces results for categories B1 and B2, the overall order could, for example, be A1, B1, A2, B2, or it could be A1, A2, B1, B2, or it could be A1, B2, B1, A2 (among others).

If you want to ensure that all categories from child A arrive in a particular order, followed by all categories from child B in a particular order, you must override push() to, for example, collapse categories received from a child into a single category, or otherwise buffer results yourself until you have established the order you need.

Note that buffering fundamentally conflicts with the need to render results as soon as possible. You should avoid buffering more data than absolutely necessary in order for the display to start updating as soon as possible after a query was sent.

If you create a custom implementation of a forwarder, you must push results via the proxy returned by BufferedResultForwarder::upstream(). (This is a different proxy than the one that is passed to the constructor.) Your forwarder then must declare itself ready by calling BufferedResultForwarder::set_ready() as soon as it knows it will not push results for any new categories. In the case where your aggregator aggregates all results from given child scope into a single category, you can call set_ready() as soon as you have pushed the first result.

Here is a code example that shows how to write a result forwarder that creates a separate category for results from each of three children and controls the order in which these categories are rendered.

<span class="keyword">class </span>SearchReceiver : <span class="keyword">public</span> <a class="code" href="#acd998587334a306b04e3e3a5e548ff93">BufferedResultForwarder</a>
{
<span class="keyword">public</span>:
SearchReceiver(unity::scopes::Category::SCPtr target_cat, <a class="code" href="unity.scopes.md#a9cd604d9b842ac3b2b8636c2165dec1f">unity::scopes::SearchReplyProxy</a> <span class="keyword">const</span>&amp; <a class="code" href="#a55fd083a188f5dd2a940b1f280409347">upstream</a>, BufferedResultForwarder::SPtr <span class="keyword">const</span>&amp;
next_forwarder = BufferedResultForwarder::SPtr())
: <a class="code" href="#acd998587334a306b04e3e3a5e548ff93">BufferedResultForwarder</a>(upstream, next_forwarder),
category_(target_cat)
{
}
<span class="keywordtype">void</span> <a class="code" href="#af712d8a72e6cd0818ab9d2c3274b25e6">push</a>(CategorisedResult result)<span class="keyword"> override</span>
<span class="keyword">    </span>{
result.set_category(category_); <span class="comment">// put all incoming results in single category</span>
<a class="code" href="#a55fd083a188f5dd2a940b1f280409347">upstream</a>()-&gt;push(result); <span class="comment">// push modified result to the client</span>
<span class="comment">// we push into a single target category, so we&#39;re ready as soon as we received and pushed first result</span>
<a class="code" href="#a20816aac742adffdc16b8e8405c61c87">set_ready</a>();
}
<span class="keyword">private</span>:
unity::scopes::Category::SCPtr category_;
};
<span class="keywordtype">void</span> AggregatorSearchQueryBase::run(<a class="code" href="unity.scopes.md#a9cd604d9b842ac3b2b8636c2165dec1f">SearchReplyProxy</a> <span class="keyword">const</span>&amp; upstream_reply)
{
<span class="keyword">auto</span> cat1 = upstream_reply-&gt;register_category(<span class="stringliteral">&quot;cat1&quot;</span>, <span class="stringliteral">&quot;Results from scope 1&quot;</span>, <span class="stringliteral">&quot;&quot;</span>, CategoryRenderer());
<span class="keyword">auto</span> cat2 = upstream_reply-&gt;register_category(<span class="stringliteral">&quot;cat2&quot;</span>, <span class="stringliteral">&quot;Results from scope 2&quot;</span>, <span class="stringliteral">&quot;&quot;</span>, CategoryRenderer());
<span class="keyword">auto</span> cat3 = upstream_reply-&gt;register_category(<span class="stringliteral">&quot;cat3&quot;</span>, <span class="stringliteral">&quot;Results from scope 3&quot;</span>, <span class="stringliteral">&quot;&quot;</span>, CategoryRenderer());
<span class="comment">// note: the order of construction is reversed</span>
<span class="keyword">auto</span> scope3fwd = std::make_shared&lt;SearchReceiver&gt;(cat3, upstream_reply);
<span class="keyword">auto</span> scope2fwd = std::make_shared&lt;SearchReceiver&gt;(cat2, upstream_reply, scope3fwd);
<span class="keyword">auto</span> scope1fwd = std::make_shared&lt;SearchReceiver&gt;(cat1, upstream_reply, scope2fwd);
<span class="comment">// invoke search for child scopes; make sure you do this only after all forwarders are created</span>
subsearch(scope1proxy, <span class="stringliteral">&quot;&quot;</span>, scope1fwd);
subsearch(scope2proxy, <span class="stringliteral">&quot;&quot;</span>, scope2fwd);
subsearch(scope3proxy, <span class="stringliteral">&quot;&quot;</span>, scope3fwd);
}
See also
SearchListenerBase.

Constructor & Destructor Documentation

unity::scopes::utility::BufferedResultForwarder::BufferedResultForwarder ( unity::scopes::SearchReplyProxy const &  upstream,
BufferedResultForwarder::SPtr const &  next_forwarder = BufferedResultForwarder::SPtr() 
)

Create a forwarder that sends (at least one) result to its upstream reply proxy before indicating that it is ready to its follower.

Parameters
upstreamThe reply proxy for the upstream receiver.
next_forwarderThe forwarder that becomes ready once this forwarder calls set_ready().
Exceptions
unity::LogicExceptionwhen passed next_forwarder that has already been linked to another BufferedResultForwarder.

Member Function Documentation

void unity::scopes::utility::BufferedResultForwarder::finished ( CompletionDetails const &  details)
overrideprotectedvirtual

Called once by the scopes runtime after the final result for a request was sent.

Calls to finished() are made by an arbitrary thread.

Exceptions thrown from finished() are ignored.

Parameters
detailsContains details about the completion status of a query as well as any additional information regarding the operation of the request.

Implements unity::scopes::ListenerBase.

bool unity::scopes::utility::BufferedResultForwarder::is_ready ( ) const

Check if this forwarder is ready.

Once ready, the forwarder no longer buffers any results and passes them to the upstream proxy immediately.

Returns
true if this forwarder called set_ready(), false otherwise.
void unity::scopes::utility::BufferedResultForwarder::push ( CategorisedResult  result)
overridevirtual

Forwards a single result before calling set_ready().

This default implementation forwards incoming results unchanged to the upstream reply proxy and marks the forwarder ready after forwarding the first result.

This method is called once by the scopes run time for each result that is returned by a query().

Parameters
resultThe received result.

Implements unity::scopes::SearchListenerBase.

void unity::scopes::utility::BufferedResultForwarder::set_ready ( )
protected

Mark this forwarder as ready.

If you create a custom forwarder, you should call this method as soon as your forwarder will no longer push results for new categories.

unity::scopes::SearchReplyProxy unity::scopes::utility::BufferedResultForwarder::upstream ( ) const
protected

Get the upstream proxy.

Returns an instance of buffered reply proxy for all push, register_departments, and register_category operations. Note that this proxy is not the same proxy as the one passed to the constructor.

Returns
The buffered reply proxy.