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.controller;
029
030import org.opencms.file.CmsObject;
031import org.opencms.jsp.search.config.I_CmsSearchConfigurationCommon;
032import org.opencms.jsp.search.state.CmsSearchStateCommon;
033import org.opencms.jsp.search.state.I_CmsSearchStateCommon;
034import org.opencms.search.solr.CmsSolrQuery;
035import org.opencms.util.CmsRequestUtil;
036
037import java.util.Arrays;
038import java.util.HashMap;
039import java.util.Map;
040import java.util.Map.Entry;
041import java.util.TimeZone;
042import java.util.regex.Pattern;
043
044import org.apache.solr.client.solrj.util.ClientUtils;
045import org.apache.solr.common.params.CommonParams;
046
047/** Search controller for the common search options. */
048public class CmsSearchControllerCommon implements I_CmsSearchControllerCommon {
049
050    /** Value macro. */
051    private static final String MACRO_VALUE = "value";
052    /** Site root macro. */
053    private static final String MACRO_SITE_ROOT = "site_root";
054    /** Configuration of common search options. */
055    private final I_CmsSearchConfigurationCommon m_config;
056    /** State of the common search options. */
057    private final I_CmsSearchStateCommon m_state;
058
059    /** Constructor taking the managed configuration.
060     * @param config The configuration to manage by the controller.
061     */
062    public CmsSearchControllerCommon(final I_CmsSearchConfigurationCommon config) {
063
064        m_config = config;
065        m_state = new CmsSearchStateCommon();
066    }
067
068    /**
069     * @see org.opencms.jsp.search.controller.I_CmsSearchController#addParametersForCurrentState(java.util.Map)
070     */
071    @Override
072    public void addParametersForCurrentState(final Map<String, String[]> parameters) {
073
074        if (!m_state.getQuery().isEmpty()) {
075            parameters.put(m_config.getQueryParam(), new String[] {m_state.getQuery()});
076        }
077        parameters.put(m_config.getReloadedParam(), null);
078        for (Entry<String, String> e : m_state.getAdditionalParameters().entrySet()) {
079            parameters.put(e.getKey(), new String[] {e.getValue()});
080        }
081    }
082
083    /**
084     * @see org.opencms.jsp.search.controller.I_CmsSearchController#addQueryParts(CmsSolrQuery, CmsObject)
085     */
086    @Override
087    public void addQueryParts(CmsSolrQuery query, CmsObject cms) {
088
089        String queryString = m_state.getQuery();
090        if (!m_config.getIgnoreQueryParam()) {
091            if (m_config.getEscapeQueryChars()) {
092                queryString = ClientUtils.escapeQueryChars(queryString);
093            }
094            if (queryString.isEmpty() && m_config.getSearchForEmptyQueryParam()) {
095                queryString = "*";
096            }
097            String modifiedQuery = m_config.getModifiedQuery(queryString);
098            if (modifiedQuery.startsWith("{!")) {
099                modifiedQuery = "{!tag=q " + modifiedQuery.substring(2);
100            } else {
101                modifiedQuery = "{!tag=q}" + modifiedQuery;
102            }
103            query.set("q", modifiedQuery);
104        }
105
106        if (m_config.getSolrIndex() != null) {
107            query.set("index", m_config.getSolrIndex());
108        }
109        if (m_config.getSolrCore() != null) {
110            query.set("core", m_config.getSolrCore());
111        }
112
113        if (!m_config.getExtraSolrParams().isEmpty()) {
114            String currentSiteRoot = null == cms ? null : cms.getRequestContext().getSiteRoot();
115            if ((null != currentSiteRoot) && !currentSiteRoot.endsWith("/")) {
116                currentSiteRoot = currentSiteRoot + "/";
117            }
118            Map<String, String[]> extraParamsMap = CmsRequestUtil.createParameterMap(m_config.getExtraSolrParams());
119            for (String key : extraParamsMap.keySet()) {
120                for (String value : Arrays.asList(extraParamsMap.get(key))) {
121                    value = resolveMacro(value, MACRO_SITE_ROOT, currentSiteRoot);
122                    if (SET_VARIABLES.contains(key)) {
123                        if (key.equals(CommonParams.FL)) {
124                            query.setReturnFields(value);
125                        } else {
126                            query.set(key, value);
127                        }
128                    } else {
129                        query.add(key, value);
130                    }
131                }
132            }
133        }
134        for (String additionalParam : m_state.getAdditionalParameters().keySet()) {
135            String solrValue = m_config.getAdditionalParameters().get(additionalParam);
136            if (null != solrValue) {
137                String additionalParamString = resolveMacro(
138                    solrValue,
139                    MACRO_VALUE,
140                    m_state.getAdditionalParameters().get(additionalParam));
141                Map<String, String[]> extraParamsMap = CmsRequestUtil.createParameterMap(additionalParamString);
142                for (String key : extraParamsMap.keySet()) {
143                    for (String value : Arrays.asList(extraParamsMap.get(key))) {
144                        if (SET_VARIABLES.contains(key)) {
145                            query.set(key, value);
146                        } else {
147                            query.add(key, value);
148                        }
149                    }
150                }
151            }
152        }
153        // Add timezone query parameter to allow for correct date/time handling if not already present.
154        if (!query.getMap().keySet().contains("TZ")) {
155            query.add("TZ", TimeZone.getDefault().getID());
156        }
157    }
158
159    /**
160     * @see org.opencms.jsp.search.controller.I_CmsSearchControllerCommon#getConfig()
161     */
162    @Override
163    public I_CmsSearchConfigurationCommon getConfig() {
164
165        return m_config;
166    }
167
168    /**
169     * @see org.opencms.jsp.search.controller.I_CmsSearchControllerCommon#getState()
170     */
171    @Override
172    public I_CmsSearchStateCommon getState() {
173
174        return m_state;
175    }
176
177    /**
178     * @see org.opencms.jsp.search.controller.I_CmsSearchController#updateForQueryChange()
179     */
180    @Override
181    public void updateForQueryChange() {
182
183        // Nothing to do
184
185    }
186
187    /**
188     * @see org.opencms.jsp.search.controller.I_CmsSearchController#updateFromRequestParameters(java.util.Map, boolean)
189     */
190    @Override
191    public void updateFromRequestParameters(final Map<String, String[]> parameters, boolean isReloaded) {
192
193        m_state.setQuery("");
194
195        if (parameters.containsKey(m_config.getQueryParam())) {
196            final String[] queryStrings = parameters.get(m_config.getQueryParam());
197            if (queryStrings.length > 0) {
198                m_state.setQuery(queryStrings[0]);
199            }
200        }
201        if (parameters.containsKey(m_config.getLastQueryParam())) {
202            final String[] queryStrings = parameters.get(m_config.getLastQueryParam());
203            if (queryStrings.length > 0) {
204                m_state.setLastQuery(queryStrings[0]);
205            }
206        }
207        // Set state for additional query parameters
208        Map<String, String> additionalParameters = new HashMap<String, String>(
209            m_config.getAdditionalParameters().size());
210        for (String key : m_config.getAdditionalParameters().keySet()) {
211            if (parameters.containsKey(key)
212                && ((parameters.get(key).length > 0) && (parameters.get(key)[0].length() > 0))) {
213                additionalParameters.put(key, parameters.get(key)[0]);
214            }
215        }
216        m_state.setAdditionalParameters(additionalParameters);
217    }
218
219    /**
220     * Replaces the macro with the value, unless the value is <code>null</code>, then the macro is kept.
221     *
222     * @param string The String where the macros should be replaced.
223     * @param value The value used for the replacement.
224     * @param macroName The name of the macro to resolve.
225     *
226     * @return The original String with %(value) macros replaced.
227     */
228    private String resolveMacro(final String string, final String macroName, final String value) {
229
230        return null != value ? string.replaceAll("\\%\\(" + Pattern.quote(macroName) + "\\)", value) : string;
231    }
232}