Supporting Filtering Content Type Instances

Version 1

    You can add support that allows people to filter listed instances of your content type. With this support, people can filter instances by user, creation date, and modification date.


    Note: The code in this topic is from the Memo sample content type. You'll find the sample in the Jive public sample Subversion repository. The content in this topic assumes you've implemented a manager class to locate content type instances based on their ID in the system.


    Note: The content type API is still a new feature that might change as developers provide feedback about it.


    Here are the high-level steps. You'll find more about each in the sections below.

    • Describe how to filter your instance content by implementing FilteredContentProvider.
    • Signal that your content type supports filtering by implementing FilteredContentEnabledType.

    Provide Information About Filtering Support

    Implement the FilteredContentProvider interface to describe how your content type supports filtering. Most of your implementation's work will be to return the SQL statement that queries for instances based on filter parameters. You'll do that in the getFilteredContentQuery method, where you'll receive the parameters and insert them into the SQL statement you build.

    • Create an info provider class that implements FilteredContentProvider.
    • Add setters that Spring will use to inject instances your code will need.


    The following example is from the memo sample.

    • Create a filtered content info provider class that implements the interface and provides accessors for Spring-injected dependencies. Here, a CommunityManager instance will be used to retrieve community information needed to build the filter query.
     * Provides information on the memo content type's support for filtering
     * lists of content in the user interface. This class translates filter parameters
     * set by the user into an SQL query designed to return a list of memo
     * instances constrained by the parameters.
    public class MemoFilteredContentProvider implements FilteredContentProvider {
        // Field and accessors for the CommunityManager instance
        // injected by Spring.
        private ExtendedCommunityManager communityManager;  
        public void setCommunityManager(ExtendedCommunityManager communityManager) {
            this.communityManager = communityManager;
        public ExtendedCommunityManager getCommunityManager() {
            return communityManager;
        // Code follows.
    • Implement the getFilteredContentQuery method to return the filter query SQL statement. This method tests for each of the filter parameters, building the statement based on whether each exists and on their values.
     * Gets the query for filtering content, based on the context defined through values
     * in the parameter list. This method instantiates a QueryContainer by building a SQL
     * statement and adding statement argument values along the way. This makes it
     * possible to build the statement's clauses conditionally based on the context
     * values received as parameters. The resulting SQL statement must be designed to
     * return four columns: objectID, objectType, modDate, and createDate. Those will be
     * used to display the list of content.
     * @param contentListFilter Parameters for filtering.
     * @param targetContainer The container in which the filter will be created.
     * @param isContainerRoot true if the container is the root; false if it isn't.
     * @return The generated query.
    public QueryContainer getFilteredContentQuery(ResultFilter contentListFilter,
        JiveContainer targetContainer, boolean isContainerRoot)
        // Find out if the user requested to filter by user, creation date range or modified date
        // range. If so, assign those values to variables. Those that have been specified
        // will be used later to build the SQL statement.
        boolean filterUser = contentListFilter.getUserID() != ResultFilter.NULL_INT;
        boolean filterCreationDate = contentListFilter.getCreationDateRangeMin() != null
                || contentListFilter.getCreationDateRangeMax() != null;
        boolean filterModifiedDate = contentListFilter.getModificationDateRangeMin() != null
                || contentListFilter.getModificationDateRangeMax() != null;
        // The container that will hold the SQL statement and parameters.
        QueryContainer query = new QueryContainer();
        // Start by selecting the columns that must be included in the returned
        // QueryContainer instance: objectID, objectType, modDate, and createDate.
        query.appendText("SELECT DISTINCT jiveMemo.memoID as objectID, ");
        query.appendText(" as objectType, jiveMemo.modificationDate as modDate,");
        query.appendText(" jiveMemo.creationDate as createDate");
        // Select from the content type's instance table.
        query.appendText(" FROM jiveMemo");
        if (!isContainerRoot && contentListFilter.isRecursive()
                && targetContainer.getObjectType() == JiveConstants.COMMUNITY)
            query.appendText(", jiveCommunity");
        // Append an innocuous WHERE clause that will work for appending AND clauses,
        // yet will work even if no AND clauses are appended.
        query.appendText(" WHERE 1=1");
        // If the current context isn't the root space, add clauses that constrain the
        // query for a sub-space.
        if (!isContainerRoot) {
            // If the filter is recursive and the filter container is a space,
            // specify this in the statement, along with left and right values.
            if (contentListFilter.isRecursive() && targetContainer.getObjectType()
                    == JiveConstants.COMMUNITY) {
                query.appendText(" AND jiveMemo.containerType = ?");
                query.appendText(" AND jiveMemo.containerID = jiveCommunity.communityID");
                int[] lftRgtValues = getCommunityManager().getLftRgtValues(targetContainer.getID());
                query.appendText(" AND jiveCommunity.lft >= ?");
                query.appendText(" AND jiveCommunity.rgt <= ?");
            // Otherwise simply specify targetContainer type and ID.
            else {
                query.appendText(" AND jiveMemo.containerType = ?");
                query.appendText(" AND jiveMemo.containerID = ?");
        // If the filter parameters specify a user to filter by, append their ID
        // as a query parameter.
        if (filterUser) {
            query.appendText(" AND jiveMemo.userID = ?");
        // If filter parameters specify a creation date range, append those parameters
        // to the SQL statement.
        if (filterCreationDate) {
            if (contentListFilter.getCreationDateRangeMin() != null) {
                query.appendText(" AND jiveMemo.creationDate >= ?");
            if (contentListFilter.getCreationDateRangeMax() != null) {
                query.appendText(" AND jiveMemo.creationDate <= ?");
        // If filter parameters specify a modification date range, append
        // the range to the query.
        if (filterModifiedDate) {
            if (contentListFilter.getModificationDateRangeMin() != null) {
                query.appendText(" AND jiveMemo.modificationDate >= ?");
            if (contentListFilter.getModificationDateRangeMax() != null) {
                query.appendText(" AND jiveMemo.modificationDate <= ?");
        return query;
    • Configure Spring to inject the dependencies you'll need.
    <bean id="memoFilteredContentProvider" class="com.jivesoftware.clearspace.plugin.test_dynamic.MemoFilteredContentProvider">
        <property name="communityManager" ref="communityManagerImpl"/>

    Signal Support for Filtering

    You can declare your content type's support for filtering by implementing the FilteredContentEnabledType, whose single method returns the info provider you've created.

    • Implement FilteredContentEnabledType, providing accessors through which Spring can inject your info provider instance and the application can retrieve the instance via your getFilteredContentProvider method.
    public class MemoObjectType implements FilteredContentEnabledType
        // Field and accessors for Spring injection and method required
        // when implementing the interface.
        private FilteredContentProvider filteredContentProvider;
        public FilteredContentProvider getFilteredContentProvider() {
            return filteredContentProvider;
        public void setFilteredContentProvider(FilteredContentProvider filteredContentProvider) {
            this.filteredContentProvider = filteredContentProvider;
        // Code omitted.
    • Configure Spring to inject the info provider instance.
    <bean id="memoObjectType" class="com.jivesoftware.clearspace.plugin.test_dynamic.MemoObjectType">
        <property name="filteredContentProvider" ref="memoFilteredContentProvider"/>