001/* 002 * Copyright 2018 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.web.frontoffice.search.requesttime.impl; 017 018import java.util.Collection; 019import java.util.List; 020import java.util.Map; 021import java.util.Set; 022import java.util.stream.Collectors; 023 024import org.apache.commons.collections4.CollectionUtils; 025import org.slf4j.Logger; 026 027import org.ametys.cms.search.solr.SearcherFactory.Searcher; 028import org.ametys.web.frontoffice.search.metamodel.FacetDefinition; 029import org.ametys.web.frontoffice.search.requesttime.SearchComponent; 030import org.ametys.web.frontoffice.search.requesttime.SearchComponentArguments; 031import org.ametys.web.frontoffice.search.requesttime.input.SearchUserInputs; 032import org.ametys.web.frontoffice.search.requesttime.input.impl.UserPrefsSearchUserInputs; 033 034/** 035 * {@link SearchComponent} for executing the search with facets. 036 */ 037public class FacetSearchComponent implements SearchComponent 038{ 039 @Override 040 public int priority() 041 { 042 return SEARCH_PRIORITY - 7000; 043 } 044 045 @Override 046 public boolean supports(SearchComponentArguments args) 047 { 048 return args.launchSearch(); 049 } 050 051 @Override 052 public void execute(SearchComponentArguments args) throws Exception 053 { 054 Searcher searcher = args.searcher(); 055 Collection<FacetDefinition> serviceFacets = args.serviceInstance().getFacets(); 056 SearchUserInputs userInputs = args.userInputs(); 057 Map<String, List<String>> userFacets = checkValidInputs(serviceFacets, userInputs.facets(), userInputs instanceof UserPrefsSearchUserInputs, args.logger()); 058 059 searcher.withFacets(serviceFacets.stream() 060 .map(FacetDefinition::getSearchField) 061 .collect(Collectors.toList())); 062 063 searcher.withFacetValues(userFacets); 064 } 065 066 /** 067 * Checks the user inputs are valid 068 * @param serviceFacets The facets of the service instance 069 * @param userFacets The user input facets 070 * @param isFromUserPref <code>true</code> if the facets are from user pref. Then return only the valid input, otherwise throw an exception 071 * @param logger The logger 072 * @return the filtered user facets 073 * @throws InvalidUserInputException if at least user one input is invalid 074 */ 075 protected Map<String, List<String>> checkValidInputs(Collection<FacetDefinition> serviceFacets, Map<String, List<String>> userFacets, boolean isFromUserPref, Logger logger) throws InvalidUserInputException 076 { 077 Map<String, List<String>> filteredUserFacets = userFacets; 078 079 Collection<String> facetIds = serviceFacets 080 .stream() 081 .map(FacetDefinition::getId) 082 .collect(Collectors.toList()); 083 Set<String> userFacetIds = userFacets.keySet(); 084 085 if (!CollectionUtils.containsAll(facetIds, userFacetIds)) 086 { 087 throw new InvalidUserInputException("At least one of the user input facets is invalid because it was not declared by the service instance."); 088 } 089 090 // If the user input is from user pref, just ignore the invalid input 091 if (isFromUserPref) 092 { 093 filteredUserFacets = filteredUserFacets.entrySet() 094 .stream() 095 .filter(f -> this._isFromFacets(userFacetIds, f.getKey(), logger)) 096 .collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue())); 097 } 098 else if (!CollectionUtils.containsAll(facetIds, userFacetIds)) 099 { 100 throw new InvalidUserInputException("At least one of the user input criterion is invalid because it was not declared by the service instance."); 101 } 102 103 return filteredUserFacets; 104 105 } 106 107 private boolean _isFromFacets(Set<String> userFacetIds, String facetId, Logger logger) 108 { 109 boolean isFromCriteria = userFacetIds.contains(facetId); 110 if (!isFromCriteria) 111 { 112 if (logger.isDebugEnabled()) 113 { 114 logger.debug("The user input criterion ({}) from user preferences is invalid because it was not declared by the service instance.", facetId); 115 } 116 } 117 return isFromCriteria; 118 } 119}