Channel Filtering - Bloomreach Experience - Open Source CMS
09-04-2020

Channel Filtering

Default filtering

HST supports pluggable filtering on the channels that are visible below the [view] button for a document or in the Experience manager for a logged in CMS user. By default, the  ContentReadChannelFilter and PrivilegeBasedChannelFilter are always present and are always applied, also see Access Channels. It filters out all channels that the current CMS user is not allowed to see in the Channel Manager. For example, if there are three channels with the content roots 

/content:
  /documents:
    /intranet:
    /extranet:
    /management:

and the logged-in CMS user has read access to the content of 'intranet' and 'extranet', then he won't see the Channel that has 'management' as content root in the Experience manager application. 

Customize filtering

Channel filtering can be customized by adding extra channel filters to the built in channel filters. To add a custom channel filter you need to:

  1. Create a filter that implements  java.util.function.BiPredicate<Session,Channel>
  2. Add a Spring bean for your custom filter to  customChannelFilters

Built-in Channel Filters

As examples, we show the default ContentReadChannelFilter and PrivilegeBasedChannelFilter since they serve as good examples. The provided Session in the #apply method is the Session of the currently logged-in CMS user.

public class ContentReadChannelFilter implements BiPredicate<Session, Channel> {

    private static final Logger log = LoggerFactory.getLogger(ContentReadChannelFilter.class);

    @Override
    public boolean test(final Session userSession, final Channel channel) {
        try {
            if (userSession.nodeExists(channel.getContentRoot())) {
                log.debug("Predicate passed for channel '{}' because user '{}' has read access on '{}'",
                        new String[]{channel.toString(), userSession.getUserID(), channel.getContentRoot()});
                return true;
            }
            log.info("Skipping channel '{}' for user '{}' because she has no read access on '{}'",
                    new String[]{channel.toString(), userSession.getUserID(), channel.getContentRoot()});
            return false;
        } catch (RepositoryException e) {
            log.warn("Exception while trying to check channel content root '{}'. Skip that channel:", channel.getContentRoot(), e);
            return false;
        }
    }
}
public class PrivilegeBasedChannelFilter implements BiPredicate<Session, Channel> {

    private static final Logger log = LoggerFactory.getLogger(ContentReadChannelFilter.class);

    @Override
    public boolean test(final Session userSession, final Channel channel) {

        try {
            final Privilege privilege = userSession.getAccessControlManager().privilegeFromName("hippo:channel-viewer");
            return userSession.getAccessControlManager().hasPrivileges(channel.getHstConfigPath(), new Privilege[]{privilege});
        } catch (RepositoryException e) {
            log.warn("Exception while checking privilege 'hippo:channel-viewer' for channel '{}'. Skip that
                     channel:", channel.getHstConfigPath(), e);
            return false;
        }
    }
}

Example of adding a custom filter

Assume (contrived example) you want to add a channel filter such that a channel is only shown in the Experience manager application, if the CMS user his locale is the same as the locale of the channel, you can achieve that through the following steps:

Create ChannelLocaleBasedFilter

public class ChannelLocaleBasedFilter implements BiPredicate<Session, Channel> {

    private static final Logger log = LoggerFactory.getLogger(ChannelNodeBasedFilter.class);

    @Override
    public boolean apply(final Session cmsSession, final Channel channel) {
       try {
            if (channel.getLocale() == null) {
                // no specific locale
                return true;
            }
            final HstRequestContext requestContext = RequestContextProvider.get();
            if (requestContext == null {
               // invoked by background thread, no filtering
               return true;
            }
            final HttpSession session = requestContext.getServletRequest().getSession();
            final CmsSessionContext cmsSessionContext = CmsSessionContext.getContext(session);
            final Locale userLocale = cmsSessionContext.getLocale();
            if (userLocale.getLanguage().equals(new Locale(channel.getLocale()).getLanguage())) {
                // matching locale
                return true;
            } else {
                return false;
            }
        } catch (Exception e) {
            log.warn("Exception while trying to check channel content root '{}'. 
                           Skip that channel:", channel.getContentRoot(), e);
            return false;
        }
    }
}

Add the ChannelLocaleBasedFilter to the customFilters 

Below  

site/components/src/main/resources/META-INF/hst-assembly/overrides

, add the following bean to an XML Spring configuration file (for example to custom-channel-filters.xml):

<!-- Custom channel filters be added here. -->
<bean id="customChannelFilters" class="org.springframework.beans.factory.config.ListFactoryBean">
  <property name="sourceList">
    <list>
      <bean id="channelNodeBasedFilter" class="org.example.filter.ChannelLocaleBasedFilter"/>
    </list>
  </property>
</bean>

Access the HstRequestContext in a Channel Filter

In a Channel Filter #apply method you can access the HstRequestContext via

HstRequestContext hstRequestContext = RequestContextProvider.get();

If using it, always make sure to do a null check on the hstRequestContext object since the Channel Filters can also be applied to background threads which do not have an HstRequestContext. The hstRequestContext is the request context for the CMS request. When getting the JCR Session via the request context, you'll get the JCR Session for the currently logged-in CMS user.

Did you find this page helpful?
How could this documentation serve you better?
On this page
    Did you find this page helpful?
    How could this documentation serve you better?