Nav

Adding Query Pagination Support

Query Pagination comes as a need when dealing with a high quantity of records. The main advantage is performance as Mule runtime partially processes chunks of records at a time instead of trying to process all the records in memory at the same time. 

To implement pagination in your connector, ensure that the service’s API to which you want to connect provides pagination functionality.
Be aware that enabling pagination on your connector may break backward compatibility with older Mule versions (prior to Mule Runtime 3.5.x) as it might change the returned type of a processor.

Enabling Pagination

Enabling pagination in your connector is fairly straightforward. There are only three required conditions that your @Processor method must meet:

  1. Annotate the method with @Paged

  2. Must receive a parameter with type org.mule.api.streaming.PagingConfiguration 

  3. The return type must be a ProviderAwarePagingDelegate


         
      
1
2
3
4
5
6
7
8
9
10
@Paged
@Processor
    public ProviderAwarePagingDelegate query(String query, final PagingConfiguration pagingConfiguration) throws Exception
{
    return new CustomPagingDelegate(query,pagingConfiguration);
}

public QueryResult executeQuery(String query, String nextItem) throws Exception {
        myServiceClient.query(query,nextItem);
}

Note: The difference between the @Processor method and the operation executeQuery. The processor returns a PagingDelegate that later on (when retrieving a page) receives a connector instance already connected and executes executeQuery accordingly. 

Creating a CustomPagingDelegate

The ProviderAwarePagingDelegate is where the pagination happens. Take a look at the ProviderAwarePagingDelegate abstract class, which requires two type arguments (T and P in this case). In the class definition below, T represents the data to be returned and P represents the provider of the data, your Anypoint Connector.


         
      
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public abstract class ProviderAwarePagingDelegate<T, P> implements Closeable

{
    /**
     * Returns the next page of items. If the return value is
     * <code>null</code> or an empty list, then it means
     * no more items are available
     *
     * @param provider The provider to be used to do the query.
     * You can assume this provider is already properly initialised
     * @return a populated list of elements. <code>null</code>
     * or an empty list, then it means no more items are available
     * @throws Exception
     */
    public abstract List<T> getPage(P provider) throws Exception;

    /**
     * Returns the total amount of items in the non-paged result set.
     * In some scenarios, it might not be possible or
     * convenient to actually retrieve this value. -1 is
     * returned in such a case.
     *
     * @param provider The provider to be used to do the query.
     * You can assume this provider is already properly initialised.
     */
    public abstract int getTotalResults(P provider) throws Exception;

    /**
     * Close whatever external resource you might use
     */
    @Override
    public void close() throws MuleException;

}

Note again that when executing the methods getPage(P provider) and getTotalResults(P provider), Anypoint Connector DevKit picks the correct instance of your connector out of the connection pool.


         
      
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/**
 * Example of Paging Delegate implementation
 */
public class CustomPagingDelegate extends ProviderAwarePagingDelegate<Item,CustomConnector> {
    List<Item> cachedPage;
    String query;
    String nextItem;
    int totalItems = -1;

    public CustomPagingDelegate(String query, PagingConfiguration pagingConfiguration) {
        this.query = query;
    }

    @Override
    public List<Item> getPage(CustomConnector provider) throws Exception {
        if (cachedPage != null) return cachedPage;
        QueryResult queryResult = provider.executeQuery(query,nextItem);
        nextItem = queryResult.nextItem();
        return queryResult.items();
    }
    @Override
    public int getTotalResults(CustomConnector provider) throws Exception {
        if (totalItems != -1) return totalItems;
        QueryResult queryResult = provider.executeQuery(query,nextItem);
        nextItem = queryResult.nextItem();
        totalItems = queryResult.totalItemsCount();
        cachedPage = queryResult.items();
        return totalItems;
    }
    @Override
    public void close() throws MuleException {
        //Close whatever external resource you might use
    }
}

To create your own version of ProviderAwarePagingDelegate, you must extend it. Below is an example of a simple extension of this class:

See Also