Server

Page Providers

Updated: December 2, 2024

Page providers allow retrieving items with pagination facilities, they can be used in a non-UI context like event listeners or core services.

Watch the related courses on Hyland University

Standard Page Providers

Page provider offers many advantages comparing to hard coded NXQL queries:

  • Pagination logics do not have to be coded again, the AbstractPageProvider implementation already offers corresponding logics.
  • Code duplication can be prevented, by re-using registered page providers.
  • Overriding an existing page provider definition is easy.
  • The default implementation (CoreQueryDocumentPageProvider) that handles Nuxeo documents can be switched from VCS (database) to Elasticsearch by just setting a configuration in the nuxeo.conf file.

Here is a sample page provider definition:

<extension target="org.nuxeo.ecm.platform.query.api.PageProviderService"
  point="providers">

  <coreQueryPageProvider name="TREE_CHILDREN_PP">
    <pattern>
      SELECT * FROM Document WHERE ecm:parentId = ? AND ecm:isProxy = 0 AND
      ecm:mixinType = 'Folderish' AND ecm:mixinType != 'HiddenInNavigation'
      AND ecm:isVersion = 0 AND ecm:isTrashed = 0
    </pattern>
    <sort column="dc:title" ascending="true" />
    <pageSize>50</pageSize>
  </coreQueryPageProvider>

</extension>

A typical usage of this page provider would be:

PageProviderService ppService = Framework.getService(PageProviderService.class);
Map<String, Serializable> props = new HashMap<>();
props.put(CoreQueryDocumentPageProvider.CORE_SESSION_PROPERTY, (Serializable) coreSession);
PageProvider<DocumentModel> pp = (PageProvider<DocumentModel>) ppService.getPageProvider(
        "TREE_CHILDREN_PP", null, null, null, props,
        new Object[] { myDoc.getId() });
List<DocumentModel> documents = pp.getCurrentPage();

Here you can see that the page provider properties (needed for the query to be executed) and its parameters (needed for the query to be built) cannot be resolved from EL expressions: they need to be given explicitly to the page provider service.

There is also a syntax to reference "named parameters" in the page provider fixed part. This is mostly useful when working with page providers from the Search Endpoints. You can also find extensive test cases in the code.

Available Parameters

parameter and property Elements

The coreQueryPageProvider element accepts any number of property elements, defining needed context variables for the page provider to perform its work. The coreSession property is mandatory for a core query to be processed and is bound to the core session proxy named documentManager available in a default Nuxeo application.

It also accepts any number of parameter elements, where order of definition matters: this EL expression will be resolved when performing the query, replacing the ? characters it holds.

The main difference between properties and parameters is that properties will not be recomputed when refreshing the provider, whereas parameters will be. Properties will only be recomputed when resetting the provider.

sort Element

The sort element defines the default sort, that can be changed later through the interface. There can be any number of sort elements. The sortInfosBinding element can also be defined: it can resolve an EL expression in case the sort infos are held by a third party instance (document, Seam component...) and will be used instead of the default sort information if not null or empty. The EL expression can either resolve to a list of org.nuxeo.ecm.core.api.SortInfo instances, or a list of map items using keys sortColumn (with a String value) and sortAscending (with a boolean value).

quickFilter Element

Since version 8.10, the quickFilter element enables to refine the results obtained by a search. There can be any number of quickFilter elements. Each quick filter is composed of a clause element which enables to extend the query, and additional sort elements.
The quick filters appears in the interface as buttons where each action on a button enables or disables its associated quick filter. In the previous example, activating "myQuickFilter" will display the children of the current document with the titles "Title1" or "Title2". The search results will be ordered by creator.

pageSize Element

The pageSize element defines the default page size, it can also be changed later. The pageSizeBinding element can also be defined: it can resolve an EL expression in case the page size is held by a third party instance (document, Seam component...), and will be used instead of the default page size if not null.

The optional maxPageSize element can be placed at the same level than pageSize. It makes it possible to define the maximum page size so that the content view does not overload the server when retrieving a large number of items. When not set, the default value "1000" will be used: even when asking for all the results with a page size with value "0" (when exporting the content view in CSV format for instance), only 1000 items will be returned. This is configurable by contributing the property nuxeo.pageprovider.default-max-page-size to the Configuration service.

maxResults Element

To set this limit you need to add a maxResults parameter to coreQueryPageProvider, either using an integer value or one of the following keywords:

Note that when using an Elasticsearch page provider, the maxResults limit is not taken in account because the total number of results is always available.

For performance reason by default Elasticsearch does not allow you to do unlimited deep scrolling on results. Only the index.max_result_window results (which defaults to 10000) are accessible. Content view will not allow you to access pages out of this window to prevent errors.

If you change the Elasticsearch configuration you can adapt the Nuxeo limit by contributing the property org.nuxeo.elasticsearch.provider.maxResultWindow to the Configuration service.

whereClause Element

This kind of core query can also perform a more complex form of query, using a document model to store query parameters. Using a document model makes it easy to:

  • use a layout to display the form that will define query parameters;
  • save this document in the repository, so that the same query can be replayed when viewing this document.

Here is an example of such a registration:

    <coreQueryPageProvider>
      <property name="coreSession">#{documentManager}</property>
      <property name="maxResults">DEFAULT_NAVIGATION_RESULTS</property>
      <whereClause docType="AdvancedSearch">

        <predicate parameter="dc:title" operator="FULLTEXT">
          <field schema="advanced_search" name="title" />
        </predicate>

        <predicate parameter="dc:created" operator="BETWEEN">
          <field schema="advanced_search" name="created_min" />
          <field schema="advanced_search" name="created_max" />
        </predicate>

        <predicate parameter="dc:modified" operator="BETWEEN">
          <field schema="advanced_search" name="modified_min" />
          <field schema="advanced_search" name="modified_max" />
        </predicate>

        <predicate parameter="dc:language" operator="LIKE">
          <field schema="advanced_search" name="language" />
        </predicate>

        <predicate parameter="ecm:currentLifeCycleState" operator="IN">
          <field schema="advanced_search" name="currentLifeCycleStates" />
        </predicate>

        <fixedPart>
          ecm:parentId = ? AND ecm:isVersion = 0 AND ecm:mixinType !=
          'HiddenInNavigation' AND ecm:isTrashed = 0
        </fixedPart>

      </whereClause>
      <parameter>#{currentDocument.id}</parameter>
      <sort column="dc:title" ascending="true" />
      <pageSize>20</pageSize>
    </coreQueryPageProvider>

The above definition holds a whereClause element, stating the search document type and predicates explaining how the document model properties will be translated into a NXQL query. It can also state a fixedPart element that will added as to the query string. This fixed part can also take parameters using the '?' character and parameter elements. It can also accept "named parameters", e.g. parameters prefixed by a comma, that can also match the search document model properties (for instance: SELECT * FROM Document WHERE [dc:title](http://dctitle) = :[searchdoc:title](http://searchdoctitle) ).

The fixedPart element also accepts attributes to better control its behavior:

  • statement makes is possible to declare the select statement to use (as contrary to the pattern element, the fixedPart element is not supposed to hold the select statement). This optional parameter default to "Select * from document" for default core page providers.
  • escapeParameters is a boolean value that allows to avoid escaping parameters when building the fixed part (defaults to true).
  • quoteParameters is a boolean value that allows to avoid adding quotes around the parameter (defaults to true). This is useful when parameters actually hold a complete predicate, for instance (and in this case, the escapeParameters element must also be set to true.

Note that when using an Elasticsearch page provider you can use NXQL hints inside predicates like this:

<predicate hint="ES: INDEX(dc:title,dc:description)" parameter="dc:title" operator="FULLTEXT">
  <field schema="advanced_search" name="fulltext_all"/>
</predicate>

Attributes escapeParameters and quoteParameters are also accepted on the pattern element.

It might be useful to add the ContentViewDisplay facet (this facet includes the content_view_display schema, using the cvd prefix to the definition of the AdvandedSearch document type, when configuring one of the elements described below: pageSizeBinding, sortInfosBinding, resultColumns or resultLayout.

searchDocumentType Element

The searchDocumentType element is an alternative way to define the search document type to use on the whereClause element. It's been made available to make it possible to define such a search document model, even if no whereClause is defined. This can be useful when defining aggregates without any other filtering, for instance.

Sample usage:

  <coreQueryPageProvider>
    <property name="coreSession">#{documentManager}</property>
    <searchDocumentType>AdvancedSearch</searchDocumentType>
  </coreQueryPageProvider>

Custom Page Providers

The <coreQueryPageProvider> element makes it possible to answer to most common use cases. If you would like to use another kind of query, you can use an alternate element and specify the PageProvider class to use.

Here is a sample example of a custom page provider configuration:

<extension point="providers" target="org.nuxeo.ecm.platform.query.api.PageProviderService">
    <genericPageProvider name="CUSTOM_PAGE_PROVIDER"
      class="org.nuxeo.ecm.platform.query.nxql.CoreQueryAndFetchPageProvider">
      <property name="coreSession">#{documentManager}</property>
      <pattern>
        SELECT dc:title FROM Document WHERE ecm:parentId = ? AND
        ecm:isVersion = 0 AND ecm:mixinType != 'HiddenInNavigation'
        AND ecm:isTrashed = 0
      </pattern>
      <parameter>#{currentDocument.id}</parameter>
      <sort column="dc:title" ascending="true" />
      <pageSize>2</pageSize>
    </genericPageProvider>

    ...
</extension>

The <genericPageProvider> element takes an additional class attribute stating the page provider class. This class has to follow the org.nuxeo.ecm.core.api.PageProvider interface and does not need to list document models. The abstract class org.nuxeo.ecm.core.api.AbstractPageProvider makes it easier to define a new page provider as it implements most of the interface methods in a generic way.

As result layouts can apply to other objects than document models, their definition can be adapted to fit to the kind of results provided by the custom page provider.

In the given example, another kind of query will be performed on a core session, and will return a list of maps, each map holding the  dc:title key and corresponding value on the matching documents.

The <genericPageProvider> element accepts all the other configurations present on the <coreQueryPageProvider> element: it is up to the PageProvider implementation to use them to build its query or not. It can also perform its own caching.

The properties can be defined as EL expressions and make it possible for the query provider to have access to contextual information. In the above example, the core session to the Nuxeo repository is taken from the Seam context and passed as the property with name coreSession.

Use Cases

Using Query Parameters and 'IN' Operator

By passing query String list parameters:

list.add("\"Art/Architecture\", \"Art/Culture\"");

 

And setting quoteParameters to false:

<genericPageProvider class="org.nuxeo.ecm.platform.query.nxql.CoreQueryAndFetchPageProvider"
                     name="searchWithInOperatorAndQueryParams">
  <property name="searchAllRepositories">true</property>
  <pattern quoteParameters="false">
    SELECT * FROM Document WHERE ecm:mixinType != 'HiddenInNavigation'
    AND ecm:isVersion = 0
    AND ecm:isTrashed = 0
    AND dc:subjects IN (?)
  </pattern>
  <pageSize>50</pageSize>
</genericPageProvider>

Result will be the following query:

SELECT * FROM Document WHERE ecm:mixinType != 'HiddenInNavigation' AND ecm:isVersion = 0 AND ecm:isTrashed = 0 AND dc:subjects IN ("Art/Architecture", "Art/Culture")

 

Using Named Parameters and Dates with Automation

By setting quoteParameters to false:

<genericPageProvider class="org.nuxeo.ecm.platform.query.nxql.CoreQueryAndFetchPageProvider" name="testPP">
  <property name="searchAllRepositories">true</property>
  <pattern quoteParameters="false">
    SELECT * FROM Document WHERE dc:created &gt; :mydate AND dc:title = "hello"
  </pattern>
  <pageSize>50</pageSize>
</genericPageProvider>

And defining a named parameter date:

<operation id="Repository.PageProvider">
  <param type="string" name="language">NXQL</param>
  <param type="properties" name="namedParameters">expr:mydate=@{CurrentDate}</param>
  <param type="string" name="providerName">testPP</param>
  <param type="string" name="sortOrder">ASC</param>
</operation>

Result will be the following query:

SELECT * FROM Document WHERE dc:created > TIMESTAMP '2015-04-04 00:00:00.000'

Page provider related topics