001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com) 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * For further information about Alkacon Software, please see the 018 * company website: http://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: http://www.opencms.org 022 * 023 * You should have received a copy of the GNU Lesser General Public 024 * License along with this library; if not, write to the Free Software 025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 026 */ 027 028package org.opencms.jsp.search.result; 029 030import org.opencms.i18n.CmsEncoder; 031import org.opencms.jsp.search.controller.I_CmsSearchControllerFacetField; 032import org.opencms.jsp.search.controller.I_CmsSearchControllerFacetQuery; 033import org.opencms.jsp.search.controller.I_CmsSearchControllerFacetRange; 034import org.opencms.main.CmsLog; 035import org.opencms.util.CmsCollectionsGenericWrapper; 036 037import java.util.Arrays; 038import java.util.Collection; 039import java.util.HashMap; 040import java.util.List; 041import java.util.Map; 042 043import org.apache.commons.collections.Transformer; 044import org.apache.commons.logging.Log; 045 046/** 047 * State parameter wrapper that allows to manipulate the request parameters representing the state 048 * of the current search. It can be used to generate links for an adjusted search. 049 */ 050public class CmsSearchStateParameters implements I_CmsSearchStateParameters { 051 052 /** Logger for the class. */ 053 protected static final Log LOG = CmsLog.getLog(CmsSearchStateParameters.class); 054 055 /** Map of request parameters, representing the search's state. */ 056 Map<String, String[]> m_params; 057 /** The result of the search. */ 058 I_CmsSearchResultWrapper m_result; 059 060 /** Map with page numbers as keys and the according state parameters as values. */ 061 Map<String, I_CmsSearchStateParameters> m_paginationMap; 062 /** Map from sort options to state parameters. */ 063 Map<String, I_CmsSearchStateParameters> m_sortingMap; 064 /** Map from facet names to state parameters without the filter queries for the facet. */ 065 Map<String, I_CmsSearchStateParameters> m_resetFacetMap; 066 /** Map from facet names to state parameters with parameters for ignoring the facet's limit added. */ 067 Map<String, I_CmsSearchStateParameters> m_ignoreLimitFacetMap; 068 /** Map new queries to state parameters with the query replaced by the new query. */ 069 Map<String, I_CmsSearchStateParameters> m_newQueryMap; 070 /** Map from facet names to state parameters with parameters for ignoring the facet's limit removed. */ 071 Map<String, I_CmsSearchStateParameters> m_respectLimitFacetMap; 072 /** Map from facet names to a map from facet items to state parameters with the item unchecked. */ 073 Map<String, Map<String, I_CmsSearchStateParameters>> m_uncheckFacetMap; 074 /** Map from facet names to a map from facet items to state parameters with the item checked. */ 075 Map<String, Map<String, I_CmsSearchStateParameters>> m_checkFacetMap; 076 077 /** Constructor for a state parameters object. 078 * @param result The search result, according to which the parameters are manipulated. 079 * @param params The original parameter set. 080 */ 081 public CmsSearchStateParameters(final I_CmsSearchResultWrapper result, final Map<String, String[]> params) { 082 083 m_params = params; 084 m_result = result; 085 } 086 087 /** Converts a parameter map to the parameter string. 088 * @param parameters the parameter map. 089 * @return the parameter string. 090 */ 091 public static String paramMapToString(final Map<String, String[]> parameters) { 092 093 final StringBuffer result = new StringBuffer(); 094 for (final String key : parameters.keySet()) { 095 String[] values = parameters.get(key); 096 if (null == values) { 097 result.append(key).append('&'); 098 } else { 099 for (final String value : parameters.get(key)) { 100 result.append(key).append('=').append(CmsEncoder.encode(value)).append('&'); 101 } 102 } 103 } 104 // remove last '&' 105 if (result.length() > 0) { 106 result.setLength(result.length() - 1); 107 } 108 return result.toString(); 109 } 110 111 /** 112 * @see org.opencms.jsp.search.result.I_CmsSearchStateParameters#getAddIgnoreFacetLimit() 113 */ 114 public Map<String, I_CmsSearchStateParameters> getAddIgnoreFacetLimit() { 115 116 if (m_ignoreLimitFacetMap == null) { 117 m_ignoreLimitFacetMap = CmsCollectionsGenericWrapper.createLazyMap(new Transformer() { 118 119 @Override 120 public Object transform(final Object facet) { 121 122 final Map<String, String[]> parameters = new HashMap<String, String[]>(m_params); 123 String facetParamKey = null; 124 try { 125 facetParamKey = m_result.getController().getFieldFacets().getFieldFacetController().get( 126 facet).getConfig().getIgnoreMaxParamKey(); 127 } catch (Exception e) { 128 // Facet did not exist 129 LOG.warn(Messages.get().getBundle().key(Messages.LOG_FACET_NOT_CONFIGURED_1, facet), e); 130 } 131 if ((facetParamKey != null) && !parameters.containsKey(facetParamKey)) { 132 parameters.put(facetParamKey, null); 133 } 134 return new CmsSearchStateParameters(m_result, parameters); 135 } 136 }); 137 } 138 return m_ignoreLimitFacetMap; 139 } 140 141 /** 142 * @see org.opencms.jsp.search.result.I_CmsSearchStateParameters#getCheckFacetItem() 143 */ 144 @Override 145 public Map<String, Map<String, I_CmsSearchStateParameters>> getCheckFacetItem() { 146 147 if (m_checkFacetMap == null) { 148 m_checkFacetMap = CmsCollectionsGenericWrapper.createLazyMap(new Transformer() { 149 150 @Override 151 public Object transform(final Object facet) { 152 153 Map<String, I_CmsSearchStateParameters> m_checkEntries = CmsCollectionsGenericWrapper.createLazyMap( 154 new Transformer() { 155 156 @Override 157 public Object transform(final Object facetItem) { 158 159 final Map<String, String[]> parameters = new HashMap<String, String[]>(m_params); 160 String facetParamKey = getFacetParamKey((String)facet); 161 if (facetParamKey != null) { // otherwise the facet was not configured, thus no item can be added 162 if (parameters.containsKey(facetParamKey)) { 163 String[] values = parameters.get(facetParamKey); 164 if (!Arrays.asList(values).contains(facetItem)) { 165 String[] newValues = new String[Arrays.asList(values).size() + 1]; 166 for (int i = 0; i < (values.length); i++) { 167 newValues[i] = values[i]; 168 } 169 newValues[values.length] = (String)facetItem; 170 parameters.put(facetParamKey, newValues); 171 } 172 } else { 173 parameters.put(facetParamKey, new String[] {(String)facetItem}); 174 } 175 176 } 177 return new CmsSearchStateParameters(m_result, parameters); 178 } 179 }); 180 return m_checkEntries; 181 } 182 }); 183 } 184 return m_checkFacetMap; 185 186 } 187 188 /** 189 * @see org.opencms.jsp.search.result.I_CmsSearchStateParameters#getNewQuery() 190 */ 191 @Override 192 public Map<String, I_CmsSearchStateParameters> getNewQuery() { 193 194 if (m_newQueryMap == null) { 195 m_newQueryMap = CmsCollectionsGenericWrapper.createLazyMap(new Transformer() { 196 197 @Override 198 public Object transform(final Object queryString) { 199 200 final Map<String, String[]> parameters = new HashMap<String, String[]>(m_params); 201 String queryKey = m_result.getController().getCommon().getConfig().getQueryParam(); 202 if (parameters.containsKey(queryKey)) { 203 parameters.remove(queryKey); 204 } 205 parameters.put(queryKey, new String[] {(String)queryString}); 206 return new CmsSearchStateParameters(m_result, parameters); 207 } 208 }); 209 } 210 return m_newQueryMap; 211 } 212 213 /** 214 * @see org.opencms.jsp.search.result.I_CmsSearchStateParameters#getRemoveIgnoreFacetLimit() 215 */ 216 public Map<String, I_CmsSearchStateParameters> getRemoveIgnoreFacetLimit() { 217 218 if (m_ignoreLimitFacetMap == null) { 219 m_ignoreLimitFacetMap = CmsCollectionsGenericWrapper.createLazyMap(new Transformer() { 220 221 @Override 222 public Object transform(final Object facet) { 223 224 final Map<String, String[]> parameters = new HashMap<String, String[]>(m_params); 225 String facetParamKey = null; 226 try { 227 facetParamKey = m_result.getController().getFieldFacets().getFieldFacetController().get( 228 facet).getConfig().getIgnoreMaxParamKey(); 229 } catch (Exception e) { 230 // Facet did not exist 231 LOG.warn(Messages.get().getBundle().key(Messages.LOG_FACET_NOT_CONFIGURED_1, facet), e); 232 } 233 if ((facetParamKey != null) && parameters.containsKey(facetParamKey)) { 234 parameters.remove(facetParamKey); 235 } 236 return new CmsSearchStateParameters(m_result, parameters); 237 } 238 }); 239 } 240 return m_ignoreLimitFacetMap; 241 } 242 243 /** 244 * @see org.opencms.jsp.search.result.I_CmsSearchStateParameters#getResetAllFacetStates() 245 */ 246 @Override 247 public I_CmsSearchStateParameters getResetAllFacetStates() { 248 249 final Map<String, String[]> parameters = new HashMap<String, String[]>(m_params); 250 // Remove selected entries from field facets 251 Collection<I_CmsSearchControllerFacetField> fieldFacets = m_result.getController().getFieldFacets().getFieldFacetControllers(); 252 for (I_CmsSearchControllerFacetField facet : fieldFacets) { 253 String facetParamKey = facet.getConfig().getParamKey(); 254 if (parameters.containsKey(facetParamKey)) { 255 parameters.remove(facetParamKey); 256 } 257 } 258 // Remove selected entries from range facets 259 Collection<I_CmsSearchControllerFacetRange> rangeFacets = m_result.getController().getRangeFacets().getRangeFacetControllers(); 260 for (I_CmsSearchControllerFacetRange facet : rangeFacets) { 261 String facetParamKey = facet.getConfig().getParamKey(); 262 if (parameters.containsKey(facetParamKey)) { 263 parameters.remove(facetParamKey); 264 } 265 } 266 // Remove selected entries from the query facet 267 I_CmsSearchControllerFacetQuery facet = m_result.getController().getQueryFacet(); 268 if (null != facet) { 269 String facetParamKey = facet.getConfig().getParamKey(); 270 if (parameters.containsKey(facetParamKey)) { 271 parameters.remove(facetParamKey); 272 } 273 } 274 return new CmsSearchStateParameters(m_result, parameters); 275 } 276 277 /** 278 * @see org.opencms.jsp.search.result.I_CmsSearchStateParameters#getResetFacetState() 279 */ 280 @Override 281 public Map<String, I_CmsSearchStateParameters> getResetFacetState() { 282 283 if (m_resetFacetMap == null) { 284 m_resetFacetMap = CmsCollectionsGenericWrapper.createLazyMap(new Transformer() { 285 286 @Override 287 public Object transform(final Object facet) { 288 289 final Map<String, String[]> parameters = new HashMap<String, String[]>(m_params); 290 String facetParamKey = getFacetParamKey((String)facet); 291 if ((facetParamKey != null) && parameters.containsKey(facetParamKey)) { 292 parameters.remove(facetParamKey); 293 } 294 return new CmsSearchStateParameters(m_result, parameters); 295 } 296 }); 297 } 298 return m_resetFacetMap; 299 } 300 301 /** 302 * @see org.opencms.jsp.search.result.I_CmsSearchStateParameters#getSetPage() 303 */ 304 @Override 305 public Map<String, I_CmsSearchStateParameters> getSetPage() { 306 307 if (m_paginationMap == null) { 308 m_paginationMap = CmsCollectionsGenericWrapper.createLazyMap(new Transformer() { 309 310 @Override 311 public Object transform(final Object page) { 312 313 final Map<String, String[]> parameters = new HashMap<String, String[]>(m_params); 314 parameters.put( 315 m_result.getController().getPagination().getConfig().getPageParam(), 316 new String[] {(String)page}); 317 return new CmsSearchStateParameters(m_result, parameters); 318 } 319 }); 320 } 321 return m_paginationMap; 322 } 323 324 /** 325 * @see org.opencms.jsp.search.result.I_CmsSearchStateParameters#getSetSortOption() 326 */ 327 @Override 328 public Map<String, I_CmsSearchStateParameters> getSetSortOption() { 329 330 if (m_sortingMap == null) { 331 m_sortingMap = CmsCollectionsGenericWrapper.createLazyMap(new Transformer() { 332 333 @Override 334 public Object transform(final Object sortOption) { 335 336 final Map<String, String[]> parameters = new HashMap<String, String[]>(m_params); 337 m_result.getController().addParametersForCurrentState(parameters); 338 parameters.put( 339 m_result.getController().getSorting().getConfig().getSortParam(), 340 new String[] {(String)sortOption}); 341 return new CmsSearchStateParameters(m_result, parameters); 342 } 343 }); 344 } 345 return m_sortingMap; 346 } 347 348 /** 349 * @see org.opencms.jsp.search.result.I_CmsSearchStateParameters#getUncheckFacetItem() 350 */ 351 @Override 352 public Map<String, Map<String, I_CmsSearchStateParameters>> getUncheckFacetItem() { 353 354 if (m_uncheckFacetMap == null) { 355 m_uncheckFacetMap = CmsCollectionsGenericWrapper.createLazyMap(new Transformer() { 356 357 @Override 358 public Object transform(final Object facet) { 359 360 Map<String, I_CmsSearchStateParameters> m_uncheckEntries = CmsCollectionsGenericWrapper.createLazyMap( 361 new Transformer() { 362 363 @Override 364 public Object transform(final Object facetItem) { 365 366 final Map<String, String[]> parameters = new HashMap<String, String[]>(m_params); 367 String facetParamKey = getFacetParamKey((String)facet); 368 if ((facetParamKey != null) && parameters.containsKey(facetParamKey)) { 369 String[] values = parameters.get(facetParamKey); 370 List<String> valueList = Arrays.asList(values); 371 String item = (String)facetItem; 372 if (valueList.contains(facetItem)) { 373 String[] newValues = new String[valueList.size() - 1]; 374 int i = 0; 375 for (String value : valueList) { 376 if (!value.equals(item)) { 377 newValues[i++] = value; 378 } 379 } 380 parameters.put(facetParamKey, newValues); 381 } 382 } 383 return new CmsSearchStateParameters(m_result, parameters); 384 } 385 }); 386 return m_uncheckEntries; 387 } 388 }); 389 } 390 return m_uncheckFacetMap; 391 } 392 393 /** 394 * @see java.lang.Object#toString() 395 */ 396 @Override 397 public String toString() { 398 399 return paramMapToString(m_params); 400 } 401 402 /** 403 * Returns the parameter key of the facet with the given name. 404 * @param facet the facet's name. 405 * @return the parameter key for the facet. 406 */ 407 String getFacetParamKey(String facet) { 408 409 I_CmsSearchControllerFacetField fieldFacet = m_result.getController().getFieldFacets().getFieldFacetController().get( 410 facet); 411 if (fieldFacet != null) { 412 return fieldFacet.getConfig().getParamKey(); 413 } 414 I_CmsSearchControllerFacetRange rangeFacet = m_result.getController().getRangeFacets().getRangeFacetController().get( 415 facet); 416 if (rangeFacet != null) { 417 return rangeFacet.getConfig().getParamKey(); 418 } 419 I_CmsSearchControllerFacetQuery queryFacet = m_result.getController().getQueryFacet(); 420 if ((queryFacet != null) && queryFacet.getConfig().getName().equals(facet)) { 421 return queryFacet.getConfig().getParamKey(); 422 } 423 424 // Facet did not exist 425 LOG.warn(Messages.get().getBundle().key(Messages.LOG_FACET_NOT_CONFIGURED_1, facet), new Throwable()); 426 427 return null; 428 } 429 430}