org.gbif.portal.web.view.search.SearchWidgetController.java Source code

Java tutorial

Introduction

Here is the source code for org.gbif.portal.web.view.search.SearchWidgetController.java

Source

/***************************************************************************
 * Copyright (C) 2005 Global Biodiversity Information Facility Secretariat.  
 * All Rights Reserved.
 *
 * The contents of this file are subject to the Mozilla Public
 * License Version 1.1 (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.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * rights and limitations under the License.
 ***************************************************************************/
package org.gbif.portal.web.view.search;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.gbif.portal.dto.SearchResultsDTO;
import org.gbif.portal.dto.resources.DataProviderDTO;
import org.gbif.portal.dto.resources.DataResourceDTO;
import org.gbif.portal.dto.resources.ResourceNetworkDTO;
import org.gbif.portal.dto.taxonomy.TaxonConceptDTO;
import org.gbif.portal.dto.util.SearchConstraints;
import org.gbif.portal.service.DataResourceManager;
import org.gbif.portal.service.GeospatialManager;
import org.gbif.portal.service.TaxonomyManager;
import org.gbif.portal.web.util.QueryHelper;
import org.gbif.portal.web.view.WidgetControllerSupport;
import org.springframework.web.servlet.support.RequestContextUtils;

/**
 * Widgets for blanket search screen.
 * 
 * @author dmartin
 */
public class SearchWidgetController extends WidgetControllerSupport {

    /** Search string attribute - would ideally be spring configured but how? */
    public static final String SEARCH_STRING_ATTR = "searchString";
    public static final Integer DEFAULT_MAX_RESULTS = 10;
    public static final Integer DEFAULT_START_INDEX_RESULTS = 0;
    /** Whether to allow unconfirmed names for name resolving */
    protected boolean allowUnconfirmedNames = true;
    protected int minLengthToSort = 6;

    /**
     * Adds content for the taxon name search widget. The ordering should be like so:
     * 
     * 1. Exact scientific name match
     * 2. Exact specific epithet matches
     * 3. Other scientific name matches
     * 
     * TODO Add Scientific name parsing
     * 
     * @param request
     * @param response
     * @throws Exception
     */
    public void addTaxa(HttpServletRequest request, HttpServletResponse response) throws Exception {

        String searchString = getSearchString(request);

        TaxonomyManager taxonomyManager = (TaxonomyManager) getWebAppContext(request).getBean("taxonomyManager");
        DataResourceManager dataResourceManager = (DataResourceManager) getWebAppContext(request)
                .getBean("dataResourceManager");

        //use the nub provider
        DataProviderDTO nubProvider = dataResourceManager.getNubDataProvider();
        //use the nub resource
        DataResourceDTO nubResource = dataResourceManager.getNubDataResource();
        String providerKey = null;
        String resourceKey = null;
        if (nubProvider != null && nubProvider.getKey() != null)
            providerKey = nubProvider.getKey();
        if (nubResource != null && nubResource.getKey() != null)
            resourceKey = nubResource.getKey();

        //exact scientific name matches
        SearchResultsDTO exactTaxonMatches = taxonomyManager.findTaxonConcepts(searchString, false, null, null,
                resourceKey, null, null, RequestContextUtils.getLocale(request).getLanguage(), null,
                allowUnconfirmedNames, false, new SearchConstraints(0, 100));
        request.setAttribute("exactTaxonMatches", exactTaxonMatches);

        //exact specific epithet matches
        SearchResultsDTO exactEpithetMatches = taxonomyManager.findSpeciesConcepts(null, searchString, false, null,
                resourceKey, null, new SearchConstraints(0, 100));
        request.setAttribute("exactEpithetMatches", exactEpithetMatches);

        int matchesTotal = exactTaxonMatches.size() + exactEpithetMatches.size();
        boolean hasMore = false; //shall we provide a paging link

        SearchConstraints searchConstraints = getSearchConstraints(request);

        if (matchesTotal <= DEFAULT_MAX_RESULTS) {

            boolean sortAlpha = false;
            if (searchString != null && searchString.length() > minLengthToSort) {
                sortAlpha = true;
            }

            //exact scientific name matches
            SearchResultsDTO fuzzyTaxonMatches = taxonomyManager.findTaxonConcepts(searchString, true, null, null,
                    resourceKey, null, null, RequestContextUtils.getLocale(request).getLanguage(), null,
                    allowUnconfirmedNames, sortAlpha, searchConstraints);
            //remove the exact matches
            for (Object exactMatch : exactTaxonMatches) {
                if (fuzzyTaxonMatches.contains(exactMatch))
                    fuzzyTaxonMatches.remove(exactMatch);
            }
            request.setAttribute("fuzzyTaxonMatches", fuzzyTaxonMatches);
            matchesTotal += fuzzyTaxonMatches.size();
            hasMore = fuzzyTaxonMatches.hasMoreResults();
        } else {
            hasMore = true;
        }

        // if there are still no results, then try a soundex
        if (matchesTotal == 0) {
            logger.debug("No names found, trying the SoundEx search");
            SearchResultsDTO soundExMatches = taxonomyManager.findMatchingScientificNames(searchString, true, null,
                    null, true, null, resourceKey, true, new SearchConstraints(0, DEFAULT_MAX_RESULTS));
            request.setAttribute("soundexNameMatches", soundExMatches);
            matchesTotal = soundExMatches.size();
            // it's just a suggestion list so no need for paging
            hasMore = false;
        }

        if (matchesTotal == 0) {
            //match on remote concept ids
            List<TaxonConceptDTO> taxonConcepts = taxonomyManager.getTaxonConceptForRemoteId(searchString);
            request.setAttribute("remoteConceptMatches", taxonConcepts);
        }

        request.setAttribute("moreTaxaMatches", hasMore);
    }

    /**
     * Adds the content for the common names widget. The ordering should be like so:
     * 
     * 1. Common names starting with search string
     * 2. Common names with other words starting with search string (e.g. return "African Elephant" if user searches for "elephant")
     * 
     * @param request
     * @param response
     * @throws Exception
     */
    public void addCommonNames(HttpServletRequest request, HttpServletResponse response) throws Exception {
        String searchString = getSearchString(request);
        TaxonomyManager taxonomyManager = (TaxonomyManager) getWebAppContext(request).getBean("taxonomyManager");

        boolean hasMore = false;

        //get exact common name matches - show all exact matches
        SearchResultsDTO exactCommonNameMatches = taxonomyManager.findTaxonConceptsForCommonName(searchString,
                false, new SearchConstraints(0, 100));
        request.setAttribute("exactCommonNameMatches", exactCommonNameMatches);

        //get fuzzy matches
        SearchConstraints searchConstraints = getSearchConstraints(request);
        searchConstraints.setMaxResults(searchConstraints.getMaxResults() + exactCommonNameMatches.size());
        SearchResultsDTO fuzzyCommonNameMatches = taxonomyManager.findTaxonConceptsForCommonName(searchString, true,
                searchConstraints);
        //remove duplicate matches
        for (Object exactMatch : exactCommonNameMatches) {
            if (fuzzyCommonNameMatches.contains(exactMatch))
                fuzzyCommonNameMatches.remove(exactMatch);
        }
        request.setAttribute("fuzzyCommonNameMatches", fuzzyCommonNameMatches);
        if (fuzzyCommonNameMatches.hasMoreResults())
            hasMore = true;

        //get ending with matches
        //TODO this could be very slow - may require a db change with the splitting out of common name
        searchConstraints.setMaxResults(searchConstraints.getMaxResults() + exactCommonNameMatches.size());
        SearchResultsDTO endingWithCommonNameMatches = taxonomyManager
                .findTaxonConceptsForCommonName("% " + searchString, true, searchConstraints);
        request.setAttribute("endingWithCommonNameMatches", endingWithCommonNameMatches);
        if (endingWithCommonNameMatches.hasMoreResults())
            hasMore = true;

        //indicate if paging is required
        request.setAttribute("moreCommonNameMatches", hasMore);
    }

    /**
     * Adds the content for the countries widget.
     * 
     * @param request
     * @param response
     * @throws Exception
     */
    public void addCountries(HttpServletRequest request, HttpServletResponse response) throws Exception {
        String searchString = getSearchString(request);
        GeospatialManager geospatialManager = (GeospatialManager) getWebAppContext(request)
                .getBean("geospatialManager");
        Locale locale = RequestContextUtils.getLocale(request);
        SearchResultsDTO geospatialMatches = geospatialManager.findCountries(searchString, true, true, false,
                locale, getSearchConstraints(request));
        request.setAttribute("countryMatches", geospatialMatches);
        request.setAttribute("moreCountryMatches", geospatialMatches.hasMoreResults());
    }

    /**
     * Adds the content for the Datasets widget.
     * 
     * @param request
     * @param response
     * @throws Exception
     */
    @SuppressWarnings("unchecked")
    public void addDatasets(HttpServletRequest request, HttpServletResponse response) throws Exception {
        String searchString = getSearchString(request);
        DataResourceManager dataResourceManager = (DataResourceManager) getWebAppContext(request)
                .getBean("dataResourceManager");

        SearchResultsDTO resourceResultsDTO = dataResourceManager.findDatasets(searchString, true, true, true,
                getSearchConstraints(request));
        //split into 3 lists - providers and resources
        List<Object> resourceMatches = resourceResultsDTO.getResults();
        List<DataProviderDTO> providers = new ArrayList<DataProviderDTO>();
        List<DataResourceDTO> resources = new ArrayList<DataResourceDTO>();
        List<ResourceNetworkDTO> networks = new ArrayList<ResourceNetworkDTO>();

        for (Object resourceMatch : resourceMatches) {
            if (resourceMatch instanceof DataResourceDTO)
                resources.add((DataResourceDTO) resourceMatch);
            if (resourceMatch instanceof DataProviderDTO)
                providers.add((DataProviderDTO) resourceMatch);
            if (resourceMatch instanceof ResourceNetworkDTO)
                networks.add((ResourceNetworkDTO) resourceMatch);
        }
        request.setAttribute("datasetMatches", resourceResultsDTO);
        request.setAttribute("dataProviders", providers);
        request.setAttribute("dataResources", resources);
        request.setAttribute("resourceNetworks", networks);

        request.setAttribute("moreDatasetMatches", resourceResultsDTO.hasMoreResults());
    }

    /**
     * Replaces wildcard with supported service layer wildcard
     * 
     * @param request
     * @return
     */
    public String getSearchString(HttpServletRequest request) {
        String searchString = (String) request.getAttribute(SEARCH_STRING_ATTR);
        if (StringUtils.isNotEmpty(searchString)) {
            try {
                searchString = URLDecoder.decode(searchString, "UTF-8");
                request.setAttribute(SEARCH_STRING_ATTR, searchString);
                searchString = QueryHelper.tidyValue(searchString);
            } catch (UnsupportedEncodingException e) {
                logger.debug(e.getMessage(), e);
            }
            searchString = searchString.replace('*', '%');
        }
        if (logger.isDebugEnabled())
            logger.debug("search string: " + searchString);
        return searchString;
    }

    /**
     * Creates search constraints based on the request.
     * 
     * @param request
     * @return SearchConstraints
     */
    public SearchConstraints getSearchConstraints(HttpServletRequest request) {
        String maxResultsAsString = (String) request.getAttribute("maxResults");
        Integer maxResults = null;
        if (StringUtils.isNotEmpty(maxResultsAsString)) {
            try {
                maxResults = Integer.parseInt(maxResultsAsString);
            } catch (NumberFormatException e) {
                logger.debug(e);
            }
        }
        if (maxResults == null)
            maxResults = DEFAULT_MAX_RESULTS;
        String startIndexAsString = (String) request.getAttribute("startIndex");
        Integer startIndex = null;
        if (StringUtils.isNotEmpty(startIndexAsString)) {
            try {
                startIndex = Integer.parseInt(startIndexAsString);
            } catch (NumberFormatException e) {
                logger.debug(e);
            }
        }
        if (startIndex == null)
            startIndex = DEFAULT_START_INDEX_RESULTS;

        return new SearchConstraints(startIndex, maxResults);
    }

    /**
     * @param minLengthToSort the minLengthToSort to set
     */
    public void setMinLengthToSort(int minLengthToSort) {
        this.minLengthToSort = minLengthToSort;
    }
}