org.gbif.portal.web.controller.occurrence.OccurrenceFilterController.java Source code

Java tutorial

Introduction

Here is the source code for org.gbif.portal.web.controller.occurrence.OccurrenceFilterController.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.controller.occurrence;

import org.gbif.portal.dto.CountDTO;
import org.gbif.portal.dto.PropertyStoreTripletDTO;
import org.gbif.portal.dto.SearchResultsDTO;
import org.gbif.portal.dto.geospatial.CellDensityDTO;
import org.gbif.portal.dto.geospatial.CountryDTO;
import org.gbif.portal.dto.resources.DataProviderDTO;
import org.gbif.portal.dto.resources.DataResourceDTO;
import org.gbif.portal.dto.util.BoundingBoxDTO;
import org.gbif.portal.dto.util.EntityType;
import org.gbif.portal.dto.util.SearchConstraints;
import org.gbif.portal.service.DataResourceManager;
import org.gbif.portal.service.GeospatialManager;
import org.gbif.portal.service.ServiceException;
import org.gbif.portal.service.TaxonomyManager;
import org.gbif.portal.service.triplet.TripletQueryManager;
import org.gbif.portal.util.geospatial.CellIdUtils;
import org.gbif.portal.util.geospatial.LatLongBoundingBox;
import org.gbif.portal.util.propertystore.PropertyStore;
import org.gbif.portal.web.content.filter.FilterContentProvider;
import org.gbif.portal.web.content.filter.PagingTripletQueryProvider;
import org.gbif.portal.web.content.geospatial.BoundingBoxFilterHelper;
import org.gbif.portal.web.content.map.MapContentProvider;
import org.gbif.portal.web.download.Field;
import org.gbif.portal.web.filter.CriteriaDTO;
import org.gbif.portal.web.filter.CriteriaUtil;
import org.gbif.portal.web.filter.CriterionDTO;
import org.gbif.portal.web.filter.FilterDTO;
import org.gbif.portal.web.filter.FilterMapWrapper;
import org.gbif.portal.web.filter.FilterUtils;
import org.gbif.portal.web.util.QueryHelper;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.List;
import java.util.Locale;

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

import net.sibcolombia.portal.service.DepartmentManager;
import org.apache.commons.lang.StringUtils;
import org.springframework.context.MessageSource;
import org.springframework.web.bind.ServletRequestUtils;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.multiaction.MultiActionController;
import org.springframework.web.servlet.mvc.multiaction.NoSuchRequestHandlingMethodException;
import org.springframework.web.servlet.support.RequestContextUtils;
import org.springframework.web.servlet.view.RedirectView;

/**
 * Controller for Filter queries. The Controller is responsible for retrieving
 * the search criteria from the request, executing the query and then sending
 * results to the correct view.
 * 
 * @author dmartin
 */
public class OccurrenceFilterController extends MultiActionController {

    /** The property store to use to produce the queries */
    protected PropertyStore webappPropertyStore;
    /** The property store namespace to use to produce the queries */
    protected String namespace;

    /** Query helper used to produce triplets from urls strings */
    protected QueryHelper queryHelper;

    /** Service managers */
    protected TripletQueryManager tripletQueryManager;
    protected TripletQueryManager countsQueryManager;
    protected TripletQueryManager mapLayerQueryManager;
    protected GeospatialManager geospatialManager;
    protected DepartmentManager departmentManager;
    protected DataResourceManager dataResourceManager;
    protected TaxonomyManager taxonomyManager;

    /** Triplet query provider that provides paging over occurrence results */
    protected PagingTripletQueryProvider pagingTripletQueryProvider;

    /** Fields available for download */
    protected List<Field> mandatoryDownloadFields;
    protected List<Field> taxonomyDownloadFields;
    protected List<Field> geospatialDownloadFields;
    protected List<Field> datasetDownloadFields;

    /** Species count limit for the species list view */
    protected int speciesCountLimit = 1000;

    public String minXRequestKey = "minX";
    public String minYRequestKey = "minY";
    public String maxXRequestKey = "maxX";
    public String maxYRequestKey = "maxY";

    /** Filter stuff */
    protected FilterMapWrapper occurrenceFilters;
    protected FilterDTO dataResourceFilter;
    protected FilterDTO dataResourceIdFilter;
    protected FilterDTO dataProviderIdFilter;
    protected FilterDTO countryFilter;

    /* Filter for Colombian Departments */
    protected FilterDTO departmentFilter;

    /* Filter for Colombian Counties */
    protected FilterDTO countyFilter;

    /* Filter for Colombian Paramos */
    protected FilterDTO paramoFilter;

    /* Filter for Colombian Marine Zones */
    protected FilterDTO marineZoneFilter;

    /* Filter for Colombian Protected Areas */
    protected FilterDTO protectedAreaFilter;

    /* Filter for Colombian Ecosystems */
    protected FilterDTO ecosystemFilter;

    /* Filter for Colombian Zonificaciones Hidrograficas */
    protected FilterDTO zonificacionFilter;

    protected FilterDTO regionFilter;
    protected FilterDTO scientificNameFilter;
    protected FilterDTO classificationFilter;
    protected FilterDTO boundingBoxFilter;
    protected FilterDTO georeferencedFilter;
    protected FilterDTO geoConsistencyFilter;

    /** Content providers */
    protected FilterContentProvider filterContentProvider;
    protected MapContentProvider mapContentProvider;

    protected String returnPredicateSubject = "SERVICE.QUERY.PREDICATE.RETURN";
    protected String selectFieldSubject = "SERVICE.QUERY.SUBJECT.SELECTFIELD";

    /** The max number of records to count up to before display "over x records" */
    protected int maxCount = 1000;

    /** Parameter for the selected data providers */
    protected String dataProviderParameterKey = "dp";
    /** Parameter for the selected data resources */
    protected String dataResourceParameterKey = "dr";
    /** Parameter for the selected countries */
    protected String countryParameterKey = "cn";

    /** The catch all entity key */
    protected String catchAllEntityKey = "0";

    /** View names */
    protected String occurrenceFilterProviderCountsView = "occurrenceFilterProviderCounts";
    protected String occurrenceFilterResourceCountsView = "occurrenceFilterResourceCounts";
    protected String occurrenceFilterCountryCountsView = "occurrenceFilterCountryCounts";
    protected String occurrenceFilterDepartmentCountsView = "occurrenceFilterDepartmentCounts";
    protected String occurrenceFilterCountyCountsView = "occurrenceFilterCountyCounts";
    protected String occurrenceFilterParamoCountsView = "occurrenceFilterParamoCounts";
    protected String occurrenceFilterMarineZoneCountsView = "occurrenceFilterMarineZoneCounts";
    protected String occurrenceFilterProtectedAreaCountsView = "occurrenceFilterProtectedAreaCounts";
    protected String occurrenceFilterEcosystemCountsView = "occurrenceFilterEcosystemsCounts";
    protected String occurrenceFilterZonificacionCountsView = "occurrenceFilterZonificacionesCounts";
    protected String occurrenceFilterSpeciesCountsView = "occurrenceFilterSpeciesCounts";
    protected String downloadSpreadsheetView = "occurrenceDownloadSpreadsheet";
    protected String downloadXMLView = "occurrenceDownloadXML";
    protected String defaultView;
    protected String defaultMapView;

    /** Model key for the last edited criterion */
    protected String currentCriterionModelKey = "currentCriterion";

    /** Parameter indicating if counts are available to view for rendering */
    protected String countsAvailableModelKey = "countsAvailable";

    /** The results limit for a distinct query */
    protected String resultsLimitModelKey = "resultsLimit";

    /** Model key for the retrieved counts */
    protected String countsModelKey = "counts";

    /** Model key for the results */
    protected String resultsModelKey = "results";

    /** Model key for the criteria */
    protected String criteriaRequestKey = "criteria";

    /** Model key for one classification */
    protected String oneClassificationKey = "oneClassification";

    /** Model key for the points totals */
    protected String pointsTotalRequestKey = "pointsTotal";

    /** Model key for the available filters for the drop down */
    protected String filtersRequestKey = "filters";

    /** The map layer root */
    protected String filterMapLayerRoot = "filter";

    /** Request parameter giving the requested format */
    protected String formatRequestParam = "format";

    /** Download redirect path */
    protected String downloadRedirectPath = "startDownload.htm";

    /** The results limit for a distinct query */
    protected String messageSourceKey = "messageSource";

    /** Message source for i18n lookups */
    protected MessageSource messageSource;

    /** The root url for search wizards */
    protected String rootWizardUrl;

    /** The root url for search wizards */
    protected String rootWizardUrlModelKey = "rootWizardUrl";

    /** Number of sample results to display */
    protected int maxSampleResults = 5;

    /** Filter value for 'classification' **/
    protected String classificationFilterValue = "20";

    protected List<String> geoFormats;

    /**
     * Determines the view based on the map provided, and if none found defaults to the
     * "occurrenceFilter" view.
     * 
     * @param request To get the view from
     * @param response To write to
     * @return The model and view for the filter params provided
     */
    public ModelAndView actionsOccurrenceCount(HttpServletRequest request, HttpServletResponse response)
            throws Exception {
        // retrieve the criteria from the request
        CriteriaDTO criteria = CriteriaUtil.getCriteriaAndPopulate(request, occurrenceFilters.getFilters());
        // fix criteria value
        CriteriaUtil.fixEncoding(request, criteria);
        ModelAndView mav = new ModelAndView("actionsOccurrenceCountView");
        // convert to triplets
        List<PropertyStoreTripletDTO> triplets = queryHelper.getTriplets(occurrenceFilters.getFilters(), criteria,
                request, response);
        triplets.add(new PropertyStoreTripletDTO(queryHelper.getQueryNamespace(), selectFieldSubject,
                returnPredicateSubject, "SERVICE.OCCURRENCE.QUERY.RETURNFIELDS.ID"));
        // do the query
        SearchResultsDTO searchResults = countsQueryManager.doTripletQuery(triplets, true,
                new SearchConstraints(0, maxCount + 1));
        Integer recordCount = searchResults.getResults().size();
        // construct the model
        mav.addObject(criteriaRequestKey, criteria);
        mav.addObject(filtersRequestKey, occurrenceFilters.getFilters());
        mav.addObject("maxCount", maxCount);
        mav.addObject("recordCount", recordCount);
        return mav;
    }

    /**
     * Prototype full screen bounding box wizard.
     * TODO the switching to full to small.
     * 
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    public ModelAndView boundingBoxFullScreen(HttpServletRequest request, HttpServletResponse response)
            throws Exception {

        // retrieve the criteria from the request
        CriteriaDTO criteria = CriteriaUtil.getCriteriaAndPopulate(request, occurrenceFilters.getFilters());
        // fix criteria value
        CriteriaUtil.fixEncoding(request, criteria);
        // convert to triplets
        ModelAndView mav = new ModelAndView("boundingBoxFull");
        // do the query
        mav.addObject(criteriaRequestKey, criteria);
        mav.addObject(filtersRequestKey, occurrenceFilters.getFilters());
        mav.addObject("fullScreen", Boolean.TRUE);

        // add bounding box to context
        String currValue = request.getParameter("currValue");
        if (StringUtils.isNotEmpty(currValue)) {
            LatLongBoundingBox llbb = BoundingBoxFilterHelper.getLatLongBoundingBox(currValue);
            if (llbb != null)
                mav.addObject("boundingBox", llbb);
        }
        return mav;
    }

    /**
     * Redirect to filter view with a bounding box set along with the supplied criteria.
     * 
     * @param request
     * @param response
     * @param criteria
     * @return ModelAndView, filter view
     * @throws UnsupportedEncodingException
     */
    public ModelAndView boundingBoxWithCriteria(HttpServletRequest request, HttpServletResponse response)
            throws Exception, UnsupportedEncodingException {
        CriteriaDTO criteria = CriteriaUtil.getCriteria(request, occurrenceFilters.getFilters());
        // fix criteria value
        CriteriaUtil.fixEncoding(request, criteria);
        float minx = ServletRequestUtils.getFloatParameter(request, minXRequestKey, 0);
        float miny = ServletRequestUtils.getFloatParameter(request, minYRequestKey, 0);
        float maxx = ServletRequestUtils.getFloatParameter(request, maxXRequestKey, 0);
        float maxy = ServletRequestUtils.getFloatParameter(request, maxYRequestKey, 0);
        criteria.getCriteria()
                .add(new CriterionDTO(boundingBoxFilter.getId(), boundingBoxFilter.getDefaultPredicateId(),
                        BoundingBoxFilterHelper.getBoundingBoxQueryString(minx, miny, maxx, maxy)));
        // this should remove old bounding boxes if they exist
        CriteriaUtil.checkFilterConstraints(occurrenceFilters.getFilters(), criteria);
        return new ModelAndView(new RedirectView("searchWithTable.htm?" + CriteriaUtil.getUrl(criteria)));
    }

    /**
     * Redirects to a virtual file path.
     * 
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    public ModelAndView downloadResults(HttpServletRequest request, HttpServletResponse response) throws Exception {

        StringBuffer sb = new StringBuffer();
        sb.append(downloadRedirectPath);
        sb.append("?");
        // reconstruct the url with parameters and some meddling
        Enumeration<String> parameterNames = request.getParameterNames();

        String searchId = ServletRequestUtils.getStringParameter(request, "searchId",
                Long.toString(System.currentTimeMillis()));
        sb.append("searchId");
        sb.append("=");
        sb.append(searchId);
        sb.append("&");

        while (parameterNames.hasMoreElements()) {

            sb.append("&");
            String paramName = parameterNames.nextElement();
            String paramValue = request.getParameter(paramName);

            if ("criteria".equals(paramName)) {
                CriteriaDTO criteria = CriteriaUtil.getCriteria(paramValue, occurrenceFilters.getFilters(), null);
                // fix criteria value
                CriteriaUtil.fixEncoding(request, criteria);
                // if its a format requiring georeferencing - add criteria if not there
                String format = request.getParameter("format");
                if (format != null && geoFormats != null && geoFormats.contains(format)) {
                    criteria.add(new CriterionDTO("28", "0", "0"));
                }
                sb.append("criteria=" + URLEncoder.encode(CriteriaUtil.getUrl(criteria), "UTF-8"));
            } else if (!"searchId".equals(paramName)) {
                sb.append(paramName);
                sb.append("=");
                sb.append(paramValue);
            }
        }
        return new ModelAndView(new RedirectView(sb.toString()));
    }

    /**
     * Retrieves the counts against the species for this set of criteria
     * 
     * @param request
     * @param response
     * @return ModelAndView which contains the provider list and counts
     * @throws UnsupportedEncodingException
     */
    public ModelAndView downloadSpecies(HttpServletRequest request, HttpServletResponse response)
            throws Exception, ServiceException, UnsupportedEncodingException {

        ModelAndView mav = getCountsView(request, response, "SERVICE.OCCURRENCE.QUERY.RETURNFIELDS.SPECIESCOUNTS",
                occurrenceFilterSpeciesCountsView, new SearchConstraints(0, speciesCountLimit));
        mav.addObject(resultsLimitModelKey, speciesCountLimit);
        return mav;
    }

    /**
     * Determines the view based on the map provided, and if none found defaults to the
     * "occurrenceFilter" view.
     * 
     * @param request To get the view from
     * @param response To write to
     * @return The model and view for the filter params provided
     */
    public ModelAndView downloadSpreadsheet(HttpServletRequest request, HttpServletResponse response)
            throws Exception {
        // retrieve the criteria from the request
        CriteriaDTO criteria = CriteriaUtil.getCriteriaAndPopulate(request, occurrenceFilters.getFilters());
        // fix criteria value
        CriteriaUtil.fixEncoding(request, criteria);
        ModelAndView mav = new ModelAndView(downloadSpreadsheetView);
        mav.addObject("mandatoryFields", mandatoryDownloadFields);
        mav.addObject("taxonomyFields", taxonomyDownloadFields);
        mav.addObject("geospatialFields", geospatialDownloadFields);
        mav.addObject("datasetFields", datasetDownloadFields);
        mav.addObject("searchId", System.currentTimeMillis());
        mav.addObject(criteriaRequestKey, criteria);
        mav.addObject(filtersRequestKey, occurrenceFilters.getFilters());
        return mav;
    }

    /**
     * Performs the count triplet query and returns the generic count view for occurrences.
     * 
     * @param triplets
     * @return
     * @throws UnsupportedEncodingException
     */
    @SuppressWarnings("unchecked")
    private ModelAndView getCountryCountsView(HttpServletRequest request, HttpServletResponse response,
            String returnFieldsKey, String viewName, SearchConstraints searchConstraints)
            throws Exception, ServiceException, UnsupportedEncodingException {
        CriteriaDTO criteriaDTO = CriteriaUtil.getCriteria(request, occurrenceFilters.getFilters());
        // fix criteria value
        request.setCharacterEncoding("UTF-8");
        CriteriaUtil.fixEncoding(request, criteriaDTO);
        List<PropertyStoreTripletDTO> triplets = queryHelper.getTriplets(occurrenceFilters.getFilters(),
                criteriaDTO, request, response);
        triplets.add(new PropertyStoreTripletDTO(queryHelper.getQueryNamespace(), selectFieldSubject,
                returnPredicateSubject, returnFieldsKey));
        SearchResultsDTO searchResults = countsQueryManager.doTripletQuery(triplets, criteriaDTO.isMatchAll(),
                searchConstraints);

        List<CountDTO> countDTOs = searchResults.getResults();
        final Locale locale = RequestContextUtils.getLocale(request);

        Collections.sort(countDTOs, new Comparator() {

            public int compare(Object count1, Object count2) {
                CountDTO countDTO1 = (CountDTO) count1;
                CountDTO countDTO2 = (CountDTO) count2;

                CountryDTO countryDTO1 = geospatialManager.getCountryForIsoCountryCode(countDTO1.getKey(), locale);
                CountryDTO countryDTO2 = geospatialManager.getCountryForIsoCountryCode(countDTO2.getKey(), locale);

                if (countryDTO1 == null)
                    return 1;
                if (countryDTO2 == null)
                    return -1;

                return countryDTO1.getName().compareToIgnoreCase(countryDTO2.getName());
            }
        });

        ModelAndView mav = new ModelAndView(viewName);
        mav.addObject(countsModelKey, searchResults);
        mav.addObject(resultsModelKey, countDTOs);
        // add filters
        mav.addObject(filtersRequestKey, occurrenceFilters.getFilters());
        mav.addObject(criteriaRequestKey, criteriaDTO);
        return mav;
    }

    /**
     * Performs the count triplet query and returns the generic count view for occurrences.
     * 
     * @param triplets
     * @return
     * @throws UnsupportedEncodingException
     */
    private ModelAndView getCountsView(HttpServletRequest request, HttpServletResponse response,
            String returnFieldsKey, String viewName, SearchConstraints searchConstraints)
            throws Exception, ServiceException, UnsupportedEncodingException {
        CriteriaDTO criteriaDTO = CriteriaUtil.getCriteria(request, occurrenceFilters.getFilters());
        // fix criteria value
        request.setCharacterEncoding("ISO-8859-1");
        CriteriaUtil.fixEncoding(request, criteriaDTO);
        List<PropertyStoreTripletDTO> triplets = queryHelper.getTriplets(occurrenceFilters.getFilters(),
                criteriaDTO, request, response);
        triplets.add(new PropertyStoreTripletDTO(queryHelper.getQueryNamespace(), selectFieldSubject,
                returnPredicateSubject, returnFieldsKey));
        SearchResultsDTO searchResults = countsQueryManager.doTripletQuery(triplets, criteriaDTO.isMatchAll(),
                searchConstraints);
        ModelAndView mav = new ModelAndView(viewName);
        mav.addObject(countsModelKey, searchResults);
        mav.addObject(resultsModelKey, searchResults.getResults());
        // add filters
        mav.addObject(filtersRequestKey, occurrenceFilters.getFilters());
        mav.addObject(criteriaRequestKey, criteriaDTO);
        return mav;
    }

    /**
     * @see org.springframework.web.servlet.mvc.multiaction.MultiActionController#handleNoSuchRequestHandlingMethod(org.springframework.web.servlet.mvc.multiaction.NoSuchRequestHandlingMethodException,
     *      javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
     */
    @Override
    protected ModelAndView handleNoSuchRequestHandlingMethod(NoSuchRequestHandlingMethodException exception,
            HttpServletRequest request, HttpServletResponse response) throws Exception {
        return search(request, response);
    }

    /**
     * Maps a criteria query to a entity map layer.
     * 
     * @param request
     * @param criteria
     * @throws ServiceException
     */
    private void mapQueryToCellDensities(HttpServletRequest request, CriteriaDTO criteria) throws ServiceException {

        logger.debug("Mapping: switching to using cell densities");
        request.setAttribute("noGeospatialIssues", true);

        // get bounding box criterion
        CriterionDTO boundingBoxCriterion = filterContentProvider.getBoundingBoxCriterion(criteria);
        // get entity type
        EntityType entityType = filterContentProvider.getCellDensityEntityType(criteria);
        // get list of ids
        List<String> entityKeys = filterContentProvider.getCellDensityEntityIds(criteria);

        BoundingBoxDTO bbDTO = null;

        // if bounding box selected and entity type selected
        if (boundingBoxCriterion != null && entityType != null && !entityType.equals(EntityType.TYPE_ALL)) {
            logger.debug("Mapping: found entity type and bounding box");
            if (logger.isDebugEnabled())
                logger.debug("Mapping: using entityType:" + entityType);
            bbDTO = BoundingBoxFilterHelper.getBoundingBoxDTO(boundingBoxCriterion.getValue());
            mapContentProvider.addPointsTotalsToRequest(request, entityType, entityKeys, bbDTO);

        } else if (boundingBoxCriterion != null) {
            logger.debug("Mapping: found bounding box - using catch all entity type");
            bbDTO = BoundingBoxFilterHelper.getBoundingBoxDTO(boundingBoxCriterion.getValue());
            // add points totals
            mapContentProvider.addPointsTotalsToRequest(request, EntityType.TYPE_ALL, catchAllEntityKey, bbDTO);

        } else {
            if (logger.isDebugEnabled())
                logger.debug("Mapping: using entityType:" + entityType);
            // add points totals
            mapContentProvider.addPointsTotalsToRequest(request, entityType, entityKeys, null);
        }

        List<CellDensityDTO> cellDensities = null;

        if (bbDTO == null)
            cellDensities = geospatialManager.get1DegCellDensities(entityType, entityKeys);
        else
            cellDensities = geospatialManager.get1DegCellDensities(entityType, entityKeys, bbDTO);

        // add the map layer information to the request.
        String criteriaUrl = CriteriaUtil.getUrl(criteria);
        if (entityType.equals(EntityType.TYPE_DEPARTMENT)) {
            mapContentProvider.addMapContentDepartment(request, filterMapLayerRoot, criteriaUrl, cellDensities,
                    bbDTO);
        } else {
            mapContentProvider.addMapContent(request, filterMapLayerRoot, criteriaUrl, cellDensities, bbDTO);
        }
    }

    /**
     * Determines the view based on the map provided, and if none found defaults to the
     * "occurrenceFilter" view.
     * 
     * @param request To get the view from
     * @param response To write to
     * @return The model and view for the filter params provided
     */
    public ModelAndView occurrenceCount(HttpServletRequest request, HttpServletResponse response) throws Exception {

        // retrieve the criteria from the request
        CriteriaDTO criteria = CriteriaUtil.getCriteriaAndPopulate(request, occurrenceFilters.getFilters());
        // fix criteria value
        CriteriaUtil.fixEncoding(request, criteria);
        ModelAndView mav = new ModelAndView("occurrenceCountView");
        // convert to triplets
        List<PropertyStoreTripletDTO> triplets = queryHelper.getTriplets(occurrenceFilters.getFilters(), criteria,
                request, response);
        triplets.add(new PropertyStoreTripletDTO(queryHelper.getQueryNamespace(), selectFieldSubject,
                returnPredicateSubject, "SERVICE.OCCURRENCE.QUERY.RETURNFIELDS.ID"));
        // do the query
        SearchResultsDTO searchResults = countsQueryManager.doTripletQuery(triplets, true,
                new SearchConstraints(0, maxCount + 1));
        Integer recordCount = searchResults.getResults().size();
        // construct the model
        mav.addObject(criteriaRequestKey, criteria);
        mav.addObject(filtersRequestKey, occurrenceFilters.getFilters());
        mav.addObject("maxCount", maxCount);
        mav.addObject("recordCount", recordCount);
        return mav;
    }

    /**
     * Determines the view based on the map provided, and if none found defaults to the
     * "occurrenceFilter" view.
     * 
     * @param request To get the view from
     * @param response To write to
     * @return The model and view for the filter params provided
     */
    public ModelAndView search(HttpServletRequest request, HttpServletResponse response) throws Exception {

        // retrieve the criteria from the request
        CriteriaDTO criteria = CriteriaUtil.getCriteria(request, occurrenceFilters.getFilters());
        // fix criteria value
        CriteriaUtil.fixEncoding(request, criteria);

        logger.debug("Criteria list: " + criteria);

        // check for data provider ids
        String[] dataProviderIds = request.getParameterValues(dataProviderParameterKey);
        if (dataProviderIds != null && dataProviderIds.length > 0) {
            for (String dataProviderId : dataProviderIds) {
                CriterionDTO criterionDTO = new CriterionDTO(dataProviderIdFilter.getId(),
                        dataProviderIdFilter.getDefaultPredicateId(), dataProviderId);
                criteria.getCriteria().add(criterionDTO);
            }
        }
        // check for data resource ids
        String[] dataResourceIds = request.getParameterValues(dataResourceParameterKey);
        if (dataResourceIds != null && dataResourceIds.length > 0) {
            for (String dataResourceId : dataResourceIds) {
                CriterionDTO criterionDTO = new CriterionDTO(dataResourceIdFilter.getId(),
                        dataResourceIdFilter.getDefaultPredicateId(), dataResourceId);
                criteria.getCriteria().add(criterionDTO);
            }
        }
        // check for country ids
        String[] countryIds = request.getParameterValues(countryParameterKey);
        if (countryIds != null && countryIds.length > 0) {
            for (String countryId : countryIds) {
                CriterionDTO criterionDTO = new CriterionDTO(countryFilter.getId(),
                        countryFilter.getDefaultPredicateId(), countryId);
                criteria.getCriteria().add(criterionDTO);
            }
        }
        Locale locale = RequestContextUtils.getLocale(request);
        CriteriaUtil.populateCriteria(occurrenceFilters.getFilters(), criteria, locale);
        criteria.setCriteria(CriteriaUtil.removeDuplicates(criteria.getCriteria()));

        // convert to triplets
        List<PropertyStoreTripletDTO> triplets = queryHelper.getTriplets(occurrenceFilters.getFilters(), criteria,
                request, response);
        ModelAndView mav = new ModelAndView("occurrenceSearchWithEditorPane");

        // check for a set filter
        String subject = request.getParameter("newFilterSubject");
        String predicate = request.getParameter("newFilterPredicate");
        String value = request.getParameter("newFilterValue");
        value = QueryHelper.tidyValue(value);

        if (subject != null && predicate != null && value != null) {
            // initialise the filter
            CriterionDTO criterion = new CriterionDTO(subject, predicate, value);
            CriteriaUtil.setCriterionDisplayValue(occurrenceFilters.getFilters(), criterion, locale);
            mav.addObject(currentCriterionModelKey, criterion);
            FilterDTO filter = FilterUtils.getFilterById(occurrenceFilters.getFilters(), criterion.getSubject());
            if (filter.getFilterHelper() != null)
                filter.getFilterHelper().addCriterion2Request(criterion, mav, request);
        }

        // do the query
        if (FilterUtils.isFilterQueryRequestValid(request)) {
            SearchResultsDTO searchResults = tripletQueryManager.doTripletQuery(triplets, true,
                    new SearchConstraints(0, maxSampleResults));
            mav.addObject(resultsModelKey, searchResults.getResults());
        }
        // construct the model
        boolean oneClassification = false;
        int classificationCount = 0;
        for (CriterionDTO criterion : criteria.getCriteria()) {
            logger.debug("criterion: " + criterion);
            // search request contains a classification filter
            if (criterion.getSubject().equals(classificationFilterValue)) {
                if (classificationCount < 1) {
                    // check that classification contains a species level (or lower) taxon
                    if (taxonomyManager.getBriefTaxonConceptFor(criterion.getValue()).getRankValue() >= 6000) {
                        logger.debug("Taxon included on the classification filter is species level or lower");
                        oneClassification = true;
                    }
                }
                // there is more than one classification
                else {
                    oneClassification = false;
                    // no use to continue searching
                    break;
                }
                classificationCount++;
            }
        }
        mav.addObject(oneClassificationKey, oneClassification);
        mav.addObject(criteriaRequestKey, criteria);
        mav.addObject(filtersRequestKey, occurrenceFilters.getFilters());
        mav.addObject(messageSourceKey, messageSource);
        mav.addObject(rootWizardUrlModelKey, rootWizardUrl);
        return mav;
    }

    /**
     * Retrieves the counts against the countries for this set of criteria
     * 
     * @param request
     * @param response
     * @return ModelAndView which contains the provider list and counts
     * @throws UnsupportedEncodingException
     */
    public ModelAndView searchCountries(HttpServletRequest request, HttpServletResponse response)
            throws Exception, ServiceException, UnsupportedEncodingException {
        // interrogate the criteria - if it only contains a taxon filter then switch
        CriteriaDTO criteriaDTO = CriteriaUtil.getCriteria(request, occurrenceFilters.getFilters());
        // fix criteria value
        request.setCharacterEncoding("ISO-8859-1");
        CriteriaUtil.fixEncoding(request, criteriaDTO);
        if (criteriaDTO.size() == 1) {
            logger.debug("Switching to using service layer method getCountryCountsForTaxonConcept");
            CriterionDTO criterionDTO = criteriaDTO.get(0);
            FilterDTO filterDTO = FilterUtils.getFilterById(occurrenceFilters.getFilters(),
                    criterionDTO.getSubject());
            if (filterDTO.getSubject().equals(classificationFilter.getSubject())) {
                List<CountDTO> counts = taxonomyManager.getCountryCountsForTaxonConcept(criterionDTO.getValue(),
                        RequestContextUtils.getLocale(request));
                ModelAndView mav = new ModelAndView(occurrenceFilterCountryCountsView);
                mav.addObject(countsModelKey, counts);
                mav.addObject(resultsModelKey, counts);
                // add filters
                mav.addObject(filtersRequestKey, occurrenceFilters.getFilters());
                mav.addObject(criteriaRequestKey, criteriaDTO);
                mav.addObject(countsAvailableModelKey, true);
                return mav;
            }
        }
        int totalNoOfCountries = geospatialManager.getTotalCountryCount();
        return getCountryCountsView(request, response, "SERVICE.OCCURRENCE.QUERY.RETURNFIELDS.COUNTRYCOUNTS",
                occurrenceFilterCountryCountsView, new SearchConstraints(0, totalNoOfCountries));
    }

    /**
     * Retrieves the counts against the departments for this set of criteria
     * 
     * @param request
     * @param response
     * @return ModelAndView which contains the provider list and counts
     * @throws UnsupportedEncodingException
     */
    public ModelAndView searchDepartments(HttpServletRequest request, HttpServletResponse response)
            throws Exception, ServiceException, UnsupportedEncodingException {
        // interrogate the criteria - if it only contains a taxon filter then switch
        CriteriaDTO criteriaDTO = CriteriaUtil.getCriteria(request, occurrenceFilters.getFilters());
        // fix criteria value
        request.setCharacterEncoding("ISO-8859-1");
        CriteriaUtil.fixEncoding(request, criteriaDTO);
        if (criteriaDTO.size() == 1) {
            logger.debug("Switching to using service layer method getDepartmentCountsForTaxonConcept");
            CriterionDTO criterionDTO = criteriaDTO.get(0);
            FilterDTO filterDTO = FilterUtils.getFilterById(occurrenceFilters.getFilters(),
                    criterionDTO.getSubject());
            if (filterDTO.getSubject().equals(classificationFilter.getSubject())) {
                List<CountDTO> counts = taxonomyManager.getDepartmentCountsForTaxonConcept(criterionDTO.getValue());
                ModelAndView mav = new ModelAndView(occurrenceFilterDepartmentCountsView);
                mav.addObject(countsModelKey, counts);
                mav.addObject(resultsModelKey, counts);
                // add filters
                mav.addObject(filtersRequestKey, occurrenceFilters.getFilters());
                mav.addObject(criteriaRequestKey, criteriaDTO);
                mav.addObject(countsAvailableModelKey, true);
                return mav;
            }
        }
        int totalNoOfDepartments = departmentManager.getTotalDepartmentCount();
        return getCountryCountsView(request, response, "SERVICE.OCCURRENCE.QUERY.RETURNFIELDS.DEPARTMENTCOUNTS",
                occurrenceFilterDepartmentCountsView, new SearchConstraints(0, totalNoOfDepartments));
    }

    /**
     * Retrieves the counts against the counties for this set of criteria
     * 
     * @param request
     * @param response
     * @return ModelAndView which contains the provider list and counts
     * @throws UnsupportedEncodingException
     */
    public ModelAndView searchCounties(HttpServletRequest request, HttpServletResponse response)
            throws Exception, ServiceException, UnsupportedEncodingException {
        // interrogate the criteria - if it only contains a taxon filter then switch
        CriteriaDTO criteriaDTO = CriteriaUtil.getCriteria(request, occurrenceFilters.getFilters());
        // fix criteria value
        request.setCharacterEncoding("ISO-8859-1");
        CriteriaUtil.fixEncoding(request, criteriaDTO);
        if (criteriaDTO.size() == 1) {
            logger.debug("Switching to using service layer method getCountyCountsForTaxonConcept");
            CriterionDTO criterionDTO = criteriaDTO.get(0);
            FilterDTO filterDTO = FilterUtils.getFilterById(occurrenceFilters.getFilters(),
                    criterionDTO.getSubject());
            if (filterDTO.getSubject().equals(classificationFilter.getSubject())) {
                List<CountDTO> counts = taxonomyManager.getCountyCountsForTaxonConcept(criterionDTO.getValue());
                ModelAndView mav = new ModelAndView(occurrenceFilterCountyCountsView);
                mav.addObject(countsModelKey, counts);
                mav.addObject(resultsModelKey, counts);
                // add filters
                mav.addObject(filtersRequestKey, occurrenceFilters.getFilters());
                mav.addObject(criteriaRequestKey, criteriaDTO);
                mav.addObject(countsAvailableModelKey, true);
                return mav;
            }
        }
        int totalNoOfCounties = departmentManager.getTotalCountyCount();
        return getCountryCountsView(request, response, "SERVICE.OCCURRENCE.QUERY.RETURNFIELDS.COUNTYCOUNTS",
                occurrenceFilterCountyCountsView, new SearchConstraints(0, totalNoOfCounties));
    }

    /**
     * Retrieves the counts against the paramos for this set of criteria
     * 
     * @param request
     * @param response
     * @return ModelAndView which contains the provider list and counts
     * @throws UnsupportedEncodingException
     */
    public ModelAndView searchParamos(HttpServletRequest request, HttpServletResponse response)
            throws Exception, ServiceException, UnsupportedEncodingException {
        // interrogate the criteria - if it only contains a taxon filter then switch
        CriteriaDTO criteriaDTO = CriteriaUtil.getCriteria(request, occurrenceFilters.getFilters());
        // fix criteria value
        request.setCharacterEncoding("ISO-8859-1");
        CriteriaUtil.fixEncoding(request, criteriaDTO);
        if (criteriaDTO.size() == 1) {
            logger.debug("Switching to using service layer method getParamoCountsForTaxonConcept");
            CriterionDTO criterionDTO = criteriaDTO.get(0);
            FilterDTO filterDTO = FilterUtils.getFilterById(occurrenceFilters.getFilters(),
                    criterionDTO.getSubject());
            if (filterDTO.getSubject().equals(classificationFilter.getSubject())) {
                List<CountDTO> counts = taxonomyManager.getParamoCountsForTaxonConcept(criterionDTO.getValue());
                ModelAndView mav = new ModelAndView(occurrenceFilterParamoCountsView);
                mav.addObject(countsModelKey, counts);
                mav.addObject(resultsModelKey, counts);
                // add filters
                mav.addObject(filtersRequestKey, occurrenceFilters.getFilters());
                mav.addObject(criteriaRequestKey, criteriaDTO);
                mav.addObject(countsAvailableModelKey, true);
                return mav;
            }
        }
        int totalNoOfParamos = departmentManager.getTotalParamoCount();
        return getCountryCountsView(request, response, "SERVICE.OCCURRENCE.QUERY.RETURNFIELDS.PARAMOCOUNTS",
                occurrenceFilterParamoCountsView, new SearchConstraints(0, totalNoOfParamos));
    }

    /**
     * Retrieves the counts against the marine zone for this set of criteria
     * 
     * @param request
     * @param response
     * @return ModelAndView which contains the provider list and counts
     * @throws UnsupportedEncodingException
     */
    public ModelAndView searchMarineZones(HttpServletRequest request, HttpServletResponse response)
            throws Exception, ServiceException, UnsupportedEncodingException {
        // interrogate the criteria - if it only contains a taxon filter then switch
        CriteriaDTO criteriaDTO = CriteriaUtil.getCriteria(request, occurrenceFilters.getFilters());
        // fix criteria value
        request.setCharacterEncoding("ISO-8859-1");
        CriteriaUtil.fixEncoding(request, criteriaDTO);
        if (criteriaDTO.size() == 1) {
            logger.debug("Switching to using service layer method getMarineZoneCountsForTaxonConcept");
            CriterionDTO criterionDTO = criteriaDTO.get(0);
            FilterDTO filterDTO = FilterUtils.getFilterById(occurrenceFilters.getFilters(),
                    criterionDTO.getSubject());
            if (filterDTO.getSubject().equals(classificationFilter.getSubject())) {
                List<CountDTO> counts = taxonomyManager.getMarineZoneCountsForTaxonConcept(criterionDTO.getValue());
                ModelAndView mav = new ModelAndView(occurrenceFilterMarineZoneCountsView);
                mav.addObject(countsModelKey, counts);
                mav.addObject(resultsModelKey, counts);
                // add filters
                mav.addObject(filtersRequestKey, occurrenceFilters.getFilters());
                mav.addObject(criteriaRequestKey, criteriaDTO);
                mav.addObject(countsAvailableModelKey, true);
                return mav;
            }
        }
        int totalNoOfMarineZones = departmentManager.getTotalMarineZoneCount();
        return getCountryCountsView(request, response, "SERVICE.OCCURRENCE.QUERY.RETURNFIELDS.MARINEZONECOUNTS",
                occurrenceFilterMarineZoneCountsView, new SearchConstraints(0, totalNoOfMarineZones));
    }

    /**
     * Retrieves the counts against the protected area for this set of criteria
     * 
     * @param request
     * @param response
     * @return ModelAndView which contains the provider list and counts
     * @throws UnsupportedEncodingException
     */
    public ModelAndView searchProtectedAreas(HttpServletRequest request, HttpServletResponse response)
            throws Exception, ServiceException, UnsupportedEncodingException {
        // interrogate the criteria - if it only contains a taxon filter then switch
        CriteriaDTO criteriaDTO = CriteriaUtil.getCriteria(request, occurrenceFilters.getFilters());
        // fix criteria value
        request.setCharacterEncoding("ISO-8859-1");
        CriteriaUtil.fixEncoding(request, criteriaDTO);
        if (criteriaDTO.size() == 1) {
            logger.debug("Switching to using service layer method getProtectedAreaCountsForTaxonConcept");
            CriterionDTO criterionDTO = criteriaDTO.get(0);
            FilterDTO filterDTO = FilterUtils.getFilterById(occurrenceFilters.getFilters(),
                    criterionDTO.getSubject());
            if (filterDTO.getSubject().equals(classificationFilter.getSubject())) {
                List<CountDTO> counts = taxonomyManager
                        .getProtectedAreaCountsForTaxonConcept(criterionDTO.getValue());
                ModelAndView mav = new ModelAndView(occurrenceFilterProtectedAreaCountsView);
                mav.addObject(countsModelKey, counts);
                mav.addObject(resultsModelKey, counts);
                // add filters
                mav.addObject(filtersRequestKey, occurrenceFilters.getFilters());
                mav.addObject(criteriaRequestKey, criteriaDTO);
                mav.addObject(countsAvailableModelKey, true);
                return mav;
            }
        }
        int totalNoOfProtectedAreas = departmentManager.getTotalProtectedAreaCount();
        return getCountryCountsView(request, response, "SERVICE.OCCURRENCE.QUERY.RETURNFIELDS.PROTECTEDAREACOUNTS",
                occurrenceFilterProtectedAreaCountsView, new SearchConstraints(0, totalNoOfProtectedAreas));
    }

    /**
     * Retrieves the counts against the ecosystem for this set of criteria
     * 
     * @param request
     * @param response
     * @return ModelAndView which contains the provider list and counts
     * @throws UnsupportedEncodingException
     */
    public ModelAndView searchEcosystems(HttpServletRequest request, HttpServletResponse response)
            throws Exception, ServiceException, UnsupportedEncodingException {
        // interrogate the criteria - if it only contains a taxon filter then switch
        CriteriaDTO criteriaDTO = CriteriaUtil.getCriteria(request, occurrenceFilters.getFilters());
        // fix criteria value
        request.setCharacterEncoding("ISO-8859-1");
        CriteriaUtil.fixEncoding(request, criteriaDTO);
        if (criteriaDTO.size() == 1) {
            logger.debug("Switching to using service layer method getEcosystemCountsForTaxonConcept");
            CriterionDTO criterionDTO = criteriaDTO.get(0);
            FilterDTO filterDTO = FilterUtils.getFilterById(occurrenceFilters.getFilters(),
                    criterionDTO.getSubject());
            if (filterDTO.getSubject().equals(classificationFilter.getSubject())) {
                List<CountDTO> counts = taxonomyManager.getEcosystemCountsForTaxonConcept(criterionDTO.getValue());
                ModelAndView mav = new ModelAndView(occurrenceFilterEcosystemCountsView);
                mav.addObject(countsModelKey, counts);
                mav.addObject(resultsModelKey, counts);
                // add filters
                mav.addObject(filtersRequestKey, occurrenceFilters.getFilters());
                mav.addObject(criteriaRequestKey, criteriaDTO);
                mav.addObject(countsAvailableModelKey, true);
                return mav;
            }
        }
        int totalNoOfEcosystems = departmentManager.getTotalEcosystemCount();
        String view;
        if (criteriaDTO.get(0).getValue() == "1") {
            view = "SERVICE.OCCURRENCE.QUERY.RETURNFIELDS.ECOSYSTEMCOUNTS";
        } else {
            view = "SERVICE.OCCURRENCE.QUERY.RETURNFIELDS.PARAMOCOUNTS";
        }
        return getCountryCountsView(request, response, view, occurrenceFilterEcosystemCountsView,
                new SearchConstraints(0, totalNoOfEcosystems));
    }

    /**
     * Retrieves the counts against the zonificacion for this set of criteria
     * 
     * @param request
     * @param response
     * @return ModelAndView which contains the provider list and counts
     * @throws UnsupportedEncodingException
     */
    public ModelAndView searchZonificaciones(HttpServletRequest request, HttpServletResponse response)
            throws Exception, ServiceException, UnsupportedEncodingException {
        // interrogate the criteria - if it only contains a taxon filter then switch
        CriteriaDTO criteriaDTO = CriteriaUtil.getCriteria(request, occurrenceFilters.getFilters());
        // fix criteria value
        request.setCharacterEncoding("ISO-8859-1");
        CriteriaUtil.fixEncoding(request, criteriaDTO);
        if (criteriaDTO.size() == 1) {
            logger.debug("Switching to using service layer method getZonificacionCountsForTaxonConcept");
            CriterionDTO criterionDTO = criteriaDTO.get(0);
            FilterDTO filterDTO = FilterUtils.getFilterById(occurrenceFilters.getFilters(),
                    criterionDTO.getSubject());
            if (filterDTO.getSubject().equals(classificationFilter.getSubject())) {
                List<CountDTO> counts = taxonomyManager
                        .getZonificacionCountsForTaxonConcept(criterionDTO.getValue());
                ModelAndView mav = new ModelAndView(occurrenceFilterZonificacionCountsView);
                mav.addObject(countsModelKey, counts);
                mav.addObject(resultsModelKey, counts);
                // add filters
                mav.addObject(filtersRequestKey, occurrenceFilters.getFilters());
                mav.addObject(criteriaRequestKey, criteriaDTO);
                mav.addObject(countsAvailableModelKey, true);
                return mav;
            }
        }
        int totalNoOfZonificaciones = departmentManager.getTotalZonificacionCount();
        return getCountryCountsView(request, response, "SERVICE.OCCURRENCE.QUERY.RETURNFIELDS.ZONIFICACIONCOUNTS",
                occurrenceFilterZonificacionCountsView, new SearchConstraints(0, totalNoOfZonificaciones));
    }

    /**
     * Retrieves the counts against the providers for this set of criteria
     * 
     * @param request
     * @param response
     * @return ModelAndView which contains the provider list and counts
     * @throws UnsupportedEncodingException
     */
    public ModelAndView searchProviders(HttpServletRequest request, HttpServletResponse response)
            throws Exception, ServiceException, UnsupportedEncodingException {
        // interrogate the criteria - if it only contains a country filter then switch
        CriteriaDTO criteriaDTO = CriteriaUtil.getCriteria(request, occurrenceFilters.getFilters());
        // fix criteria value
        request.setCharacterEncoding("ISO-8859-1");
        CriteriaUtil.fixEncoding(request, criteriaDTO);
        if (criteriaDTO.size() == 0) {
            logger.debug("Switching to using service layer method getAllDataProviders");
            ModelAndView mav = new ModelAndView(occurrenceFilterProviderCountsView);
            List<DataProviderDTO> dps = dataResourceManager.getAllDataProviders();
            mav.addObject(countsModelKey, dps);
            mav.addObject(resultsModelKey, dps);
            // add filters
            mav.addObject(filtersRequestKey, occurrenceFilters.getFilters());
            mav.addObject(criteriaRequestKey, criteriaDTO);
            mav.addObject(countsAvailableModelKey, true);
            return mav;
        }
        if (criteriaDTO.size() == 1) {
            logger.debug("Switching to using service layer method getDataProviderCountsForCountry");
            CriterionDTO criterionDTO = criteriaDTO.get(0);
            FilterDTO filterDTO = FilterUtils.getFilterById(occurrenceFilters.getFilters(),
                    criterionDTO.getSubject());
            if (filterDTO.getSubject().equals(countryFilter.getSubject())) {
                List<CountDTO> counts = geospatialManager.getDataProviderCountsForCountry(criterionDTO.getValue());
                ModelAndView mav = new ModelAndView(occurrenceFilterProviderCountsView);
                mav.addObject(countsModelKey, counts);
                mav.addObject(resultsModelKey, counts);
                // add filters
                mav.addObject(filtersRequestKey, occurrenceFilters.getFilters());
                mav.addObject(criteriaRequestKey, criteriaDTO);
                mav.addObject(countsAvailableModelKey, true);
                return mav;
            }
        }
        int totalNoOfDataProviders = dataResourceManager.getTotalDataProviderCount();
        return getCountsView(request, response, "SERVICE.OCCURRENCE.QUERY.RETURNFIELDS.PROVIDERCOUNTS",
                occurrenceFilterProviderCountsView, new SearchConstraints(0, totalNoOfDataProviders));
    }

    /**
     * Retrieves the counts against the providers for this set of criteria
     * 
     * @param request
     * @param response
     * @return ModelAndView which contains the provider list and counts
     * @throws UnsupportedEncodingException
     */
    public ModelAndView searchResources(HttpServletRequest request, HttpServletResponse response)
            throws Exception, ServiceException, UnsupportedEncodingException {
        // interrogate the criteria - if it only contains a country filter then switch
        CriteriaDTO criteriaDTO = CriteriaUtil.getCriteria(request, occurrenceFilters.getFilters());
        // fix criteria value
        CriteriaUtil.fixEncoding(request, criteriaDTO);
        if (criteriaDTO.size() == 0) {
            logger.debug("Switching to using service layer method getAllDataResources");
            ModelAndView mav = new ModelAndView(occurrenceFilterResourceCountsView);
            List<DataResourceDTO> drs = dataResourceManager.getAllDataResources();
            mav.addObject(countsModelKey, drs);
            mav.addObject(resultsModelKey, drs);
            // add filters
            mav.addObject(filtersRequestKey, occurrenceFilters.getFilters());
            mav.addObject(criteriaRequestKey, criteriaDTO);
            mav.addObject(countsAvailableModelKey, true);
            return mav;
        }
        if (criteriaDTO.size() == 1) {
            logger.debug("Switching to using service layer method getDataResourceCountsForCountry");
            CriterionDTO criterionDTO = criteriaDTO.get(0);
            FilterDTO filterDTO = FilterUtils.getFilterById(occurrenceFilters.getFilters(),
                    criterionDTO.getSubject());
            if (filterDTO.getSubject().equals(countryFilter.getSubject())) {
                List<CountDTO> counts = geospatialManager.getDataResourceCountsForCountry(criterionDTO.getValue(),
                        false);
                ModelAndView mav = new ModelAndView(occurrenceFilterResourceCountsView);
                mav.addObject(countsModelKey, counts);
                mav.addObject(resultsModelKey, counts);
                // add filters
                mav.addObject(filtersRequestKey, occurrenceFilters.getFilters());
                mav.addObject(criteriaRequestKey, criteriaDTO);
                mav.addObject(countsAvailableModelKey, true);
                return mav;
            }
        }
        int totalNoOfDataResource = dataResourceManager.getTotalDataResourceCount();
        return getCountsView(request, response, "SERVICE.OCCURRENCE.QUERY.RETURNFIELDS.RESOURCECOUNTS",
                occurrenceFilterResourceCountsView, new SearchConstraints(0, totalNoOfDataResource));
    }

    /**
     * Determines the view based on the map provided, and if none found defaults to the
     * "occurrenceFilter" view.
     * TODO Add a switch so that if the filter search consists of 1 entity type (taxon, resource, provider, network)
     * and/or just
     * geospatial filters, make use of cell density tables
     * 
     * @param request To get the view from
     * @param response To write to
     * @return The model and view for the filter params provided
     * @throws Exception On error in underlying layers
     */
    @SuppressWarnings("unchecked")
    public ModelAndView searchWithMap(HttpServletRequest request, HttpServletResponse response) throws Exception {

        ModelAndView mav = new ModelAndView("occurrenceSearchWithMap");
        // retrieve the criteria from the request
        CriteriaDTO criteria = CriteriaUtil.getCriteriaAndPopulate(request, occurrenceFilters.getFilters());
        // fix criteria value
        CriteriaUtil.fixEncoding(request, criteria);

        List<PropertyStoreTripletDTO> triplets = queryHelper.getTriplets(occurrenceFilters.getFilters(), criteria,
                request, response);

        // if query suitable for cell density, switch over
        if (filterContentProvider.isQuerySuitableForCellDensity(criteria)) {
            mapQueryToCellDensities(request, criteria);
        } else {

            // add extra triplets to say we require only geospatially aware records
            filterContentProvider.addGeoreferencedOnlyOccurrenceTriplets(triplets, queryHelper.getQueryNamespace());

            // choose the correct return fields
            PropertyStoreTripletDTO returnTypeTriplet = new PropertyStoreTripletDTO(queryHelper.getQueryNamespace(),
                    selectFieldSubject, returnPredicateSubject,
                    "SERVICE.OCCURRENCE.QUERY.RETURNFIELDS.MAPLAYERCOUNTS");
            triplets.add(returnTypeTriplet);

            // do the query
            SearchConstraints constraints = new SearchConstraints(0, 64800);
            SearchResultsDTO searchResults = mapLayerQueryManager.doTripletQuery(triplets, criteria.isMatchAll(),
                    constraints);

            // get a points total
            List<CellDensityDTO> cellDensities = searchResults.getResults();
            int pointsTotal = MapContentProvider.getPointsTotal(cellDensities);
            mav.addObject(pointsTotalRequestKey, pointsTotal);

            // get a bounding box for the specified zoom level
            BoundingBoxDTO bbDTO = mapContentProvider.getSpecifiedViewArea(request);

            // iterate through drawing up a total of the points that are viewable
            int[] minMaxCellIds = CellIdUtils.getMinMaxCellIdsForBoundingBox(bbDTO.getLeft(), bbDTO.getLower(),
                    bbDTO.getRight(), bbDTO.getUpper());

            int viewablePoints = 0;
            for (CellDensityDTO cd : cellDensities) {
                if (CellIdUtils.isCellIdInBoundingBox(cd.getCellId(), minMaxCellIds[0], minMaxCellIds[1]))
                    viewablePoints += cd.getCount();
            }
            mav.addObject("viewablePoints", viewablePoints);

            // set the map layer content
            mapContentProvider.addMapContent(request, filterMapLayerRoot, CriteriaUtil.getUrl(criteria),
                    cellDensities, bbDTO);
        }

        mav.addObject(criteriaRequestKey, criteria);
        mav.addObject(filtersRequestKey, occurrenceFilters.getFilters());
        return mav;
    }

    /**
     * Determines the view based on the map provided, and if none found defaults to the
     * "occurrenceFilter" view.
     * 
     * @param request To get the view from
     * @param response To write to
     * @return The model and view for the filter params provided
     */
    public ModelAndView searchWithTable(HttpServletRequest request, HttpServletResponse response) throws Exception {
        // retrieve the criteria from the request
        CriteriaDTO criteria = CriteriaUtil.getCriteriaAndPopulate(request, occurrenceFilters.getFilters());
        // fix criteria value
        CriteriaUtil.fixEncoding(request, criteria);
        // convert to triplets
        List<PropertyStoreTripletDTO> triplets = queryHelper.getTriplets(occurrenceFilters.getFilters(), criteria,
                request, response);
        ModelAndView mav = new ModelAndView("occurrenceSearchWithTable");
        // do the query - pagingTripletQueryProvider will store the results within the request
        pagingTripletQueryProvider.doTripletQuery(triplets, criteria.isMatchAll(), request, response);
        // construct the model
        mav.addObject(criteriaRequestKey, criteria);
        mav.addObject(filtersRequestKey, occurrenceFilters.getFilters());
        mav.addObject(messageSourceKey, messageSource);
        return mav;
    }

    /**
     * @param boundingBoxFilter the boundingBoxFilter to set
     */
    public void setBoundingBoxFilter(FilterDTO boundingBoxFilter) {
        this.boundingBoxFilter = boundingBoxFilter;
    }

    /**
     * @param catchAllEntityKey the catchAllEntityKey to set
     */
    public void setCatchAllEntityKey(String catchAllEntityKey) {
        this.catchAllEntityKey = catchAllEntityKey;
    }

    /**
     * @param classificationFilter the classificationFilter to set
     */
    public void setClassificationFilter(FilterDTO classificationFilter) {
        this.classificationFilter = classificationFilter;
    }

    /**
     * @param countryFilter the countryFilter to set
     */
    public void setCountryFilter(FilterDTO countryFilter) {
        this.countryFilter = countryFilter;
    }

    /**
     * @param countryParameterKey the countryParameterKey to set
     */
    public void setCountryParameterKey(String countryParameterKey) {
        this.countryParameterKey = countryParameterKey;
    }

    /**
     * @param countsAvailableModelKey the countsAvailableModelKey to set
     */
    public void setCountsAvailableModelKey(String countsAvailableModelKey) {
        this.countsAvailableModelKey = countsAvailableModelKey;
    }

    /**
     * @param countsModelKey the countsModelKey to set
     */
    public void setCountsModelKey(String countsModelKey) {
        this.countsModelKey = countsModelKey;
    }

    /**
     * @param countsQueryManager the countsQueryManager to set
     */
    public void setCountsQueryManager(TripletQueryManager countsQueryManager) {
        this.countsQueryManager = countsQueryManager;
    }

    /**
     * @param criteriaRequestKey the criteriaRequestKey to set
     */
    public void setCriteriaRequestKey(String criteriaRequestKey) {
        this.criteriaRequestKey = criteriaRequestKey;
    }

    /**
     * @param currentCriterionModelKey the currentCriterionModelKey to set
     */
    public void setCurrentCriterionModelKey(String currentCriterionModelKey) {
        this.currentCriterionModelKey = currentCriterionModelKey;
    }

    /**
     * @param dataProviderIdFilter the dataProviderIdFilter to set
     */
    public void setDataProviderIdFilter(FilterDTO dataProviderIdFilter) {
        this.dataProviderIdFilter = dataProviderIdFilter;
    }

    /**
     * @param dataProviderParameterKey the dataProviderParameterKey to set
     */
    public void setDataProviderParameterKey(String dataProviderParameterKey) {
        this.dataProviderParameterKey = dataProviderParameterKey;
    }

    /**
     * @param dataResourceFilter the dataResourceFilter to set
     */
    public void setDataResourceFilter(FilterDTO dataResourceFilter) {
        this.dataResourceFilter = dataResourceFilter;
    }

    /**
     * @param dataResourceIdFilter the dataResourceIdFilter to set
     */
    public void setDataResourceIdFilter(FilterDTO dataResourceIdFilter) {
        this.dataResourceIdFilter = dataResourceIdFilter;
    }

    /**
     * @param dataResourceManager the dataResourceManager to set
     */
    public void setDataResourceManager(DataResourceManager dataResourceManager) {
        this.dataResourceManager = dataResourceManager;
    }

    /**
     * @param dataResourceParameterKey the dataResourceParameterKey to set
     */
    public void setDataResourceParameterKey(String dataResourceParameterKey) {
        this.dataResourceParameterKey = dataResourceParameterKey;
    }

    /**
     * @param datasetFields the datasetFields to set
     */
    public void setDatasetDownloadFields(List<Field> datasetDownloadFields) {
        this.datasetDownloadFields = datasetDownloadFields;
    }

    /**
     * @param defaultMapView the defaultMapView to set
     */
    public void setDefaultMapView(String defaultMapView) {
        this.defaultMapView = defaultMapView;
    }

    /**
     * @param defaultView the defaultView to set
     */
    public void setDefaultView(String defaultView) {
        this.defaultView = defaultView;
    }

    /**
     * @param departmentFilter the departmentFilter to set
     */
    public void setDepartmentFilter(FilterDTO departmentFilter) {
        this.departmentFilter = departmentFilter;
    }

    /**
     * @param countyFilter the countyFilter to set
     */
    public void setCountyFilter(FilterDTO countyFilter) {
        this.countyFilter = countyFilter;
    }

    /**
     * @param paramoFilter the paramoFilter to set
     */
    public void setParamoFilter(FilterDTO paramoFilter) {
        this.paramoFilter = paramoFilter;
    }

    /**
     * @param marineZoneFilter the marineZoneFilter to set
     */
    public void setMarineZoneFilter(FilterDTO marineZoneFilter) {
        this.marineZoneFilter = marineZoneFilter;
    }

    /**
     * @param protectedAreaFilter the protectedAreaFilter to set
     */
    public void setProtectedAreaFilter(FilterDTO protectedAreaFilter) {
        this.protectedAreaFilter = protectedAreaFilter;
    }

    /**
     * @param ecosystemFilter the ecosystemFilter to set
     */
    public void setEcosystemFilter(FilterDTO ecosystemFilter) {
        this.ecosystemFilter = ecosystemFilter;
    }

    /**
     * @param zonificacionFilter the zonificacionFilter to set
     */
    public void setZonificacionFilter(FilterDTO zonificacionFilter) {
        this.zonificacionFilter = zonificacionFilter;
    }

    /**
     * @param downloadRedirectPath the downloadRedirectPath to set
     */
    public void setDownloadRedirectPath(String downloadRedirectPath) {
        this.downloadRedirectPath = downloadRedirectPath;
    }

    /**
     * @param downloadSpreadsheetView the downloadSpreadsheetView to set
     */
    public void setDownloadSpreadsheetView(String downloadSpreadsheetView) {
        this.downloadSpreadsheetView = downloadSpreadsheetView;
    }

    /**
     * @param downloadXMLView the downloadXMLView to set
     */
    public void setDownloadXMLView(String downloadXMLView) {
        this.downloadXMLView = downloadXMLView;
    }

    /**
     * @param filterContentProvider the filterContentProvider to set
     */
    public void setFilterContentProvider(FilterContentProvider filterContentProvider) {
        this.filterContentProvider = filterContentProvider;
    }

    /**
     * @param filterMapLayerRoot the filterMapLayerRoot to set
     */
    public void setFilterMapLayerRoot(String filterMapLayerRoot) {
        this.filterMapLayerRoot = filterMapLayerRoot;
    }

    /**
     * @param filtersRequestKey the filtersRequestKey to set
     */
    public void setFiltersRequestKey(String filtersRequestKey) {
        this.filtersRequestKey = filtersRequestKey;
    }

    /**
     * @param formatRequestParam the formatRequestParam to set
     */
    public void setFormatRequestParam(String formatRequestParam) {
        this.formatRequestParam = formatRequestParam;
    }

    /**
     * @param coordinateIssuesFilter the coordinateIssuesFilter to set
     */
    public void setGeoConsistencyFilter(FilterDTO coordinateIssuesFilter) {
        this.geoConsistencyFilter = coordinateIssuesFilter;
    }

    /**
     * @param geoFormats the geoFormats to set
     */
    public void setGeoFormats(List<String> geoFormats) {
        this.geoFormats = geoFormats;
    }

    /**
     * @param coordinateStatusFilter the coordinateStatusFilter to set
     */
    public void setGeoreferencedFilter(FilterDTO coordinateStatusFilter) {
        this.georeferencedFilter = coordinateStatusFilter;
    }

    /**
     * @param geospatialFields the geospatialFields to set
     */
    public void setGeospatialDownloadFields(List<Field> geospatialFields) {
        this.geospatialDownloadFields = geospatialFields;
    }

    /**
     * @param geospatialManager the geospatialManager to set
     */
    public void setGeospatialManager(GeospatialManager geospatialManager) {
        this.geospatialManager = geospatialManager;
    }

    /**
     * @param mandatoryDownloadFields the mandatoryDownloadFields to set
     */
    public void setMandatoryDownloadFields(List<Field> mandatoryDownloadFields) {
        this.mandatoryDownloadFields = mandatoryDownloadFields;
    }

    /**
     * @param mapContentProvider the mapContentProvider to set
     */
    public void setMapContentProvider(MapContentProvider mapContentProvider) {
        this.mapContentProvider = mapContentProvider;
    }

    /**
     * @param mapLayerQueryManager the mapLayerQueryManager to set
     */
    public void setMapLayerQueryManager(TripletQueryManager mapLayerQueryManager) {
        this.mapLayerQueryManager = mapLayerQueryManager;
    }

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

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

    /**
     * @param maxXRequestKey the maxXRequestKey to set
     */
    public void setMaxXRequestKey(String maxXRequestKey) {
        this.maxXRequestKey = maxXRequestKey;
    }

    /**
     * @param maxYRequestKey the maxYRequestKey to set
     */
    public void setMaxYRequestKey(String maxYRequestKey) {
        this.maxYRequestKey = maxYRequestKey;
    }

    /**
     * @param messageSource the messageSource to set
     */
    public void setMessageSource(MessageSource messageSource) {
        this.messageSource = messageSource;
    }

    /**
     * @param messageSourceKey the messageSourceKey to set
     */
    public void setMessageSourceKey(String messageSourceKey) {
        this.messageSourceKey = messageSourceKey;
    }

    /**
     * @param minXRequestKey the minXRequestKey to set
     */
    public void setMinXRequestKey(String minXRequestKey) {
        this.minXRequestKey = minXRequestKey;
    }

    /**
     * @param minYRequestKey the minYRequestKey to set
     */
    public void setMinYRequestKey(String minYRequestKey) {
        this.minYRequestKey = minYRequestKey;
    }

    /**
     * @param namespace the namespace to set
     */
    public void setNamespace(String namespace) {
        this.namespace = namespace;
    }

    /**
     * @param occurrenceFilterCountryCountsView the occurrenceFilterCountryCountsView to set
     */
    public void setOccurrenceFilterCountryCountsView(String occurrenceFilterCountryCountsView) {
        this.occurrenceFilterCountryCountsView = occurrenceFilterCountryCountsView;
    }

    /**
     * @param occurrenceFilterDepartmentCountsView the occurrenceFilterDepartmentCountsView to set
     */
    public void setOccurrenceFilterDepartmentCountsView(String occurrenceFilterDepartmentCountsView) {
        this.occurrenceFilterDepartmentCountsView = occurrenceFilterDepartmentCountsView;
    }

    /**
     * @param occurrenceFilterCountyCountsView the occurrenceFilterCountyCountsView to set
     */
    public void setOccurrenceFilterCountyCountsView(String occurrenceFilterCountyCountsView) {
        this.occurrenceFilterCountyCountsView = occurrenceFilterCountyCountsView;
    }

    /**
     * @param occurrenceFilterProviderCountsView the occurrenceFilterProviderCountsView to set
     */
    public void setOccurrenceFilterProviderCountsView(String occurrenceFilterProviderCountsView) {
        this.occurrenceFilterProviderCountsView = occurrenceFilterProviderCountsView;
    }

    /**
     * @param occurrenceFilterResourceCountsView the occurrenceFilterResourceCountsView to set
     */
    public void setOccurrenceFilterResourceCountsView(String occurrenceFilterResourceCountsView) {
        this.occurrenceFilterResourceCountsView = occurrenceFilterResourceCountsView;
    }

    /**
     * @param occurrenceFilters the occurrenceFilters to set
     */
    public void setOccurrenceFilters(FilterMapWrapper occurrenceFilters) {
        this.occurrenceFilters = occurrenceFilters;
    }

    /**
     * @param occurrenceFilterSpeciesCountsView the occurrenceFilterSpeciesCountsView to set
     */
    public void setOccurrenceFilterSpeciesCountsView(String occurrenceFilterSpeciesCountsView) {
        this.occurrenceFilterSpeciesCountsView = occurrenceFilterSpeciesCountsView;
    }

    /**
     * @param tripletQueryProvider the tripletQueryProvider to set
     */
    public void setPagingTripletQueryProvider(PagingTripletQueryProvider pagingTripletQueryProvider) {
        this.pagingTripletQueryProvider = pagingTripletQueryProvider;
    }

    /**
     * @param pointsTotalRequestKey the pointsTotalRequestKey to set
     */
    public void setPointsTotalRequestKey(String pointsTotalRequestKey) {
        this.pointsTotalRequestKey = pointsTotalRequestKey;
    }

    /**
     * @param queryHelper the queryHelper to set
     */
    public void setQueryHelper(QueryHelper queryHelper) {
        this.queryHelper = queryHelper;
    }

    /**
     * @param regionFilter the regionFilter to set
     */
    public void setRegionFilter(FilterDTO regionFilter) {
        this.regionFilter = regionFilter;
    }

    /**
     * @param resultsLimitModelKey the resultsLimitModelKey to set
     */
    public void setResultsLimitModelKey(String resultsLimitModelKey) {
        this.resultsLimitModelKey = resultsLimitModelKey;
    }

    /**
     * @param resultsModelKey the resultsModelKey to set
     */
    public void setResultsModelKey(String resultsModelKey) {
        this.resultsModelKey = resultsModelKey;
    }

    /**
     * @param returnPredicateSubject the returnPredicateSubject to set
     */
    public void setReturnPredicateSubject(String returnPredicateSubject) {
        this.returnPredicateSubject = returnPredicateSubject;
    }

    /**
     * @param rootWizardUrl the rootWizardUrl to set
     */
    public void setRootWizardUrl(String rootWizardUrl) {
        this.rootWizardUrl = rootWizardUrl;
    }

    /**
     * @param rootWizardUrlModelKey the rootWizardUrlModelKey to set
     */
    public void setRootWizardUrlModelKey(String rootWizardUrlModelKey) {
        this.rootWizardUrlModelKey = rootWizardUrlModelKey;
    }

    /**
     * @param scientificNameFilter the scientificNameFilter to set
     */
    public void setScientificNameFilter(FilterDTO scientificNameFilter) {
        this.scientificNameFilter = scientificNameFilter;
    }

    /**
     * @param selectFieldSubject the selectFieldSubject to set
     */
    public void setSelectFieldSubject(String selectFieldSubject) {
        this.selectFieldSubject = selectFieldSubject;
    }

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

    /**
     * @param taxonomyFields the taxonomyFields to set
     */
    public void setTaxonomyDownloadFields(List<Field> taxonomyDownloadFields) {
        this.taxonomyDownloadFields = taxonomyDownloadFields;
    }

    /**
     * @param taxonomyManager the taxonomyManager to set
     */
    public void setTaxonomyManager(TaxonomyManager taxonomyManager) {
        this.taxonomyManager = taxonomyManager;
    }

    /**
     * @param tripletQueryManager the tripletQueryManager to set
     */
    public void setTripletQueryManager(TripletQueryManager tripletQueryManager) {
        this.tripletQueryManager = tripletQueryManager;
    }

    /**
     * @param webappPropertyStore the webappPropertyStore to set
     */
    public void setWebappPropertyStore(PropertyStore webappPropertyStore) {
        this.webappPropertyStore = webappPropertyStore;
    }
}