Creating a Segment Criteria Contributor

To demonstrate the Segment Criteria Contributor, you’ll create a contributor that segments users based on the title of Knowledge Base articles they have authored.

The first step is to make your related entity searchable through OData queries. For this purpose, you must have classes:

  • EntityModel: represents your associated entity (in this case, the KBArticle) with its fields of interest.

  • ODataRetriever: obtains the KBArticles that match a given OData query.

You can view the full project on Github.

Follow the instructions below to get started.

  1. Create a module.

  2. Create the following packages within the module:

    • com.liferay.segments.criteria.extension.sample.internal.odata.retreiver
    • com.liferay.segments.criteria.extension.sample.internal.odata.entity
    • com.liferay.segments.criteria.extension.sample.internal.criteria.contributor

Excellent! You have your module ready. Next, you’ll create the entity model.

Creating the Entity Model

First, create the Entity Model for KBArticle.

  1. Inside the ...internal.odata.entity package, create the KBArticleEntityModel class which implements EntityModel:

    public class KBArticleEntityModel implements EntityModel {
  2. Create the key for the entity name:

    public static final String NAME = "KBArticle";
  3. Create the variable for the entity field map:

    private final Map<String, EntityField> _entityFieldsMap;
  4. Create the methods to retrieve the KBArticleEntity, entity map, and entity name key:

    public KBArticleEntityModel() {
        _entityFieldsMap = Stream.of(
            new StringEntityField("title", locale -> "titleKeyword")
                Collectors.toMap(EntityField::getName, Function.identity())
    public Map<String, EntityField> getEntityFieldsMap() {
        return _entityFieldsMap;
    public String getName() {
        return NAME;

Next, you’ll create the OData Retriever.

Creating the ODataRetriever

Next, create the ODataRetriever which gets the data using the relevant filter.

  1. Inside the ...internal.odata.retreiver package, create which implements ODataRetriever:

    public class KBArticleODataRetriever implements ODataRetriever<KBArticle> {
  2. Add the @Component declaration above the class declaration:

        immediate = true,
        property = "",
        service = ODataRetriever.class
  3. Create the @Reference objects that you need for the Filter Parser, Knowledge Base Article Service, and OData Search Adapter:

    private FilterParserProvider _filterParserProvider;
    private KBArticleLocalService _kbArticleLocalService;
    private ODataSearchAdapter _oDataSearchAdapter;
  4. Create and instantiate the _entityModel object for the KBArticle model:

    private static final EntityModel _entityModel = new KBArticleEntityModel();
  5. Create the public methods to retrieve the results and the results count from the OData filter:

    public List<KBArticle> getResults(
            long companyId, String filterString, Locale locale, int start,  int end)
        throws PortalException {
        Hits hits =
            companyId, filterString, KBArticle.class.getName(), _entityModel,
            	_getFilterParser(), locale, start, end);
        return _getKBArticles(hits);
    public int getResultsCount(
            long companyId, String filterString, Locale locale)
        throws PortalException {
        return _oDataSearchAdapter.searchCount(
            companyId, filterString, KBArticle.class.getName(), _entityModel,
                _getFilterParser(), locale);
  6. Create the private methods for instantiating the FilterParser and retrieving the Knowledge Base article(s) that meet the criteria:

    private FilterParser _getFilterParser() {
        return _filterParserProvider.provide(_entityModel);
    private KBArticle _getKBArticle(Document document) throws PortalException {
        long resourcePrimKey = GetterUtil.getLong(
        return _kbArticleLocalService.getLatestKBArticle(resourcePrimKey, 0);
    private List<KBArticle> _getKBArticles(Hits hits) throws PortalException {
        Document[] documents = hits.getDocs();
        List<KBArticle> kbArticles = new ArrayList<>(documents.length);
        for (Document document : documents) {
        return kbArticles;

You’re all set to create the Segments Criteria Contributor!

Creating the SegmentsCriteriaContributor

Now create the SegmentsCriteriaContributor class that consumes the previous classes to retrieve the articles that match the query generated by the criteria editor, and contributes a query to filter users based on the articles they authored.

  1. In the ...internal.criteria.contributor package, create a UserKBArticleSegmentCritieriaContributor class that implements SegmentsCriteriaContributor.

    public class UserKBArticleSegmentsCriteriaContributor
        implements SegmentsCriteriaContributor {
  2. Create the @Component declaration to set properties and declare the service class.

        immediate = true,
        property = {
            "segments.criteria.contributor.key=" + UserKBArticleSegmentsCriteriaContributor.KEY,
        service = SegmentsCriteriaContributor.class
  3. Create the variables to enable logging, retrieve the entity model, and entity key.

    private static final Log _log = LogFactoryUtil.getLog(
        private static final EntityModel _entityModel = new KBArticleEntityModel();
        public static final String KEY = "user-kb-article";
  4. Create the reference variables for the OData retriever and Portal instance.

        target = "("
    private ODataRetriever<KBArticle> _oDataRetriever;
    private Portal _portal;
  5. Create the methods to define the implementation of SegmentsCriteriaContributor.

    public void contribute(
        Criteria criteria, String filterString,
            Criteria.Conjunction conjunction) {
        criteria.addCriterion(getKey(), getType(), filterString, conjunction);
        long companyId = CompanyThreadLocal.getCompanyId();
        String newFilterString = null;
        try {
            StringBundler sb = new StringBundler();
            List<KBArticle> kbArticles = _oDataRetriever.getResults(
                companyId, filterString, LocaleUtil.getDefault(),
                QueryUtil.ALL_POS, QueryUtil.ALL_POS);
            for (int i = 0; i < kbArticles.size(); i++) {
                KBArticle kbArticle = kbArticles.get(i);
                sb.append("(userId eq '");
                if (i < (kbArticles.size() - 1)) {
                    sb.append(" or ");
            newFilterString = sb.toString();
        catch (PortalException pe) {
                    "Unable to evaluate criteria ", criteria, " with filter ",
                    filterString, " and conjunction ", conjunction.getValue()),
        if (Validator.isNull(newFilterString)) {
            newFilterString = "(userId eq '0')";
        criteria.addFilter(getType(), newFilterString, conjunction);
    public EntityModel getEntityModel() {
        return _entityModel;
    public String getEntityName() {
        return KBArticleEntityModel.NAME;
    public List<Field> getFields(PortletRequest portletRequest) {
        return Collections.singletonList(
            new Field(
                LanguageUtil.get(_portal.getLocale(portletRequest), "title"),
    public String getKey() {
        return KEY;
    public Criteria.Type getType() {
        return Criteria.Type.MODEL;
  6. Deploy your module.

After deploying your extension, the segment criteria editor includes a new section containing Knowledge Base properties. Notice that the section’s UI, the properties, and their associated input fields and operations have been automatically generated based on the information provided by the extension services. For instance, the Knowledge Base article title supports equals, not equals, contains, and not contains operations because it was defined as a StringEntityField.

Figure 1: The sample field appears.

Figure 1: The sample field appears.

Awesome! You’ve created a Segment Criteria Contributor!

« Creating a Request Context ContributorServiceContext »
¿Fue útil este artículo?
Usuarios a los que les pareció útil: 1 de 1