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.search.solr;
033
034import org.opencms.configuration.CmsConfigurationException;
035import org.opencms.main.CmsLog;
036import org.opencms.main.OpenCms;
037import org.opencms.util.CmsStringUtil;
038
039import java.io.File;
040import java.io.FileInputStream;
041import java.io.FileNotFoundException;
042import java.io.IOException;
043import java.nio.file.Paths;
044
045import org.apache.commons.logging.Log;
046import org.apache.solr.core.SolrConfig;
047import org.apache.solr.schema.IndexSchema;
048
049import org.xml.sax.InputSource;
050
051/**
052 * The Solr configuration class.<p>
053 *
054 * @since 8.5.0
055 */
056public class CmsSolrConfiguration {
057
058    /** The default config set path. */
059    public static final String DEFAULT_CONFIGSET_FOLDER = File.separatorChar
060        + "configsets"
061        + File.separatorChar
062        + "default";
063    /** The 'conf' folder inside the Solr home directory. */
064    public static final String CONF_FOLDER = File.separatorChar + "conf" + File.separatorChar;
065
066    /** The Solr configuration file name. */
067    public static final String SOLR_CONFIG_FILE = "solr.xml";
068
069    /** The default maximum number of results to return in a Solr search. */
070    public static final int DEFAULT_MAX_PROCESSED_RESULTS = 400;
071
072    /**
073     * The default max time in ms before a commit will happen (10 seconds by default).<p>
074     *
075     * Can be configured in 'opencms-search.xml'.<p>
076     */
077    public static final long SOLR_DEFAULT_COMMIT_MS = 10000;
078
079    /** The default name of the Solr home directory. */
080    public static final String SOLR_HOME_DEFAULT = "solr" + File.separatorChar;
081
082    /** The system property name for the Solr home directory. */
083    public static final String SOLR_HOME_PROPERTY = "solr.solr.home";
084
085    /** The Solr schema name. */
086    public static final String SOLR_SCHEMA_NAME = "OpenCms SOLR schema";
087
088    /** The log object for this class. */
089    private static final Log LOG = CmsLog.getLog(CmsSolrConfiguration.class);
090
091    /** Max time (in ms) before a commit will happen. */
092    private long m_commitMs = SOLR_DEFAULT_COMMIT_MS;
093
094    /** Signals whether the server is enabled or disabled. */
095    private boolean m_enabled;
096
097    /** The Solr home. */
098    private String m_home;
099
100    /** The configured path to the Solr home. */
101    private String m_homeFolderPath;
102
103    /** The schema file. */
104    private IndexSchema m_schema;
105
106    /** The servers URL, must be set if embedded is false. */
107    private String m_serverUrl;
108
109    /** The Solr configuration. */
110    private SolrConfig m_solrConfig;
111
112    /** The Solr configuration file "solr.xml". */
113    private File m_solrFile;
114
115    /** The file name of the Solr configuration. */
116    private String m_solrFileName;
117
118    /** The maximal number of results to be processed in a search request to a Solr index. */
119    private int m_maxProcessedResults = DEFAULT_MAX_PROCESSED_RESULTS;
120
121    /**
122     * Default constructor.<p>
123     */
124    public CmsSolrConfiguration() {
125
126        // needed for the digester
127    }
128
129    /**
130     * Returns the home directory of Solr as String.<p>
131     *
132     * @return the home directory of Solr as String
133     */
134    public String getHome() {
135
136        if (m_homeFolderPath == null) {
137            if (CmsStringUtil.isNotEmpty(System.getProperty(SOLR_HOME_PROPERTY))) {
138                m_home = System.getProperty(SOLR_HOME_PROPERTY);
139            } else {
140                m_home = OpenCms.getSystemInfo().getAbsoluteRfsPathRelativeToWebInf(SOLR_HOME_DEFAULT);
141            }
142            m_home = (m_home.endsWith(File.separator)
143            ? m_home.substring(0, m_home.lastIndexOf(File.separator))
144            : m_home);
145        } else {
146            m_home = m_homeFolderPath;
147        }
148        return m_home;
149    }
150
151    /**
152     * Returns the configured Solr home.<p>
153     *
154     * @return the configured Solr home
155     */
156    public String getHomeFolderPath() {
157
158        return m_homeFolderPath;
159    }
160
161    /**
162     * Returns the maximal number of results processed when querying a Solr index.
163     *
164     * Each index has a configuration option to overwrite this global value.
165     *
166     * @return the maximal number of results processed when querying a Solr index.
167     */
168    public int getMaxProcessedResults() {
169
170        return m_maxProcessedResults;
171    }
172
173    /**
174     * Returns the servers URL if embedded is set to <code>false</code>.<p>
175     *
176     * @return the external servers URL
177     */
178    public String getServerUrl() {
179
180        return m_serverUrl;
181    }
182
183    /**
184     * Returns the max time (in ms) before a commit will happen.<p>
185     *
186     * @return the max time (in ms) before a commit will happen
187     */
188    public long getSolrCommitMs() {
189
190        return m_commitMs;
191    }
192
193    /**
194     * Returns the Solr configuration (object representation of <code>'solrconfig.xml'</code>).<p>
195     *
196     * @return the Solr configuration
197     *
198     */
199    public SolrConfig getSolrConfig() {
200
201        if (m_solrConfig == null) {
202            try (FileInputStream fis = new FileInputStream(getSolrConfigFile())) {
203                m_solrConfig = new SolrConfig(
204                    Paths.get(getHome(), DEFAULT_CONFIGSET_FOLDER),
205                    null,
206                    new InputSource(fis));
207            } catch (FileNotFoundException e) {
208                CmsConfigurationException ex = new CmsConfigurationException(
209                    Messages.get().container(Messages.LOG_SOLR_ERR_CONFIG_XML_NOT_FOUND_1, getSolrConfigFile()),
210                    e);
211                LOG.error(ex.getLocalizedMessage(), ex);
212            } catch (Exception e) {
213                CmsConfigurationException ex = new CmsConfigurationException(
214                    Messages.get().container(Messages.LOG_SOLR_ERR_CONFIG_XML_NOT_READABLE_1, getSolrConfigFile()),
215                    e);
216                LOG.error(ex.getLocalizedMessage(), ex);
217            }
218        }
219        return m_solrConfig;
220    }
221
222    /**
223     * Returns the solr configuration file, default: <code>'conf/solrconfig.xml'</code>.<p>
224     *
225     * @return the solr configuration file
226     */
227    public File getSolrConfigFile() {
228
229        return new File(getHome() + DEFAULT_CONFIGSET_FOLDER + CONF_FOLDER + SolrConfig.DEFAULT_CONF_FILE);
230    }
231
232    /**
233     * Returns the Solr xml file, default: <code>'solr.xml'</code>.<p>
234     *
235     * @return the Solr xml file
236     */
237    public File getSolrFile() {
238
239        if (m_solrFile == null) {
240            String solrFileName = m_solrFileName != null ? m_solrFileName : SOLR_CONFIG_FILE;
241            m_solrFile = new File(getHome() + File.separator + solrFileName);
242        }
243        return m_solrFile;
244    }
245
246    /**
247     * Returns the Solr xml file name, default: <code>'solr.xml'</code>.<p>
248     *
249     * @return the Solr xml file name
250     */
251    public String getSolrFileName() {
252
253        return m_solrFileName;
254    }
255
256    /**
257     * Returns the Solr index schema.<p>
258     *
259     * @return the Solr index schema
260     */
261    public IndexSchema getSolrSchema() {
262
263        if (m_schema == null) {
264            try (FileInputStream fis = new FileInputStream(getSolrSchemaFile())) {
265                InputSource solrSchema = new InputSource(fis);
266                m_schema = new IndexSchema(getSolrConfig(), SOLR_SCHEMA_NAME, solrSchema);
267            } catch (IOException e) {
268                CmsConfigurationException ex = new CmsConfigurationException(
269                    Messages.get().container(
270                        Messages.LOG_SOLR_ERR_SCHEMA_XML_NOT_FOUND_1,
271                        getSolrSchemaFile().getPath()),
272                    e);
273                LOG.error(ex.getLocalizedMessage(), ex);
274            }
275        }
276        return m_schema;
277    }
278
279    /**
280     * Returns the Solr index schema file.<p>
281     *
282     * @return the Solr index schema file
283     */
284    public File getSolrSchemaFile() {
285
286        final String dir = getHome() + DEFAULT_CONFIGSET_FOLDER + CONF_FOLDER;
287        //SOLR7 Schema took a new name, also removed the file extension.
288        File file = new File(dir, "managed-schema");
289        if (file.exists()) {
290            return file;
291        }
292
293        //If use the old Schema.xml, it will automatically "upgrade" to a new filename.
294        file = new File(dir, IndexSchema.DEFAULT_SCHEMA_FILE);
295        return file;
296    }
297
298    /**
299     * Returns <code>true</code> if the Solr server is embedded, <code>false</code> otherwise.<p>
300     *
301     * @return <code>true</code> if the Solr server is embedded, <code>false</code> otherwise
302     */
303    public boolean isEnabled() {
304
305        return m_enabled;
306    }
307
308    /**
309     * Sets the enabled flag.<p>
310     *
311     * @param isEnabled <code>true</code>, if the Solr server should be used, <code>false</code> otherwise
312     */
313    public void setEnabled(String isEnabled) {
314
315        m_enabled = Boolean.valueOf(isEnabled).booleanValue();
316    }
317
318    /**
319     * Sets the home folder for Solr.<p>
320     *
321     * @param homeFolderPath the Solr home folder to set
322     */
323    public void setHomeFolderPath(String homeFolderPath) {
324
325        m_homeFolderPath = homeFolderPath;
326    }
327
328    /**
329     * Sets the maximal number of results processed for a query to a Solr index.<p>
330     *
331     * The globally set value can be overwritten for each index.
332     *
333     * @param maxProcessedResults the maximal number of results processed for a query to a Solr index.
334     */
335    public void setMaxProcessedResults(String maxProcessedResults) {
336
337        try {
338            m_maxProcessedResults = Integer.parseInt(maxProcessedResults);
339        } catch (Exception e) {
340            LOG.warn(
341                "Could not parse value "
342                    + maxProcessedResults
343                    + " as Integer to set the limit for the number of results a Solr index can return.");
344        }
345        if (m_maxProcessedResults <= 0) {
346            m_maxProcessedResults = DEFAULT_MAX_PROCESSED_RESULTS;
347            LOG.warn(
348                "The maximal number of results to return by a Solr index should be greater than 0. Reset it to the default value "
349                    + DEFAULT_MAX_PROCESSED_RESULTS
350                    + ".");
351        }
352    }
353
354    /**
355     * Sets the external servers URL, should be not null if the embedded falg is <code>false</code>.<p>
356     *
357     * @param url the URL
358     */
359    public void setServerUrl(String url) {
360
361        m_serverUrl = url;
362    }
363
364    /**
365     * Sets the max time (in ms) before a commit will happen.<p>
366     *
367     * @param time the time as long value
368     */
369    public void setSolrCommitMs(String time) {
370
371        m_commitMs = new Long(time).longValue();
372    }
373
374    /**
375     * Sets the Solr file name.<p>
376     *
377     * @param name the file name to set
378     */
379    public void setSolrFileName(String name) {
380
381        m_solrFileName = name;
382    }
383}