/** * Copyright 2008 The University of North Carolina at Chapel Hill * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package edu.unc.lib.dl.search.solr.util; import java.net.URLDecoder; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import org.springframework.beans.factory.annotation.Autowired; import edu.unc.lib.dl.search.solr.model.SearchFacet; import edu.unc.lib.dl.search.solr.model.SearchState; import edu.unc.lib.dl.search.solr.model.SearchState.RangePair; /** * Utility class which transforms search states to other formats. * @author bbpennel */ public class SearchStateUtil { private static SearchSettings searchSettings; public SearchStateUtil(){ } private static String urlEncodeParameter(String value) { char[] chars = value.toCharArray(); StringBuilder sb = new StringBuilder(); for (char character: chars) { if (character == '&') sb.append("%26"); else if (character == '=') sb.append("%3D"); else if (character == '#') sb.append("%23"); else sb.append(character); } return sb.toString(); } public static HashMap<String,String> generateSearchParameters(SearchState searchState) { HashMap<String,String> params = new HashMap<String,String>(); if (searchState.getSearchFields() != null && searchState.getSearchFields().size() > 0){ for (Entry<String,String> field: searchState.getSearchFields().entrySet()) { String fieldName = searchSettings.searchFieldParam(field.getKey()); params.put(fieldName, urlEncodeParameter(field.getValue())); } } if (searchState.getRangeFields() != null && searchState.getRangeFields().size() > 0){ for (Entry<String, RangePair> field: searchState.getRangeFields().entrySet()) { String fieldName = searchSettings.searchFieldParam(field.getKey()); params.put(fieldName, urlEncodeParameter(field.getValue().toString())); } } String ancestorPath = SearchFieldKeys.ANCESTOR_PATH.toString(); if (searchState.getFacets() != null && searchState.getFacets().size() > 0){ for (Entry<String,Object> field: searchState.getFacets().entrySet()) { if (!ancestorPath.equals(field.getKey())) { String fieldName = searchSettings.searchFieldParam(field.getKey()); if (field.getValue() instanceof SearchFacet) params.put(fieldName, urlEncodeParameter(((SearchFacet) field.getValue()).getLimitToValue())); else params.put(fieldName, urlEncodeParameter(field.getValue().toString())); } } } return params; } /** * Returns the search state as a URL query string. * @param searchState * @return */ public static HashMap<String,String> generateStateParameters(SearchState searchState){ HashMap<String,String> params = generateSearchParameters(searchState); if (searchState.getRowsPerPage() != null && searchState.getRowsPerPage() >= 0) { params.put(searchSettings.searchStateParam("ROWS_PER_PAGE"), ""+searchState.getRowsPerPage()); } if (searchState.getFacetsToRetrieve() != null && searchState.getFacetsToRetrieve().size() > 0 && !searchState.getFacetsToRetrieve().containsAll(searchSettings.facetNames)){ params.put(searchSettings.searchStateParam("FACET_FIELDS_TO_RETRIEVE"), joinFields(searchState.getFacetsToRetrieve(), ",", true)); } if (searchState.getFacetLimits() != null && searchState.getFacetLimits().size() > 0){ params.put(searchSettings.searchStateParam("FACET_LIMIT_FIELDS"), joinFields(searchState.getFacetLimits())); } if (searchState.getStartRow() != null && searchState.getStartRow() != 0){ params.put(searchSettings.searchStateParam("START_ROW"), ""+searchState.getStartRow()); } //Add base facet limit if it isn't the default if (searchState.getBaseFacetLimit() != null && searchState.getBaseFacetLimit() != searchSettings.facetsPerGroup){ params.put(searchSettings.searchStateParam("BASE_FACET_LIMIT"), ""+searchState.getBaseFacetLimit()); } if (searchState.getSortType() != null && searchState.getSortType().length() != 0){ if (!"default".equals(searchState.getSortType()) || !searchState.getSortNormalOrder()) { StringBuilder sortValue = new StringBuilder(); sortValue.append(searchState.getSortType()); if (!searchState.getSortNormalOrder()) sortValue.append(',').append(searchSettings.sortReverse); params.put(searchSettings.searchStateParam("SORT_TYPE"), sortValue.toString()); } } //Append search term operator if its not the default if (searchState.getSearchTermOperator() != null && !searchState.getSearchTermOperator().equals(searchSettings.defaultOperator)){ params.put(searchSettings.searchStateParam("SEARCH_TERM_OPERATOR"), searchState.getSearchTermOperator()); } if (searchState.getResourceTypes() != null && !searchState.getResourceTypes().containsAll(searchSettings.defaultResourceTypes)){ params.put(searchSettings.searchStateParam("RESOURCE_TYPES"), joinFields(searchState.getResourceTypes(), ",", false)); } return params; } public static String generateSearchParameterString(SearchState searchState) { return generateStateParameterString(generateSearchParameters(searchState)); } public static String generateStateParameterString(SearchState searchState){ return generateStateParameterString(generateStateParameters(searchState)); } public static String generateStateParameterString(HashMap<String,String> stateParameters){ return joinFields(stateParameters, '&', '=', false); } private static String joinFields(Collection<String> collection, String delimiter, boolean performFieldLookup) { StringBuilder sb = new StringBuilder(); boolean first = true; for (String object: collection){ if (first) first = false; else sb.append(delimiter); if (performFieldLookup){ sb.append(searchSettings.searchFieldParam(object)); } else { sb.append(object); } } return sb.toString(); } private static String joinFields(Map<?,?> fields, char pairDelimiter, char keyValueDelimiter){ return joinFields(fields, pairDelimiter, keyValueDelimiter, true); } private static String joinFields(Map<?,?> fields, char pairDelimiter, char keyValueDelimiter, boolean performFieldLookup){ StringBuilder sb = new StringBuilder(); boolean firstField = true; Iterator<?> fieldIt = fields.keySet().iterator(); while (fieldIt.hasNext()){ String fieldName = (String)fieldIt.next(); Object value = fields.get(fieldName); if (value != null && value.toString().trim().length() > 0) { if (firstField) firstField = false; else sb.append(pairDelimiter); if (performFieldLookup) sb.append(searchSettings.searchFieldParam(fieldName)); else sb.append(fieldName); sb.append(keyValueDelimiter); if (value != null) sb.append(value); } } return sb.toString(); } private static String joinFacets(Map<String,Object> fields, char pairDelimiter, char keyValueDelimiter){ StringBuffer sb = new StringBuffer(); boolean firstField = true; Iterator<String> fieldIt = fields.keySet().iterator(); while (fieldIt.hasNext()){ String fieldName = fieldIt.next(); if (firstField) firstField = false; else sb.append(pairDelimiter); sb.append(searchSettings.searchFieldParam(fieldName)).append(keyValueDelimiter); Object fieldValue = fields.get(fieldName); if (fieldValue != null){ if (fieldValue instanceof SearchFacet){ sb.append(((SearchFacet) fieldValue).getLimitToValue().replace("|", "%7C")); } else { sb.append(fieldValue.toString().replace("|", "%7C")); } } } return sb.toString(); } private static String joinFields(Map<?,?> fields){ return joinFields(fields, '|', ':'); } /** * Transforms a search state in URL format to a parameter map. * @param searchStateUrl * @return */ public static HashMap<String, String[]> getParametersAsHashMap(String searchStateUrl){ HashMap<String,String[]> parameterHashMap = new HashMap<String,String[]>(); String[] parameterList = searchStateUrl.split("&"); for (String parameter: parameterList){ String[] parameterPair = parameter.split("="); if (parameterPair.length == 2){ try { String[] valueArray = new String[1]; valueArray[0] = URLDecoder.decode(parameterPair[1], "UTF-8"); parameterHashMap.put(parameterPair[0], valueArray); } catch (Exception e){ } } } return parameterHashMap; } public SearchSettings getSearchSettings() { return searchSettings; } @Autowired public void setSearchSettings(SearchSettings searchSettings) { SearchStateUtil.searchSettings = searchSettings; } }