org.sakaiproject.nakamura.files.search.AbstractContentSearchQueryHandler.java Source code

Java tutorial

Introduction

Here is the source code for org.sakaiproject.nakamura.files.search.AbstractContentSearchQueryHandler.java

Source

/*
 * Licensed to the Sakai Foundation (SF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The SF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 */
package org.sakaiproject.nakamura.files.search;

import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Reference;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.commons.json.JSONException;
import org.apache.sling.commons.json.io.JSONWriter;
import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.params.GroupParams;
import org.sakaiproject.nakamura.api.files.FileUtils;
import org.sakaiproject.nakamura.api.lite.Repository;
import org.sakaiproject.nakamura.api.lite.Session;
import org.sakaiproject.nakamura.api.lite.StorageClientException;
import org.sakaiproject.nakamura.api.lite.accesscontrol.AccessDeniedException;
import org.sakaiproject.nakamura.api.lite.content.Content;
import org.sakaiproject.nakamura.api.search.solr.DomainObjectSearchQueryHandler;
import org.sakaiproject.nakamura.api.search.solr.Query;
import org.sakaiproject.nakamura.api.search.solr.Result;
import org.sakaiproject.nakamura.api.search.solr.SolrSearchException;
import org.sakaiproject.nakamura.api.search.solr.SolrSearchPropertyProvider;
import org.sakaiproject.nakamura.api.search.solr.SolrSearchResultProcessor;
import org.sakaiproject.nakamura.api.search.solr.SolrSearchResultSet;
import org.sakaiproject.nakamura.api.search.solr.SolrSearchServiceFactory;
import org.sakaiproject.nakamura.util.ExtendedJSONWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.Map;

/**
 * Provides default functionality for pooled-content search entry-points.
 */
@Component(componentAbstract = true, inherit = true)
public abstract class AbstractContentSearchQueryHandler extends DomainObjectSearchQueryHandler
        implements SolrSearchResultProcessor, SolrSearchPropertyProvider {

    private final static Logger LOGGER = LoggerFactory.getLogger(AbstractContentSearchQueryHandler.class);

    private final static String Q_TEMPLATE = "(content:(%s) OR filename:(%<s) OR "
            + "tag:(%<s) OR description:(%<s) OR ngram:(%<s) OR edgengram:(%<s) OR widgetdata:(%<s))";

    public enum REQUEST_PARAMETERS {
        q, mimetype, levels, userid, role
    }

    @Reference
    protected Repository repository;

    public AbstractContentSearchQueryHandler() {

    }

    public AbstractContentSearchQueryHandler(SolrSearchServiceFactory searchServiceFactory, Repository repository) {
        super(searchServiceFactory);
        this.repository = repository;
    }

    /**
     * {@inheritDoc}
     * @see org.sakaiproject.nakamura.api.search.solr.DomainObjectSearchQueryHandler#getResourceTypeClause(java.util.Map)
     */
    @Override
    public String getResourceTypeClause(Map<String, String> parametersMap) {
        /*
         * If there is a query string parameter 'q', then we need to search widget data content
         * for that match as well.
         */
        if (hasGeneralQuery(parametersMap)) {
            return "resourceType:(sakai\\/pooled-content OR sakai\\/widget-data)";
        } else {
            return "resourceType:sakai\\/pooled-content";
        }
    }

    /**
     * {@inheritDoc}
     * @see org.sakaiproject.nakamura.api.search.solr.DomainObjectSearchQueryHandler#refineQuery(java.util.Map, org.sakaiproject.nakamura.api.search.solr.Query)
     */
    @Override
    public void refineQuery(Map<String, String> parametersMap, Query query) {
        query.getOptions().put(CommonParams.FL, "path");

        /*
         * If there is a query string 'q' specified, then we will also need to search on
         * widget data contents. Because of this, to avoid duplicate content (e.g, multiple
         * widgets of a pooled content item match on the content), we need to group by the
         * widget content "returnpath". See also the #getResourceTypeClause(Map) method to
         * see how the widget data resourceType is dynamically included in the query.
         */
        if (hasGeneralQuery(parametersMap)) {
            query.getOptions().put(GroupParams.GROUP, Boolean.TRUE);
            query.getOptions().put(GroupParams.GROUP_FIELD, "returnpath");

            // record the number "groups" matched to give accurate total of elements
            // returned. Here, one GROUP is one actual result, instead of all the
            // identical elements aggregated in those groups.
            query.getOptions().put(GroupParams.GROUP_TOTAL_COUNT, Boolean.TRUE);
        }
    }

    /**
     * {@inheritDoc}
     * @see org.sakaiproject.nakamura.api.search.solr.DomainObjectSearchQueryHandler#getSearchResultSet(org.apache.sling.api.SlingHttpServletRequest, org.sakaiproject.nakamura.api.search.solr.Query)
     */
    @Override
    public SolrSearchResultSet getSearchResultSet(SlingHttpServletRequest request, Query query)
            throws SolrSearchException {
        LOGGER.debug("Input Query configuration = {}", query);
        Map<String, String> parametersMap = loadParametersMap(request);
        configureQuery(parametersMap, query);
        return searchServiceFactory.getSearchResultSet(request, query);
    }

    /**
     * {@inheritDoc}
     * @see org.sakaiproject.nakamura.api.search.solr.DomainObjectSearchQueryHandler#writeResult(org.sakaiproject.nakamura.api.lite.Session, java.util.Map, org.apache.sling.commons.json.io.JSONWriter, org.sakaiproject.nakamura.api.search.solr.Result)
     */
    @Override
    public void writeResult(Session session, Map<String, String> parametersMap, JSONWriter jsonWriter,
            Result result) throws JSONException {
        String path = result.getPath();
        Content content;
        try {
            content = session.getContentManager().get(path);
            if (content != null) {
                jsonWriter.object();
                int traversalDepth = 0;
                if (parametersMap.containsKey(REQUEST_PARAMETERS_PROPS._traversalDepth.toString())) {
                    String traversalDepthValue = parametersMap
                            .get(REQUEST_PARAMETERS_PROPS._traversalDepth.toString());
                    try {
                        traversalDepth = Integer.parseInt(traversalDepthValue);
                    } catch (NumberFormatException e) {
                        LOGGER.error(e.getMessage(), e);
                    }
                }
                ExtendedJSONWriter.writeContentTreeToWriter(jsonWriter, content, true, traversalDepth);
                FileUtils.writeCommentCountProperty(content, session, jsonWriter);
                jsonWriter.endObject();
            }
        } catch (StorageClientException e) {
            LOGGER.error(e.getMessage(), e);
        } catch (AccessDeniedException e) {
            LOGGER.error(e.getMessage(), e);
        }
    }

    /**
     * Determine whether or not general text is being queried on in this search (i.e., a 'q'
     * query string parameters was provided).
     * 
     * @param parametersMap
     * @return
     */
    protected boolean hasGeneralQuery(Map<String, String> parametersMap) {
        return getSearchParam(parametersMap, REQUEST_PARAMETERS.q.toString()) != null;
    }

    /**
     * Apply the 'search by mimetype' filter to the lucene query string.
     * @param parametersMap
     * @param queryString
     */
    protected void buildSearchByMimetype(Map<String, String> parametersMap, List<String> filters) {
        String mimeType = getSearchParam(parametersMap, REQUEST_PARAMETERS.mimetype.toString());
        if (mimeType != null) {
            filters.add(String.format("mimeType:%s", mimeType));
        }
    }

    /**
     * Apply the 'search by general text' filter to the lucene query string.
     * 
     * @param parametersMap
     * @param queryString
     */
    protected void buildSearchByGeneralQuery(Map<String, String> parametersMap, List<String> filters) {
        String q = getSearchParam(parametersMap, REQUEST_PARAMETERS.q.toString());
        if (q != null) {
            filters.add(String.format(Q_TEMPLATE, q));
        }
    }

}