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.config.parser; 029 030import org.opencms.file.CmsObject; 031import org.opencms.json.JSONArray; 032import org.opencms.json.JSONException; 033import org.opencms.json.JSONObject; 034import org.opencms.jsp.search.config.CmsSearchConfigurationCommon; 035import org.opencms.jsp.search.config.CmsSearchConfigurationDidYouMean; 036import org.opencms.jsp.search.config.CmsSearchConfigurationFacetField; 037import org.opencms.jsp.search.config.CmsSearchConfigurationFacetQuery; 038import org.opencms.jsp.search.config.CmsSearchConfigurationFacetQuery.CmsFacetQueryItem; 039import org.opencms.jsp.search.config.CmsSearchConfigurationFacetRange; 040import org.opencms.jsp.search.config.CmsSearchConfigurationGeoFilter; 041import org.opencms.jsp.search.config.CmsSearchConfigurationHighlighting; 042import org.opencms.jsp.search.config.CmsSearchConfigurationPagination; 043import org.opencms.jsp.search.config.CmsSearchConfigurationSortOption; 044import org.opencms.jsp.search.config.CmsSearchConfigurationSorting; 045import org.opencms.jsp.search.config.I_CmsSearchConfiguration; 046import org.opencms.jsp.search.config.I_CmsSearchConfigurationCommon; 047import org.opencms.jsp.search.config.I_CmsSearchConfigurationDidYouMean; 048import org.opencms.jsp.search.config.I_CmsSearchConfigurationFacet; 049import org.opencms.jsp.search.config.I_CmsSearchConfigurationFacetField; 050import org.opencms.jsp.search.config.I_CmsSearchConfigurationFacetQuery; 051import org.opencms.jsp.search.config.I_CmsSearchConfigurationFacetQuery.I_CmsFacetQueryItem; 052import org.opencms.jsp.search.config.I_CmsSearchConfigurationFacetRange; 053import org.opencms.jsp.search.config.I_CmsSearchConfigurationGeoFilter; 054import org.opencms.jsp.search.config.I_CmsSearchConfigurationHighlighting; 055import org.opencms.jsp.search.config.I_CmsSearchConfigurationPagination; 056import org.opencms.jsp.search.config.I_CmsSearchConfigurationSortOption; 057import org.opencms.jsp.search.config.I_CmsSearchConfigurationSorting; 058import org.opencms.main.CmsLog; 059import org.opencms.main.OpenCms; 060import org.opencms.search.solr.CmsSolrIndex; 061 062import java.util.ArrayList; 063import java.util.Collections; 064import java.util.HashMap; 065import java.util.Iterator; 066import java.util.LinkedHashMap; 067import java.util.LinkedList; 068import java.util.List; 069import java.util.Map; 070import java.util.Objects; 071 072import org.apache.commons.logging.Log; 073 074/** Search configuration parser reading JSON. */ 075public class CmsJSONSearchConfigurationParser implements I_CmsSearchConfigurationParser { 076 077 /** Logger for the class. */ 078 protected static final Log LOG = CmsLog.getLog(CmsJSONSearchConfigurationParser.class); 079 080 /** The keys that can be used in the JSON object */ 081 /** JSON keys for common options. */ 082 /** A JSON key. */ 083 public static final String JSON_KEY_QUERYPARAM = "queryparam"; 084 /** A JSON key. */ 085 public static final String JSON_KEY_LAST_QUERYPARAM = "lastqueryparam"; 086 /** A JSON key. */ 087 public static final String JSON_KEY_ESCAPE_QUERY_CHARACTERS = "escapequerychars"; 088 /** A JSON key. */ 089 public static final String JSON_KEY_RELOADED_PARAM = "reloadedparam"; 090 /** A JSON key. */ 091 public static final String JSON_KEY_SEARCH_FOR_EMPTY_QUERY = "searchforemptyquery"; 092 /** A JSON key. */ 093 public static final String JSON_KEY_IGNORE_QUERY = "ignorequery"; 094 /** A JSON key. */ 095 public static final String JSON_KEY_IGNORE_RELEASE_DATE = "ignoreReleaseDate"; 096 /** A JSON key. */ 097 public static final String JSON_KEY_MAX_RETURNED_RESULTS = "maxReturnedResults"; 098 /** A JSON key. */ 099 public static final String JSON_KEY_IGNORE_EXPIRATION_DATE = "ignoreExpirationDate"; 100 /** A JSON key. */ 101 public static final String JSON_KEY_QUERY_MODIFIER = "querymodifier"; 102 /** A JSON key. */ 103 public static final String JSON_KEY_PAGEPARAM = "pageparam"; 104 /** A JSON key. */ 105 public static final String JSON_KEY_INDEX = "index"; 106 /** A JSON key. */ 107 public static final String JSON_KEY_CORE = "core"; 108 /** A JSON key. */ 109 public static final String JSON_KEY_EXTRASOLRPARAMS = "extrasolrparams"; 110 /** A JSON key. */ 111 public static final String JSON_KEY_ADDITIONAL_PARAMETERS = "additionalrequestparams"; 112 /** A JSON key. */ 113 public static final String JSON_KEY_ADDITIONAL_PARAMETERS_PARAM = "param"; 114 /** A JSON key. */ 115 public static final String JSON_KEY_ADDITIONAL_PARAMETERS_SOLRQUERY = "solrquery"; 116 /** A JSON key. */ 117 public static final String JSON_KEY_PAGESIZE = "pagesize"; 118 /** A JSON key. */ 119 public static final String JSON_KEY_PAGENAVLENGTH = "pagenavlength"; 120 /** JSON keys for facet configuration. */ 121 /** The JSON key for the sub-node with all field facet configurations. */ 122 public static final String JSON_KEY_FIELD_FACETS = "fieldfacets"; 123 /** The JSON key for the sub-node with all field facet configurations. */ 124 public static final String JSON_KEY_RANGE_FACETS = "rangefacets"; 125 /** The JSON key for the sub-node with the query facet configuration. */ 126 public static final String JSON_KEY_QUERY_FACET = "queryfacet"; 127 /** JSON keys for a single facet. */ 128 /** A JSON key. */ 129 public static final String JSON_KEY_FACET_LIMIT = "limit"; 130 /** A JSON key. */ 131 public static final String JSON_KEY_FACET_MINCOUNT = "mincount"; 132 /** A JSON key. */ 133 public static final String JSON_KEY_FACET_LABEL = "label"; 134 /** A JSON key. */ 135 public static final String JSON_KEY_FACET_FIELD = "field"; 136 /** A JSON key. */ 137 public static final String JSON_KEY_FACET_NAME = "name"; 138 /** A JSON key. */ 139 public static final String JSON_KEY_FACET_PREFIX = "prefix"; 140 /** A JSON key. */ 141 public static final String JSON_KEY_FACET_ORDER = "order"; 142 /** A JSON key. */ 143 public static final String JSON_KEY_FACET_FILTERQUERYMODIFIER = "filterquerymodifier"; 144 /** A JSON key. */ 145 public static final String JSON_KEY_FACET_ISANDFACET = "isAndFacet"; 146 /** A JSON key. */ 147 public static final String JSON_KEY_FACET_IGNOREALLFACETFILTERS = "ignoreAllFacetFilters"; 148 /** A JSON key. */ 149 public static final String JSON_KEY_FACET_EXCLUDETAGS = "excludeTags"; 150 /** A JSON key. */ 151 public static final String JSON_KEY_FACET_PRESELECTION = "preselection"; 152 /** A JSON key. */ 153 public static final String JSON_KEY_RANGE_FACET_RANGE = "range"; 154 /** A JSON key. */ 155 public static final String JSON_KEY_RANGE_FACET_START = "start"; 156 /** A JSON key. */ 157 public static final String JSON_KEY_RANGE_FACET_END = "end"; 158 /** A JSON key. */ 159 public static final String JSON_KEY_RANGE_FACET_GAP = "gap"; 160 /** A JSON key. */ 161 public static final String JSON_KEY_RANGE_FACET_OTHER = "other"; 162 /** A JSON key. */ 163 public static final String JSON_KEY_RANGE_FACET_HARDEND = "hardend"; 164 /** A JSON key. */ 165 public static final String JSON_KEY_QUERY_FACET_QUERY = "queryitems"; 166 /** A JSON key. */ 167 public static final String JSON_KEY_QUERY_FACET_QUERY_QUERY = "query"; 168 /** A JSON key. */ 169 public static final String JSON_KEY_QUERY_FACET_QUERY_LABEL = "label"; 170 171 /** JSON keys for sort options. */ 172 /** A JSON key. */ 173 public static final String JSON_KEY_SORTPARAM = "sortby"; 174 /** The JSON key for the default sort option, should hold the name paramvalue for the default option. */ 175 public static final String JSON_KEY_DEFAULT_SORT_OPTION = "defaultSortOption"; 176 /** The JSON key for the sub-node with all search option configurations. */ 177 public static final String JSON_KEY_SORTOPTIONS = "sortoptions"; 178 /** JSON keys for a single search option. */ 179 /** A JSON key. */ 180 public static final String JSON_KEY_SORTOPTION_LABEL = "label"; 181 /** A JSON key. */ 182 public static final String JSON_KEY_SORTOPTION_PARAMVALUE = "paramvalue"; 183 /** A JSON key. */ 184 public static final String JSON_KEY_SORTOPTION_SOLRVALUE = "solrvalue"; 185 /** JSON keys for the highlighting configuration. */ 186 /** The JSON key for the subnode of all highlighting configuration. */ 187 public static final String JSON_KEY_HIGHLIGHTER = "highlighter"; 188 /** A JSON key. */ 189 public static final String JSON_KEY_HIGHLIGHTER_FIELD = "field"; 190 /** A JSON key. */ 191 public static final String JSON_KEY_HIGHLIGHTER_SNIPPETS = "snippets"; 192 /** A JSON key. */ 193 public static final String JSON_KEY_HIGHLIGHTER_FRAGSIZE = "fragsize"; 194 /** A JSON key. */ 195 public static final String JSON_KEY_HIGHLIGHTER_ALTERNATE_FIELD = "alternateField"; 196 /** A JSON key. */ 197 public static final String JSON_KEY_HIGHLIGHTER_MAX_LENGTH_ALTERNATE_FIELD = "maxAlternateFieldLength"; 198 /** A JSON key. */ 199 public static final String JSON_KEY_HIGHLIGHTER_SIMPLE_PRE = "simple.pre"; 200 /** A JSON key. */ 201 public static final String JSON_KEY_HIGHLIGHTER_SIMPLE_POST = "simple.post"; 202 /** A JSON key. */ 203 public static final String JSON_KEY_HIGHLIGHTER_FORMATTER = "formatter"; 204 /** A JSON key. */ 205 public static final String JSON_KEY_HIGHLIGHTER_FRAGMENTER = "fragmenter"; 206 /** A JSON key. */ 207 public static final String JSON_KEY_HIGHLIGHTER_FASTVECTORHIGHLIGHTING = "useFastVectorHighlighting"; 208 209 /** JSON keys for "Did you mean ...?" */ 210 /** A JSON key. */ 211 public static final String JSON_KEY_DIDYOUMEAN = "didYouMean"; 212 /** The JSON key for the subnode of all "Did you mean?" configuration. */ 213 /** A JSON key. */ 214 public static final String JSON_KEY_DIDYOUMEAN_QUERYPARAM = "didYouMeanQueryParam"; 215 /** A JSON key. */ 216 public static final String JSON_KEY_DIDYOUMEAN_COLLATE = "didYouMeanCollate"; 217 /** A JSON key. */ 218 public static final String JSON_KEY_DIDYOUMEAN_COUNT = "didYouMeanCount"; 219 220 /** JSON keys for the Geo filter. */ 221 public static final String JSON_KEY_GEO_FILTER = "geofilter"; 222 /** A JSON key. */ 223 public static final String JSON_KEY_GEO_FILTER_COORDINATES = "coordinates"; 224 /** A JSON key. */ 225 public static final String JSON_KEY_GEO_FILTER_COORDINATES_PARAM = "coordinatesparam"; 226 /** A JSON key. */ 227 public static final String JSON_KEY_GEO_FILTER_FIELD_NAME = "fieldName"; 228 /** A JSON key. */ 229 public static final String JSON_KEY_GEO_FILTER_RADIUS = "radius"; 230 /** A JSON key. */ 231 public static final String JSON_KEY_GEO_FILTER_RADIUS_PARAM = "radiusparam"; 232 /** A JSON key. */ 233 public static final String JSON_KEY_GEO_FILTER_UNITS = "units"; 234 /** A JSON key. */ 235 public static final String JSON_KEY_GEO_FILTER_UNITS_PARAM = "unitsparam"; 236 237 /** The default values. */ 238 /** A JSON key. */ 239 public static final String DEFAULT_QUERY_PARAM = "q"; 240 /** A JSON key. */ 241 public static final String DEFAULT_LAST_QUERY_PARAM = "lq"; 242 /** A JSON key. */ 243 public static final String DEFAULT_RELOADED_PARAM = "reloaded"; 244 245 /** The whole JSON file. */ 246 protected JSONObject m_configObject; 247 248 /** The optional base configuration that should be changed by the JSON configuration. */ 249 private I_CmsSearchConfiguration m_baseConfig; 250 251 /** Constructor taking the JSON as String. 252 * @param json The JSON that should be parsed as String. 253 * @throws JSONException Thrown if parsing fails. 254 */ 255 public CmsJSONSearchConfigurationParser(String json) 256 throws JSONException { 257 258 init(json, null); 259 } 260 261 /** Constructor taking the JSON as String. 262 * @param json The JSON that should be parsed as String. 263 * @param baseConfig A base configuration that is adjusted by the JSON configuration string. 264 * @throws JSONException Thrown if parsing fails. 265 */ 266 public CmsJSONSearchConfigurationParser(String json, I_CmsSearchConfiguration baseConfig) 267 throws JSONException { 268 269 init(json, baseConfig); 270 } 271 272 /** Helper for reading a mandatory String value list - throwing an Exception if parsing fails. 273 * @param json The JSON object where the list should be read from. 274 * @param key The key of the value to read. 275 * @return The value from the JSON. 276 * @throws JSONException thrown when parsing fails. 277 */ 278 protected static List<String> parseMandatoryStringValues(JSONObject json, String key) throws JSONException { 279 280 List<String> list = null; 281 JSONArray array = json.getJSONArray(key); 282 list = new ArrayList<String>(array.length()); 283 for (int i = 0; i < array.length(); i++) { 284 try { 285 String entry = array.getString(i); 286 list.add(entry); 287 } catch (JSONException e) { 288 LOG.info(Messages.get().getBundle().key(Messages.LOG_OPTIONAL_STRING_ENTRY_UNPARSABLE_1, key), e); 289 } 290 } 291 return list; 292 } 293 294 /** Helper for reading an optional Boolean value - returning <code>null</code> if parsing fails. 295 * @param json The JSON object where the value should be read from. 296 * @param key The key of the value to read. 297 * @return The value from the JSON, or <code>null</code> if the value does not exist, or is no Boolean. 298 */ 299 protected static Boolean parseOptionalBooleanValue(JSONObject json, String key) { 300 301 try { 302 return Boolean.valueOf(json.getBoolean(key)); 303 } catch (JSONException e) { 304 LOG.info(Messages.get().getBundle().key(Messages.LOG_OPTIONAL_BOOLEAN_MISSING_1, key), e); 305 return null; 306 } 307 } 308 309 /** Helper for reading an optional Integer value - returning <code>null</code> if parsing fails. 310 * @param json The JSON object where the value should be read from. 311 * @param key The key of the value to read. 312 * @return The value from the JSON, or <code>null</code> if the value does not exist, or is no Integer. 313 */ 314 protected static Integer parseOptionalIntValue(JSONObject json, String key) { 315 316 try { 317 return Integer.valueOf(json.getInt(key)); 318 } catch (JSONException e) { 319 LOG.info(Messages.get().getBundle().key(Messages.LOG_OPTIONAL_INTEGER_MISSING_1, key), e); 320 return null; 321 } 322 } 323 324 /** Helper for reading an optional String value - returning <code>null</code> if parsing fails. 325 * @param json The JSON object where the value should be read from. 326 * @param key The key of the value to read. 327 * @return The value from the JSON, or <code>null</code> if the value does not exist. 328 */ 329 protected static String parseOptionalStringValue(JSONObject json, String key) { 330 331 try { 332 return json.getString(key); 333 } catch (JSONException e) { 334 LOG.info(Messages.get().getBundle().key(Messages.LOG_OPTIONAL_STRING_MISSING_1, key), e); 335 return null; 336 } 337 } 338 339 /** Helper for reading an optional String value list - returning <code>null</code> if parsing fails for the whole list, otherwise just skipping unparsable entries. 340 * @param json The JSON object where the list should be read from. 341 * @param key The key of the value to read. 342 * @return The value from the JSON, or <code>null</code> if the value does not exist. 343 */ 344 protected static List<String> parseOptionalStringValues(JSONObject json, String key) { 345 346 List<String> list = null; 347 try { 348 list = parseMandatoryStringValues(json, key); 349 } catch (JSONException e) { 350 LOG.info(Messages.get().getBundle().key(Messages.LOG_OPTIONAL_STRING_LIST_MISSING_1, key), e); 351 return null; 352 } 353 return list; 354 } 355 356 /** 357 * @see org.opencms.jsp.search.config.parser.I_CmsSearchConfigurationParser#parseCommon(CmsObject) 358 */ 359 @Override 360 public I_CmsSearchConfigurationCommon parseCommon(CmsObject cms) { 361 362 String indexName = getIndex(cms); 363 364 return new CmsSearchConfigurationCommon( 365 getQueryParam(), 366 getLastQueryParam(), 367 getEscapeQueryChars(), 368 getFirstCallParam(), 369 getSearchForEmptyQuery(), 370 getIgnoreQuery(), 371 getQueryModifier(), 372 indexName, 373 getCore(), 374 getExtraSolrParams(), 375 getAdditionalParameters(), 376 getIgnoreReleaseDate(), 377 getIgnoreExpirationDate(), 378 getMaxReturnedResults(indexName)); 379 } 380 381 /** 382 * @see org.opencms.jsp.search.config.parser.I_CmsSearchConfigurationParser#parseDidYouMean() 383 */ 384 public I_CmsSearchConfigurationDidYouMean parseDidYouMean() { 385 386 try { 387 JSONObject didYouMean = m_configObject.getJSONObject(JSON_KEY_DIDYOUMEAN); 388 String param = parseOptionalStringValue(didYouMean, JSON_KEY_DIDYOUMEAN_QUERYPARAM); 389 // default to the normal query param 390 if (null == param) { 391 param = getQueryParam(); 392 } 393 Boolean collate = parseOptionalBooleanValue(didYouMean, JSON_KEY_DIDYOUMEAN_COLLATE); 394 Integer count = parseOptionalIntValue(didYouMean, JSON_KEY_DIDYOUMEAN_COUNT); 395 return new CmsSearchConfigurationDidYouMean(param, collate, count); 396 397 } catch (JSONException e) { 398 if (null == m_baseConfig) { 399 if (LOG.isInfoEnabled()) { 400 LOG.info(Messages.get().getBundle().key(Messages.LOG_NO_HIGHLIGHTING_CONFIG_0), e); 401 } 402 return null; 403 } else { 404 return m_baseConfig.getDidYouMeanConfig(); 405 } 406 } 407 408 } 409 410 /** 411 * @see org.opencms.jsp.search.config.parser.I_CmsSearchConfigurationParser#parseFieldFacets() 412 */ 413 @Override 414 public Map<String, I_CmsSearchConfigurationFacetField> parseFieldFacets() { 415 416 Map<String, I_CmsSearchConfigurationFacetField> facetConfigs = new LinkedHashMap<String, I_CmsSearchConfigurationFacetField>(); 417 try { 418 JSONArray fieldFacets = m_configObject.getJSONArray(JSON_KEY_FIELD_FACETS); 419 for (int i = 0; i < fieldFacets.length(); i++) { 420 421 I_CmsSearchConfigurationFacetField config = parseFieldFacet(fieldFacets.getJSONObject(i)); 422 if (config != null) { 423 facetConfigs.put(config.getName(), config); 424 } 425 } 426 } catch (JSONException e) { 427 if (null == m_baseConfig) { 428 if (LOG.isInfoEnabled()) { 429 LOG.info(Messages.get().getBundle().key(Messages.LOG_NO_FACET_CONFIG_0), e); 430 } 431 } else { 432 facetConfigs = m_baseConfig.getFieldFacetConfigs(); 433 } 434 } 435 return facetConfigs; 436 } 437 438 /** 439 * @see org.opencms.jsp.search.config.parser.I_CmsSearchConfigurationParser#parseGeoFilter() 440 */ 441 @Override 442 public I_CmsSearchConfigurationGeoFilter parseGeoFilter() { 443 444 try { 445 JSONObject geoFilter = m_configObject.getJSONObject(JSON_KEY_GEO_FILTER); 446 String coordinates = parseOptionalStringValue(geoFilter, JSON_KEY_GEO_FILTER_COORDINATES); 447 String coordinatesParam = parseOptionalStringValue(geoFilter, JSON_KEY_GEO_FILTER_COORDINATES_PARAM); 448 String fieldName = parseOptionalStringValue(geoFilter, JSON_KEY_GEO_FILTER_FIELD_NAME); 449 String radius = parseOptionalStringValue(geoFilter, JSON_KEY_GEO_FILTER_RADIUS); 450 String radiusParam = parseOptionalStringValue(geoFilter, JSON_KEY_GEO_FILTER_RADIUS_PARAM); 451 String units = parseOptionalStringValue(geoFilter, JSON_KEY_GEO_FILTER_UNITS); 452 String unitsParam = parseOptionalStringValue(geoFilter, JSON_KEY_GEO_FILTER_UNITS_PARAM); 453 return new CmsSearchConfigurationGeoFilter( 454 coordinates, 455 coordinatesParam, 456 fieldName, 457 radius, 458 radiusParam, 459 units, 460 unitsParam); 461 } catch (JSONException e) { 462 if (null == m_baseConfig) { 463 if (LOG.isInfoEnabled()) { 464 LOG.info(Messages.get().getBundle().key(Messages.LOG_NO_GEOFILTER_CONFIG_0), e); 465 } 466 return null; 467 } else { 468 return m_baseConfig.getGeoFilterConfig(); 469 } 470 } 471 } 472 473 /** 474 * @see org.opencms.jsp.search.config.parser.I_CmsSearchConfigurationParser#parseHighlighter() 475 */ 476 @Override 477 public I_CmsSearchConfigurationHighlighting parseHighlighter() { 478 479 try { 480 JSONObject highlighter = m_configObject.getJSONObject(JSON_KEY_HIGHLIGHTER); 481 String field = highlighter.getString(JSON_KEY_HIGHLIGHTER_FIELD); 482 Integer snippets = parseOptionalIntValue(highlighter, JSON_KEY_HIGHLIGHTER_SNIPPETS); 483 Integer fragsize = parseOptionalIntValue(highlighter, JSON_KEY_HIGHLIGHTER_FRAGSIZE); 484 String alternateField = parseOptionalStringValue(highlighter, JSON_KEY_HIGHLIGHTER_ALTERNATE_FIELD); 485 Integer maxAlternateFieldLength = parseOptionalIntValue( 486 highlighter, 487 JSON_KEY_HIGHLIGHTER_MAX_LENGTH_ALTERNATE_FIELD); 488 String pre = parseOptionalStringValue(highlighter, JSON_KEY_HIGHLIGHTER_SIMPLE_PRE); 489 String post = parseOptionalStringValue(highlighter, JSON_KEY_HIGHLIGHTER_SIMPLE_POST); 490 String formatter = parseOptionalStringValue(highlighter, JSON_KEY_HIGHLIGHTER_FORMATTER); 491 String fragmenter = parseOptionalStringValue(highlighter, JSON_KEY_HIGHLIGHTER_FRAGMENTER); 492 Boolean useFastVectorHighlighting = parseOptionalBooleanValue( 493 highlighter, 494 JSON_KEY_HIGHLIGHTER_FASTVECTORHIGHLIGHTING); 495 return new CmsSearchConfigurationHighlighting( 496 field, 497 snippets, 498 fragsize, 499 alternateField, 500 maxAlternateFieldLength, 501 pre, 502 post, 503 formatter, 504 fragmenter, 505 useFastVectorHighlighting); 506 } catch (JSONException e) { 507 if (null == m_baseConfig) { 508 if (LOG.isInfoEnabled()) { 509 LOG.info(Messages.get().getBundle().key(Messages.LOG_NO_HIGHLIGHTING_CONFIG_0), e); 510 } 511 return null; 512 } else { 513 return m_baseConfig.getHighlighterConfig(); 514 } 515 } 516 } 517 518 /** 519 * @see org.opencms.jsp.search.config.parser.I_CmsSearchConfigurationParser#parsePagination() 520 */ 521 @Override 522 public I_CmsSearchConfigurationPagination parsePagination() { 523 524 return CmsSearchConfigurationPagination.create(getPageParam(), getPageSizes(), getPageNavLength()); 525 } 526 527 /** 528 * @see org.opencms.jsp.search.config.parser.I_CmsSearchConfigurationParser#parseQueryFacet() 529 */ 530 @Override 531 public I_CmsSearchConfigurationFacetQuery parseQueryFacet() { 532 533 try { 534 JSONObject queryFacetObject = m_configObject.getJSONObject(JSON_KEY_QUERY_FACET); 535 try { 536 List<I_CmsFacetQueryItem> queries = parseFacetQueryItems(queryFacetObject); 537 String label = parseOptionalStringValue(queryFacetObject, JSON_KEY_FACET_LABEL); 538 Boolean isAndFacet = parseOptionalBooleanValue(queryFacetObject, JSON_KEY_FACET_ISANDFACET); 539 List<String> preselection = parseOptionalStringValues(queryFacetObject, JSON_KEY_FACET_PRESELECTION); 540 Boolean ignoreAllFacetFilters = parseOptionalBooleanValue( 541 queryFacetObject, 542 JSON_KEY_FACET_IGNOREALLFACETFILTERS); 543 List<String> excludeTags = parseOptionalStringValues(queryFacetObject, JSON_KEY_FACET_EXCLUDETAGS); 544 return new CmsSearchConfigurationFacetQuery( 545 queries, 546 label, 547 isAndFacet, 548 preselection, 549 ignoreAllFacetFilters, 550 excludeTags); 551 } catch (JSONException e) { 552 LOG.error( 553 Messages.get().getBundle().key( 554 Messages.ERR_QUERY_FACET_MANDATORY_KEY_MISSING_1, 555 JSON_KEY_QUERY_FACET_QUERY), 556 e); 557 return null; 558 } 559 } catch (JSONException e) { 560 // nothing to do, configuration is optional 561 return null != m_baseConfig ? m_baseConfig.getQueryFacetConfig() : null; 562 } 563 } 564 565 /** 566 * @see org.opencms.jsp.search.config.parser.I_CmsSearchConfigurationParser#parseRangeFacets() 567 */ 568 public Map<String, I_CmsSearchConfigurationFacetRange> parseRangeFacets() { 569 570 Map<String, I_CmsSearchConfigurationFacetRange> facetConfigs = new LinkedHashMap<String, I_CmsSearchConfigurationFacetRange>(); 571 try { 572 JSONArray rangeFacets = m_configObject.getJSONArray(JSON_KEY_RANGE_FACETS); 573 for (int i = 0; i < rangeFacets.length(); i++) { 574 575 I_CmsSearchConfigurationFacetRange config = parseRangeFacet(rangeFacets.getJSONObject(i)); 576 if (config != null) { 577 facetConfigs.put(config.getName(), config); 578 } 579 } 580 } catch (JSONException e) { 581 if (null == m_baseConfig) { 582 if (LOG.isInfoEnabled()) { 583 LOG.info(Messages.get().getBundle().key(Messages.LOG_NO_FACET_CONFIG_0), e); 584 } 585 } else { 586 facetConfigs = m_baseConfig.getRangeFacetConfigs(); 587 } 588 } 589 return facetConfigs; 590 591 } 592 593 /** 594 * @see org.opencms.jsp.search.config.parser.I_CmsSearchConfigurationParser#parseSorting() 595 */ 596 @Override 597 public I_CmsSearchConfigurationSorting parseSorting() { 598 599 List<I_CmsSearchConfigurationSortOption> options = getSortOptions(); 600 String defaultOptionParamValue = parseOptionalStringValue(m_configObject, JSON_KEY_DEFAULT_SORT_OPTION); 601 I_CmsSearchConfigurationSortOption defaultSortOption = null; 602 if (null != defaultOptionParamValue) { 603 Iterator<I_CmsSearchConfigurationSortOption> optIterator = options.iterator(); 604 while ((null == defaultSortOption) && optIterator.hasNext()) { 605 I_CmsSearchConfigurationSortOption opt = optIterator.next(); 606 if (Objects.equals(opt.getParamValue(), defaultOptionParamValue)) { 607 defaultSortOption = opt; 608 } 609 } 610 } 611 if ((null == defaultSortOption) && !options.isEmpty()) { 612 defaultSortOption = options.get(0); 613 } 614 return CmsSearchConfigurationSorting.create(getSortParam(), options, defaultSortOption); 615 } 616 617 /** Returns a map with additional request parameters, mapping the parameter names to Solr query parts. 618 * @return A map with additional request parameters, mapping the parameter names to Solr query parts. 619 */ 620 protected Map<String, String> getAdditionalParameters() { 621 622 Map<String, String> result; 623 try { 624 JSONArray additionalParams = m_configObject.getJSONArray(JSON_KEY_ADDITIONAL_PARAMETERS); 625 result = new HashMap<String, String>(additionalParams.length()); 626 for (int i = 0; i < additionalParams.length(); i++) { 627 try { 628 JSONObject currentParam = additionalParams.getJSONObject(i); 629 String param = currentParam.getString(JSON_KEY_ADDITIONAL_PARAMETERS_PARAM); 630 String solrQuery = parseOptionalStringValue(currentParam, JSON_KEY_ADDITIONAL_PARAMETERS_SOLRQUERY); 631 result.put(param, solrQuery); 632 } catch (JSONException e) { 633 LOG.error(Messages.get().getBundle().key(Messages.ERR_ADDITIONAL_PARAMETER_CONFIG_WRONG_0), e); 634 continue; 635 } 636 } 637 } catch (JSONException e) { 638 LOG.info(Messages.get().getBundle().key(Messages.LOG_ADDITIONAL_PARAMETER_CONFIG_NOT_PARSED_0), e); 639 return null != m_baseConfig 640 ? m_baseConfig.getGeneralConfig().getAdditionalParameters() 641 : new HashMap<String, String>(); 642 } 643 return result; 644 } 645 646 /** Returns the configured Solr core, or <code>null</code> if no core is configured. 647 * @return The configured Solr core, or <code>null</code> if no core is configured. 648 */ 649 protected String getCore() { 650 651 try { 652 return m_configObject.getString(JSON_KEY_CORE); 653 } catch (JSONException e) { 654 if (null == m_baseConfig) { 655 if (LOG.isInfoEnabled()) { 656 LOG.info(Messages.get().getBundle().key(Messages.LOG_NO_CORE_SPECIFIED_0), e); 657 } 658 return null; 659 } else { 660 return m_baseConfig.getGeneralConfig().getSolrCore(); 661 } 662 } 663 } 664 665 /** 666 * Returns the flag, indicating if the characters in the query string that are commands to Solr should be escaped. 667 * @return the flag, indicating if the characters in the query string that are commands to Solr should be escaped. 668 */ 669 protected Boolean getEscapeQueryChars() { 670 671 Boolean isEscape = parseOptionalBooleanValue(m_configObject, JSON_KEY_ESCAPE_QUERY_CHARACTERS); 672 return (null == isEscape) && (m_baseConfig != null) 673 ? Boolean.valueOf(m_baseConfig.getGeneralConfig().getEscapeQueryChars()) 674 : isEscape; 675 } 676 677 /** Returns the configured extra parameters that should be given to Solr, or the empty string if no parameters are configured. 678 * @return The configured extra parameters that should be given to Solr, or the empty string if no parameters are configured. 679 */ 680 protected String getExtraSolrParams() { 681 682 try { 683 return m_configObject.getString(JSON_KEY_EXTRASOLRPARAMS); 684 } catch (JSONException e) { 685 if (null == m_baseConfig) { 686 if (LOG.isInfoEnabled()) { 687 LOG.info(Messages.get().getBundle().key(Messages.LOG_NO_EXTRA_PARAMETERS_0), e); 688 } 689 return ""; 690 } else { 691 return m_baseConfig.getGeneralConfig().getExtraSolrParams(); 692 } 693 } 694 } 695 696 /** Returns the configured request parameter for the last query, or the default parameter if no core is configured. 697 * @return The configured request parameter for the last query, or the default parameter if no core is configured. 698 */ 699 protected String getFirstCallParam() { 700 701 String param = parseOptionalStringValue(m_configObject, JSON_KEY_RELOADED_PARAM); 702 if (param == null) { 703 return null != m_baseConfig ? m_baseConfig.getGeneralConfig().getReloadedParam() : DEFAULT_RELOADED_PARAM; 704 } else { 705 return param; 706 } 707 } 708 709 /** Returns a flag indicating if also expired resources should be found. 710 * @return A flag indicating if also expired resources should be found. 711 */ 712 protected Boolean getIgnoreExpirationDate() { 713 714 Boolean isIgnoreExpirationDate = parseOptionalBooleanValue(m_configObject, JSON_KEY_IGNORE_EXPIRATION_DATE); 715 return (null == isIgnoreExpirationDate) && (m_baseConfig != null) 716 ? Boolean.valueOf(m_baseConfig.getGeneralConfig().getIgnoreExpirationDate()) 717 : isIgnoreExpirationDate; 718 } 719 720 /** Returns a flag indicating if the query given by the parameters should be ignored. 721 * @return A flag indicating if the query given by the parameters should be ignored. 722 */ 723 protected Boolean getIgnoreQuery() { 724 725 Boolean isIgnoreQuery = parseOptionalBooleanValue(m_configObject, JSON_KEY_IGNORE_QUERY); 726 return (null == isIgnoreQuery) && (m_baseConfig != null) 727 ? Boolean.valueOf(m_baseConfig.getGeneralConfig().getIgnoreQueryParam()) 728 : isIgnoreQuery; 729 } 730 731 /** Returns a flag indicating if also unreleased resources should be found. 732 * @return A flag indicating if also unreleased resources should be found. 733 */ 734 protected Boolean getIgnoreReleaseDate() { 735 736 Boolean isIgnoreReleaseDate = parseOptionalBooleanValue(m_configObject, JSON_KEY_IGNORE_RELEASE_DATE); 737 return (null == isIgnoreReleaseDate) && (m_baseConfig != null) 738 ? Boolean.valueOf(m_baseConfig.getGeneralConfig().getIgnoreReleaseDate()) 739 : isIgnoreReleaseDate; 740 } 741 742 /** Returns the configured Solr index, or <code>null</code> if no core is configured. 743 * @param cms the current context. 744 * @return The configured Solr index, or <code>null</code> if no core is configured. 745 */ 746 protected String getIndex(CmsObject cms) { 747 748 String indexName = null; 749 try { 750 indexName = m_configObject.getString(JSON_KEY_INDEX); 751 } catch (JSONException e) { 752 if (null == m_baseConfig) { 753 if (LOG.isInfoEnabled()) { 754 LOG.info(Messages.get().getBundle().key(Messages.LOG_NO_INDEX_SPECIFIED_0), e); 755 } 756 } else { 757 indexName = m_baseConfig.getGeneralConfig().getSolrIndex(); 758 } 759 } 760 return null != indexName 761 ? indexName 762 : (cms.getRequestContext().getCurrentProject().isOnlineProject() 763 ? CmsSolrIndex.DEFAULT_INDEX_NAME_ONLINE 764 : CmsSolrIndex.DEFAULT_INDEX_NAME_OFFLINE); 765 } 766 767 /** Returns the configured request parameter for the last query, or the default parameter if no core is configured. 768 * @return The configured request parameter for the last query, or the default parameter if no core is configured. 769 */ 770 protected String getLastQueryParam() { 771 772 String param = parseOptionalStringValue(m_configObject, JSON_KEY_LAST_QUERYPARAM); 773 if (param == null) { 774 return null != m_baseConfig 775 ? m_baseConfig.getGeneralConfig().getLastQueryParam() 776 : DEFAULT_LAST_QUERY_PARAM; 777 } else { 778 return param; 779 } 780 } 781 782 /** Returns the number of maximally returned results, or <code>null</code> if the indexes default should be used. 783 * @param indexName the name of the index to search in. 784 * @return The number of maximally returned results, or <code>null</code> if the indexes default should be used. 785 */ 786 protected int getMaxReturnedResults(String indexName) { 787 788 Integer maxReturnedResults = parseOptionalIntValue(m_configObject, JSON_KEY_MAX_RETURNED_RESULTS); 789 if (null != maxReturnedResults) { 790 return maxReturnedResults.intValue(); 791 } else if (m_baseConfig != null) { 792 return m_baseConfig.getGeneralConfig().getMaxReturnedResults(); 793 } else { 794 try { 795 CmsSolrIndex idx = OpenCms.getSearchManager().getIndexSolr(indexName); 796 if (null != idx) { 797 return idx.getMaxProcessedResults(); 798 } 799 } catch (Throwable t) { 800 // This is ok, it's allowed to have an external other index here. 801 LOG.debug( 802 "Parsing JSON search configuration for none-CmsSolrIndex " 803 + indexName 804 + ". Setting max processed results to unlimited."); 805 } 806 return CmsSolrIndex.MAX_RESULTS_UNLIMITED; 807 } 808 } 809 810 /** Returns the configured length of the "Google"-like page navigation, or the default parameter if no core is configured. 811 * @return The configured length of the "Google"-like page navigation, or the default parameter if no core is configured. 812 */ 813 protected Integer getPageNavLength() { 814 815 return parseOptionalIntValue(m_configObject, JSON_KEY_PAGENAVLENGTH); 816 } 817 818 /** Returns the configured request parameter for the current page, or the default parameter if no core is configured. 819 * @return The configured request parameter for the current page, or the default parameter if no core is configured. 820 */ 821 protected String getPageParam() { 822 823 return parseOptionalStringValue(m_configObject, JSON_KEY_PAGEPARAM); 824 } 825 826 /** Returns the configured page sizes, or the default page size if no core is configured. 827 * @return The configured page sizes, or the default page size if no core is configured. 828 */ 829 protected List<Integer> getPageSizes() { 830 831 try { 832 return Collections.singletonList(Integer.valueOf(m_configObject.getInt(JSON_KEY_PAGESIZE))); 833 } catch (JSONException e) { 834 List<Integer> result = null; 835 String pageSizesString = null; 836 try { 837 pageSizesString = m_configObject.getString(JSON_KEY_PAGESIZE); 838 String[] pageSizesArray = pageSizesString.split("-"); 839 if (pageSizesArray.length > 0) { 840 result = new ArrayList<>(pageSizesArray.length); 841 for (int i = 0; i < pageSizesArray.length; i++) { 842 result.add(Integer.valueOf(pageSizesArray[i])); 843 } 844 } 845 return result; 846 } catch (NumberFormatException | JSONException e1) { 847 LOG.warn(Messages.get().getBundle().key(Messages.LOG_PARSING_PAGE_SIZES_FAILED_1, pageSizesString), e); 848 } 849 if (null == m_baseConfig) { 850 if (LOG.isInfoEnabled()) { 851 LOG.info(Messages.get().getBundle().key(Messages.LOG_NO_PAGESIZE_SPECIFIED_0), e); 852 } 853 return null; 854 } else { 855 return m_baseConfig.getPaginationConfig().getPageSizes(); 856 } 857 } 858 } 859 860 /** Returns the optional query modifier. 861 * @return the optional query modifier. 862 */ 863 protected String getQueryModifier() { 864 865 String queryModifier = parseOptionalStringValue(m_configObject, JSON_KEY_QUERY_MODIFIER); 866 return (null == queryModifier) && (null != m_baseConfig) 867 ? m_baseConfig.getGeneralConfig().getQueryModifier() 868 : queryModifier; 869 } 870 871 /** Returns the configured request parameter for the query string, or the default parameter if no core is configured. 872 * @return The configured request parameter for the query string, or the default parameter if no core is configured. 873 */ 874 protected String getQueryParam() { 875 876 String param = parseOptionalStringValue(m_configObject, JSON_KEY_QUERYPARAM); 877 if (param == null) { 878 return null != m_baseConfig ? m_baseConfig.getGeneralConfig().getQueryParam() : DEFAULT_QUERY_PARAM; 879 } else { 880 return param; 881 } 882 } 883 884 /** Returns a flag, indicating if search should be performed using a wildcard if the empty query is given. 885 * @return A flag, indicating if search should be performed using a wildcard if the empty query is given. 886 */ 887 protected Boolean getSearchForEmptyQuery() { 888 889 Boolean isSearchForEmptyQuery = parseOptionalBooleanValue(m_configObject, JSON_KEY_SEARCH_FOR_EMPTY_QUERY); 890 return (isSearchForEmptyQuery == null) && (null != m_baseConfig) 891 ? Boolean.valueOf(m_baseConfig.getGeneralConfig().getSearchForEmptyQueryParam()) 892 : isSearchForEmptyQuery; 893 } 894 895 /** Returns the list of the configured sort options, or the empty list if no sort options are configured. 896 * @return The list of the configured sort options, or the empty list if no sort options are configured. 897 */ 898 protected List<I_CmsSearchConfigurationSortOption> getSortOptions() { 899 900 List<I_CmsSearchConfigurationSortOption> options = new LinkedList<I_CmsSearchConfigurationSortOption>(); 901 try { 902 JSONArray sortOptions = m_configObject.getJSONArray(JSON_KEY_SORTOPTIONS); 903 for (int i = 0; i < sortOptions.length(); i++) { 904 I_CmsSearchConfigurationSortOption option = parseSortOption(sortOptions.getJSONObject(i)); 905 if (option != null) { 906 options.add(option); 907 } 908 } 909 } catch (JSONException e) { 910 if (null == m_baseConfig) { 911 if (LOG.isInfoEnabled()) { 912 LOG.info(Messages.get().getBundle().key(Messages.LOG_NO_SORT_CONFIG_0), e); 913 } 914 } else { 915 options = m_baseConfig.getSortConfig().getSortOptions(); 916 } 917 } 918 return options; 919 } 920 921 /** Returns the configured request parameter for the sort option, or the default parameter if no core is configured. 922 * @return The configured request parameter for the sort option, or the default parameter if no core is configured. 923 */ 924 protected String getSortParam() { 925 926 return parseOptionalStringValue(m_configObject, JSON_KEY_SORTPARAM); 927 } 928 929 /** Initialization that parses the String to a JSON object. 930 * @param configString The JSON as string. 931 * @param baseConfig The optional basic search configuration to overwrite (partly) by the JSON configuration. 932 * @throws JSONException thrown if parsing fails. 933 */ 934 protected void init(String configString, I_CmsSearchConfiguration baseConfig) throws JSONException { 935 936 m_configObject = new JSONObject(configString); 937 m_baseConfig = baseConfig; 938 } 939 940 /** Parses a single query item for the query facet. 941 * @param item JSON object of the query item. 942 * @return the parsed query item, or <code>null</code> if parsing failed. 943 */ 944 protected I_CmsFacetQueryItem parseFacetQueryItem(JSONObject item) { 945 946 String query; 947 try { 948 query = item.getString(JSON_KEY_QUERY_FACET_QUERY_QUERY); 949 } catch (JSONException e) { 950 // TODO: Log 951 return null; 952 } 953 String label = parseOptionalStringValue(item, JSON_KEY_QUERY_FACET_QUERY_LABEL); 954 return new CmsFacetQueryItem(query, label); 955 } 956 957 /** Parses the list of query items for the query facet. 958 * @param queryFacetObject JSON object representing the node with the query facet. 959 * @return list of query options 960 * @throws JSONException if the list cannot be parsed. 961 */ 962 protected List<I_CmsFacetQueryItem> parseFacetQueryItems(JSONObject queryFacetObject) throws JSONException { 963 964 JSONArray items = queryFacetObject.getJSONArray(JSON_KEY_QUERY_FACET_QUERY); 965 List<I_CmsFacetQueryItem> result = new ArrayList<I_CmsFacetQueryItem>(items.length()); 966 for (int i = 0; i < items.length(); i++) { 967 I_CmsFacetQueryItem item = parseFacetQueryItem(items.getJSONObject(i)); 968 if (item != null) { 969 result.add(item); 970 } 971 } 972 return result; 973 } 974 975 /** Parses the field facet configurations. 976 * @param fieldFacetObject The JSON sub-node with the field facet configurations. 977 * @return The field facet configurations. 978 */ 979 protected I_CmsSearchConfigurationFacetField parseFieldFacet(JSONObject fieldFacetObject) { 980 981 try { 982 String field = fieldFacetObject.getString(JSON_KEY_FACET_FIELD); 983 String name = parseOptionalStringValue(fieldFacetObject, JSON_KEY_FACET_NAME); 984 String label = parseOptionalStringValue(fieldFacetObject, JSON_KEY_FACET_LABEL); 985 Integer minCount = parseOptionalIntValue(fieldFacetObject, JSON_KEY_FACET_MINCOUNT); 986 Integer limit = parseOptionalIntValue(fieldFacetObject, JSON_KEY_FACET_LIMIT); 987 String prefix = parseOptionalStringValue(fieldFacetObject, JSON_KEY_FACET_PREFIX); 988 String sorder = parseOptionalStringValue(fieldFacetObject, JSON_KEY_FACET_ORDER); 989 I_CmsSearchConfigurationFacet.SortOrder order; 990 try { 991 order = I_CmsSearchConfigurationFacet.SortOrder.valueOf(sorder); 992 } catch (Exception e) { 993 order = null; 994 } 995 String filterQueryModifier = parseOptionalStringValue(fieldFacetObject, JSON_KEY_FACET_FILTERQUERYMODIFIER); 996 Boolean isAndFacet = parseOptionalBooleanValue(fieldFacetObject, JSON_KEY_FACET_ISANDFACET); 997 List<String> preselection = parseOptionalStringValues(fieldFacetObject, JSON_KEY_FACET_PRESELECTION); 998 Boolean ignoreFilterAllFacetFilters = parseOptionalBooleanValue( 999 fieldFacetObject, 1000 JSON_KEY_FACET_IGNOREALLFACETFILTERS); 1001 List<String> excludeTags = parseOptionalStringValues(fieldFacetObject, JSON_KEY_FACET_EXCLUDETAGS); 1002 return new CmsSearchConfigurationFacetField( 1003 field, 1004 name, 1005 minCount, 1006 limit, 1007 prefix, 1008 label, 1009 order, 1010 filterQueryModifier, 1011 isAndFacet, 1012 preselection, 1013 ignoreFilterAllFacetFilters, 1014 excludeTags); 1015 } catch (JSONException e) { 1016 LOG.error( 1017 Messages.get().getBundle().key(Messages.ERR_FIELD_FACET_MANDATORY_KEY_MISSING_1, JSON_KEY_FACET_FIELD), 1018 e); 1019 return null; 1020 } 1021 } 1022 1023 /** Parses the query facet configurations. 1024 * @param rangeFacetObject The JSON sub-node with the query facet configurations. 1025 * @return The query facet configurations. 1026 */ 1027 protected I_CmsSearchConfigurationFacetRange parseRangeFacet(JSONObject rangeFacetObject) { 1028 1029 try { 1030 String range = rangeFacetObject.getString(JSON_KEY_RANGE_FACET_RANGE); 1031 String name = parseOptionalStringValue(rangeFacetObject, JSON_KEY_FACET_NAME); 1032 String label = parseOptionalStringValue(rangeFacetObject, JSON_KEY_FACET_LABEL); 1033 Integer minCount = parseOptionalIntValue(rangeFacetObject, JSON_KEY_FACET_MINCOUNT); 1034 String start = rangeFacetObject.getString(JSON_KEY_RANGE_FACET_START); 1035 String end = rangeFacetObject.getString(JSON_KEY_RANGE_FACET_END); 1036 String gap = rangeFacetObject.getString(JSON_KEY_RANGE_FACET_GAP); 1037 List<String> sother = parseOptionalStringValues(rangeFacetObject, JSON_KEY_RANGE_FACET_OTHER); 1038 Boolean hardEnd = parseOptionalBooleanValue(rangeFacetObject, JSON_KEY_RANGE_FACET_HARDEND); 1039 List<I_CmsSearchConfigurationFacetRange.Other> other = null; 1040 if (sother != null) { 1041 other = new ArrayList<I_CmsSearchConfigurationFacetRange.Other>(sother.size()); 1042 for (String so : sother) { 1043 try { 1044 I_CmsSearchConfigurationFacetRange.Other o = I_CmsSearchConfigurationFacetRange.Other.valueOf( 1045 so); 1046 other.add(o); 1047 } catch (Exception e) { 1048 LOG.error(Messages.get().getBundle().key(Messages.ERR_INVALID_OTHER_OPTION_1, so), e); 1049 } 1050 } 1051 } 1052 Boolean isAndFacet = parseOptionalBooleanValue(rangeFacetObject, JSON_KEY_FACET_ISANDFACET); 1053 List<String> preselection = parseOptionalStringValues(rangeFacetObject, JSON_KEY_FACET_PRESELECTION); 1054 Boolean ignoreAllFacetFilters = parseOptionalBooleanValue( 1055 rangeFacetObject, 1056 JSON_KEY_FACET_IGNOREALLFACETFILTERS); 1057 List<String> excludeTags = parseOptionalStringValues(rangeFacetObject, JSON_KEY_FACET_EXCLUDETAGS); 1058 return new CmsSearchConfigurationFacetRange( 1059 range, 1060 start, 1061 end, 1062 gap, 1063 other, 1064 hardEnd, 1065 name, 1066 minCount, 1067 label, 1068 isAndFacet, 1069 preselection, 1070 ignoreAllFacetFilters, 1071 excludeTags); 1072 } catch (JSONException e) { 1073 LOG.error( 1074 Messages.get().getBundle().key( 1075 Messages.ERR_RANGE_FACET_MANDATORY_KEY_MISSING_1, 1076 JSON_KEY_RANGE_FACET_RANGE 1077 + ", " 1078 + JSON_KEY_RANGE_FACET_START 1079 + ", " 1080 + JSON_KEY_RANGE_FACET_END 1081 + ", " 1082 + JSON_KEY_RANGE_FACET_GAP), 1083 e); 1084 return null; 1085 } 1086 1087 } 1088 1089 /** Returns a single sort option configuration as configured via the methods parameter, or null if the parameter does not specify a sort option. 1090 * @param json The JSON sort option configuration. 1091 * @return The sort option configuration, or null if the JSON could not be read. 1092 */ 1093 protected I_CmsSearchConfigurationSortOption parseSortOption(JSONObject json) { 1094 1095 try { 1096 String solrValue = json.getString(JSON_KEY_SORTOPTION_SOLRVALUE); 1097 String paramValue = parseOptionalStringValue(json, JSON_KEY_SORTOPTION_PARAMVALUE); 1098 paramValue = (paramValue == null) ? solrValue : paramValue; 1099 String label = parseOptionalStringValue(json, JSON_KEY_SORTOPTION_LABEL); 1100 label = (label == null) ? paramValue : label; 1101 return new CmsSearchConfigurationSortOption(label, paramValue, solrValue); 1102 } catch (JSONException e) { 1103 LOG.error( 1104 Messages.get().getBundle().key(Messages.ERR_SORT_OPTION_NOT_PARSABLE_1, JSON_KEY_SORTOPTION_SOLRVALUE), 1105 e); 1106 return null; 1107 } 1108 } 1109}