001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (https://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: https://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: https://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.jsp.search.config.CmsSearchConfigurationCommon; 032import org.opencms.jsp.search.config.I_CmsSearchConfiguration; 033import org.opencms.jsp.search.config.I_CmsSearchConfigurationCommon; 034import org.opencms.jsp.search.config.I_CmsSearchConfigurationDidYouMean; 035import org.opencms.jsp.search.config.I_CmsSearchConfigurationFacetField; 036import org.opencms.jsp.search.config.I_CmsSearchConfigurationFacetQuery; 037import org.opencms.jsp.search.config.I_CmsSearchConfigurationFacetRange; 038import org.opencms.jsp.search.config.I_CmsSearchConfigurationGeoFilter; 039import org.opencms.jsp.search.config.I_CmsSearchConfigurationHighlighting; 040import org.opencms.jsp.search.config.I_CmsSearchConfigurationPagination; 041import org.opencms.jsp.search.config.I_CmsSearchConfigurationSorting; 042import org.opencms.main.CmsLog; 043import org.opencms.main.OpenCms; 044import org.opencms.search.solr.CmsSolrIndex; 045import org.opencms.util.CmsPair; 046 047import java.util.Collections; 048import java.util.Map; 049 050import org.apache.commons.logging.Log; 051 052/** Search configuration parser reading a configuration containing a plain Solr query. 053 * Only fl might be added additionally. */ 054public class CmsPlainQuerySearchConfigurationParser implements I_CmsSearchConfigurationParser { 055 056 /** Logger for the class. */ 057 protected static final Log LOG = CmsLog.getLog(CmsPlainQuerySearchConfigurationParser.class); 058 059 /** The default return fields. */ 060 private static final String DEFAULT_FL = "id,path"; 061 062 /** The whole query string. */ 063 protected String m_queryString; 064 065 /** The optional base configuration that should be changed by the JSON configuration. */ 066 private I_CmsSearchConfiguration m_baseConfig; 067 068 /** Constructor taking the JSON as String. 069 * @param query The query that is passed to Solr. 070 */ 071 public CmsPlainQuerySearchConfigurationParser(String query) { 072 073 this(query, null); 074 } 075 076 /** Constructor taking the JSON as String. 077 * @param query The query that is passed to Solr (additional Solr params). 078 * @param baseConfig A base configuration that is adjusted by the JSON configuration string. 079 */ 080 public CmsPlainQuerySearchConfigurationParser(String query, I_CmsSearchConfiguration baseConfig) { 081 082 if ((null != query) && !(query.startsWith("fl=") || query.contains("&fl="))) { 083 query = query + "&fl=" + DEFAULT_FL; 084 } 085 m_queryString = query; 086 m_baseConfig = baseConfig; 087 088 } 089 090 /** 091 * @see org.opencms.jsp.search.config.parser.I_CmsSearchConfigurationParser#parseCommon(CmsObject) 092 */ 093 @Override 094 public I_CmsSearchConfigurationCommon parseCommon(CmsObject cms) { 095 096 String queryString = m_queryString; 097 CmsPair<String, String> idxExtract = extractParam(queryString, "index"); 098 CmsPair<String, String> coreExtract = extractParam(idxExtract.getFirst(), "core"); 099 CmsPair<String, String> maxResultsExtract = extractParam(coreExtract.getFirst(), "maxresults"); 100 String resString = maxResultsExtract.getSecond(); 101 String indexName = idxExtract.getSecond(); 102 if (null != indexName) { 103 indexName = indexName.trim(); 104 } 105 if (null == indexName) { 106 indexName = cms.getRequestContext().getCurrentProject().isOnlineProject() 107 ? CmsSolrIndex.DEFAULT_INDEX_NAME_ONLINE 108 : CmsSolrIndex.DEFAULT_INDEX_NAME_OFFLINE; 109 } 110 Integer maxResNum = null; 111 if (null != resString) { 112 try { 113 maxResNum = Integer.valueOf(resString); 114 } catch (NumberFormatException e) { 115 if (LOG.isErrorEnabled()) { 116 LOG.error("Ignoring param \"maxresults=" + resString + "\" since its not a valid integer.", e); 117 } 118 } 119 } 120 if (null == maxResNum) { 121 try { 122 CmsSolrIndex idx = OpenCms.getSearchManager().getIndexSolr(indexName); 123 if (null != idx) { 124 maxResNum = Integer.valueOf(idx.getMaxProcessedResults()); 125 } else { 126 maxResNum = Integer.valueOf(CmsSolrIndex.MAX_RESULTS_UNLIMITED); 127 } 128 } catch (Throwable t) { 129 // This is ok, it's allowed to have an external other index here. 130 LOG.debug( 131 "Parsing plain search configuration for none-CmsSolrIndex " 132 + indexName 133 + ". Setting max processed results to unlimited."); 134 maxResNum = Integer.valueOf(CmsSolrIndex.MAX_RESULTS_UNLIMITED); 135 } 136 } 137 138 return new CmsSearchConfigurationCommon( 139 null, 140 null, 141 null, 142 null, 143 Boolean.TRUE, 144 Boolean.TRUE, 145 null, 146 indexName, 147 coreExtract.getSecond(), 148 maxResultsExtract.getFirst(), 149 null, 150 null, 151 null, 152 maxResNum.intValue()); 153 } 154 155 /** 156 * @see org.opencms.jsp.search.config.parser.I_CmsSearchConfigurationParser#parseDidYouMean() 157 */ 158 @Override 159 public I_CmsSearchConfigurationDidYouMean parseDidYouMean() { 160 161 return null != m_baseConfig ? m_baseConfig.getDidYouMeanConfig() : null; 162 } 163 164 /** 165 * @see org.opencms.jsp.search.config.parser.I_CmsSearchConfigurationParser#parseFieldFacets() 166 */ 167 @Override 168 public Map<String, I_CmsSearchConfigurationFacetField> parseFieldFacets() { 169 170 return null != m_baseConfig ? m_baseConfig.getFieldFacetConfigs() : Collections.emptyMap(); 171 } 172 173 /** 174 * @see org.opencms.jsp.search.config.parser.I_CmsSearchConfigurationParser#parseGeoFilter() 175 */ 176 @Override 177 public I_CmsSearchConfigurationGeoFilter parseGeoFilter() { 178 179 return null; 180 } 181 182 /** 183 * @see org.opencms.jsp.search.config.parser.I_CmsSearchConfigurationParser#parseHighlighter() 184 */ 185 @Override 186 public I_CmsSearchConfigurationHighlighting parseHighlighter() { 187 188 return null != m_baseConfig ? m_baseConfig.getHighlighterConfig() : null; 189 } 190 191 /** 192 * @see org.opencms.jsp.search.config.parser.I_CmsSearchConfigurationParser#parsePagination() 193 */ 194 @Override 195 public I_CmsSearchConfigurationPagination parsePagination() { 196 197 return null != m_baseConfig ? m_baseConfig.getPaginationConfig() : null; 198 } 199 200 /** 201 * @see org.opencms.jsp.search.config.parser.I_CmsSearchConfigurationParser#parseQueryFacet() 202 */ 203 @Override 204 public I_CmsSearchConfigurationFacetQuery parseQueryFacet() { 205 206 return null != m_baseConfig ? m_baseConfig.getQueryFacetConfig() : null; 207 } 208 209 /** 210 * @see org.opencms.jsp.search.config.parser.I_CmsSearchConfigurationParser#parseRangeFacets() 211 */ 212 @Override 213 public Map<String, I_CmsSearchConfigurationFacetRange> parseRangeFacets() { 214 215 return null != m_baseConfig ? m_baseConfig.getRangeFacetConfigs() : Collections.emptyMap(); 216 } 217 218 /** 219 * @see org.opencms.jsp.search.config.parser.I_CmsSearchConfigurationParser#parseSorting() 220 */ 221 @Override 222 public I_CmsSearchConfigurationSorting parseSorting() { 223 224 return null != m_baseConfig ? m_baseConfig.getSortConfig() : null; 225 } 226 227 /** 228 * Extracts the value of a parameter from a query string. 229 * 230 * For example, extractParam("a=foo&b=bar", "a") will return CmsPair("b=bar", "foo"). 231 * @param params the parameter string. 232 * @param paramKey the key of the parameter to extract the value for. 233 * @return a pair of "params without the extracted parameter" and the value of the extracted parameter. 234 */ 235 CmsPair<String, String> extractParam(String params, String paramKey) { 236 237 String extract = null; 238 int beginIdx = params.indexOf(paramKey + "="); 239 if (beginIdx >= 0) { 240 String sub = params.substring(beginIdx + paramKey.length() + 1); 241 int endIdx = sub.indexOf("&"); 242 if (endIdx >= 0) { 243 extract = sub.substring(0, endIdx); 244 params = params.substring(0, beginIdx) + sub.substring(endIdx + 1); 245 } else { 246 extract = sub; 247 params = beginIdx > 0 ? params.substring(0, beginIdx - 1) : ""; // cut trailing '&' 248 } 249 } 250 return new CmsPair<>(params, extract); 251 252 } 253}