Introduction

I have always wanted the ability to “call some Nuxeo Automation” from JSF so that I could build widgets that did not rely on a certain context (e.g. viewing a certain folder or document). In this case I am building a navigation action to display a count of “Alerts” in the system and then navigate to the list of alerts, like:

Alerts

In this way the user is always aware if there are any alerts pending and immediately sees any new alerts.

There are so many JSF tags and objects in the Nuxeo Platform that cover many use cases. When working with a Content View for example, there is a “contentView” object that can be used to get the total number of results like so:

#{contentView.getCurrentPageProvider().getResultsCount()}

If my Alert count was part of my content, e.g. a field for the Domain object, then I could access that field data via JSF when viewing the Domain. But in this case I want to display the Alert count everywhere. I want the user to have access to this information at any time, any place within the application.

The logical way to do this to me is to use Automation and I figured there has to be a way to access Automation Chains from JSF. More to the point, I wanted to build something that did not require customization. I realize I could have built a custom Seam bean to make this work but one of my goals is to find solutions that involve only Nuxeo Studio configuration whenever possible, and especially for a small feature like this.

Luckily the Nuxeo Platform provides a plethora of Seam components already. A list of them for each Nuxeo version can be found at http://explorer.nuxeo.com (here is the list for 8.3). Know what’s even cooler? The Nuxeo Platform Explorer package offers the same functionality when installed in a Nuxeo server and it will include any extra Seam components that might be installed on the server (whereas the Explorer website is limited to the core packages).

The point is, there is already a Seam component for executing Automation tasks! It’s called OperationActionBean. With this in mind, I set out to build my ubiquitous Alert count feature.

Alert Count Widget

The solution involves three parts:

Automation

The Automation Chain to get the alert count involves an NXQL query to get the count of all Alert documents:

- Repository.ResultSetQuery:
    query: "SELECT COUNT(ecm:uuid) FROM Document WHERE ecm:mixinType != 'HiddenInNavigation' AND ecm:isProxy = 0 AND ecm:isCheckedInVersion = 0 AND ecm:currentLifeCycleState != 'deleted' AND ecm:primaryType = 'Alert'"
    language: NXQL
    sortOrder: ASC
- Context.SetVar:
    name: Outcome
    value: "@{Integer.toString(This[0][\"COUNT(ecm:uuid)\"])}"

It is necessary to use the “Repository.ResultSetQuery” operation because the query uses the “COUNT” aggregate; “Repository.Query” will not work. Finally, in order to be used by OperationActionBean, the Automation Chain needs to provide a result via a context variable named “Outcome” (capitalization is important).

Widget Template

Here is the Widget Template to display the Alert count with a link to the Alerts folder

<h:panelGroup layout="block"
    style="display: inline-block; margin-left: 10px;"
    xmlns:h="http://java.sun.com/jsf/html">

  <style>
    .count[count^="-"],
    .count[count="0"] {
      display: none;
    }
  </style>

  <a href="#{baseURL}nxpath/default/default-domain/Alerts@view_documents">
    <span class="count label label-error"
        count="#{operationActionBean.doOperation('GetAlertCount')}">
      Alerts #{operationActionBean.doOperation("GetAlertCount")}
    </span>
  </a>
</h:panelGroup>

To keep things simple the link to the “Alerts” folder is hard-coded. The secret sauce is using operationActionBean.doOperation() to call the Automation Chain. Note that Automation Scripts are also supported, just make sure to add the “javascript.” prefix to the name of the script.

Notice that operationActionBean.doOperation() is used twice. The attribute “count” on the “span” tag is used just to trigger some CSS. In the case that there are no Alerts (or the count is negative) the widget is not displayed.

It is also worth mentioning that the “style” values for the “panelGroup” are necessary in order to have the widget display correctly when used as a Header Group Action (see below).

Here is an Action to display the widget template:

<extension point="actions" target="org.nuxeo.ecm.platform.actions.ActionService">
  <action id="Alerts" label="Alerts" order="1000" type="template">
    <category>USER_SERVICES</category>
    <properties>
      <property name="template">
        /widgets/alert-count-widget.xhtml
      </property>
    </properties>
  </action>
</extension>

I chose the “USER_SERVICES” category (aka Header Links) so that the widget would be available no matter where the user is within the application.

Here’s the final product:

Alerts Results

Conclusion

This exercise really reminds me of the rich depth of functionality that the Nuxeo Platform provides. The extensive list of Seam components affords a tremendous amount of features that can be accessed via JSF templates. More often than not I find that the Nuxeo Platform already has a feature I want to use. Perhaps the best part is that this solution requires no extra tooling, no customization, no plug-ins; just good ol’ Nuxeo Studio.