org.dspace.app.webui.discovery.DiscoverySearchRequestProcessor.java Source code

Java tutorial

Introduction

Here is the source code for org.dspace.app.webui.discovery.DiscoverySearchRequestProcessor.java

Source

/**
 * The contents of this file are subject to the license and copyright
 * detailed in the LICENSE and NOTICE files at the root of the source
 * tree and available online at
 *
 * http://www.dspace.org/license/
 */
package org.dspace.app.webui.discovery;

import java.io.IOException;
import java.io.PrintWriter;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.dspace.app.bulkedit.DSpaceCSV;
import org.dspace.app.bulkedit.MetadataExport;
import org.dspace.app.util.OpenSearch;
import org.dspace.app.util.SyndicationFeed;
import org.dspace.app.webui.search.SearchProcessorException;
import org.dspace.app.webui.search.SearchRequestProcessor;
import org.dspace.app.webui.util.JSPManager;
import org.dspace.app.webui.util.UIUtil;
import org.dspace.authorize.AuthorizeManager;
import org.dspace.content.Collection;
import org.dspace.content.Community;
import org.dspace.content.DSpaceObject;
import org.dspace.content.Item;
import org.dspace.content.ItemIterator;
import org.dspace.core.ConfigurationManager;
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.dspace.core.I18nUtil;
import org.dspace.core.LogManager;
import org.dspace.discovery.DiscoverQuery;
import org.dspace.discovery.DiscoverResult;
import org.dspace.discovery.SearchServiceException;
import org.dspace.discovery.SearchUtils;
import org.dspace.discovery.configuration.DiscoveryConfiguration;
import org.dspace.discovery.configuration.DiscoverySearchFilter;
import org.dspace.discovery.configuration.DiscoverySearchFilterFacet;
import org.dspace.discovery.configuration.DiscoverySortFieldConfiguration;
import org.w3c.dom.Document;

public class DiscoverySearchRequestProcessor implements SearchRequestProcessor {
    private static final int ITEMMAP_RESULT_PAGE_SIZE = 50;

    private static String msgKey = "org.dspace.app.webui.servlet.FeedServlet";

    /** log4j category */
    private static Logger log = Logger.getLogger(DiscoverySearchRequestProcessor.class);

    // locale-sensitive metadata labels
    private Map<String, Map<String, String>> localeLabels = null;

    private List<String> searchIndices = null;

    public synchronized void init() {
        if (localeLabels == null) {
            localeLabels = new HashMap<String, Map<String, String>>();
        }

        if (searchIndices == null) {
            searchIndices = new ArrayList<String>();
            DiscoveryConfiguration discoveryConfiguration = SearchUtils.getDiscoveryConfiguration();
            searchIndices.add("any");
            for (DiscoverySearchFilter sFilter : discoveryConfiguration.getSearchFilters()) {
                searchIndices.add(sFilter.getIndexFieldName());
            }
        }
    }

    public void doOpenSearch(Context context, HttpServletRequest request, HttpServletResponse response)
            throws SearchProcessorException, IOException, ServletException {
        init();

        // dispense with simple service document requests
        String scope = request.getParameter("scope");
        if (scope != null && "".equals(scope)) {
            scope = null;
        }
        String path = request.getPathInfo();
        if (path != null && path.endsWith("description.xml")) {
            String svcDescrip = OpenSearch.getDescription(scope);
            response.setContentType(OpenSearch.getContentType("opensearchdescription"));
            response.setContentLength(svcDescrip.length());
            response.getWriter().write(svcDescrip);
            return;
        }

        // get enough request parameters to decide on action to take
        String format = request.getParameter("format");
        if (format == null || "".equals(format)) {
            // default to atom
            format = "atom";
        }

        // do some sanity checking
        if (!OpenSearch.getFormats().contains(format)) {
            response.sendError(HttpServletResponse.SC_BAD_REQUEST);
            return;
        }

        // then the rest - we are processing the query
        DSpaceObject container;
        try {
            container = DiscoverUtility.getSearchScope(context, request);
        } catch (Exception e) {
            throw new SearchProcessorException(e.getMessage(), e);
        }
        DiscoverQuery queryArgs = DiscoverUtility.getDiscoverQuery(context, request, container, false);
        String query = queryArgs.getQuery();

        // Perform the search
        DiscoverResult qResults = null;
        try {
            qResults = SearchUtils.getSearchService().search(context, container, queryArgs);
        } catch (SearchServiceException e) {
            log.error(LogManager.getHeader(context, "opensearch",
                    "query=" + queryArgs.getQuery() + ",scope=" + scope + ",error=" + e.getMessage()), e);
            throw new RuntimeException(e.getMessage(), e);
        }

        // Log
        log.info(LogManager.getHeader(context, "opensearch",
                "scope=" + scope + ",query=\"" + query + "\",results=(" + qResults.getTotalSearchResults() + ")"));

        // format and return results
        Map<String, String> labelMap = getLabels(request);
        DSpaceObject[] dsoResults = new DSpaceObject[qResults.getDspaceObjects().size()];
        qResults.getDspaceObjects().toArray(dsoResults);
        Document resultsDoc = OpenSearch.getResultsDoc(format, query, (int) qResults.getTotalSearchResults(),
                qResults.getStart(), qResults.getMaxResults(), container, dsoResults, labelMap);
        try {
            Transformer xf = TransformerFactory.newInstance().newTransformer();
            response.setContentType(OpenSearch.getContentType(format));
            xf.transform(new DOMSource(resultsDoc), new StreamResult(response.getWriter()));
        } catch (TransformerException e) {
            log.error(e);
            throw new ServletException(e.toString());
        }
    }

    private Map<String, String> getLabels(HttpServletRequest request) {
        // Get access to the localized resource bundle
        Locale locale = UIUtil.getSessionLocale(request);
        Map<String, String> labelMap = localeLabels.get(locale.toString());
        if (labelMap == null) {
            labelMap = getLocaleLabels(locale);
            localeLabels.put(locale.toString(), labelMap);
        }
        return labelMap;
    }

    private Map<String, String> getLocaleLabels(Locale locale) {
        Map<String, String> labelMap = new HashMap<String, String>();
        labelMap.put(SyndicationFeed.MSG_UNTITLED, I18nUtil.getMessage(msgKey + ".notitle", locale));
        labelMap.put(SyndicationFeed.MSG_LOGO_TITLE, I18nUtil.getMessage(msgKey + ".logo.title", locale));
        labelMap.put(SyndicationFeed.MSG_FEED_DESCRIPTION,
                I18nUtil.getMessage(msgKey + ".general-feed.description", locale));
        labelMap.put(SyndicationFeed.MSG_UITYPE, SyndicationFeed.UITYPE_JSPUI);
        for (String selector : SyndicationFeed.getDescriptionSelectors()) {
            labelMap.put("metadata." + selector,
                    I18nUtil.getMessage(SyndicationFeed.MSG_METADATA + selector, locale));
        }
        return labelMap;
    }

    public void doSimpleSearch(Context context, HttpServletRequest request, HttpServletResponse response)
            throws SearchProcessorException, IOException, ServletException {
        Item[] resultsItems;
        Collection[] resultsCollections;
        Community[] resultsCommunities;
        DSpaceObject scope;
        try {
            scope = DiscoverUtility.getSearchScope(context, request);
        } catch (IllegalStateException e) {
            throw new SearchProcessorException(e.getMessage(), e);
        } catch (SQLException e) {
            throw new SearchProcessorException(e.getMessage(), e);
        }

        DiscoveryConfiguration discoveryConfiguration = SearchUtils.getDiscoveryConfiguration(scope);
        List<DiscoverySortFieldConfiguration> sortFields = discoveryConfiguration.getSearchSortConfiguration()
                .getSortFields();
        List<String> sortOptions = new ArrayList<String>();
        for (DiscoverySortFieldConfiguration sortFieldConfiguration : sortFields) {
            String sortField = SearchUtils.getSearchService()
                    .toSortFieldIndex(sortFieldConfiguration.getMetadataField(), sortFieldConfiguration.getType());
            sortOptions.add(sortField);
        }
        request.setAttribute("sortOptions", sortOptions);

        DiscoverQuery queryArgs = DiscoverUtility.getDiscoverQuery(context, request, scope, true);

        queryArgs.setSpellCheck(discoveryConfiguration.isSpellCheckEnabled());

        List<DiscoverySearchFilterFacet> availableFacet = discoveryConfiguration.getSidebarFacets();

        request.setAttribute("facetsConfig",
                availableFacet != null ? availableFacet : new ArrayList<DiscoverySearchFilterFacet>());
        int etal = UIUtil.getIntParameter(request, "etal");
        if (etal == -1) {
            etal = ConfigurationManager.getIntProperty("webui.itemlist.author-limit");
        }

        request.setAttribute("etal", etal);

        String query = queryArgs.getQuery();
        request.setAttribute("query", query);
        request.setAttribute("queryArgs", queryArgs);
        List<DiscoverySearchFilter> availableFilters = discoveryConfiguration.getSearchFilters();
        request.setAttribute("availableFilters", availableFilters);

        List<String[]> appliedFilters = DiscoverUtility.getFilters(request);
        request.setAttribute("appliedFilters", appliedFilters);
        List<String> appliedFilterQueries = new ArrayList<String>();
        for (String[] filter : appliedFilters) {
            appliedFilterQueries.add(filter[0] + "::" + filter[1] + "::" + filter[2]);
        }
        request.setAttribute("appliedFilterQueries", appliedFilterQueries);
        List<DSpaceObject> scopes = new ArrayList<DSpaceObject>();
        if (scope == null) {
            Community[] topCommunities;
            try {
                topCommunities = Community.findAllTop(context);
            } catch (SQLException e) {
                throw new SearchProcessorException(e.getMessage(), e);
            }
            for (Community com : topCommunities) {
                scopes.add(com);
            }
        } else {
            try {
                DSpaceObject pDso = scope.getParentObject();
                while (pDso != null) {
                    // add to the available scopes in reverse order
                    scopes.add(0, pDso);
                    pDso = pDso.getParentObject();
                }
                scopes.add(scope);
                if (scope instanceof Community) {
                    Community[] comms = ((Community) scope).getSubcommunities();
                    for (Community com : comms) {
                        scopes.add(com);
                    }
                    Collection[] colls = ((Community) scope).getCollections();
                    for (Collection col : colls) {
                        scopes.add(col);
                    }
                }
            } catch (SQLException e) {
                throw new SearchProcessorException(e.getMessage(), e);
            }
        }
        request.setAttribute("scope", scope);
        request.setAttribute("scopes", scopes);

        // Perform the search
        DiscoverResult qResults = null;
        try {
            qResults = SearchUtils.getSearchService().search(context, scope, queryArgs);

            List<Community> resultsListComm = new ArrayList<Community>();
            List<Collection> resultsListColl = new ArrayList<Collection>();
            List<Item> resultsListItem = new ArrayList<Item>();

            for (DSpaceObject dso : qResults.getDspaceObjects()) {
                if (dso instanceof Item) {
                    resultsListItem.add((Item) dso);
                } else if (dso instanceof Collection) {
                    resultsListColl.add((Collection) dso);

                } else if (dso instanceof Community) {
                    resultsListComm.add((Community) dso);
                }
            }

            // Make objects from the handles - make arrays, fill them out
            resultsCommunities = new Community[resultsListComm.size()];
            resultsCollections = new Collection[resultsListColl.size()];
            resultsItems = new Item[resultsListItem.size()];

            resultsCommunities = resultsListComm.toArray(resultsCommunities);
            resultsCollections = resultsListColl.toArray(resultsCollections);
            resultsItems = resultsListItem.toArray(resultsItems);

            // Log
            log.info(LogManager.getHeader(context, "search",
                    "scope=" + scope + ",query=\"" + query + "\",results=(" + resultsCommunities.length + ","
                            + resultsCollections.length + "," + resultsItems.length + ")"));

            // Pass in some page qualities
            // total number of pages
            long pageTotal = 1 + ((qResults.getTotalSearchResults() - 1) / qResults.getMaxResults());

            // current page being displayed
            long pageCurrent = 1 + (qResults.getStart() / qResults.getMaxResults());

            // pageLast = min(pageCurrent+3,pageTotal)
            long pageLast = ((pageCurrent + 3) > pageTotal) ? pageTotal : (pageCurrent + 3);

            // pageFirst = max(1,pageCurrent-3)
            long pageFirst = ((pageCurrent - 3) > 1) ? (pageCurrent - 3) : 1;

            // Pass the results to the display JSP
            request.setAttribute("items", resultsItems);
            request.setAttribute("communities", resultsCommunities);
            request.setAttribute("collections", resultsCollections);

            request.setAttribute("pagetotal", new Long(pageTotal));
            request.setAttribute("pagecurrent", new Long(pageCurrent));
            request.setAttribute("pagelast", new Long(pageLast));
            request.setAttribute("pagefirst", new Long(pageFirst));
            request.setAttribute("spellcheck", qResults.getSpellCheckQuery());

            request.setAttribute("queryresults", qResults);

            try {
                if (AuthorizeManager.isAdmin(context)) {
                    // Set a variable to create admin buttons
                    request.setAttribute("admin_button", new Boolean(true));
                }
            } catch (SQLException e) {
                throw new SearchProcessorException(e.getMessage(), e);
            }

            if ("submit_export_metadata".equals(UIUtil.getSubmitButton(request, "submit"))) {
                exportMetadata(context, response, resultsItems);
            }
        } catch (SearchServiceException e) {
            log.error(LogManager.getHeader(context, "search",
                    "query=" + queryArgs.getQuery() + ",scope=" + scope + ",error=" + e.getMessage()), e);
            request.setAttribute("search.error", true);
            request.setAttribute("search.error.message", e.getMessage());
        }

        JSPManager.showJSP(request, response, "/search/discovery.jsp");
    }

    /**
     * Export the search results as a csv file
     * 
     * @param context
     *            The DSpace context
     * @param response
     *            The request object
     * @param items
     *            The result items
     * @throws IOException
     * @throws ServletException
     */
    protected void exportMetadata(Context context, HttpServletResponse response, Item[] items)
            throws IOException, ServletException {
        // Log the attempt
        log.info(LogManager.getHeader(context, "metadataexport", "exporting_search"));

        // Export a search view
        ArrayList iids = new ArrayList();
        for (Item item : items) {
            iids.add(item.getID());
        }
        ItemIterator ii = new ItemIterator(context, iids);
        MetadataExport exporter = new MetadataExport(context, ii, false);

        // Perform the export
        DSpaceCSV csv = exporter.export();

        // Return the csv file
        response.setContentType("text/csv; charset=UTF-8");
        response.setHeader("Content-Disposition", "attachment; filename=search-results.csv");
        PrintWriter out = response.getWriter();
        out.write(csv.toString());
        out.flush();
        out.close();
        log.info(LogManager.getHeader(context, "metadataexport", "exported_file:search-results.csv"));
        return;
    }

    /**
     * Method for constructing the discovery advanced search form
     * 
     * author: Andrea Bollini
     */
    @Override
    public void doAdvancedSearch(Context context, HttpServletRequest request, HttpServletResponse response)
            throws SearchProcessorException, IOException, ServletException {
        // just redirect to the simple search servlet.
        // The advanced form is always displayed with Discovery togheter with
        // the search result
        // the first access to the advanced form performs a search for
        // "anythings" (SOLR *:*)
        response.sendRedirect(request.getContextPath() + "/simple-search");
    }

    /**
     * Method for searching authors in item map
     * 
     * author: gam
     */
    @Override
    public void doItemMapSearch(Context context, HttpServletRequest request, HttpServletResponse response)
            throws SearchProcessorException, ServletException, IOException {
        String queryString = (String) request.getParameter("query");
        Collection collection = (Collection) request.getAttribute("collection");
        int page = UIUtil.getIntParameter(request, "page") - 1;
        int offset = page > 0 ? page * ITEMMAP_RESULT_PAGE_SIZE : 0;
        String idx = (String) request.getParameter("index");
        if (StringUtils.isNotBlank(idx) && !idx.equalsIgnoreCase("any")) {
            queryString = idx + ":(" + queryString + ")";
        }
        DiscoverQuery query = new DiscoverQuery();
        query.setQuery(queryString);
        query.addFilterQueries("-location:l" + collection.getID());
        query.setMaxResults(ITEMMAP_RESULT_PAGE_SIZE);
        query.setStart(offset);

        DiscoverResult results = null;
        try {
            results = SearchUtils.getSearchService().search(context, query);
        } catch (SearchServiceException e) {
            throw new SearchProcessorException(e.getMessage(), e);
        }

        Map<Integer, Item> items = new HashMap<Integer, Item>();

        List<DSpaceObject> resultDSOs = results.getDspaceObjects();
        for (DSpaceObject dso : resultDSOs) {
            if (dso != null && dso.getType() == Constants.ITEM) {
                // no authorization check is required as discovery is right aware
                Item item = (Item) dso;
                items.put(Integer.valueOf(item.getID()), item);
            }
        }

        request.setAttribute("browsetext", queryString);
        request.setAttribute("items", items);
        request.setAttribute("more", results.getTotalSearchResults() > offset + ITEMMAP_RESULT_PAGE_SIZE);
        request.setAttribute("browsetype", "Add");
        request.setAttribute("page", page > 0 ? page + 1 : 1);

        JSPManager.showJSP(request, response, "itemmap-browse.jsp");
    }

    @Override
    public String getI18NKeyPrefix() {
        return "jsp.search.filter.";
    }

    @Override
    public List<String> getSearchIndices() {
        init();
        return searchIndices;
    }
}