Dashboard > Community Wiki > ... > Developing with Magnolia > Limiting number of search results with simpleSearch
Limiting number of search results with simpleSearch Log In View a printable version of the current page.

Added by Jason Groves , last edited by Ruben Reusser on Aug 12, 2008  (view change)
Labels: 
(None)

This code snippet shows how to modify the cmsu:simpleSearch tag to allow for a limit on the number of results.  int page should be set > 0 and represents where in the query the results will be taken from.

This approach has been taken due to the fact that JCR (JSR-170) does not support query result paging but Jackrabbit does starting with version 1.4. A different approach may be needed for CRX.

Code:

private String itemType = info.magnolia.cms.core.ItemType.CONTENT.getSystemName();

    public int doStartTag() throws javax.servlet.jsp.JspException {
        String queryString = generateXPathQuery();

        if (queryString == null) {
            if (log.isDebugEnabled()) {
                log.debug("A valid query could not be built, skipping"); //$NON-NLS-1$
            }
            return EVAL_PAGE;
        }

        if (log.isDebugEnabled()) {
            log.debug("Executing xpath query " + queryString); //$NON-NLS-1$
        }

        org.apache.jackrabbit.core.query.QueryImpl q;
        try {
            // Cheating way of getting the query done
            info.magnolia.cms.core.search.QueryManager manager = info.magnolia.context.MgnlContext.getQueryManager(repository);
            Class managerClass = manager.getClass();
            java.lang.reflect.Field field = managerClass.getDeclaredField("queryManager");
            field.setAccessible(true);
            javax.jcr.query.QueryManager jcrManager = (javax.jcr.query.QueryManager) field.get(manager);
            q = (org.apache.jackrabbit.core.query.QueryImpl) jcrManager.createQuery(queryString, "xpath");
            q.setLimit(10);
            q.setOffset((page-1)*10);
            field = managerClass.getDeclaredField("accessManager");
            field.setAccessible(true);
            info.magnolia.cms.security.AccessManager accessManager = (info.magnolia.cms.security.AccessManager) field.get(manager);
            javax.jcr.query.QueryResult result = q.execute();
            java.util.Map objectStore = new java.util.Hashtable();
            java.util.Map dirtyHandles = new java.util.Hashtable();

            java.util.Collection resultSet = (java.util.Collection) objectStore.get(itemType);
            if (resultSet == null) {
                /* build it first time */
                resultSet = new java.util.ArrayList();
                try {
                    build(itemType, resultSet, objectStore, result, dirtyHandles, accessManager);
                }
                catch (javax.jcr.RepositoryException re) {
                    log.error(re.getMessage());
                }
            }

            pageContext.setAttribute(var, resultSet, scope);
        }
        catch (Exception e) {
            log.error(java.text.MessageFormat.format(
                "{0} caught while parsing query for search term [{1}] - query is [{2}]: {3}", //$NON-NLS-1$
                new Object[]{e.getClass().getName(), this.query, queryString, e.getMessage()}), e);
        }

        return EVAL_PAGE;
    }

    private void build(String nodeType, java.util.Collection collection, java.util.Map objectStore,
    		javax.jcr.query.QueryResult result, java.util.Map dirtyHandles,
    		info.magnolia.cms.security.AccessManager accessManager) throws javax.jcr.RepositoryException {
        objectStore.put(nodeType, collection);
        javax.jcr.NodeIterator nodeIterator = result.getNodes();
        while (nodeIterator.hasNext()) {
        	javax.jcr.Node node = nodeIterator.nextNode();
            try {
                build(node, nodeType, collection, dirtyHandles, accessManager);
            }
            catch (javax.jcr.RepositoryException re) {
                log.error("{} caught while iterating on query results: {}", re.getClass().getName(), re.getMessage());
                if (log.isDebugEnabled()) {
                    log.debug(
                        re.getClass().getName() + " caught while iterating on query results: " + re.getMessage(),
                        re);
                }
            }
        }
    }

    private void build(javax.jcr.Node node, String nodeType, java.util.Collection collection, java.util.Map dirtyHandles,
    		info.magnolia.cms.security.AccessManager accessManager) throws javax.jcr.RepositoryException {
        if ((node.isNodeType(nodeType) || org.apache.commons.lang.StringUtils.isEmpty(nodeType)) &&
                !node.isNodeType(info.magnolia.cms.core.ItemType.NT_RESOURCE)) {
            if (dirtyHandles.get(node.getPath()) == null) {
                boolean isAllowed = accessManager.isGranted(info.magnolia.cms.core.Path.getAbsolutePath(node.getPath()),
                        info.magnolia.cms.security.Permission.READ);
                if (isAllowed) {
                    collection.add(new info.magnolia.cms.core.DefaultContent(node, accessManager));
                    dirtyHandles.put(node.getPath(), org.apache.commons.lang.StringUtils.EMPTY);
                }
            }
            return;
        }
        if (node.getDepth() > 0) {
            build(node.getParent(), nodeType, collection, dirtyHandles, accessManager);
        }
    }

Thanks Jason, but why not patch QueryManager to allow passing of limit and offset parameters, and use it proper in the tag? (and in turn, reporting this in Jira along with patches, which will benefit everyone without the need to resort to hackery)

I like Jason's approach - the JCR does not support paging for the queries, Jackrabbit started supporting it with release 1.4 (older releases do not support it). Different implementations may be needed if one opts for CRX as a repository.

What I meant was patching info.magnolia.cms.core.search.QueryManager, which is just a wrapper around jcr

Since the JCR does not support the paging you would have to do it per implementation - note that the class org.apache.jackrabbit.core.query.QueryImpl - the Query interface does not support the paging.

oh, right, I hadn't noticed this was hacking into jackrabbit's QueryImpl class.

Powered by a free Atlassian Confluence Open Source Project License granted to Magnolia International. Evaluate Confluence today.
Powered by Atlassian Confluence 2.7, the Enterprise Wiki. Bug/feature request - Atlassian news - Contact administrators