001/* 002 * Licensed under the Apache License, Version 2.0 (the "License"); 003 * you may not use this file except in compliance with the License. 004 * You may obtain a copy of the License at 005 * 006 * http://www.apache.org/licenses/LICENSE-2.0 007 * 008 * Unless required by applicable law or agreed to in writing, software 009 * distributed under the License is distributed on an "AS IS" BASIS, 010 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 011 * See the License for the specific language governing permissions and 012 * limitations under the License. 013 */ 014package org.gbif.ws.server.provider; 015 016import org.gbif.api.model.common.search.FacetedSearchRequest; 017import org.gbif.api.model.common.search.SearchParameter; 018 019import java.util.Arrays; 020import java.util.Collections; 021import java.util.List; 022import java.util.Map; 023 024import org.apache.commons.lang3.StringUtils; 025import org.springframework.web.context.request.WebRequest; 026 027import static org.gbif.ws.util.CommonWsUtils.getFirst; 028import static org.gbif.ws.util.WebserviceParameter.PARAM_FACET; 029import static org.gbif.ws.util.WebserviceParameter.PARAM_FACET_LIMIT; 030import static org.gbif.ws.util.WebserviceParameter.PARAM_FACET_MINCOUNT; 031import static org.gbif.ws.util.WebserviceParameter.PARAM_FACET_MULTISELECT; 032import static org.gbif.ws.util.WebserviceParameter.PARAM_FACET_OFFSET; 033 034/** 035 * Provider class that transforms a set of HTTP parameters into a FacetedSearchRequest class instance. 036 * This assumes the existence of the following parameters in the HTTP request: 037 * 'page_size', 'offset', 'facet', 'q' and any of the search parameter enum member names case insensitively. 038 */ 039public class FacetedSearchRequestProvider< 040 RT extends FacetedSearchRequest<P>, P extends Enum<?> & SearchParameter> 041 extends SearchRequestProvider<RT, P> { 042 043 private static final int DEFAULT_FACET_LIMIT = 10; 044 045 public FacetedSearchRequestProvider(Class<RT> requestType, Class<P> searchParameterClass) { 046 super(requestType, searchParameterClass); 047 } 048 049 public FacetedSearchRequestProvider( 050 Class<RT> requestType, Class<P> searchParameterClass, Integer maxPageSize) { 051 super(requestType, searchParameterClass, maxPageSize); 052 } 053 054 @Override 055 protected RT getSearchRequest(WebRequest webRequest, RT searchRequest) { 056 RT request = super.getSearchRequest(webRequest, searchRequest); 057 058 final Map<String, String[]> params = webRequest.getParameterMap(); 059 060 final String facetMultiSelectValue = getFirstIgnoringCase(PARAM_FACET_MULTISELECT, params); 061 if (facetMultiSelectValue != null) { 062 searchRequest.setMultiSelectFacets(Boolean.parseBoolean(facetMultiSelectValue)); 063 } 064 065 final String facetMinCountValue = getFirstIgnoringCase(PARAM_FACET_MINCOUNT, params); 066 if (facetMinCountValue != null) { 067 searchRequest.setFacetMinCount(Integer.parseInt(facetMinCountValue)); 068 } 069 070 final String facetLimit = getFirstIgnoringCase(PARAM_FACET_LIMIT, params); 071 if (facetLimit != null) { 072 searchRequest.setFacetLimit(Integer.parseInt(facetLimit)); 073 } 074 075 final String facetOffset = getFirstIgnoringCase(PARAM_FACET_OFFSET, params); 076 if (facetOffset != null) { 077 searchRequest.setFacetOffset(Integer.parseInt(facetOffset)); 078 } 079 080 final List<String> facets = 081 params.get(PARAM_FACET) != null 082 ? Arrays.asList(params.get(PARAM_FACET)) 083 : Collections.emptyList(); 084 if (!facets.isEmpty()) { 085 for (String f : facets) { 086 P p = findSearchParam(f); 087 if (p != null) { 088 searchRequest.addFacets(p); 089 String pFacetOffset = getFirstIgnoringCase(f + '.' + PARAM_FACET_OFFSET, params); 090 String pFacetLimit = getFirstIgnoringCase(f + '.' + PARAM_FACET_LIMIT, params); 091 if (pFacetLimit != null) { 092 if (pFacetOffset != null) { 093 searchRequest.addFacetPage( 094 p, Integer.parseInt(pFacetOffset), Integer.parseInt(pFacetLimit)); 095 } else { 096 searchRequest.addFacetPage(p, 0, Integer.parseInt(pFacetLimit)); 097 } 098 } else if (pFacetOffset != null) { 099 searchRequest.addFacetPage(p, Integer.parseInt(pFacetOffset), DEFAULT_FACET_LIMIT); 100 } 101 } 102 } 103 } 104 105 return request; 106 } 107 108 /** 109 * Get the first parameter value, the parameter is searched in a case-insensitive manner. 110 * First tries with the exact match, then the lowercase and finally the uppercase value of the parameter. 111 */ 112 private static String getFirstIgnoringCase(String parameter, Map<String, String[]> params) { 113 String value = getFirst(params, parameter); 114 if (StringUtils.isNotEmpty(value)) { 115 return value; 116 } 117 value = getFirst(params, parameter.toLowerCase()); 118 if (StringUtils.isNotEmpty(value)) { 119 return value; 120 } 121 value = getFirst(params, parameter.toUpperCase()); 122 if (StringUtils.isNotEmpty(value)) { 123 return value; 124 } 125 return null; 126 } 127}