001/* 002 * Copyright 2019 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.input.impl; 017 018import java.util.Arrays; 019import java.util.Collections; 020import java.util.Comparator; 021import java.util.Enumeration; 022import java.util.List; 023import java.util.Map; 024import java.util.stream.Collectors; 025import java.util.stream.Stream; 026 027import org.apache.cocoon.environment.Request; 028import org.apache.commons.lang3.StringUtils; 029import org.apache.commons.lang3.tuple.Pair; 030import org.apache.commons.lang3.tuple.Triple; 031import org.slf4j.Logger; 032import org.slf4j.LoggerFactory; 033 034import org.ametys.cms.search.Sort; 035 036/** 037 * The search user inputs from a submitted form. 038 */ 039public class FormSearchUserInputs extends AbstractSearchUserInputs 040{ 041 /** Logger */ 042 protected static final Logger __LOGGER = LoggerFactory.getLogger(FormSearchUserInputs.class); 043 044 private static final String USER_INPUT_PREFIX = "user.input."; 045 046 /** The prefix for the criteria */ 047 public static final String CRITERION_PREFIX = USER_INPUT_PREFIX + "criterion."; 048 /** The prefix for the facets */ 049 public static final String FACET_PREFIX = USER_INPUT_PREFIX + "facet."; 050 /** The prefix for the sorts */ 051 public static final String SORT_PREFIX = USER_INPUT_PREFIX + "sort."; 052 053 /** 054 * The constructor for search user inputs from a form. 055 * @param request The request 056 */ 057 public FormSearchUserInputs(Request request) 058 { 059 _criteria = _retrieveUserCriteria(request); 060 _facets = _retrieveUserFacets(request); 061 _sorts = _retrieveUserSorts(request); 062 } 063 064 /** 065 * Retrieves the user criteria 066 * @param request the request 067 * @return the user criteria 068 */ 069 protected Map<String, Object> _retrieveUserCriteria(Request request) 070 { 071 return Collections.list((Enumeration<String>) request.getParameterNames()) 072 .stream() 073 .filter(param -> param.startsWith(CRITERION_PREFIX)) 074 .filter(param -> _isNotBlank(request, param)) 075 .collect(Collectors.toMap( 076 param -> StringUtils.removeStart(param, CRITERION_PREFIX), 077 param -> _requestParameterToTypedObject(request, param) 078 )); 079 } 080 081 /** 082 * Returns <code>true</code> if at least one of the parameter values is not blank 083 * @param request the request 084 * @param param the parameter name 085 * @return <code>true</code> if at least one of the parameter values is not blank 086 */ 087 protected boolean _isNotBlank(Request request, String param) 088 { 089 String[] parameterValues = request.getParameterValues(param); 090 if (parameterValues == null) 091 { 092 return false; 093 } 094 095 for (String parameterValue : parameterValues) 096 { 097 if (StringUtils.isNotBlank(parameterValue)) 098 { 099 // at least one is not blank 100 return true; 101 } 102 } 103 104 // all values are blank 105 return false; 106 } 107 108 /** 109 * Gets a typed object from request parameters 110 * @param request the request 111 * @param param the parameter name 112 * @return a typed object 113 */ 114 protected Object _requestParameterToTypedObject(Request request, String param) 115 { 116 String[] parameterValues = request.getParameterValues(param); // cannot be null due to #_isNotBlank 117 List<String> notBlankValues = Stream.of(parameterValues) 118 .filter(StringUtils::isNotBlank) 119 .collect(Collectors.toList()); 120 121 if (notBlankValues.size() == 1) 122 { 123 return notBlankValues.get(0); 124 } 125 else 126 { 127 return notBlankValues; 128 } 129 } 130 131 /** 132 * Retrieves the user facets 133 * @param request the request 134 * @return the user facets 135 */ 136 protected Map<String, List<String>> _retrieveUserFacets(Request request) 137 { 138 return Collections.list((Enumeration<String>) request.getParameterNames()) 139 .stream() 140 .filter(param -> param.startsWith(FACET_PREFIX)) 141 .collect(Collectors.toMap( 142 param -> StringUtils.removeStart(param, FACET_PREFIX), 143 param -> Arrays.asList(StringUtils.split(request.getParameter(param), ',')) 144 )); 145 } 146 147 /** 148 * Retrieves the user sorts 149 * @param request the request 150 * @return the user sorts 151 */ 152 protected List<Pair<String, Sort.Order>> _retrieveUserSorts(Request request) 153 { 154 return Collections.list((Enumeration<String>) request.getParameterNames()) // parameters have the following format: "user.input.sort.foo=ASC,1" 155 .stream() 156 .filter(param -> param.startsWith(SORT_PREFIX)) 157 .map(param -> Pair.of(StringUtils.removeStart(param, SORT_PREFIX), request.getParameter(param))) 158 .peek(pair -> 159 { 160 String sortValue = pair.getRight(); 161 if (!sortValue.contains(",")) 162 { 163 __LOGGER.warn("'{}{}' parameter does not have a valid value: '{}'. Missing a \",\" character to distinguish the sort (ASC or DESC) from the sort order (integer)", SORT_PREFIX, pair.getLeft(), sortValue); 164 } 165 }) 166 .filter(pair -> pair.getRight().contains(",")) 167 .map(pair -> 168 { 169 String sortValue = pair.getRight(); 170 String[] strings = sortValue.split(","); 171 return Triple.of(pair.getLeft(), strings[0]/*ASC or DESC*/, strings[1]/*order in the list of all sorts*/); 172 }) 173 .sorted(Comparator.comparing(triple -> Integer.parseInt(triple.getRight()))) 174 .map(triple -> Pair.of(triple.getLeft(), Sort.Order.valueOf(triple.getMiddle()))) 175 .collect(Collectors.toList()); 176 } 177}