Page providers allow retrieving items with pagination facilities, they can be used in a non-UI or non-JSF context like event listeners or core services.
For an introduction to content views, please refer to the Content Views page.
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 thenuxeo.conf
file. - When using Elasticsearch, page providers support aggregation features.
Page providers can be registered on their own service and queried outside of an UI context. These page providers can also be referenced from content views, to keep a common definition of the provider.
Content views are very linked to the rendering as they hold UI configuration and need the JSF context to resolve variables.
Page providers defined inside content views are also registered on the PageProviderService
, reusing the original content view name, so that they're available outside of the content view.
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>
This definition is identical to the one within a content view, except it cannot use EL expressions for variables resolution.
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.
A typical usage of this page provider, referenced in a content view, would be:
<extension target="org.nuxeo.ecm.platform.ui.web.ContentViewService" point="contentViews">
<contentView name="TREE_CHILDREN_CV">
<title>tree children</title>
<pageProvider name="TREE_CHILDREN_PP">
<property name="coreSession">#{documentManager}</property>
<property name="checkQueryCache">true</property>
<parameter>#{currentDocument.id}</parameter>
</pageProvider>
</contentView>
</extension>
Here you can see that properties and parameters can be put on the referenced page provider as content views all have a JSF context.
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.
Custom Page Providers
This chapter focuses on writing custom page providers, for instance when you'd like to use content views to query and display results from an external system.
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 target="org.nuxeo.ecm.platform.ui.web.ContentViewService"
point="contentViews">
<contentView name="CURRENT_DOCUMENT_CHILDREN_FETCH">
<genericPageProvider
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>
...
</contentView>
</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: content views do not force the item type to a given interface. 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 > :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'