<div dir="ltr">For AEROGEAR-863 &quot;<span style="font-family:Arial,FreeSans,Helvetica,sans-serif">Make PagingStrategy pluggable&quot; the following suggestion is being proposed:</span><div><span style="font-family:Arial,FreeSans,Helvetica,sans-serif"><br>
</span></div><div><div><h2 style="margin:0px 0px 10px;padding:0px;font-size:24px;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(204,204,204);color:rgb(0,0,0);font-family:Helvetica,arial,freesans,clean,sans-serif">
Custom PaginationStrategy</h2><p style="margin:0px 0px 15px;color:rgb(0,0,0);font-family:Helvetica,arial,freesans,clean,sans-serif;font-size:14px;line-height:22px">This section describes how a custom pagination strategy can be implemented in AeroGear Controller.<br>
Depending on if you need a completely different strategy, or if you simply want to change/add/rename the returned HTTP response headers, you have two options:</p><ul style="margin:15px 0px;padding:0px 0px 0px 30px;color:rgb(0,0,0);font-family:Helvetica,arial,freesans,clean,sans-serif;font-size:14px;line-height:22px">
<li>Extend AbstractPaginationStrategy<br style="margin-top:0px"></li><li>Implement PaginationStrategy<br style="margin-top:0px"></li></ul><h3 style="margin:20px 0px 10px;padding:0px;font-size:18px;color:rgb(0,0,0);font-family:Helvetica,arial,freesans,clean,sans-serif">
<a name="extend-abstractpaginationstrategy" class="" href="https://gist.github.com/danbev/ed51e57e9a1f718f1848#extend-abstractpaginationstrategy" style="color:rgb(65,131,196);text-decoration:initial;display:block;padding-left:30px"></a>Extend AbstractPaginationStrategy</h3>
<p style="margin:0px 0px 15px;color:rgb(0,0,0);font-family:Helvetica,arial,freesans,clean,sans-serif;font-size:14px;line-height:22px">You would extend AbstractPaginationStrategy if you simply want to change/add/rename the returned HTTP response headers.</p>
<h4 style="margin:20px 0px 10px;padding:0px;font-size:16px;color:rgb(0,0,0);font-family:Helvetica,arial,freesans,clean,sans-serif"><a name="example-of-extending-abstractpaginationstrategy" class="" href="https://gist.github.com/danbev/ed51e57e9a1f718f1848#example-of-extending-abstractpaginationstrategy" style="color:rgb(65,131,196);text-decoration:initial;display:block;padding-left:30px"></a>Example of extending AbstractPaginationStrategy:</h4>
<div class="" style="border:0px;padding:0px;color:rgb(0,0,0);font-family:Helvetica,arial,freesans,clean,sans-serif;font-size:14px;line-height:22px"><pre style="font-size:13px;line-height:19px;font-family:Consolas,&#39;Liberation Mono&#39;,Courier,monospace;word-wrap:break-word;margin-top:15px;margin-bottom:15px;background-color:rgb(248,248,248);border:1px solid rgb(204,204,204);overflow:auto;padding:6px 10px;border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">
<span class="" style="font-weight:bold">public</span> <span class="" style="font-weight:bold">class</span> <span class="" style="color:rgb(68,85,136);font-weight:bold">MyStrategy</span> <span class="" style="font-weight:bold">extends</span> <span class="" style="color:rgb(51,51,51)">AbstractPaginationStrategy</span> <span class="" style="font-weight:bold">{</span>

    <span class="">@Override</span>
    <span class="" style="font-weight:bold">public</span> <span class="" style="color:rgb(68,85,136);font-weight:bold">void</span> <span class="" style="color:rgb(153,0,0);font-weight:bold">setResponseHeaders</span><span class="" style="font-weight:bold">(</span><span class="" style="color:rgb(51,51,51)">PaginationMetadata</span> <span class="" style="color:rgb(51,51,51)">md</span><span class="" style="font-weight:bold">,</span> 
        <span class="" style="color:rgb(51,51,51)">HttpServletResponse</span> <span class="" style="color:rgb(51,51,51)">response</span><span class="" style="font-weight:bold">,</span> 
        <span class="" style="color:rgb(68,85,136);font-weight:bold">int</span> <span class="" style="color:rgb(51,51,51)">resultSize</span><span class="" style="font-weight:bold">)</span> <span class="" style="font-weight:bold">{</span>
        <span class="" style="font-weight:bold">for</span> <span class="" style="font-weight:bold">(</span><span class="" style="color:rgb(51,51,51)">Entry</span><span class="" style="font-weight:bold">&lt;</span><span class="" style="color:rgb(51,51,51)">String</span><span class="" style="font-weight:bold">,</span> <span class="" style="color:rgb(51,51,51)">String</span><span class="" style="font-weight:bold">&gt;</span> <span class="" style="color:rgb(51,51,51)">entry</span> <span class="" style="font-weight:bold">:</span> <span class="" style="color:rgb(51,51,51)">md</span><span class="" style="font-weight:bold">.</span><span class="" style="color:teal">getHeaders</span><span class="" style="font-weight:bold">(</span><span class="" style="color:rgb(51,51,51)">resultSize</span><span class="" style="font-weight:bold">).</span><span class="" style="color:teal">entrySet</span><span class="" style="font-weight:bold">())</span> <span class="" style="font-weight:bold">{</span>
            <span class="" style="color:rgb(51,51,51)">response</span><span class="" style="font-weight:bold">.</span><span class="" style="color:teal">setHeader</span><span class="" style="font-weight:bold">(</span><span class="" style="color:rgb(51,51,51)">entry</span><span class="" style="font-weight:bold">.</span><span class="" style="color:teal">getKey</span><span class="" style="font-weight:bold">(),</span> <span class="" style="color:rgb(51,51,51)">entry</span><span class="" style="font-weight:bold">.</span><span class="" style="color:teal">getValue</span><span class="" style="font-weight:bold">());</span>
        <span class="" style="font-weight:bold">}</span>
    <span class="" style="font-weight:bold">}</span>

<span class="" style="font-weight:bold">}</span>
</pre></div><p style="margin:15px 0px;color:rgb(0,0,0);font-family:Helvetica,arial,freesans,clean,sans-serif;font-size:14px;line-height:22px">This implementation actually does exactly what the default implementation does. But you can of course modify this to suite your own requirements. You have access to all the <a href="http://aerogear.org/docs/specs/aerogear-controller/org/jboss/aerogear/controller/router/rest/pagination/PagingMetadata.html" style="color:rgb(65,131,196);text-decoration:initial">metadata</a> for the pagination, like the raw <a href="http://aerogear.org/docs/specs/aerogear-controller/org/jboss/aerogear/controller/router/rest/pagination/Links.html" style="color:rgb(65,131,196);text-decoration:initial">links</a> etc, so you could assemble headers in any way you see fit.</p>
<h3 style="margin:20px 0px 10px;padding:0px;font-size:18px;color:rgb(0,0,0);font-family:Helvetica,arial,freesans,clean,sans-serif"><a name="implement-paginationstrategy" class="" href="https://gist.github.com/danbev/ed51e57e9a1f718f1848#implement-paginationstrategy" style="color:rgb(65,131,196);text-decoration:initial;display:block;padding-left:30px"></a>Implement PaginationStrategy</h3>
<p style="margin:0px 0px 15px;color:rgb(0,0,0);font-family:Helvetica,arial,freesans,clean,sans-serif;font-size:14px;line-height:22px">This will give you more control over the pagination strategy. The interface you have to implement looks like this:</p>
<div class="" style="border:0px;padding:0px;color:rgb(0,0,0);font-family:Helvetica,arial,freesans,clean,sans-serif;font-size:14px;line-height:22px"><pre style="font-size:13px;line-height:19px;font-family:Consolas,&#39;Liberation Mono&#39;,Courier,monospace;word-wrap:break-word;margin-top:15px;margin-bottom:15px;background-color:rgb(248,248,248);border:1px solid rgb(204,204,204);overflow:auto;padding:6px 10px;border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">
<span class="" style="color:rgb(153,153,136);font-style:italic">/**</span>
<span class="" style="color:rgb(153,153,136);font-style:italic"> * A strategy for implementing pagination in AeroGear Controller.</span>
<span class="" style="color:rgb(153,153,136);font-style:italic"> */</span>
<span class="" style="font-weight:bold">public</span> <span class="" style="font-weight:bold">interface</span> <span class="" style="color:rgb(68,85,136);font-weight:bold">PaginationStrategy</span> <span class="" style="font-weight:bold">{</span>

   <span class="" style="color:rgb(153,153,136);font-style:italic">/**</span>
<span class="" style="color:rgb(153,153,136);font-style:italic">     * Creates a PaginationInfo instance.</span>
<span class="" style="color:rgb(153,153,136);font-style:italic">     * How this information is gathered, be it from an Annotation on the target </span>
<span class="" style="color:rgb(153,153,136);font-style:italic">     * endpoint method, or by using separate request parameters is up to the </span>
<span class="" style="color:rgb(153,153,136);font-style:italic">     * concrete implementation.</span>
<span class="" style="color:rgb(153,153,136);font-style:italic">     * </span>
<span class="" style="color:rgb(153,153,136);font-style:italic">     * @param routeContext the {@link RouteContext} of the route being processed.</span>
<span class="" style="color:rgb(153,153,136);font-style:italic">     * @param arguments the extracted arguments from the current request.</span>
<span class="" style="color:rgb(153,153,136);font-style:italic">     * @return {@link PaginationInfo} the information requred for paging. </span>
<span class="" style="color:rgb(153,153,136);font-style:italic">     */</span>
    <span class="" style="color:rgb(51,51,51)">PaginationInfo</span> <span class="" style="color:rgb(153,0,0);font-weight:bold">createPaginationInfo</span><span class="" style="font-weight:bold">(</span><span class="" style="color:rgb(51,51,51)">RouteContext</span> <span class="" style="color:rgb(51,51,51)">routeContext</span><span class="" style="font-weight:bold">,</span> 
        <span class="" style="color:rgb(51,51,51)">Map</span><span class="" style="font-weight:bold">&lt;</span><span class="" style="color:rgb(51,51,51)">String</span><span class="" style="font-weight:bold">,</span> <span class="" style="color:rgb(51,51,51)">Object</span><span class="" style="font-weight:bold">&gt;</span> <span class="" style="color:rgb(51,51,51)">arguments</span><span class="" style="font-weight:bold">);</span>

    <span class="" style="color:rgb(153,153,136);font-style:italic">/**</span>
<span class="" style="color:rgb(153,153,136);font-style:italic">     * Called before the target endpoint method has been invoked and enables a </span>
<span class="" style="color:rgb(153,153,136);font-style:italic">     * concrete strategy to manipulate the arguments that will be passed to </span>
<span class="" style="color:rgb(153,153,136);font-style:italic">     * the target endpoint method.</span>
<span class="" style="color:rgb(153,153,136);font-style:italic">     * </span>
<span class="" style="color:rgb(153,153,136);font-style:italic">     * @param pagingInfo the {@link PaginationInfo} instance created by </span>
<span class="" style="color:rgb(153,153,136);font-style:italic">     * this strategy.</span>
<span class="" style="color:rgb(153,153,136);font-style:italic">     * @param arguments the extracted arguments from the current request.</span>
<span class="" style="color:rgb(153,153,136);font-style:italic">     *</span>
<span class="" style="color:rgb(153,153,136);font-style:italic">     * @return {@code Object[]} the arguments that will be passed to the target </span>
<span class="" style="color:rgb(153,153,136);font-style:italic">     * endpoint method.</span>
<span class="" style="color:rgb(153,153,136);font-style:italic">     */</span>
    <span class="" style="color:rgb(51,51,51)">Object</span><span class="" style="font-weight:bold">[]</span> <span class="" style="color:rgb(153,0,0);font-weight:bold">preInvocation</span><span class="" style="font-weight:bold">(</span><span class="" style="color:rgb(51,51,51)">PaginationInfo</span> <span class="" style="color:rgb(51,51,51)">pagingInfo</span><span class="" style="font-weight:bold">,</span> <span class="" style="color:rgb(51,51,51)">Map</span><span class="" style="font-weight:bold">&lt;</span><span class="" style="color:rgb(51,51,51)">String</span><span class="" style="font-weight:bold">,</span> <span class="" style="color:rgb(51,51,51)">Object</span><span class="" style="font-weight:bold">&gt;</span> <span class="" style="color:rgb(51,51,51)">arguments</span><span class="" style="font-weight:bold">);</span> 

    <span class="" style="color:rgb(153,153,136);font-style:italic">/**</span>
<span class="" style="color:rgb(153,153,136);font-style:italic">     * Called after the target endpoint method has been invoked and </span>
<span class="" style="color:rgb(153,153,136);font-style:italic">     * allows the strategy to set HTTP Response headers.  </span>
<span class="" style="color:rgb(153,153,136);font-style:italic">     * </span>
<span class="" style="color:rgb(153,153,136);font-style:italic">     * @param result the result returned from the target endpoint method.</span>
<span class="" style="color:rgb(153,153,136);font-style:italic">     * @param routeContext the {@link RouteContext}.</span>
<span class="" style="color:rgb(153,153,136);font-style:italic">     * @param pagingInfo the {@link PaginationInfo} instance created by this strategy.</span>
<span class="" style="color:rgb(153,153,136);font-style:italic">     *</span>
<span class="" style="color:rgb(153,153,136);font-style:italic">     * @return {@code Object} Either the unchanged result or a modified result </span>
<span class="" style="color:rgb(153,153,136);font-style:italic">     * depending on the underlying implementation.</span>
<span class="" style="color:rgb(153,153,136);font-style:italic">     */</span>
    <span class="" style="color:rgb(51,51,51)">Object</span> <span class="" style="color:rgb(153,0,0);font-weight:bold">postInvocation</span><span class="" style="font-weight:bold">(</span><span class="" style="color:rgb(51,51,51)">Object</span> <span class="" style="color:rgb(51,51,51)">result</span><span class="" style="font-weight:bold">,</span> 
        <span class="" style="color:rgb(51,51,51)">RouteContext</span> <span class="" style="color:rgb(51,51,51)">routeContext</span><span class="" style="font-weight:bold">,</span> 
        <span class="" style="color:rgb(51,51,51)">PaginationInfo</span> <span class="" style="color:rgb(51,51,51)">pagingInfo</span><span class="" style="font-weight:bold">);</span>

<span class="" style="font-weight:bold">}</span>
</pre></div><p style="margin:15px 0px;color:rgb(0,0,0);font-family:Helvetica,arial,freesans,clean,sans-serif;font-size:14px;line-height:22px">The <code style="font-size:12px;line-height:normal;font-family:Consolas,&#39;Liberation Mono&#39;,Courier,monospace;margin:0px 2px;padding:0px 5px;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;white-space:nowrap">createPaginationInfo</code> method is called by AeroGear Controller prior to invoking the target endpoint method. The arguments extracted from the current request are made available to this method. The implementation can choose whatever way it likes to match information from the request that are related to pagination. This could be using an annotation on the target endpoint method (which is what the default implementation does) or it could simply pick known parameters from the request.</p>
<p style="margin:15px 0px;color:rgb(0,0,0);font-family:Helvetica,arial,freesans,clean,sans-serif;font-size:14px;line-height:22px">The <code style="font-size:12px;line-height:normal;font-family:Consolas,&#39;Liberation Mono&#39;,Courier,monospace;margin:0px 2px;padding:0px 5px;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;white-space:nowrap">preInvocation</code> methods gives the strategy a chance to modify the actual arguments that will be used to invoke the target endpoint method. Depending on the concrete implementation there might not be anything to be done here other than simply returning the value of the arguments map. But, for example with the default strategy, an endpoint has the option to accept a <code style="font-size:12px;line-height:normal;font-family:Consolas,&#39;Liberation Mono&#39;,Courier,monospace;margin:0px 2px;padding:0px 5px;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;white-space:nowrap">PaginationInfo</code> type a parameter. In this case we have to add this instance to the arguments before calling the endpoint.</p>
<p style="margin:15px 0px;color:rgb(0,0,0);font-family:Helvetica,arial,freesans,clean,sans-serif;font-size:14px;line-height:22px">The <code style="font-size:12px;line-height:normal;font-family:Consolas,&#39;Liberation Mono&#39;,Courier,monospace;margin:0px 2px;padding:0px 5px;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;white-space:nowrap">postInvocation</code> method is called after the target endpoint method has been invoked allows the strategy to set the HTTP Response headers. This method has access to the results of the invocation which is can use to decide on what links should be returned, for example one might not want to return a previous next link header if there is no more data (the number of items in the results is less than the limit).</p>
<h2 style="margin:20px 0px 10px;padding:0px;font-size:24px;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(204,204,204);color:rgb(0,0,0);font-family:Helvetica,arial,freesans,clean,sans-serif"><a name="configuring-the-strategy-to-be-used" class="" href="https://gist.github.com/danbev/ed51e57e9a1f718f1848#configuring-the-strategy-to-be-used" style="color:rgb(65,131,196);text-decoration:initial;display:block;padding-left:30px"></a>Configuring the Strategy to be used</h2>
<p style="margin:0px 0px 15px;color:rgb(0,0,0);font-family:Helvetica,arial,freesans,clean,sans-serif;font-size:14px;line-height:22px">Configuration is done by adding a CDI Producer, for example:</p><div class="" style="border:0px;padding:0px;color:rgb(0,0,0);font-family:Helvetica,arial,freesans,clean,sans-serif;font-size:14px;line-height:22px;margin-bottom:0px!important">
<pre style="font-size:13px;line-height:19px;font-family:Consolas,&#39;Liberation Mono&#39;,Courier,monospace;word-wrap:break-word;margin-top:15px;margin-bottom:15px;background-color:rgb(248,248,248);border:1px solid rgb(204,204,204);overflow:auto;padding:6px 10px;border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">
<span class="" style="font-weight:bold">public</span> <span class="" style="font-weight:bold">class</span> <span class="" style="color:rgb(68,85,136);font-weight:bold">PaginationStrategyProducer</span> <span class="" style="font-weight:bold">{</span>

    <span class="">@Produces</span> 
    <span class="" style="font-weight:bold">public</span> <span class="" style="color:rgb(51,51,51)">PaginationStrategy</span> <span class="" style="color:rgb(153,0,0);font-weight:bold">createPagingStrategy</span><span class="" style="font-weight:bold">()</span> <span class="" style="font-weight:bold">{</span>
        <span class="" style="font-weight:bold">return</span> <span class="" style="font-weight:bold">new</span> <span class="" style="color:rgb(153,0,0);font-weight:bold">AbstractPaginationStrategy</span><span class="" style="font-weight:bold">()</span> <span class="" style="font-weight:bold">{</span>
            <span class="">@Override</span>
            <span class="" style="font-weight:bold">public</span> <span class="" style="color:rgb(68,85,136);font-weight:bold">void</span> <span class="" style="color:rgb(153,0,0);font-weight:bold">setResponseHeaders</span><span class="" style="font-weight:bold">(</span><span class="" style="color:rgb(51,51,51)">PaginationMetadata</span> <span class="" style="color:rgb(51,51,51)">md</span><span class="" style="font-weight:bold">,</span> 
                <span class="" style="color:rgb(51,51,51)">HttpServletResponse</span> <span class="" style="color:rgb(51,51,51)">response</span><span class="" style="font-weight:bold">,</span> 
                <span class="" style="color:rgb(68,85,136);font-weight:bold">int</span> <span class="" style="color:rgb(51,51,51)">resultSize</span><span class="" style="font-weight:bold">)</span> <span class="" style="font-weight:bold">{</span>
                <span class="" style="color:rgb(51,51,51)">Set</span><span class="" style="font-weight:bold">&lt;</span><span class="" style="color:rgb(51,51,51)">Entry</span><span class="" style="font-weight:bold">&lt;</span><span class="" style="color:rgb(51,51,51)">String</span><span class="" style="font-weight:bold">,</span> <span class="" style="color:rgb(51,51,51)">String</span><span class="" style="font-weight:bold">&gt;&gt;</span> <span class="" style="color:rgb(51,51,51)">hds</span> <span class="" style="font-weight:bold">=</span> <span class="" style="color:rgb(51,51,51)">md</span><span class="" style="font-weight:bold">.</span><span class="" style="color:teal">getHeaders</span><span class="" style="font-weight:bold">(</span><span class="" style="color:rgb(51,51,51)">resultSize</span><span class="" style="font-weight:bold">).</span><span class="" style="color:teal">entrySet</span><span class="" style="font-weight:bold">();</span>
                <span class="" style="font-weight:bold">for</span> <span class="" style="font-weight:bold">(</span><span class="" style="color:rgb(51,51,51)">Entry</span><span class="" style="font-weight:bold">&lt;</span><span class="" style="color:rgb(51,51,51)">String</span><span class="" style="font-weight:bold">,</span> <span class="" style="color:rgb(51,51,51)">String</span><span class="" style="font-weight:bold">&gt;</span> <span class="" style="color:rgb(51,51,51)">header</span> <span class="" style="font-weight:bold">:</span> <span class="" style="color:rgb(51,51,51)">hds</span><span class="" style="font-weight:bold">)</span> <span class="" style="font-weight:bold">{</span>
                    <span class="" style="color:rgb(51,51,51)">response</span><span class="" style="font-weight:bold">.</span><span class="" style="color:teal">setHeader</span><span class="" style="font-weight:bold">(</span><span class="" style="color:rgb(51,51,51)">header</span><span class="" style="font-weight:bold">.</span><span class="" style="color:teal">getKey</span><span class="" style="font-weight:bold">(),</span> <span class="" style="color:rgb(51,51,51)">header</span><span class="" style="font-weight:bold">.</span><span class="" style="color:teal">getValue</span><span class="" style="font-weight:bold">());</span>
                <span class="" style="font-weight:bold">}</span>
            <span class="" style="font-weight:bold">}</span>
        <span class="" style="font-weight:bold">};</span>
    <span class="" style="font-weight:bold">}</span>

<span class="" style="font-weight:bold">}</span></pre></div></div></div></div>