001/*
002* File   : $Source$
003* Date   : $Date$
004* Version: $Revision$
005*
006* This library is part of OpenCms -
007* the Open Source Content Management System
008*
009* Copyright (C) 2002 - 2009 Alkacon Software (http://www.alkacon.com)
010*
011* This library is free software; you can redistribute it and/or
012* modify it under the terms of the GNU Lesser General Public
013* License as published by the Free Software Foundation; either
014* version 2.1 of the License, or (at your option) any later version.
015*
016* This library is distributed in the hope that it will be useful,
017* but WITHOUT ANY WARRANTY; without even the implied warranty of
018* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
019* Lesser General Public License for more details.
020*
021* For further information about Alkacon Software, please see the
022* company website: http://www.alkacon.com
023*
024* For further information about OpenCms, please see the
025* project website: http://www.opencms.org
026*
027* You should have received a copy of the GNU Lesser General Public
028* License along with this library; if not, write to the Free Software
029* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
030*/
031
032package org.opencms.main;
033
034import org.opencms.file.CmsObject;
035import org.opencms.search.CmsSearchException;
036import org.opencms.search.CmsSearchManager;
037import org.opencms.search.solr.CmsSolrIndex;
038import org.opencms.search.solr.CmsSolrQuery;
039import org.opencms.site.CmsSite;
040import org.opencms.util.CmsRequestUtil;
041import org.opencms.util.CmsStringUtil;
042
043import java.io.IOException;
044import java.util.Map;
045
046import javax.servlet.http.HttpServlet;
047import javax.servlet.http.HttpServletRequest;
048import javax.servlet.http.HttpServletResponse;
049
050import org.apache.commons.logging.Log;
051import org.apache.solr.common.params.CommonParams;
052
053/**
054 * The OpenCms Solr handler.<p>
055 *
056 * Reachable under: "/opencms/opencms/handleSolrSelect".<p>
057 *
058 * Usage example:<p>
059 * <code>http://localhost:8080/opencms/opencms/handleSolrSelect?fq=parent-folders:/sites/+type=v8article&fl=path&rows=10&sort=path%20asc</code>
060 *
061 * @since 8.5.0
062 */
063public class OpenCmsSolrHandler extends HttpServlet implements I_CmsRequestHandler {
064
065    /**
066     * Encapsulate each request with an inner class in order to make OpenCmsSolrHander thread-safe.
067     */
068    class Context {
069
070        /** The CMS object. */
071        public CmsObject m_cms;
072
073        /** The Solr index. */
074        public CmsSolrIndex m_index;
075
076        /** The request parameters. */
077        public Map<String, String[]> m_params;
078
079        /** The Solr query. */
080        public CmsSolrQuery m_query;
081    }
082
083    /**
084     * An enum storing the handler names implemented by this class.<p>
085     */
086    private static enum HANDLER_NAMES {
087
088        /**
089         * A constant for the '/select' request handler of the embedded Solr server.
090         * This handler is reachable under "/opencms/opencms/handleSolrSelect".<p>
091         */
092        SolrSelect,
093
094        /**
095         * A constant for the '/spell' request handler of the embedded Solr server.
096         * This handler is reachable under "/opencms/opencms/handleSolrSpell".<p>
097         */
098        SolrSpell
099    }
100
101    /** The log object for this class. */
102    private static final Log LOG = CmsLog.getLog(OpenCmsSolrHandler.class);
103
104    /** A constant for the optional 'baseUri' parameter. */
105    public static final String PARAM_BASE_URI = "baseUri";
106
107    /** A constant for the optional 'core' parameter. */
108    public static final String PARAM_CORE = "core";
109
110    /** A constant for the optional 'index' parameter. */
111    public static final String PARAM_INDEX = "index";
112
113    /** A constant for the HTTP 'referer'. */
114    protected static final String HEADER_REFERER_KEY = "referer";
115
116    /** The UID. */
117    private static final long serialVersionUID = 2460644631508735724L;
118
119    /**
120     * OpenCms servlet main request handling method.<p>
121     *
122     * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
123     */
124    @Override
125    public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {
126
127        handle(req, res, HANDLER_NAMES.SolrSelect.toString());
128    }
129
130    /**
131     * OpenCms servlet POST request handling method,
132     * will just call {@link #doGet(HttpServletRequest, HttpServletResponse)}.<p>
133     *
134     * @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
135     */
136    @Override
137    public void doPost(HttpServletRequest req, HttpServletResponse res) throws IOException {
138
139        doGet(req, res);
140    }
141
142    /**
143     * @see org.opencms.main.I_CmsRequestHandler#getHandlerNames()
144     */
145    public String[] getHandlerNames() {
146
147        return CmsStringUtil.enumNameToStringArray(HANDLER_NAMES.values());
148    }
149
150    /**
151     * @see org.opencms.main.I_CmsRequestHandler#handle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.String)
152     */
153    public void handle(HttpServletRequest req, HttpServletResponse res, String name) throws IOException {
154
155        final HANDLER_NAMES handlerName = HANDLER_NAMES.valueOf(name);
156        if (handlerName != null) {
157            try {
158                Context context = initializeRequest(req, res);
159                if ((context.m_params.get(CommonParams.Q) != null) || (context.m_params.get(CommonParams.FQ) != null)) {
160                    switch (handlerName) {
161                        case SolrSelect:
162                            context.m_index.select(res, context.m_cms, context.m_query, true);
163                            break;
164                        case SolrSpell:
165                            context.m_index.spellCheck(res, context.m_cms, context.m_query);
166                            break;
167                        default:
168                            break;
169                    }
170                }
171            } catch (Exception e) {
172                if (LOG.isInfoEnabled()) {
173                    LOG.info(e);
174                }
175                res.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
176            }
177        }
178    }
179
180    /**
181     * Returns the CMS object.<p>
182     *
183     * @param req the request
184     *
185     * @return the CMS object
186     *
187     * @throws CmsException if something goes wrong
188     */
189    protected CmsObject getCmsObject(HttpServletRequest req) throws CmsException {
190
191        CmsObject cms = OpenCmsCore.getInstance().initCmsObjectFromSession(req);
192        // use the guest user as fall back
193        if (cms == null) {
194            cms = OpenCmsCore.getInstance().initCmsObject(OpenCms.getDefaultUsers().getUserGuest());
195            String siteRoot = OpenCmsCore.getInstance().getSiteManager().matchRequest(req).getSiteRoot();
196            cms.getRequestContext().setSiteRoot(siteRoot);
197        }
198        String baseUri = getBaseUri(req, cms);
199        if (baseUri != null) {
200            cms.getRequestContext().setUri(baseUri);
201        }
202        return cms;
203    }
204
205    /**
206     * Initialized the search request and sets the local parameter.<p>
207     *
208     * @param req the servlet request
209     * @param res the servlet response
210     *
211     * @return the generated context
212     *
213     * @throws CmsException if something goes wrong
214     * @throws Exception if something goes wrong
215     * @throws CmsSearchException if something goes wrong
216     * @throws IOException if something goes wrong
217     */
218    protected Context initializeRequest(HttpServletRequest req, HttpServletResponse res)
219    throws CmsException, Exception, CmsSearchException, IOException {
220
221        Context context = new Context();
222        context.m_cms = getCmsObject(req);
223        context.m_params = CmsRequestUtil.createParameterMap(req.getParameterMap());
224        context.m_index = CmsSearchManager.getIndexSolr(context.m_cms, context.m_params);
225
226        if (context.m_index != null) {
227            context.m_query = new CmsSolrQuery(context.m_cms, context.m_params);
228        } else {
229            res.setStatus(HttpServletResponse.SC_BAD_REQUEST);
230            if (LOG.isInfoEnabled()) {
231                String indexName = context.m_params.get(PARAM_CORE) != null
232                ? context.m_params.get(PARAM_CORE)[0]
233                : (context.m_params.get(PARAM_INDEX) != null ? context.m_params.get(PARAM_INDEX)[0] : null);
234                LOG.info(Messages.get().getBundle().key(Messages.GUI_SOLR_INDEX_NOT_FOUND_1, indexName));
235            }
236        }
237
238        return context;
239    }
240
241    /**
242     * Returns the base URI.<p>
243     *
244     * @param req the servlet request
245     * @param cms the CmsObject
246     *
247     * @return the base URI
248     */
249    private String getBaseUri(HttpServletRequest req, CmsObject cms) {
250
251        String baseUri = req.getParameter(PARAM_BASE_URI);
252        if (CmsStringUtil.isEmptyOrWhitespaceOnly(baseUri)) {
253            String referer = req.getHeader(HEADER_REFERER_KEY);
254            CmsSite site = OpenCms.getSiteManager().getSiteForSiteRoot(cms.getRequestContext().getSiteRoot());
255            if (site != null) {
256                String prefix = site.getServerPrefix(cms, "/") + OpenCms.getStaticExportManager().getVfsPrefix();
257                if ((referer != null) && referer.startsWith(prefix)) {
258                    baseUri = referer.substring(prefix.length());
259                }
260            }
261        }
262        return baseUri;
263    }
264}