Query Models and Result Providers Migration to Content Views and Page Providers

Updated: March 18, 2024

This page explains how query models and result provider farms, deprecated since version 5.4.2, can be migrated to content views and page providers.

The JIRA issue gives technical upgrade notes, this chapter gives more details depending on use cases.

Generic Migration Steps

Content views and associated page providers have been designed to replace old query models that were not as modular and easy to use.

A lot of configuration has been updated or removed, but without any feature loss. For instance, syndication links are not relying anymore on a specific module, but using native exports from the result layout listing.

Reading the Content Views chapter is highly recommended to understand migration steps.

Query models have been replaced by page providers. Page providers definition is sometimes embedded within a content view definition, as content views are useful for UI interactions. Page providers alone are still useful to generate lists of documents from core code, not involving any UI interactions. Results provider farms were used to pass UI contextual information to the query model. This is now done by using EL expressions when defining parameters on content views.

XML Configurations Migration

Components org.nuxeo.ecm.core.search.api.client.querymodel.QueryModelService and org.nuxeo.ecm.webapp.pagination.ResultsProviderService have been removed, components org.nuxeo.ecm.platform.query.api.PageProviderService (with extension point providers) and org.nuxeo.ecm.platform.ui.web.ContentViewService (with extension point contentViews) should be used instead.

The XML syntax is very close, here is a sample migration of a query model contribution without a whereClause element:

Old Configuration

<extension target="org.nuxeo.ecm.core.search.api.client.querymodel.QueryModelService"
  point="model">
  <queryModel name="MY_SEARCH">
    <pattern>
      SELECT * FROM Document WHERE ecm:isTrashed = 0 AND ecm:uuid != ?
    </pattern>
    <sortable value="true" defaultSortColumn="dc:title" defaultSortAscending="true" />
    <max>20</max>
  </queryModel>
</extension>

This can be translated into a page provider very easily (notice the pageSize and sort syntax changes):

New Configuration with Page Provider

 <extension target="org.nuxeo.ecm.platform.ui.web.ContentViewService"
  point="contentViews">
  <coreQueryPageProvider name="MY_SEARCH">
    <pattern>
      SELECT * FROM Document WHERE ecm:isTrashed = 0 AND ecm:uuid != ?
    </pattern>
    <sort column="dc:title" ascending="true" />
    <pageSize>20</pageSize>
  </coreQueryPageProvider>
</extension>

Code Migration

Classes QueryModel, QueryModelService and ResultsProviderFarm have been removed.

The QueryModel class is basically replaced by PageProvider or PageProviderDefinition instances depending on the use case. Default page providers are available and perform queries on the Nuxeo repository, for instance CoreQueryDocumentPageProvider.

Reading the Custom Page Providers and Page Providers chapters is recommended to understand how to use the new API.

Templates Migration

Old templates displaying paged lists of documents have been removed, the template at /incl/content_view.xhtml can now be included to display the results using a listing layout configured on the content view.

Sample Old Template


<div xmlns:ui="http://java.sun.com/jsf/facelets"
  xmlns:nxu="http://nuxeo.org/nxweb/util">

  <nxu:set var="documents"
    value="#{documentActions.getChildrenSelectModel()}">
    <ui:decorate template="/incl/forum_table.xhtml" />
  </nxu:set>

</div>

Alternative Sample Old Template


<div xmlns:ui="http://java.sun.com/jsf/facelets"
  xmlns:nxu="http://nuxeo.org/nxweb/util">

  <nxu:set var="provider"
    value="#{resultsProvidersCache.get('MY_SEARCH')}"
    cache="true">
    <ui:decorate template="/search/documents_table.xhtml">
      <ui:param name="provider" value="#{provider}"/>
      <ui:param name="providerName" value="#{provider.name}"/>
    </ui:decorate>
  </nxu:set>

</div>

Sample New Template


<div xmlns:ui="http://java.sun.com/jsf/facelets"
  xmlns:nxu="http://nuxeo.org/nxweb/util">

  <nxu:set var="contentViewName" value="MY_SEARCH">
    <ui:decorate template="/incl/content_view.xhtml" />
  </nxu:set>

</div>

Also, the old templates displaying listings of documents were not relying on layouts, so migration may include defining listing layouts and widget templates when migrating to content views.

Migration Use Cases

Migrating a QueryModel to a PageProvider

Let's take again the above example:

Old Configuration

<extension target="org.nuxeo.ecm.core.search.api.client.querymodel.QueryModelService"
  point="model">
  <queryModel name="MY_SEARCH">
    <pattern>
      SELECT * FROM Document WHERE ecm:isTrashed = 0 AND ecm:uuid != ?
    </pattern>
    <sortable value="true" defaultSortColumn="dc:title" defaultSortAscending="true" />
    <max>20</max>
  </queryModel>
</extension>

This query model is designed to perform a query on the Nuxeo Core Repository, using a parameter to fill the ecm:uuid filtering criterion.

Here is a sample JAVA code using this query model:

QueryModelService qmService = Framework.getService(QueryModelService.class);
QueryModelDescriptor qmd = qmService.getQueryModelDescriptor("MY_SEARCH");
QueryModel qm = new QueryModel(qmd);
Object[] params = {document.getId()};
DocumentModelList list = qm.getDocuments(coreSession, params);

Let's migrate the query model to a page provider:

New Configuration with Page Provider

<extension target="org.nuxeo.ecm.platform.ui.web.ContentViewService"
  point="contentViews">
  <coreQueryPageProvider name="MY_SEARCH">
    <pattern>
      SELECT * FROM Document WHERE ecm:isTrashed = 0 AND ecm:uuid != ?
    </pattern>
    <sort column="dc:title" ascending="true" />
    <pageSize>20</pageSize>
  </coreQueryPageProvider>
</extension>

Let's also migrate the corresponding JAVA code:

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

Here is a more complex migration involving a whereClause (the search pattern is generated according to predicates definitions, retrieving values on the search document model):

<extension target="org.nuxeo.ecm.core.search.api.client.querymodel.QueryModelService"
  point="model">
  <queryModel name="MY_SEARCH" docType="AdvancedSearch">
    <whereClause>
      <predicate parameter="ecm:fulltext" operator="FULLTEXT ALL">
        <field schema="advanced_search" name="fulltext_all"/>
      </predicate>
      <fixedPart>ecm:isTrashed = 0</fixedPart>
    </whereClause>
    <sortable value="true" defaultSortColumn="dc:title" defaultSortAscending="true" />
    <max>20</max>
  </queryModel>
</extension>

The whereClause element content is unchanged, but the associated docType element has moved from the queryModel element to the whereClause element:

<extension target="org.nuxeo.ecm.platform.ui.web.ContentViewService"
  point="contentViews">
  <coreQueryPageProvider name="MY_SEARCH">
    <whereClause docType="AdvancedSearch">
      <predicate parameter="ecm:fulltext" operator="FULLTEXT ALL">
        <field schema="advanced_search" name="fulltext_all"/>
      </predicate>
      <fixedPart>ecm:isTrashed = 0</fixedPart>
    </whereClause>
    <sort column="dc:title" ascending="true" />
    <pageSize>20</pageSize>
  </coreQueryPageProvider>
</extension>

Migrating a QueryModel to a ContentView

Sometimes it is useful to migrate the query model to a content view, where the page provider definition is embedded.

Here is a sample migration of the above example to a content view:

<extension target="org.nuxeo.ecm.platform.ui.web.ContentViewService"
  point="contentViews">
  <contentView name="MY_SEARCH">
    <coreQueryPageProvider>
      <pattern>
        SELECT * FROM Document WHERE ecm:isTrashed = 0 AND ecm:uuid != ?
      </pattern>
      <sort column="dc:title" ascending="true" />
      <pageSize>20</pageSize>
      <parameter>#{currentDocument.id}</parameter>
    </coreQueryPageProvider>
    [...]
  </contentView>
</extension>

Notice the parameter element, using an EL expression, that makes it possible to resolve Seam/JSF EL expresssions.

Migrating a QueryModel associated to a ResultsProviderFarm to a ContentView

Result provider farms were useful to pass contextual parameters to the page provider. Using EL expressions as parameter elements in the definition as above makes it possible to map directly these parameters.

For instance, if the result provider farm is a seam component named mySeamComponent and is using one of its custom contextual field myField as a parameter for the query model, the content view can simply state a parameter in the page provider definition as is (provided the Seam component holds public a getter method for this field):

<extension target="org.nuxeo.ecm.platform.ui.web.ContentViewService"
  point="contentViews">
  <contentView name="MY_SEARCH">
    <coreQueryPageProvider>
      [...]
      <parameter>#{mySeamComponent.myField}</parameter>
    </coreQueryPageProvider>
    [...]
  </contentView>
</extension>

More Migration Examples

Nuxeo source code has been upgraded too, here are sample changes that can be helpful as examples: