xref: /OpenGrok/opengrok-indexer/src/main/java/org/opengrok/indexer/configuration/RuntimeEnvironment.java (revision 5650cf1579547c2f9158c047af5b8af27ab2e6d3)
1b5840353SAdam Hornáček /*
2b5840353SAdam Hornáček  * CDDL HEADER START
3b5840353SAdam Hornáček  *
4b5840353SAdam Hornáček  * The contents of this file are subject to the terms of the
5b5840353SAdam Hornáček  * Common Development and Distribution License (the "License").
6b5840353SAdam Hornáček  * You may not use this file except in compliance with the License.
7b5840353SAdam Hornáček  *
8b5840353SAdam Hornáček  * See LICENSE.txt included in this distribution for the specific
9b5840353SAdam Hornáček  * language governing permissions and limitations under the License.
10b5840353SAdam Hornáček  *
11b5840353SAdam Hornáček  * When distributing Covered Code, include this CDDL HEADER in each
12b5840353SAdam Hornáček  * file and include the License file at LICENSE.txt.
13b5840353SAdam Hornáček  * If applicable, add the following below this CDDL HEADER, with the
14b5840353SAdam Hornáček  * fields enclosed by brackets "[]" replaced with your own identifying
15b5840353SAdam Hornáček  * information: Portions Copyright [yyyy] [name of copyright owner]
16b5840353SAdam Hornáček  *
17b5840353SAdam Hornáček  * CDDL HEADER END
18b5840353SAdam Hornáček  */
19b5840353SAdam Hornáček 
20b5840353SAdam Hornáček /*
216bfa9427SVladimir Kotal  * Copyright (c) 2006, 2022, Oracle and/or its affiliates. All rights reserved.
225d9f3aa0SAdam Hornáček  * Portions Copyright (c) 2017, 2020, Chris Fraire <cfraire@me.com>.
23b5840353SAdam Hornáček  */
249805b761SAdam Hornáček package org.opengrok.indexer.configuration;
25b5840353SAdam Hornáček 
2668830e6dSKryštof Tulinger import static org.opengrok.indexer.configuration.Configuration.makeXMLStringAsConfiguration;
27f1e34e10SVladimir Kotal import static org.opengrok.indexer.index.IndexerUtil.getWebAppHeaders;
282ffbb0cfSVladimir Kotal 
29b5840353SAdam Hornáček import java.io.File;
30b5840353SAdam Hornáček import java.io.FileNotFoundException;
31b5840353SAdam Hornáček import java.io.IOException;
32b5840353SAdam Hornáček import java.nio.file.Path;
336d9d3df9SAnatoly Akkerman import java.nio.file.Paths;
34b5840353SAdam Hornáček import java.util.ArrayList;
35937bd40dSVladimir Kotal import java.util.Arrays;
361b935619SVladimir Kotal import java.util.Collection;
372ffbb0cfSVladimir Kotal import java.util.Collections;
38b5840353SAdam Hornáček import java.util.Date;
39fadf9080SVladimir Kotal import java.util.HashMap;
409c92ca95SChris Fraire import java.util.HashSet;
41b5840353SAdam Hornáček import java.util.List;
42b5840353SAdam Hornáček import java.util.Map;
43b5840353SAdam Hornáček import java.util.Set;
44b5840353SAdam Hornáček import java.util.SortedSet;
45b5840353SAdam Hornáček import java.util.TreeSet;
46b5840353SAdam Hornáček import java.util.concurrent.ConcurrentHashMap;
47e9a23d1eSAdam Hornáček import java.util.concurrent.CopyOnWriteArraySet;
48b5840353SAdam Hornáček import java.util.concurrent.ExecutorService;
49b5840353SAdam Hornáček import java.util.concurrent.Executors;
50fb531549SVladimir Kotal import java.util.concurrent.TimeUnit;
514151dbf5SChris Fraire import java.util.function.Function;
52b5840353SAdam Hornáček import java.util.logging.Level;
53b5840353SAdam Hornáček import java.util.logging.Logger;
54b5840353SAdam Hornáček import java.util.stream.Collectors;
55aa6abf42SAdam Hornacek 
56aa6abf42SAdam Hornacek import jakarta.ws.rs.client.ClientBuilder;
57aa6abf42SAdam Hornacek import jakarta.ws.rs.client.Entity;
58aa6abf42SAdam Hornacek import jakarta.ws.rs.core.Response;
5968830e6dSKryštof Tulinger import org.apache.lucene.index.IndexReader;
6068830e6dSKryštof Tulinger import org.apache.lucene.index.MultiReader;
6168830e6dSKryštof Tulinger import org.apache.lucene.search.SearcherManager;
6268830e6dSKryštof Tulinger import org.apache.lucene.store.AlreadyClosedException;
6368830e6dSKryštof Tulinger import org.apache.lucene.store.Directory;
6468830e6dSKryštof Tulinger import org.apache.lucene.store.FSDirectory;
65fb531549SVladimir Kotal import org.apache.lucene.util.NamedThreadFactory;
6632b4cd63SVladimir Kotal import org.jetbrains.annotations.VisibleForTesting;
6768830e6dSKryštof Tulinger import org.opengrok.indexer.authorization.AuthorizationFramework;
6868830e6dSKryštof Tulinger import org.opengrok.indexer.authorization.AuthorizationStack;
69fadf9080SVladimir Kotal import org.opengrok.indexer.history.FileCollector;
7068830e6dSKryštof Tulinger import org.opengrok.indexer.history.HistoryGuru;
7168830e6dSKryštof Tulinger import org.opengrok.indexer.history.RepositoryInfo;
7268830e6dSKryštof Tulinger import org.opengrok.indexer.index.IndexDatabase;
73e829566cSChris Fraire import org.opengrok.indexer.index.IndexerParallelizer;
7468830e6dSKryštof Tulinger import org.opengrok.indexer.logger.LoggerFactory;
754151dbf5SChris Fraire import org.opengrok.indexer.util.CloseableReentrantReadWriteLock;
7668830e6dSKryštof Tulinger import org.opengrok.indexer.util.CtagsUtil;
7768830e6dSKryštof Tulinger import org.opengrok.indexer.util.ForbiddenSymlinkException;
78e829566cSChris Fraire import org.opengrok.indexer.util.LazilyInstantiate;
7968830e6dSKryštof Tulinger import org.opengrok.indexer.util.PathUtils;
804151dbf5SChris Fraire import org.opengrok.indexer.util.ResourceLock;
816068c59cSVladimir Kotal import org.opengrok.indexer.util.Statistics;
82cce4eb5fSVladimir Kotal import org.opengrok.indexer.web.ApiUtils;
8368830e6dSKryštof Tulinger import org.opengrok.indexer.web.Prefix;
84369f83fbSVladimir Kotal import org.opengrok.indexer.web.Util;
8568830e6dSKryštof Tulinger import org.opengrok.indexer.web.messages.Message;
8668830e6dSKryštof Tulinger import org.opengrok.indexer.web.messages.MessagesContainer;
8768830e6dSKryštof Tulinger import org.opengrok.indexer.web.messages.MessagesContainer.AcceptedMessage;
884ce4e2b9SAdam Hornáček 
89b5840353SAdam Hornáček /**
90b5840353SAdam Hornáček  * The RuntimeEnvironment class is used as a placeholder for the current
91b5840353SAdam Hornáček  * configuration this execution context (classloader) is using.
92b5840353SAdam Hornáček  */
93b5840353SAdam Hornáček public final class RuntimeEnvironment {
94b5840353SAdam Hornáček 
95b5840353SAdam Hornáček     private static final Logger LOGGER = LoggerFactory.getLogger(RuntimeEnvironment.class);
96b5840353SAdam Hornáček 
97b5840353SAdam Hornáček     private static final String URL_PREFIX = "/source" + Prefix.SEARCH_R + "?";
98b5840353SAdam Hornáček 
99b5840353SAdam Hornáček     private Configuration configuration;
1004151dbf5SChris Fraire     private final CloseableReentrantReadWriteLock configLock;
101e829566cSChris Fraire     private final LazilyInstantiate<IndexerParallelizer> lzIndexerParallelizer;
102e829566cSChris Fraire     private final LazilyInstantiate<ExecutorService> lzSearchExecutor;
103fb531549SVladimir Kotal     private final LazilyInstantiate<ExecutorService> lzRevisionExecutor;
104b5840353SAdam Hornáček     private static final RuntimeEnvironment instance = new RuntimeEnvironment();
105b5840353SAdam Hornáček 
106b5840353SAdam Hornáček     private final Map<Project, List<RepositoryInfo>> repository_map = new ConcurrentHashMap<>();
107b5840353SAdam Hornáček     private final Map<String, SearcherManager> searcherManagerMap = new ConcurrentHashMap<>();
108b5840353SAdam Hornáček 
10955402125SVladimir Kotal     private String configURI;
1104151dbf5SChris Fraire     IncludeFiles includeFiles = new IncludeFiles();
1114ce4e2b9SAdam Hornáček     private final MessagesContainer messagesContainer = new MessagesContainer();
1124ce4e2b9SAdam Hornáček 
113b5840353SAdam Hornáček     private static final IndexTimestamp indexTime = new IndexTimestamp();
114b5840353SAdam Hornáček 
115b5840353SAdam Hornáček     /**
116b5840353SAdam Hornáček      * Stores a transient value when
117b5840353SAdam Hornáček      * {@link #setCtags(java.lang.String)} is called -- i.e. the
118b5840353SAdam Hornáček      * value is not mediated to {@link Configuration}.
119b5840353SAdam Hornáček      */
120b5840353SAdam Hornáček     private String ctags;
121b5840353SAdam Hornáček     /**
122b5840353SAdam Hornáček      * Stores a transient value when
123b5840353SAdam Hornáček      * {@link #setMandoc(java.lang.String)} is called -- i.e. the
124b5840353SAdam Hornáček      * value is not mediated to {@link Configuration}.
125b5840353SAdam Hornáček      */
126b5840353SAdam Hornáček     private String mandoc;
127b5840353SAdam Hornáček 
1282ffbb0cfSVladimir Kotal     private transient File dtagsEftar = null;
1292ffbb0cfSVladimir Kotal 
1309c92ca95SChris Fraire     private transient volatile Boolean ctagsFound;
1319c92ca95SChris Fraire     private final transient Set<String> ctagsLanguages = new HashSet<>();
1329c92ca95SChris Fraire 
13323287255SVladimir Kotal     private final WatchDogService watchDog;
1349c92ca95SChris Fraire 
135e9a23d1eSAdam Hornáček     private final Set<ConfigurationChangedListener> listeners = new CopyOnWriteArraySet<>();
136e9a23d1eSAdam Hornáček 
getSubFiles()1370d7ace53SVladimir Kotal     public List<String> getSubFiles() {
1380d7ace53SVladimir Kotal         return subFiles;
1390d7ace53SVladimir Kotal     }
1400d7ace53SVladimir Kotal 
141c6f0939bSAdam Hornacek     private final List<String> subFiles = new ArrayList<>();
1420d7ace53SVladimir Kotal 
143b5840353SAdam Hornáček     /**
144fadf9080SVladimir Kotal      * Maps project name to FileCollector object. This is used to pass the list of files acquired when
145fadf9080SVladimir Kotal      * generating history cache in the first phase of indexing to the second phase of indexing.
146fadf9080SVladimir Kotal      */
147fadf9080SVladimir Kotal     private final Map<String, FileCollector> fileCollectorMap = new HashMap<>();
148fadf9080SVladimir Kotal 
149fadf9080SVladimir Kotal     /**
1502ffbb0cfSVladimir Kotal      * Creates a new instance of RuntimeEnvironment. Private to ensure a
1512ffbb0cfSVladimir Kotal      * singleton anti-pattern.
152b5840353SAdam Hornáček      */
RuntimeEnvironment()1532ffbb0cfSVladimir Kotal     private RuntimeEnvironment() {
1542ffbb0cfSVladimir Kotal         configuration = new Configuration();
1554151dbf5SChris Fraire         configLock = new CloseableReentrantReadWriteLock();
1562ffbb0cfSVladimir Kotal         watchDog = new WatchDogService();
157e829566cSChris Fraire         lzIndexerParallelizer = LazilyInstantiate.using(() ->
158e829566cSChris Fraire                 new IndexerParallelizer(this));
159c6f0939bSAdam Hornacek         lzSearchExecutor = LazilyInstantiate.using(this::newSearchExecutor);
160c6f0939bSAdam Hornacek         lzRevisionExecutor = LazilyInstantiate.using(this::newRevisionExecutor);
1612ffbb0cfSVladimir Kotal     }
1622ffbb0cfSVladimir Kotal 
1631cbb0597SVladimir Kotal     // Instance of authorization framework and its lock.
164b5840353SAdam Hornáček     private AuthorizationFramework authFramework;
1651cbb0597SVladimir Kotal     private final Object authFrameworkLock = new Object();
166b5840353SAdam Hornáček 
1670d7ace53SVladimir Kotal     private boolean indexer;
1680d7ace53SVladimir Kotal 
isIndexer()1690d7ace53SVladimir Kotal     public boolean isIndexer() {
1700d7ace53SVladimir Kotal         return indexer;
1710d7ace53SVladimir Kotal     }
1720d7ace53SVladimir Kotal 
setIndexer(boolean indexer)1730d7ace53SVladimir Kotal     public void setIndexer(boolean indexer) {
1740d7ace53SVladimir Kotal         this.indexer = indexer;
1750d7ace53SVladimir Kotal     }
1760d7ace53SVladimir Kotal 
17723287255SVladimir Kotal     /**
17823287255SVladimir Kotal      * @return {@code WatchDogService} instance
17923287255SVladimir Kotal      */
getWatchDog()18023287255SVladimir Kotal     public WatchDogService getWatchDog() {
18123287255SVladimir Kotal         return watchDog;
18223287255SVladimir Kotal     }
18323287255SVladimir Kotal 
184e829566cSChris Fraire     /** Gets the thread pool used for multi-project searches. */
getSearchExecutor()185e829566cSChris Fraire     public ExecutorService getSearchExecutor() {
186e829566cSChris Fraire         return lzSearchExecutor.get();
187b5840353SAdam Hornáček     }
188b5840353SAdam Hornáček 
newSearchExecutor()189e829566cSChris Fraire     private ExecutorService newSearchExecutor() {
190e829566cSChris Fraire         return Executors.newFixedThreadPool(
191b5840353SAdam Hornáček                 this.getMaxSearchThreadCount(),
192c6f0939bSAdam Hornacek                 runnable -> {
193b5840353SAdam Hornáček                     Thread thread = Executors.defaultThreadFactory().newThread(runnable);
194b5840353SAdam Hornáček                     thread.setName("search-" + thread.getId());
195b5840353SAdam Hornáček                     return thread;
196b5840353SAdam Hornáček                 });
197b5840353SAdam Hornáček     }
198b5840353SAdam Hornáček 
getRevisionExecutor()199fb531549SVladimir Kotal     public ExecutorService getRevisionExecutor() {
200fb531549SVladimir Kotal         return lzRevisionExecutor.get();
201fb531549SVladimir Kotal     }
202fb531549SVladimir Kotal 
newRevisionExecutor()203fb531549SVladimir Kotal     private ExecutorService newRevisionExecutor() {
204fb531549SVladimir Kotal         return Executors.newFixedThreadPool(this.getMaxRevisionThreadCount(),
205fb531549SVladimir Kotal                 new NamedThreadFactory("get-revision"));
206fb531549SVladimir Kotal     }
207fb531549SVladimir Kotal 
shutdownRevisionExecutor()208fb531549SVladimir Kotal     public void shutdownRevisionExecutor() throws InterruptedException {
209fb531549SVladimir Kotal         getRevisionExecutor().shutdownNow();
210a904b83aSVladimir Kotal         getRevisionExecutor().awaitTermination(getIndexerCommandTimeout(), TimeUnit.SECONDS);
211fb531549SVladimir Kotal     }
212fb531549SVladimir Kotal 
213b5840353SAdam Hornáček     /**
214ff44f24aSAdam Hornáček      * Get the one and only instance of the RuntimeEnvironment.
215b5840353SAdam Hornáček      *
216b5840353SAdam Hornáček      * @return the one and only instance of the RuntimeEnvironment
217b5840353SAdam Hornáček      */
getInstance()218b5840353SAdam Hornáček     public static RuntimeEnvironment getInstance() {
219b5840353SAdam Hornáček         return instance;
220b5840353SAdam Hornáček     }
221b5840353SAdam Hornáček 
getIndexerParallelizer()222e829566cSChris Fraire     public IndexerParallelizer getIndexerParallelizer() {
223e829566cSChris Fraire         return lzIndexerParallelizer.get();
224e829566cSChris Fraire     }
225e829566cSChris Fraire 
22640669eceSChris Fraire     /**
22740669eceSChris Fraire      * Gets an instance associated to this environment.
22840669eceSChris Fraire      */
getPathAccepter()22940669eceSChris Fraire     public PathAccepter getPathAccepter() {
23040669eceSChris Fraire         return new PathAccepter(getIgnoredNames(), getIncludedNames());
23140669eceSChris Fraire     }
23240669eceSChris Fraire 
getCanonicalPath(String s)233b5840353SAdam Hornáček     private String getCanonicalPath(String s) {
234ff44f24aSAdam Hornáček         if (s == null) {
235ff44f24aSAdam Hornáček             return null;
236ff44f24aSAdam Hornáček         }
237b5840353SAdam Hornáček         try {
238b5840353SAdam Hornáček             File file = new File(s);
239b5840353SAdam Hornáček             if (!file.exists()) {
240b5840353SAdam Hornáček                 return s;
241b5840353SAdam Hornáček             }
242b5840353SAdam Hornáček             return file.getCanonicalPath();
243b5840353SAdam Hornáček         } catch (IOException ex) {
244b5840353SAdam Hornáček             LOGGER.log(Level.SEVERE, "Failed to get canonical path", ex);
245b5840353SAdam Hornáček             return s;
246b5840353SAdam Hornáček         }
247b5840353SAdam Hornáček     }
248b5840353SAdam Hornáček 
getScanningDepth()249b5840353SAdam Hornáček     public int getScanningDepth() {
2504151dbf5SChris Fraire         return syncReadConfiguration(Configuration::getScanningDepth);
251b5840353SAdam Hornáček     }
252b5840353SAdam Hornáček 
setScanningDepth(int scanningDepth)253b5840353SAdam Hornáček     public void setScanningDepth(int scanningDepth) {
254754ebdfbSChris Fraire         syncWriteConfiguration(scanningDepth, Configuration::setScanningDepth);
255b5840353SAdam Hornáček     }
256b5840353SAdam Hornáček 
getNestingMaximum()2572402fe1cSChris Fraire     public int getNestingMaximum() {
2582402fe1cSChris Fraire         return syncReadConfiguration(Configuration::getNestingMaximum);
2592402fe1cSChris Fraire     }
2602402fe1cSChris Fraire 
setNestingMaximum(int nestingMaximum)2612402fe1cSChris Fraire     public void setNestingMaximum(int nestingMaximum) {
2622402fe1cSChris Fraire         syncWriteConfiguration(nestingMaximum, Configuration::setNestingMaximum);
2632402fe1cSChris Fraire     }
2642402fe1cSChris Fraire 
getCommandTimeout(CommandTimeoutType cmdType)265a904b83aSVladimir Kotal     public int getCommandTimeout(CommandTimeoutType cmdType) {
266a904b83aSVladimir Kotal         switch (cmdType) {
267a904b83aSVladimir Kotal             case INDEXER:
268a904b83aSVladimir Kotal                 return getIndexerCommandTimeout();
269a904b83aSVladimir Kotal             case INTERACTIVE:
270a904b83aSVladimir Kotal                 return getInteractiveCommandTimeout();
271a904b83aSVladimir Kotal             case WEBAPP_START:
272a904b83aSVladimir Kotal                 return getWebappStartCommandTimeout();
273a904b83aSVladimir Kotal             case RESTFUL:
274a904b83aSVladimir Kotal                 return getRestfulCommandTimeout();
275b5840353SAdam Hornáček         }
276b5840353SAdam Hornáček 
2778b57b0e7SVladimir Kotal         throw new IllegalArgumentException("invalid command timeout type");
278a904b83aSVladimir Kotal     }
279a904b83aSVladimir Kotal 
getRestfulCommandTimeout()280a904b83aSVladimir Kotal     public int getRestfulCommandTimeout() {
281a904b83aSVladimir Kotal         return syncReadConfiguration(Configuration::getRestfulCommandTimeout);
282a904b83aSVladimir Kotal     }
283a904b83aSVladimir Kotal 
setRestfulCommandTimeout(int timeout)284a904b83aSVladimir Kotal     public void setRestfulCommandTimeout(int timeout) {
285a904b83aSVladimir Kotal         syncWriteConfiguration(timeout, Configuration::setWebappStartCommandTimeout);
286a904b83aSVladimir Kotal     }
287a904b83aSVladimir Kotal 
getWebappStartCommandTimeout()288a904b83aSVladimir Kotal     public int getWebappStartCommandTimeout() {
289a904b83aSVladimir Kotal         return syncReadConfiguration(Configuration::getWebappStartCommandTimeout);
290a904b83aSVladimir Kotal     }
291a904b83aSVladimir Kotal 
setWebappStartCommandTimeout(int timeout)292a904b83aSVladimir Kotal     public void setWebappStartCommandTimeout(int timeout) {
293a904b83aSVladimir Kotal         syncWriteConfiguration(timeout, Configuration::setWebappStartCommandTimeout);
294a904b83aSVladimir Kotal     }
295a904b83aSVladimir Kotal 
getIndexerCommandTimeout()296a904b83aSVladimir Kotal     public int getIndexerCommandTimeout() {
297a904b83aSVladimir Kotal         return syncReadConfiguration(Configuration::getIndexerCommandTimeout);
298a904b83aSVladimir Kotal     }
299a904b83aSVladimir Kotal 
setIndexerCommandTimeout(int timeout)300a904b83aSVladimir Kotal     public void setIndexerCommandTimeout(int timeout) {
301a904b83aSVladimir Kotal         syncWriteConfiguration(timeout, Configuration::setIndexerCommandTimeout);
302b5840353SAdam Hornáček     }
303b5840353SAdam Hornáček 
getInteractiveCommandTimeout()304b5840353SAdam Hornáček     public int getInteractiveCommandTimeout() {
3054151dbf5SChris Fraire         return syncReadConfiguration(Configuration::getInteractiveCommandTimeout);
306b5840353SAdam Hornáček     }
307b5840353SAdam Hornáček 
setInteractiveCommandTimeout(int timeout)308a904b83aSVladimir Kotal     public void setInteractiveCommandTimeout(int timeout) {
309a904b83aSVladimir Kotal         syncWriteConfiguration(timeout, Configuration::setInteractiveCommandTimeout);
310b5840353SAdam Hornáček     }
311b82c5e9dSVladimir Kotal 
getCtagsTimeout()312b124dbe6SVladimir Kotal     public long getCtagsTimeout() {
3134151dbf5SChris Fraire         return syncReadConfiguration(Configuration::getCtagsTimeout);
314b82c5e9dSVladimir Kotal     }
315b82c5e9dSVladimir Kotal 
setCtagsTimeout(long timeout)316a904b83aSVladimir Kotal     public void setCtagsTimeout(long timeout) {
317a904b83aSVladimir Kotal         syncWriteConfiguration(timeout, Configuration::setCtagsTimeout);
318b82c5e9dSVladimir Kotal     }
319b5840353SAdam Hornáček 
getXrefTimeout()320e92cec67SVladimir Kotal     public long getXrefTimeout() {
321e92cec67SVladimir Kotal         return syncReadConfiguration(Configuration::getXrefTimeout);
322e92cec67SVladimir Kotal     }
323e92cec67SVladimir Kotal 
setXrefTimeout(long timeout)324e92cec67SVladimir Kotal     public void setXrefTimeout(long timeout) {
325e92cec67SVladimir Kotal         syncWriteConfiguration(timeout, Configuration::setXrefTimeout);
326e92cec67SVladimir Kotal     }
327e92cec67SVladimir Kotal 
setLastEditedDisplayMode(boolean lastEditedDisplayMode)328b5840353SAdam Hornáček     public void setLastEditedDisplayMode(boolean lastEditedDisplayMode) {
329754ebdfbSChris Fraire         syncWriteConfiguration(lastEditedDisplayMode, Configuration::setLastEditedDisplayMode);
330b5840353SAdam Hornáček     }
331b5840353SAdam Hornáček 
isLastEditedDisplayMode()332b5840353SAdam Hornáček     public boolean isLastEditedDisplayMode() {
3334151dbf5SChris Fraire         return syncReadConfiguration(Configuration::isLastEditedDisplayMode);
334b5840353SAdam Hornáček     }
335b5840353SAdam Hornáček 
336b5840353SAdam Hornáček     /**
337ff44f24aSAdam Hornáček      * Get the path to the where the web application includes are stored.
338a03922c4SAdam Hornáček      *
339a03922c4SAdam Hornáček      * @return the path to the web application include files
340a03922c4SAdam Hornáček      */
getIncludeRootPath()341a03922c4SAdam Hornáček     public String getIncludeRootPath() {
3424151dbf5SChris Fraire         return syncReadConfiguration(Configuration::getIncludeRoot);
343a03922c4SAdam Hornáček     }
344a03922c4SAdam Hornáček 
345a03922c4SAdam Hornáček     /**
346ff44f24aSAdam Hornáček      * Set include root path.
3476630f04dSVladimir Kotal      * @param includeRoot path
3486630f04dSVladimir Kotal      */
setIncludeRoot(String includeRoot)3496630f04dSVladimir Kotal     public void setIncludeRoot(String includeRoot) {
350754ebdfbSChris Fraire         syncWriteConfiguration(getCanonicalPath(includeRoot), Configuration::setIncludeRoot);
3516630f04dSVladimir Kotal     }
3526630f04dSVladimir Kotal 
3536630f04dSVladimir Kotal     /**
354ff44f24aSAdam Hornáček      * Get the path to the where the index database is stored.
355b5840353SAdam Hornáček      *
356b5840353SAdam Hornáček      * @return the path to the index database
357b5840353SAdam Hornáček      */
getDataRootPath()358b5840353SAdam Hornáček     public String getDataRootPath() {
3594151dbf5SChris Fraire         return syncReadConfiguration(Configuration::getDataRoot);
360b5840353SAdam Hornáček     }
361b5840353SAdam Hornáček 
362b5840353SAdam Hornáček     /**
363ff44f24aSAdam Hornáček      * Get a file representing the index database.
364b5840353SAdam Hornáček      *
365b5840353SAdam Hornáček      * @return the index database
366b5840353SAdam Hornáček      */
getDataRootFile()367b5840353SAdam Hornáček     public File getDataRootFile() {
368b5840353SAdam Hornáček         File ret = null;
369b5840353SAdam Hornáček         String file = getDataRootPath();
370b5840353SAdam Hornáček         if (file != null) {
371b5840353SAdam Hornáček             ret = new File(file);
372b5840353SAdam Hornáček         }
373b5840353SAdam Hornáček 
374b5840353SAdam Hornáček         return ret;
375b5840353SAdam Hornáček     }
376b5840353SAdam Hornáček 
377b5840353SAdam Hornáček     /**
378ff44f24aSAdam Hornáček      * Set the path to where the index database is stored.
379b5840353SAdam Hornáček      *
380b5840353SAdam Hornáček      * @param dataRoot the index database
381b5840353SAdam Hornáček      */
setDataRoot(String dataRoot)382b5840353SAdam Hornáček     public void setDataRoot(String dataRoot) {
383754ebdfbSChris Fraire         syncWriteConfiguration(getCanonicalPath(dataRoot), Configuration::setDataRoot);
384b5840353SAdam Hornáček     }
385b5840353SAdam Hornáček 
386b5840353SAdam Hornáček     /**
387ff44f24aSAdam Hornáček      * Get the path to where the sources are located.
388b5840353SAdam Hornáček      *
389b5840353SAdam Hornáček      * @return path to where the sources are located
390b5840353SAdam Hornáček      */
getSourceRootPath()391b5840353SAdam Hornáček     public String getSourceRootPath() {
3924151dbf5SChris Fraire         return syncReadConfiguration(Configuration::getSourceRoot);
393b5840353SAdam Hornáček     }
394b5840353SAdam Hornáček 
395b5840353SAdam Hornáček     /**
396ff44f24aSAdam Hornáček      * Get a file representing the directory where the sources are located.
397b5840353SAdam Hornáček      *
398b5840353SAdam Hornáček      * @return A file representing the directory where the sources are located
399b5840353SAdam Hornáček      */
getSourceRootFile()400b5840353SAdam Hornáček     public File getSourceRootFile() {
401b5840353SAdam Hornáček         File ret = null;
402b5840353SAdam Hornáček         String file = getSourceRootPath();
403b5840353SAdam Hornáček         if (file != null) {
404b5840353SAdam Hornáček             ret = new File(file);
405b5840353SAdam Hornáček         }
406b5840353SAdam Hornáček 
407b5840353SAdam Hornáček         return ret;
408b5840353SAdam Hornáček     }
409b5840353SAdam Hornáček 
410b5840353SAdam Hornáček     /**
411ff44f24aSAdam Hornáček      * Specify the source root.
412b5840353SAdam Hornáček      *
413b5840353SAdam Hornáček      * @param sourceRoot the location of the sources
414b5840353SAdam Hornáček      */
setSourceRoot(String sourceRoot)415b5840353SAdam Hornáček     public void setSourceRoot(String sourceRoot) {
416754ebdfbSChris Fraire         syncWriteConfiguration(getCanonicalPath(sourceRoot), Configuration::setSourceRoot);
417b5840353SAdam Hornáček     }
418b5840353SAdam Hornáček 
419b5840353SAdam Hornáček     /**
420b5840353SAdam Hornáček      * Returns a path relative to source root. This would just be a simple
421b5840353SAdam Hornáček      * substring operation, except we need to support symlinks outside the
422b5840353SAdam Hornáček      * source root.
423b5840353SAdam Hornáček      *
424b5840353SAdam Hornáček      * @param file A file to resolve
425b5840353SAdam Hornáček      * @return Path relative to source root
426b5840353SAdam Hornáček      * @throws IOException If an IO error occurs
427b5840353SAdam Hornáček      * @throws FileNotFoundException if the file is not relative to source root
4282738be5eSChris Fraire      * or if {@code sourceRoot} is not defined
429b5840353SAdam Hornáček      * @throws ForbiddenSymlinkException if symbolic-link checking encounters
430b5840353SAdam Hornáček      * an ineligible link
431b5840353SAdam Hornáček      */
getPathRelativeToSourceRoot(File file)432b5840353SAdam Hornáček     public String getPathRelativeToSourceRoot(File file)
433b5840353SAdam Hornáček             throws IOException, ForbiddenSymlinkException {
4342738be5eSChris Fraire         String sourceRoot = getSourceRootPath();
4352738be5eSChris Fraire         if (sourceRoot == null) {
4362738be5eSChris Fraire             throw new FileNotFoundException("sourceRoot is not defined");
4372738be5eSChris Fraire         }
4382738be5eSChris Fraire 
4396d9d3df9SAnatoly Akkerman         String maybeRelPath = PathUtils.getRelativeToCanonical(file.toPath(),
4406d9d3df9SAnatoly Akkerman                 Paths.get(sourceRoot), getAllowedSymlinks(), getCanonicalRoots());
4412738be5eSChris Fraire         File maybeRelFile = new File(maybeRelPath);
4422738be5eSChris Fraire         if (!maybeRelFile.isAbsolute()) {
4432738be5eSChris Fraire             /*
4442738be5eSChris Fraire              * N.b. OpenGrok has a weird convention that source-root "relative"
4452738be5eSChris Fraire              * paths must start with a '/' as they are elsewhere directly
4462738be5eSChris Fraire              * appended to getSourceRootPath() and also stored as such.
4472738be5eSChris Fraire              */
4482738be5eSChris Fraire             maybeRelPath = File.separator + maybeRelPath;
4492738be5eSChris Fraire             return maybeRelPath;
4502738be5eSChris Fraire         }
4512738be5eSChris Fraire 
4522738be5eSChris Fraire         throw new FileNotFoundException("Failed to resolve [" + file.getPath()
4532738be5eSChris Fraire                 + "] relative to source root [" + sourceRoot + "]");
454b5840353SAdam Hornáček     }
455b5840353SAdam Hornáček 
456b5840353SAdam Hornáček     /**
457b5840353SAdam Hornáček      * Do we have any projects ?
458b5840353SAdam Hornáček      *
459b5840353SAdam Hornáček      * @return true if we have projects
460b5840353SAdam Hornáček      */
hasProjects()461b5840353SAdam Hornáček     public boolean hasProjects() {
462b5840353SAdam Hornáček         return (this.isProjectsEnabled() && getProjects().size() > 0);
463b5840353SAdam Hornáček     }
464b5840353SAdam Hornáček 
465b5840353SAdam Hornáček     /**
466b5840353SAdam Hornáček      * Get list of projects.
467b5840353SAdam Hornáček      *
468fa055da0SVladimir Kotal      * @return a list containing all the projects
469b5840353SAdam Hornáček      */
getProjectList()470b5840353SAdam Hornáček     public List<Project> getProjectList() {
4712ffbb0cfSVladimir Kotal         return new ArrayList<>(getProjects().values());
472b5840353SAdam Hornáček     }
473b5840353SAdam Hornáček 
474b5840353SAdam Hornáček     /**
475b5840353SAdam Hornáček      * Get project map.
476b5840353SAdam Hornáček      *
4777e740a87SVladimir Kotal      * @return a Map with all the projects
478b5840353SAdam Hornáček      */
getProjects()479b5840353SAdam Hornáček     public Map<String, Project> getProjects() {
4804151dbf5SChris Fraire         return syncReadConfiguration(Configuration::getProjects);
481b5840353SAdam Hornáček     }
482b5840353SAdam Hornáček 
483b5840353SAdam Hornáček     /**
484b5840353SAdam Hornáček      * Get names of all projects.
485b5840353SAdam Hornáček      *
486b5840353SAdam Hornáček      * @return a list containing names of all projects.
487b5840353SAdam Hornáček      */
getProjectNames()488b5840353SAdam Hornáček     public List<String> getProjectNames() {
4892ffbb0cfSVladimir Kotal         return getProjectList().stream().map(Project::getName).collect(Collectors.toList());
490b5840353SAdam Hornáček     }
491b5840353SAdam Hornáček 
492b5840353SAdam Hornáček     /**
493ff44f24aSAdam Hornáček      * Set the list of the projects.
494b5840353SAdam Hornáček      *
495b5840353SAdam Hornáček      * @param projects the map of projects to use
496b5840353SAdam Hornáček      */
setProjects(Map<String, Project> projects)497b5840353SAdam Hornáček     public void setProjects(Map<String, Project> projects) {
498754ebdfbSChris Fraire         syncWriteConfiguration(projects, (c, p) -> {
4994151dbf5SChris Fraire             if (p != null) {
5004151dbf5SChris Fraire                 populateGroups(getGroups(), new TreeSet<>(p.values()));
501b5840353SAdam Hornáček             }
5024151dbf5SChris Fraire             c.setProjects(p);
503754ebdfbSChris Fraire         });
504b5840353SAdam Hornáček     }
505b5840353SAdam Hornáček 
506b5840353SAdam Hornáček     /**
507b5840353SAdam Hornáček      * Do we have groups?
508b5840353SAdam Hornáček      *
509b5840353SAdam Hornáček      * @return true if we have groups
510b5840353SAdam Hornáček      */
hasGroups()511b5840353SAdam Hornáček     public boolean hasGroups() {
512b5840353SAdam Hornáček         return (getGroups() != null && !getGroups().isEmpty());
513b5840353SAdam Hornáček     }
514b5840353SAdam Hornáček 
515b5840353SAdam Hornáček     /**
516ff44f24aSAdam Hornáček      * Get all of the groups.
517b5840353SAdam Hornáček      *
518b5840353SAdam Hornáček      * @return a set containing all of the groups (may be null)
519b5840353SAdam Hornáček      */
getGroups()520b5840353SAdam Hornáček     public Set<Group> getGroups() {
5214151dbf5SChris Fraire         return syncReadConfiguration(Configuration::getGroups);
522b5840353SAdam Hornáček     }
523b5840353SAdam Hornáček 
524b5840353SAdam Hornáček     /**
525ff44f24aSAdam Hornáček      * Set the list of the groups.
526b5840353SAdam Hornáček      *
527b5840353SAdam Hornáček      * @param groups the set of groups to use
528b5840353SAdam Hornáček      */
setGroups(Set<Group> groups)529b5840353SAdam Hornáček     public void setGroups(Set<Group> groups) {
530754ebdfbSChris Fraire         syncWriteConfiguration(groups, (c, g) -> {
5314151dbf5SChris Fraire             populateGroups(g, new TreeSet<>(getProjects().values()));
5324151dbf5SChris Fraire             c.setGroups(g);
533754ebdfbSChris Fraire         });
534b5840353SAdam Hornáček     }
535b5840353SAdam Hornáček 
536b5840353SAdam Hornáček     /**
537b5840353SAdam Hornáček      * Returns constructed project - repositories map.
538b5840353SAdam Hornáček      *
539b5840353SAdam Hornáček      * @return the map
540b5840353SAdam Hornáček      * @see #generateProjectRepositoriesMap
541b5840353SAdam Hornáček      */
getProjectRepositoriesMap()542b5840353SAdam Hornáček     public Map<Project, List<RepositoryInfo>> getProjectRepositoriesMap() {
543b5840353SAdam Hornáček         return repository_map;
544b5840353SAdam Hornáček     }
545b5840353SAdam Hornáček 
546b5840353SAdam Hornáček     /**
547b5840353SAdam Hornáček      * Gets a static placeholder for the web application context name that is
548b5840353SAdam Hornáček      * translated to the true servlet {@code contextPath} on demand.
549b5840353SAdam Hornáček      * @return {@code "/source"} + {@link Prefix#SEARCH_R} + {@code "?"}
550b5840353SAdam Hornáček      */
getUrlPrefix()551b5840353SAdam Hornáček     public String getUrlPrefix() {
552b5840353SAdam Hornáček         return URL_PREFIX;
553b5840353SAdam Hornáček     }
554b5840353SAdam Hornáček 
555b5840353SAdam Hornáček     /**
556b5840353SAdam Hornáček      * Gets the name of the ctags program to use: either the last value passed
557b5840353SAdam Hornáček      * successfully to {@link #setCtags(java.lang.String)}, or
558b5840353SAdam Hornáček      * {@link Configuration#getCtags()}, or the system property for
5599805b761SAdam Hornáček      * {@code "org.opengrok.indexer.analysis.Ctags"}, or "ctags" as a
560b5840353SAdam Hornáček      * default.
561b5840353SAdam Hornáček      * @return a defined value
562b5840353SAdam Hornáček      */
getCtags()563b5840353SAdam Hornáček     public String getCtags() {
5644151dbf5SChris Fraire         if (ctags != null) {
5654151dbf5SChris Fraire             return ctags;
5664151dbf5SChris Fraire         }
5674151dbf5SChris Fraire 
5684151dbf5SChris Fraire         String value = syncReadConfiguration(Configuration::getCtags);
5694151dbf5SChris Fraire         return value != null ? value :
5702ffbb0cfSVladimir Kotal                 System.getProperty(CtagsUtil.SYSTEM_CTAGS_PROPERTY, "ctags");
571b5840353SAdam Hornáček     }
572b5840353SAdam Hornáček 
573b5840353SAdam Hornáček     /**
574b5840353SAdam Hornáček      * Sets the name of the ctags program to use, or resets to use the fallbacks
575b5840353SAdam Hornáček      * documented for {@link #getCtags()}.
576b5840353SAdam Hornáček      * <p>
577b5840353SAdam Hornáček      * N.b. the value is not mediated to {@link Configuration}.
578b5840353SAdam Hornáček      *
579b5840353SAdam Hornáček      * @param ctags a defined value or {@code null} to reset to use the
580b5840353SAdam Hornáček      * {@link Configuration#getCtags()} fallbacks
581b5840353SAdam Hornáček      * @see #getCtags()
582b5840353SAdam Hornáček      */
setCtags(String ctags)583b5840353SAdam Hornáček     public void setCtags(String ctags) {
584b5840353SAdam Hornáček         this.ctags = ctags;
585b5840353SAdam Hornáček     }
586b5840353SAdam Hornáček 
587b5840353SAdam Hornáček     /**
588b5840353SAdam Hornáček      * Gets the name of the mandoc program to use: either the last value passed
589b5840353SAdam Hornáček      * successfully to {@link #setMandoc(java.lang.String)}, or
590b5840353SAdam Hornáček      * {@link Configuration#getMandoc()}, or the system property for
5919805b761SAdam Hornáček      * {@code "org.opengrok.indexer.analysis.Mandoc"}, or {@code null} as a
592b5840353SAdam Hornáček      * default.
593b5840353SAdam Hornáček      * @return a defined instance or {@code null}
594b5840353SAdam Hornáček      */
getMandoc()595b5840353SAdam Hornáček     public String getMandoc() {
5964151dbf5SChris Fraire         if (mandoc != null) {
5974151dbf5SChris Fraire             return mandoc;
5984151dbf5SChris Fraire         }
5994151dbf5SChris Fraire 
6004151dbf5SChris Fraire         String value = syncReadConfiguration(Configuration::getMandoc);
6014151dbf5SChris Fraire         return value != null ? value :
6029805b761SAdam Hornáček                 System.getProperty("org.opengrok.indexer.analysis.Mandoc");
603b5840353SAdam Hornáček     }
604b5840353SAdam Hornáček 
605b5840353SAdam Hornáček     /**
606b5840353SAdam Hornáček      * Sets the name of the mandoc program to use, or resets to use the
607b5840353SAdam Hornáček      * fallbacks documented for {@link #getMandoc()}.
608b5840353SAdam Hornáček      * <p>
609b5840353SAdam Hornáček      * N.b. the value is not mediated to {@link Configuration}.
610b5840353SAdam Hornáček      *
611b5840353SAdam Hornáček      * @param value a defined value or {@code null} to reset to use the
612b5840353SAdam Hornáček      * {@link Configuration#getMandoc()} fallbacks
613b5840353SAdam Hornáček      * @see #getMandoc()
614b5840353SAdam Hornáček      */
setMandoc(String value)615b5840353SAdam Hornáček     public void setMandoc(String value) {
616b5840353SAdam Hornáček         this.mandoc = value;
617b5840353SAdam Hornáček     }
618b5840353SAdam Hornáček 
getCachePages()619b5840353SAdam Hornáček     public int getCachePages() {
6204151dbf5SChris Fraire         return syncReadConfiguration(Configuration::getCachePages);
621b5840353SAdam Hornáček     }
622b5840353SAdam Hornáček 
setCachePages(int cachePages)623b5840353SAdam Hornáček     public void setCachePages(int cachePages) {
624754ebdfbSChris Fraire         syncWriteConfiguration(cachePages, Configuration::setCachePages);
625b5840353SAdam Hornáček     }
626b5840353SAdam Hornáček 
getHitsPerPage()627b5840353SAdam Hornáček     public int getHitsPerPage() {
6284151dbf5SChris Fraire         return syncReadConfiguration(Configuration::getHitsPerPage);
629b5840353SAdam Hornáček     }
630b5840353SAdam Hornáček 
setHitsPerPage(int hitsPerPage)631b5840353SAdam Hornáček     public void setHitsPerPage(int hitsPerPage) {
632754ebdfbSChris Fraire         syncWriteConfiguration(hitsPerPage, Configuration::setHitsPerPage);
633b5840353SAdam Hornáček     }
634b5840353SAdam Hornáček 
635b5840353SAdam Hornáček     /**
6362a63f72dSVladimir Kotal      * Validate that there is a Universal ctags program.
637b5840353SAdam Hornáček      *
638b5840353SAdam Hornáček      * @return true if success, false otherwise
639b5840353SAdam Hornáček      */
validateUniversalCtags()6402a63f72dSVladimir Kotal     public boolean validateUniversalCtags() {
6412a63f72dSVladimir Kotal         if (ctagsFound == null) {
6429c92ca95SChris Fraire             String ctagsBinary = getCtags();
6434151dbf5SChris Fraire             try (ResourceLock resourceLock = configLock.writeLockAsResource()) {
6444151dbf5SChris Fraire                 //noinspection ConstantConditions to avoid warning of no reference to auto-closeable
6454151dbf5SChris Fraire                 assert resourceLock != null;
6469c92ca95SChris Fraire                 if (ctagsFound == null) {
6479c92ca95SChris Fraire                     ctagsFound = CtagsUtil.validate(ctagsBinary);
6489c92ca95SChris Fraire                     if (ctagsFound) {
6499c92ca95SChris Fraire                         List<String> languages = CtagsUtil.getLanguages(ctagsBinary);
6509c92ca95SChris Fraire                         if (languages != null) {
6519c92ca95SChris Fraire                             ctagsLanguages.addAll(languages);
6529c92ca95SChris Fraire                         }
6539c92ca95SChris Fraire                     }
6549c92ca95SChris Fraire                 }
655b5840353SAdam Hornáček             }
656b5840353SAdam Hornáček         }
6572a63f72dSVladimir Kotal         return ctagsFound;
658b5840353SAdam Hornáček     }
659b5840353SAdam Hornáček 
660b5840353SAdam Hornáček     /**
6619c92ca95SChris Fraire      * Gets the base set of supported Ctags languages.
6629c92ca95SChris Fraire      * @return a defined set which may be empty if
6639c92ca95SChris Fraire      * {@link #validateUniversalCtags()} has not yet been called or if the call
6649c92ca95SChris Fraire      * fails
6659c92ca95SChris Fraire      */
getCtagsLanguages()6669c92ca95SChris Fraire     public Set<String> getCtagsLanguages() {
6679c92ca95SChris Fraire         return Collections.unmodifiableSet(ctagsLanguages);
6689c92ca95SChris Fraire     }
6699c92ca95SChris Fraire 
6709c92ca95SChris Fraire     /**
671b5840353SAdam Hornáček      * Is history cache currently enabled?
672b5840353SAdam Hornáček      *
673b5840353SAdam Hornáček      * @return true if history cache is enabled
674b5840353SAdam Hornáček      */
useHistoryCache()675b5840353SAdam Hornáček     public boolean useHistoryCache() {
6764151dbf5SChris Fraire         return syncReadConfiguration(Configuration::isHistoryCache);
677b5840353SAdam Hornáček     }
678b5840353SAdam Hornáček 
679b5840353SAdam Hornáček     /**
680ff44f24aSAdam Hornáček      * Specify if we should use history cache or not.
681b5840353SAdam Hornáček      *
682b5840353SAdam Hornáček      * @param useHistoryCache set false if you do not want to use history cache
683b5840353SAdam Hornáček      */
setUseHistoryCache(boolean useHistoryCache)684b5840353SAdam Hornáček     public void setUseHistoryCache(boolean useHistoryCache) {
685754ebdfbSChris Fraire         syncWriteConfiguration(useHistoryCache, Configuration::setHistoryCache);
686b5840353SAdam Hornáček     }
687b5840353SAdam Hornáček 
688b5840353SAdam Hornáček     /**
689ff44f24aSAdam Hornáček      * Should we generate HTML or not during the indexing phase.
690b5840353SAdam Hornáček      *
691b5840353SAdam Hornáček      * @return true if HTML should be generated during the indexing phase
692b5840353SAdam Hornáček      */
isGenerateHtml()693b5840353SAdam Hornáček     public boolean isGenerateHtml() {
6944151dbf5SChris Fraire         return syncReadConfiguration(Configuration::isGenerateHtml);
695b5840353SAdam Hornáček     }
696b5840353SAdam Hornáček 
697b5840353SAdam Hornáček     /**
698ff44f24aSAdam Hornáček      * Specify if we should generate HTML or not during the indexing phase.
699b5840353SAdam Hornáček      *
700b5840353SAdam Hornáček      * @param generateHtml set this to true to pregenerate HTML
701b5840353SAdam Hornáček      */
setGenerateHtml(boolean generateHtml)702b5840353SAdam Hornáček     public void setGenerateHtml(boolean generateHtml) {
703754ebdfbSChris Fraire         syncWriteConfiguration(generateHtml, Configuration::setGenerateHtml);
704b5840353SAdam Hornáček     }
705b5840353SAdam Hornáček 
706b5840353SAdam Hornáček     /**
707ff44f24aSAdam Hornáček      * Set if we should compress the xref files or not.
708b5840353SAdam Hornáček      *
709b5840353SAdam Hornáček      * @param compressXref set to true if the generated html files should be
710b5840353SAdam Hornáček      * compressed
711b5840353SAdam Hornáček      */
setCompressXref(boolean compressXref)712b5840353SAdam Hornáček     public void setCompressXref(boolean compressXref) {
713754ebdfbSChris Fraire         syncWriteConfiguration(compressXref, Configuration::setCompressXref);
714b5840353SAdam Hornáček     }
715b5840353SAdam Hornáček 
716b5840353SAdam Hornáček     /**
717b5840353SAdam Hornáček      * Are we using compressed HTML files?
718b5840353SAdam Hornáček      *
719b5840353SAdam Hornáček      * @return {@code true} if the html-files should be compressed.
720b5840353SAdam Hornáček      */
isCompressXref()721b5840353SAdam Hornáček     public boolean isCompressXref() {
7224151dbf5SChris Fraire         return syncReadConfiguration(Configuration::isCompressXref);
723b5840353SAdam Hornáček     }
724b5840353SAdam Hornáček 
isQuickContextScan()725b5840353SAdam Hornáček     public boolean isQuickContextScan() {
7264151dbf5SChris Fraire         return syncReadConfiguration(Configuration::isQuickContextScan);
727b5840353SAdam Hornáček     }
728b5840353SAdam Hornáček 
setQuickContextScan(boolean quickContextScan)729b5840353SAdam Hornáček     public void setQuickContextScan(boolean quickContextScan) {
730754ebdfbSChris Fraire         syncWriteConfiguration(quickContextScan, Configuration::setQuickContextScan);
731b5840353SAdam Hornáček     }
732b5840353SAdam Hornáček 
getRepositories()733b5840353SAdam Hornáček     public List<RepositoryInfo> getRepositories() {
7344151dbf5SChris Fraire         return syncReadConfiguration(Configuration::getRepositories);
735b5840353SAdam Hornáček     }
736b5840353SAdam Hornáček 
737b5840353SAdam Hornáček     /**
738b5840353SAdam Hornáček      * Set the list of repositories.
739b5840353SAdam Hornáček      *
740b5840353SAdam Hornáček      * @param repositories the repositories to use
741b5840353SAdam Hornáček      */
setRepositories(List<RepositoryInfo> repositories)742b5840353SAdam Hornáček     public void setRepositories(List<RepositoryInfo> repositories) {
743754ebdfbSChris Fraire         syncWriteConfiguration(repositories, Configuration::setRepositories);
744b5840353SAdam Hornáček     }
745b5840353SAdam Hornáček 
removeRepositories()746b5840353SAdam Hornáček     public void removeRepositories() {
747754ebdfbSChris Fraire         syncWriteConfiguration(null, Configuration::setRepositories);
748b5840353SAdam Hornáček     }
749b5840353SAdam Hornáček 
750b5840353SAdam Hornáček     /**
751b5840353SAdam Hornáček      * Search through the directory for repositories and use the result to replace
752b5840353SAdam Hornáček      * the lists of repositories in both RuntimeEnvironment/Configuration and HistoryGuru.
753b5840353SAdam Hornáček      *
754937bd40dSVladimir Kotal      * @param dir the directories to start the search in
755b5840353SAdam Hornáček      */
setRepositories(String... dir)756937bd40dSVladimir Kotal     public void setRepositories(String... dir) {
757b5840353SAdam Hornáček         List<RepositoryInfo> repos = new ArrayList<>(HistoryGuru.getInstance().
75840669eceSChris Fraire                 addRepositories(Arrays.stream(dir).map(File::new).toArray(File[]::new)));
7594151dbf5SChris Fraire         setRepositories(repos);
760b5840353SAdam Hornáček     }
761b5840353SAdam Hornáček 
762b5840353SAdam Hornáček     /**
763b5840353SAdam Hornáček      * Add repositories to the list.
764b5840353SAdam Hornáček      * @param repositories list of repositories
765b5840353SAdam Hornáček      */
addRepositories(List<RepositoryInfo> repositories)766b5840353SAdam Hornáček     public void addRepositories(List<RepositoryInfo> repositories) {
767754ebdfbSChris Fraire         syncWriteConfiguration(repositories, Configuration::addRepositories);
768b5840353SAdam Hornáček     }
769b5840353SAdam Hornáček 
770b5840353SAdam Hornáček     /**
771369f83fbSVladimir Kotal      * Set the specified projects as default in the configuration.
772369f83fbSVladimir Kotal      * This method should be called only after projects were discovered and became part of the configuration,
773369f83fbSVladimir Kotal      * i.e. after {@link org.opengrok.indexer.index.Indexer#prepareIndexer} was called.
774369f83fbSVladimir Kotal      *
775369f83fbSVladimir Kotal      * @param defaultProjects The default project to use
776369f83fbSVladimir Kotal      * @see #setDefaultProjects
777369f83fbSVladimir Kotal      */
setDefaultProjectsFromNames(Set<String> defaultProjects)778369f83fbSVladimir Kotal     public void setDefaultProjectsFromNames(Set<String> defaultProjects) {
779369f83fbSVladimir Kotal         if (defaultProjects != null && !defaultProjects.isEmpty()) {
780369f83fbSVladimir Kotal             Set<Project> projects = new TreeSet<>();
781369f83fbSVladimir Kotal             for (String projectPath : defaultProjects) {
782369f83fbSVladimir Kotal                 if (projectPath.equals("__all__")) {
783369f83fbSVladimir Kotal                     projects.addAll(getProjects().values());
784369f83fbSVladimir Kotal                     break;
785369f83fbSVladimir Kotal                 }
786369f83fbSVladimir Kotal                 for (Project p : getProjectList()) {
787369f83fbSVladimir Kotal                     if (p.getPath().equals(Util.fixPathIfWindows(projectPath))) {
788369f83fbSVladimir Kotal                         projects.add(p);
789369f83fbSVladimir Kotal                         break;
790369f83fbSVladimir Kotal                     }
791369f83fbSVladimir Kotal                 }
792369f83fbSVladimir Kotal             }
793369f83fbSVladimir Kotal             if (!projects.isEmpty()) {
794369f83fbSVladimir Kotal                 setDefaultProjects(projects);
795369f83fbSVladimir Kotal             }
796369f83fbSVladimir Kotal         }
797369f83fbSVladimir Kotal     }
798369f83fbSVladimir Kotal 
799369f83fbSVladimir Kotal     /**
800b5840353SAdam Hornáček      * Set the projects that are specified to be the default projects to use.
801b5840353SAdam Hornáček      * The default projects are the projects you will search (from the web
802b5840353SAdam Hornáček      * application) if the page request didn't contain the cookie..
803b5840353SAdam Hornáček      *
8042ffbb0cfSVladimir Kotal      * @param defaultProjects The default project to use
805b5840353SAdam Hornáček      */
setDefaultProjects(Set<Project> defaultProjects)8062ffbb0cfSVladimir Kotal     public void setDefaultProjects(Set<Project> defaultProjects) {
807754ebdfbSChris Fraire         syncWriteConfiguration(defaultProjects, Configuration::setDefaultProjects);
808b5840353SAdam Hornáček     }
809b5840353SAdam Hornáček 
810b5840353SAdam Hornáček     /**
811b5840353SAdam Hornáček      * Get the projects that are specified to be the default projects to use.
812b5840353SAdam Hornáček      * The default projects are the projects you will search (from the web
813b5840353SAdam Hornáček      * application) if the page request didn't contain the cookie..
814b5840353SAdam Hornáček      *
815b5840353SAdam Hornáček      * @return the default projects (may be null if not specified)
816b5840353SAdam Hornáček      */
getDefaultProjects()817b5840353SAdam Hornáček     public Set<Project> getDefaultProjects() {
8184151dbf5SChris Fraire         Set<Project> projects = syncReadConfiguration(Configuration::getDefaultProjects);
8192ffbb0cfSVladimir Kotal         if (projects == null) {
8202ffbb0cfSVladimir Kotal             return null;
8212ffbb0cfSVladimir Kotal         }
8222ffbb0cfSVladimir Kotal         return Collections.unmodifiableSet(projects);
823b5840353SAdam Hornáček     }
824b5840353SAdam Hornáček 
825b5840353SAdam Hornáček     /**
826b5840353SAdam Hornáček      *
827b5840353SAdam Hornáček      * @return at what size (in MB) we should flush the buffer
828b5840353SAdam Hornáček      */
getRamBufferSize()829b5840353SAdam Hornáček     public double getRamBufferSize() {
8304151dbf5SChris Fraire         return syncReadConfiguration(Configuration::getRamBufferSize);
831b5840353SAdam Hornáček     }
832b5840353SAdam Hornáček 
833b5840353SAdam Hornáček     /**
834b5840353SAdam Hornáček      * Set the size of buffer which will determine when the docs are flushed to
835b5840353SAdam Hornáček      * disk. Specify size in MB please. 16MB is default note that this is per
836b5840353SAdam Hornáček      * thread (lucene uses 8 threads by default in 4.x)
837b5840353SAdam Hornáček      *
838b5840353SAdam Hornáček      * @param ramBufferSize the size(in MB) when we should flush the docs
839b5840353SAdam Hornáček      */
setRamBufferSize(double ramBufferSize)840b5840353SAdam Hornáček     public void setRamBufferSize(double ramBufferSize) {
841754ebdfbSChris Fraire         syncWriteConfiguration(ramBufferSize, Configuration::setRamBufferSize);
842b5840353SAdam Hornáček     }
843b5840353SAdam Hornáček 
setPluginDirectory(String pluginDirectory)844b5840353SAdam Hornáček     public void setPluginDirectory(String pluginDirectory) {
845754ebdfbSChris Fraire         syncWriteConfiguration(pluginDirectory, Configuration::setPluginDirectory);
846b5840353SAdam Hornáček     }
847b5840353SAdam Hornáček 
getPluginDirectory()848b5840353SAdam Hornáček     public String getPluginDirectory() {
8494151dbf5SChris Fraire         return syncReadConfiguration(Configuration::getPluginDirectory);
850b5840353SAdam Hornáček     }
851b5840353SAdam Hornáček 
isAuthorizationWatchdog()852b5840353SAdam Hornáček     public boolean isAuthorizationWatchdog() {
8534151dbf5SChris Fraire         return syncReadConfiguration(Configuration::isAuthorizationWatchdogEnabled);
854b5840353SAdam Hornáček     }
855b5840353SAdam Hornáček 
setAuthorizationWatchdog(boolean authorizationWatchdogEnabled)856b5840353SAdam Hornáček     public void setAuthorizationWatchdog(boolean authorizationWatchdogEnabled) {
857754ebdfbSChris Fraire         syncWriteConfiguration(authorizationWatchdogEnabled,
858754ebdfbSChris Fraire                 Configuration::setAuthorizationWatchdogEnabled);
859b5840353SAdam Hornáček     }
860b5840353SAdam Hornáček 
getPluginStack()861b5840353SAdam Hornáček     public AuthorizationStack getPluginStack() {
8624151dbf5SChris Fraire         return syncReadConfiguration(Configuration::getPluginStack);
863b5840353SAdam Hornáček     }
864b5840353SAdam Hornáček 
setPluginStack(AuthorizationStack pluginStack)865b5840353SAdam Hornáček     public void setPluginStack(AuthorizationStack pluginStack) {
866754ebdfbSChris Fraire         syncWriteConfiguration(pluginStack, Configuration::setPluginStack);
867b5840353SAdam Hornáček     }
868b5840353SAdam Hornáček 
869b5840353SAdam Hornáček     /**
870b5840353SAdam Hornáček      * Is the progress print flag turned on?
871b5840353SAdam Hornáček      *
872b5840353SAdam Hornáček      * @return true if we can print per project progress %
873b5840353SAdam Hornáček      */
isPrintProgress()874b5840353SAdam Hornáček     public boolean isPrintProgress() {
8754151dbf5SChris Fraire         return syncReadConfiguration(Configuration::isPrintProgress);
876b5840353SAdam Hornáček     }
877b5840353SAdam Hornáček 
878b5840353SAdam Hornáček     /**
879ff44f24aSAdam Hornáček      * Set the printing of progress % flag (user convenience).
880b5840353SAdam Hornáček      *
8812ffbb0cfSVladimir Kotal      * @param printProgress new value
882b5840353SAdam Hornáček      */
setPrintProgress(boolean printProgress)8832ffbb0cfSVladimir Kotal     public void setPrintProgress(boolean printProgress) {
884754ebdfbSChris Fraire         syncWriteConfiguration(printProgress, Configuration::setPrintProgress);
885b5840353SAdam Hornáček     }
886b5840353SAdam Hornáček 
887b5840353SAdam Hornáček     /**
888b5840353SAdam Hornáček      * Specify if a search may start with a wildcard. Note that queries that
889b5840353SAdam Hornáček      * start with a wildcard will give a significant impact on the search
890b5840353SAdam Hornáček      * performance.
891b5840353SAdam Hornáček      *
892b5840353SAdam Hornáček      * @param allowLeadingWildcard set to true to activate (disabled by default)
893b5840353SAdam Hornáček      */
setAllowLeadingWildcard(boolean allowLeadingWildcard)894b5840353SAdam Hornáček     public void setAllowLeadingWildcard(boolean allowLeadingWildcard) {
895754ebdfbSChris Fraire         syncWriteConfiguration(allowLeadingWildcard, Configuration::setAllowLeadingWildcard);
896b5840353SAdam Hornáček     }
897b5840353SAdam Hornáček 
898b5840353SAdam Hornáček     /**
899b5840353SAdam Hornáček      * Is leading wildcards allowed?
900b5840353SAdam Hornáček      *
901b5840353SAdam Hornáček      * @return true if a search may start with a wildcard
902b5840353SAdam Hornáček      */
isAllowLeadingWildcard()903b5840353SAdam Hornáček     public boolean isAllowLeadingWildcard() {
9044151dbf5SChris Fraire         return syncReadConfiguration(Configuration::isAllowLeadingWildcard);
905b5840353SAdam Hornáček     }
906b5840353SAdam Hornáček 
getIgnoredNames()907b5840353SAdam Hornáček     public IgnoredNames getIgnoredNames() {
9084151dbf5SChris Fraire         return syncReadConfiguration(Configuration::getIgnoredNames);
909b5840353SAdam Hornáček     }
910b5840353SAdam Hornáček 
setIgnoredNames(IgnoredNames ignoredNames)911b5840353SAdam Hornáček     public void setIgnoredNames(IgnoredNames ignoredNames) {
912754ebdfbSChris Fraire         syncWriteConfiguration(ignoredNames, Configuration::setIgnoredNames);
913b5840353SAdam Hornáček     }
914b5840353SAdam Hornáček 
getIncludedNames()915b5840353SAdam Hornáček     public Filter getIncludedNames() {
9164151dbf5SChris Fraire         return syncReadConfiguration(Configuration::getIncludedNames);
917b5840353SAdam Hornáček     }
918b5840353SAdam Hornáček 
setIncludedNames(Filter includedNames)919b5840353SAdam Hornáček     public void setIncludedNames(Filter includedNames) {
920754ebdfbSChris Fraire         syncWriteConfiguration(includedNames, Configuration::setIncludedNames);
921b5840353SAdam Hornáček     }
922b5840353SAdam Hornáček 
923b5840353SAdam Hornáček     /**
924ff44f24aSAdam Hornáček      * Returns the user page for the history listing.
925b5840353SAdam Hornáček      *
926b5840353SAdam Hornáček      * @return the URL string fragment preceeding the username
927b5840353SAdam Hornáček      */
getUserPage()928b5840353SAdam Hornáček     public String getUserPage() {
9294151dbf5SChris Fraire         return syncReadConfiguration(Configuration::getUserPage);
930b5840353SAdam Hornáček     }
931b5840353SAdam Hornáček 
932b5840353SAdam Hornáček     /**
933b5840353SAdam Hornáček      * Get the client command to use to access the repository for the given
934b5840353SAdam Hornáček      * fully qualified classname.
935b5840353SAdam Hornáček      *
936b5840353SAdam Hornáček      * @param clazzName name of the targeting class
937b5840353SAdam Hornáček      * @return {@code null} if not yet set, the client command otherwise.
938b5840353SAdam Hornáček      */
getRepoCmd(String clazzName)939b5840353SAdam Hornáček     public String getRepoCmd(String clazzName) {
9404151dbf5SChris Fraire         return syncReadConfiguration(c -> c.getRepoCmd(clazzName));
941b5840353SAdam Hornáček     }
942b5840353SAdam Hornáček 
943b5840353SAdam Hornáček     /**
944b5840353SAdam Hornáček      * Set the client command to use to access the repository for the given
945b5840353SAdam Hornáček      * fully qualified classname.
946b5840353SAdam Hornáček      *
947b5840353SAdam Hornáček      * @param clazzName name of the targeting class. If {@code null} this method
948b5840353SAdam Hornáček      * does nothing.
949b5840353SAdam Hornáček      * @param cmd the client command to use. If {@code null} the corresponding
950b5840353SAdam Hornáček      * entry for the given clazzName get removed.
951b5840353SAdam Hornáček      * @return the client command previously set, which might be {@code null}.
952b5840353SAdam Hornáček      */
setRepoCmd(String clazzName, String cmd)953b5840353SAdam Hornáček     public String setRepoCmd(String clazzName, String cmd) {
954754ebdfbSChris Fraire         syncWriteConfiguration(null, (c, ignored) -> c.setRepoCmd(clazzName, cmd));
9552ffbb0cfSVladimir Kotal         return cmd;
956b5840353SAdam Hornáček     }
957b5840353SAdam Hornáček 
setRepoCmds(Map<String, String> cmds)95829816c3bSChris Fraire     public void setRepoCmds(Map<String, String> cmds) {
959754ebdfbSChris Fraire         syncWriteConfiguration(cmds, Configuration::setCmds);
96029816c3bSChris Fraire     }
96129816c3bSChris Fraire 
962b5840353SAdam Hornáček     /**
963ff44f24aSAdam Hornáček      * Sets the user page for the history listing.
964b5840353SAdam Hornáček      *
965b5840353SAdam Hornáček      * @param userPage the URL fragment preceeding the username from history
966b5840353SAdam Hornáček      */
setUserPage(String userPage)967b5840353SAdam Hornáček     public void setUserPage(String userPage) {
968754ebdfbSChris Fraire         syncWriteConfiguration(userPage, Configuration::setUserPage);
969b5840353SAdam Hornáček     }
970b5840353SAdam Hornáček 
971b5840353SAdam Hornáček     /**
972ff44f24aSAdam Hornáček      * Returns the user page suffix for the history listing.
973b5840353SAdam Hornáček      *
974b5840353SAdam Hornáček      * @return the URL string fragment following the username
975b5840353SAdam Hornáček      */
getUserPageSuffix()976b5840353SAdam Hornáček     public String getUserPageSuffix() {
9774151dbf5SChris Fraire         return syncReadConfiguration(Configuration::getUserPageSuffix);
978b5840353SAdam Hornáček     }
979b5840353SAdam Hornáček 
980b5840353SAdam Hornáček     /**
981ff44f24aSAdam Hornáček      * Sets the user page suffix for the history listing.
982b5840353SAdam Hornáček      *
983b5840353SAdam Hornáček      * @param userPageSuffix the URL fragment following the username from
984b5840353SAdam Hornáček      * history
985b5840353SAdam Hornáček      */
setUserPageSuffix(String userPageSuffix)986b5840353SAdam Hornáček     public void setUserPageSuffix(String userPageSuffix) {
987754ebdfbSChris Fraire         syncWriteConfiguration(userPageSuffix, Configuration::setUserPageSuffix);
988b5840353SAdam Hornáček     }
989b5840353SAdam Hornáček 
990b5840353SAdam Hornáček     /**
991ff44f24aSAdam Hornáček      * Returns the bug page for the history listing.
992b5840353SAdam Hornáček      *
993b5840353SAdam Hornáček      * @return the URL string fragment preceeding the bug ID
994b5840353SAdam Hornáček      */
getBugPage()995b5840353SAdam Hornáček     public String getBugPage() {
9964151dbf5SChris Fraire         return syncReadConfiguration(Configuration::getBugPage);
997b5840353SAdam Hornáček     }
998b5840353SAdam Hornáček 
999b5840353SAdam Hornáček     /**
1000ff44f24aSAdam Hornáček      * Sets the bug page for the history listing.
1001b5840353SAdam Hornáček      *
1002b5840353SAdam Hornáček      * @param bugPage the URL fragment preceeding the bug ID
1003b5840353SAdam Hornáček      */
setBugPage(String bugPage)1004b5840353SAdam Hornáček     public void setBugPage(String bugPage) {
1005754ebdfbSChris Fraire         syncWriteConfiguration(bugPage, Configuration::setBugPage);
1006b5840353SAdam Hornáček     }
1007b5840353SAdam Hornáček 
1008b5840353SAdam Hornáček     /**
1009ff44f24aSAdam Hornáček      * Returns the bug regex for the history listing.
1010b5840353SAdam Hornáček      *
1011b5840353SAdam Hornáček      * @return the regex that is looked for in history comments
1012b5840353SAdam Hornáček      */
getBugPattern()1013b5840353SAdam Hornáček     public String getBugPattern() {
10144151dbf5SChris Fraire         return syncReadConfiguration(Configuration::getBugPattern);
1015b5840353SAdam Hornáček     }
1016b5840353SAdam Hornáček 
1017b5840353SAdam Hornáček     /**
1018ff44f24aSAdam Hornáček      * Sets the bug regex for the history listing.
1019b5840353SAdam Hornáček      *
1020b5840353SAdam Hornáček      * @param bugPattern the regex to search history comments
1021b5840353SAdam Hornáček      */
setBugPattern(String bugPattern)10224151dbf5SChris Fraire     public void setBugPattern(String bugPattern) {
1023754ebdfbSChris Fraire         syncWriteConfiguration(bugPattern, Configuration::setBugPattern);
1024b5840353SAdam Hornáček     }
1025b5840353SAdam Hornáček 
1026b5840353SAdam Hornáček     /**
1027ff44f24aSAdam Hornáček      * Returns the review(ARC) page for the history listing.
1028b5840353SAdam Hornáček      *
1029b5840353SAdam Hornáček      * @return the URL string fragment preceeding the review page ID
1030b5840353SAdam Hornáček      */
getReviewPage()1031b5840353SAdam Hornáček     public String getReviewPage() {
10324151dbf5SChris Fraire         return syncReadConfiguration(Configuration::getReviewPage);
1033b5840353SAdam Hornáček     }
1034b5840353SAdam Hornáček 
1035b5840353SAdam Hornáček     /**
1036ff44f24aSAdam Hornáček      * Sets the review(ARC) page for the history listing.
1037b5840353SAdam Hornáček      *
1038b5840353SAdam Hornáček      * @param reviewPage the URL fragment preceeding the review page ID
1039b5840353SAdam Hornáček      */
setReviewPage(String reviewPage)1040b5840353SAdam Hornáček     public void setReviewPage(String reviewPage) {
1041754ebdfbSChris Fraire         syncWriteConfiguration(reviewPage, Configuration::setReviewPage);
1042b5840353SAdam Hornáček     }
1043b5840353SAdam Hornáček 
1044b5840353SAdam Hornáček     /**
1045ff44f24aSAdam Hornáček      * Returns the review(ARC) regex for the history listing.
1046b5840353SAdam Hornáček      *
1047b5840353SAdam Hornáček      * @return the regex that is looked for in history comments
1048b5840353SAdam Hornáček      */
getReviewPattern()1049b5840353SAdam Hornáček     public String getReviewPattern() {
10504151dbf5SChris Fraire         return syncReadConfiguration(Configuration::getReviewPattern);
1051b5840353SAdam Hornáček     }
1052b5840353SAdam Hornáček 
1053b5840353SAdam Hornáček     /**
1054ff44f24aSAdam Hornáček      * Sets the review(ARC) regex for the history listing.
1055b5840353SAdam Hornáček      *
1056b5840353SAdam Hornáček      * @param reviewPattern the regex to search history comments
1057b5840353SAdam Hornáček      */
setReviewPattern(String reviewPattern)10584151dbf5SChris Fraire     public void setReviewPattern(String reviewPattern) {
1059754ebdfbSChris Fraire         syncWriteConfiguration(reviewPattern, Configuration::setReviewPattern);
1060b5840353SAdam Hornáček     }
1061b5840353SAdam Hornáček 
getWebappLAF()1062b5840353SAdam Hornáček     public String getWebappLAF() {
10634151dbf5SChris Fraire         return syncReadConfiguration(Configuration::getWebappLAF);
1064b5840353SAdam Hornáček     }
1065b5840353SAdam Hornáček 
setWebappLAF(String webappLAF)1066754ebdfbSChris Fraire     public void setWebappLAF(String webappLAF) {
1067754ebdfbSChris Fraire         syncWriteConfiguration(webappLAF, Configuration::setWebappLAF);
1068b5840353SAdam Hornáček     }
1069b5840353SAdam Hornáček 
1070e829566cSChris Fraire     /**
1071e829566cSChris Fraire      * Gets a value indicating if the web app should run ctags as necessary.
1072e829566cSChris Fraire      * @return the value of {@link Configuration#isWebappCtags()}
1073e829566cSChris Fraire      */
isWebappCtags()1074e829566cSChris Fraire     public boolean isWebappCtags() {
10754151dbf5SChris Fraire         return syncReadConfiguration(Configuration::isWebappCtags);
1076e829566cSChris Fraire     }
1077e829566cSChris Fraire 
getRemoteScmSupported()1078b5840353SAdam Hornáček     public Configuration.RemoteSCM getRemoteScmSupported() {
10794151dbf5SChris Fraire         return syncReadConfiguration(Configuration::getRemoteScmSupported);
1080b5840353SAdam Hornáček     }
1081b5840353SAdam Hornáček 
setRemoteScmSupported(Configuration.RemoteSCM remoteScmSupported)1082754ebdfbSChris Fraire     public void setRemoteScmSupported(Configuration.RemoteSCM remoteScmSupported) {
1083754ebdfbSChris Fraire         syncWriteConfiguration(remoteScmSupported, Configuration::setRemoteScmSupported);
1084b5840353SAdam Hornáček     }
1085b5840353SAdam Hornáček 
isOptimizeDatabase()1086b5840353SAdam Hornáček     public boolean isOptimizeDatabase() {
10874151dbf5SChris Fraire         return syncReadConfiguration(Configuration::isOptimizeDatabase);
1088b5840353SAdam Hornáček     }
1089b5840353SAdam Hornáček 
setOptimizeDatabase(boolean optimizeDatabase)1090b5840353SAdam Hornáček     public void setOptimizeDatabase(boolean optimizeDatabase) {
1091754ebdfbSChris Fraire         syncWriteConfiguration(optimizeDatabase, Configuration::setOptimizeDatabase);
1092b5840353SAdam Hornáček     }
1093b5840353SAdam Hornáček 
getLuceneLocking()1094b5840353SAdam Hornáček     public LuceneLockName getLuceneLocking() {
10954151dbf5SChris Fraire         return syncReadConfiguration(Configuration::getLuceneLocking);
1096b5840353SAdam Hornáček     }
1097b5840353SAdam Hornáček 
isIndexVersionedFilesOnly()1098b5840353SAdam Hornáček     public boolean isIndexVersionedFilesOnly() {
10994151dbf5SChris Fraire         return syncReadConfiguration(Configuration::isIndexVersionedFilesOnly);
1100b5840353SAdam Hornáček     }
1101b5840353SAdam Hornáček 
setIndexVersionedFilesOnly(boolean indexVersionedFilesOnly)1102b5840353SAdam Hornáček     public void setIndexVersionedFilesOnly(boolean indexVersionedFilesOnly) {
1103754ebdfbSChris Fraire         syncWriteConfiguration(indexVersionedFilesOnly, Configuration::setIndexVersionedFilesOnly);
1104b5840353SAdam Hornáček     }
1105b5840353SAdam Hornáček 
1106b5840353SAdam Hornáček     /**
1107b5840353SAdam Hornáček      * Gets the value of {@link Configuration#getIndexingParallelism()} -- or
1108b5840353SAdam Hornáček      * if zero, then as a default gets the number of available processors.
1109b5840353SAdam Hornáček      * @return a natural number &gt;= 1
1110b5840353SAdam Hornáček      */
getIndexingParallelism()1111b5840353SAdam Hornáček     public int getIndexingParallelism() {
11124151dbf5SChris Fraire         int parallelism = syncReadConfiguration(Configuration::getIndexingParallelism);
1113b5840353SAdam Hornáček         return parallelism < 1 ? Runtime.getRuntime().availableProcessors() :
1114b5840353SAdam Hornáček                 parallelism;
1115b5840353SAdam Hornáček     }
1116b5840353SAdam Hornáček 
1117b5840353SAdam Hornáček     /**
11182123e367SVladimir Kotal      * Gets the value of {@link Configuration#getRepositoryInvalidationParallelism()} -- or
11192123e367SVladimir Kotal      * if zero, then as a default gets the number of available processors halved.
11202123e367SVladimir Kotal      * @return a natural number &gt;= 1
11212123e367SVladimir Kotal      */
getRepositoryInvalidationParallelism()11222123e367SVladimir Kotal     public int getRepositoryInvalidationParallelism() {
11232123e367SVladimir Kotal         int parallelism = syncReadConfiguration(Configuration::getRepositoryInvalidationParallelism);
11242123e367SVladimir Kotal         return parallelism < 1 ? (Runtime.getRuntime().availableProcessors() / 2) : parallelism;
11252123e367SVladimir Kotal     }
11262123e367SVladimir Kotal 
11272123e367SVladimir Kotal     /**
1128b5840353SAdam Hornáček      * Gets the value of {@link Configuration#getHistoryParallelism()} -- or
1129b5840353SAdam Hornáček      * if zero, then as a default gets the number of available processors.
1130b5840353SAdam Hornáček      * @return a natural number &gt;= 1
1131b5840353SAdam Hornáček      */
getHistoryParallelism()1132b5840353SAdam Hornáček     public int getHistoryParallelism() {
11334151dbf5SChris Fraire         int parallelism = syncReadConfiguration(Configuration::getHistoryParallelism);
1134b5840353SAdam Hornáček         return parallelism < 1 ? Runtime.getRuntime().availableProcessors() :
1135b5840353SAdam Hornáček                 parallelism;
1136b5840353SAdam Hornáček     }
1137b5840353SAdam Hornáček 
1138b5840353SAdam Hornáček     /**
1139dc607a84SVladimir Kotal      * Gets the value of {@link Configuration#getHistoryFileParallelism()} -- or
1140b5840353SAdam Hornáček      * if zero, then as a default gets the number of available processors.
1141b5840353SAdam Hornáček      * @return a natural number &gt;= 1
1142b5840353SAdam Hornáček      */
getHistoryFileParallelism()1143dc607a84SVladimir Kotal     public int getHistoryFileParallelism() {
1144dc607a84SVladimir Kotal         int parallelism = syncReadConfiguration(Configuration::getHistoryFileParallelism);
1145b5840353SAdam Hornáček         return parallelism < 1 ? Runtime.getRuntime().availableProcessors() :
1146b5840353SAdam Hornáček                 parallelism;
1147b5840353SAdam Hornáček     }
1148b5840353SAdam Hornáček 
isTagsEnabled()1149b5840353SAdam Hornáček     public boolean isTagsEnabled() {
11504151dbf5SChris Fraire         return syncReadConfiguration(Configuration::isTagsEnabled);
1151b5840353SAdam Hornáček     }
1152b5840353SAdam Hornáček 
setTagsEnabled(boolean tagsEnabled)1153b5840353SAdam Hornáček     public void setTagsEnabled(boolean tagsEnabled) {
1154754ebdfbSChris Fraire         syncWriteConfiguration(tagsEnabled, Configuration::setTagsEnabled);
1155b5840353SAdam Hornáček     }
1156b5840353SAdam Hornáček 
isScopesEnabled()1157b5840353SAdam Hornáček     public boolean isScopesEnabled() {
11584151dbf5SChris Fraire         return syncReadConfiguration(Configuration::isScopesEnabled);
1159b5840353SAdam Hornáček     }
1160b5840353SAdam Hornáček 
setScopesEnabled(boolean scopesEnabled)1161b5840353SAdam Hornáček     public void setScopesEnabled(boolean scopesEnabled) {
1162754ebdfbSChris Fraire         syncWriteConfiguration(scopesEnabled, Configuration::setScopesEnabled);
1163b5840353SAdam Hornáček     }
1164b5840353SAdam Hornáček 
isProjectsEnabled()1165b5840353SAdam Hornáček     public boolean isProjectsEnabled() {
11664151dbf5SChris Fraire         return syncReadConfiguration(Configuration::isProjectsEnabled);
1167b5840353SAdam Hornáček     }
1168b5840353SAdam Hornáček 
setProjectsEnabled(boolean projectsEnabled)1169b5840353SAdam Hornáček     public void setProjectsEnabled(boolean projectsEnabled) {
1170754ebdfbSChris Fraire         syncWriteConfiguration(projectsEnabled, Configuration::setProjectsEnabled);
1171b5840353SAdam Hornáček     }
1172b5840353SAdam Hornáček 
isFoldingEnabled()1173b5840353SAdam Hornáček     public boolean isFoldingEnabled() {
11744151dbf5SChris Fraire         return syncReadConfiguration(Configuration::isFoldingEnabled);
1175b5840353SAdam Hornáček     }
1176b5840353SAdam Hornáček 
setFoldingEnabled(boolean foldingEnabled)1177b5840353SAdam Hornáček     public void setFoldingEnabled(boolean foldingEnabled) {
1178754ebdfbSChris Fraire         syncWriteConfiguration(foldingEnabled, Configuration::setFoldingEnabled);
1179b5840353SAdam Hornáček     }
1180b5840353SAdam Hornáček 
getDateForLastIndexRun()1181b5840353SAdam Hornáček     public Date getDateForLastIndexRun() {
1182b5840353SAdam Hornáček         return indexTime.getDateForLastIndexRun();
1183b5840353SAdam Hornáček     }
1184b5840353SAdam Hornáček 
getCTagsExtraOptionsFile()1185b5840353SAdam Hornáček     public String getCTagsExtraOptionsFile() {
11864151dbf5SChris Fraire         return syncReadConfiguration(Configuration::getCTagsExtraOptionsFile);
1187b5840353SAdam Hornáček     }
1188b5840353SAdam Hornáček 
setCTagsExtraOptionsFile(String ctagsExtraOptionsFile)1189754ebdfbSChris Fraire     public void setCTagsExtraOptionsFile(String ctagsExtraOptionsFile) {
1190754ebdfbSChris Fraire         syncWriteConfiguration(ctagsExtraOptionsFile, Configuration::setCTagsExtraOptionsFile);
1191b5840353SAdam Hornáček     }
1192b5840353SAdam Hornáček 
getAllowedSymlinks()1193b5840353SAdam Hornáček     public Set<String> getAllowedSymlinks() {
11944151dbf5SChris Fraire         return syncReadConfiguration(Configuration::getAllowedSymlinks);
1195b5840353SAdam Hornáček     }
1196b5840353SAdam Hornáček 
setAllowedSymlinks(Set<String> allowedSymlinks)1197b5840353SAdam Hornáček     public void setAllowedSymlinks(Set<String> allowedSymlinks) {
1198754ebdfbSChris Fraire         syncWriteConfiguration(allowedSymlinks, Configuration::setAllowedSymlinks);
1199b5840353SAdam Hornáček     }
1200b5840353SAdam Hornáček 
getCanonicalRoots()12010e0ac58dSChris Fraire     public Set<String> getCanonicalRoots() {
12024151dbf5SChris Fraire         return syncReadConfiguration(Configuration::getCanonicalRoots);
12030e0ac58dSChris Fraire     }
12040e0ac58dSChris Fraire 
setCanonicalRoots(Set<String> canonicalRoots)12050e0ac58dSChris Fraire     public void setCanonicalRoots(Set<String> canonicalRoots) {
1206754ebdfbSChris Fraire         syncWriteConfiguration(canonicalRoots, Configuration::setCanonicalRoots);
12070e0ac58dSChris Fraire     }
12080e0ac58dSChris Fraire 
1209b5840353SAdam Hornáček     /**
1210b5840353SAdam Hornáček      * Return whether e-mail addresses should be obfuscated in the xref.
1211b5840353SAdam Hornáček      * @return if we obfuscate emails
1212b5840353SAdam Hornáček      */
isObfuscatingEMailAddresses()1213b5840353SAdam Hornáček     public boolean isObfuscatingEMailAddresses() {
12144151dbf5SChris Fraire         return syncReadConfiguration(Configuration::isObfuscatingEMailAddresses);
1215b5840353SAdam Hornáček     }
1216b5840353SAdam Hornáček 
1217b5840353SAdam Hornáček     /**
1218b5840353SAdam Hornáček      * Set whether e-mail addresses should be obfuscated in the xref.
1219754ebdfbSChris Fraire      * @param obfuscatingEMailAddresses should we obfuscate emails?
1220b5840353SAdam Hornáček      */
setObfuscatingEMailAddresses(boolean obfuscatingEMailAddresses)1221754ebdfbSChris Fraire     public void setObfuscatingEMailAddresses(boolean obfuscatingEMailAddresses) {
1222754ebdfbSChris Fraire         syncWriteConfiguration(obfuscatingEMailAddresses,
1223754ebdfbSChris Fraire                 Configuration::setObfuscatingEMailAddresses);
1224b5840353SAdam Hornáček     }
1225b5840353SAdam Hornáček 
1226b5840353SAdam Hornáček     /**
1227b5840353SAdam Hornáček      * Should status.jsp print internal settings, like paths and database URLs?
1228b5840353SAdam Hornáček      *
1229b5840353SAdam Hornáček      * @return {@code true} if status.jsp should show the configuration,
1230b5840353SAdam Hornáček      * {@code false} otherwise
1231b5840353SAdam Hornáček      */
isChattyStatusPage()1232b5840353SAdam Hornáček     public boolean isChattyStatusPage() {
12334151dbf5SChris Fraire         return syncReadConfiguration(Configuration::isChattyStatusPage);
1234b5840353SAdam Hornáček     }
1235b5840353SAdam Hornáček 
1236b5840353SAdam Hornáček     /**
1237b5840353SAdam Hornáček      * Set whether status.jsp should print internal settings.
1238b5840353SAdam Hornáček      *
1239754ebdfbSChris Fraire      * @param chattyStatusPage {@code true} if internal settings should be printed,
1240b5840353SAdam Hornáček      * {@code false} otherwise
1241b5840353SAdam Hornáček      */
setChattyStatusPage(boolean chattyStatusPage)1242754ebdfbSChris Fraire     public void setChattyStatusPage(boolean chattyStatusPage) {
1243754ebdfbSChris Fraire         syncWriteConfiguration(chattyStatusPage, Configuration::setChattyStatusPage);
1244b5840353SAdam Hornáček     }
1245b5840353SAdam Hornáček 
setFetchHistoryWhenNotInCache(boolean fetchHistoryWhenNotInCache)1246754ebdfbSChris Fraire     public void setFetchHistoryWhenNotInCache(boolean fetchHistoryWhenNotInCache) {
1247754ebdfbSChris Fraire         syncWriteConfiguration(fetchHistoryWhenNotInCache,
1248754ebdfbSChris Fraire                 Configuration::setFetchHistoryWhenNotInCache);
1249b5840353SAdam Hornáček     }
1250b5840353SAdam Hornáček 
isFetchHistoryWhenNotInCache()1251b5840353SAdam Hornáček     public boolean isFetchHistoryWhenNotInCache() {
12524151dbf5SChris Fraire         return syncReadConfiguration(Configuration::isFetchHistoryWhenNotInCache);
12532ffbb0cfSVladimir Kotal     }
12542ffbb0cfSVladimir Kotal 
isHistoryCache()12552ffbb0cfSVladimir Kotal     public boolean isHistoryCache() {
12564151dbf5SChris Fraire         return syncReadConfiguration(Configuration::isHistoryCache);
1257b5840353SAdam Hornáček     }
1258b5840353SAdam Hornáček 
setHandleHistoryOfRenamedFiles(boolean handleHistoryOfRenamedFiles)1259754ebdfbSChris Fraire     public void setHandleHistoryOfRenamedFiles(boolean handleHistoryOfRenamedFiles) {
1260754ebdfbSChris Fraire         syncWriteConfiguration(handleHistoryOfRenamedFiles,
1261754ebdfbSChris Fraire                 Configuration::setHandleHistoryOfRenamedFiles);
1262b5840353SAdam Hornáček     }
1263b5840353SAdam Hornáček 
isHandleHistoryOfRenamedFiles()1264b5840353SAdam Hornáček     public boolean isHandleHistoryOfRenamedFiles() {
12654151dbf5SChris Fraire         return syncReadConfiguration(Configuration::isHandleHistoryOfRenamedFiles);
1266b5840353SAdam Hornáček     }
1267b5840353SAdam Hornáček 
setMergeCommitsEnabled(boolean flag)12688e5e1036SVladimir Kotal     public void setMergeCommitsEnabled(boolean flag) {
12698e5e1036SVladimir Kotal         syncWriteConfiguration(flag, Configuration::setMergeCommitsEnabled);
12708e5e1036SVladimir Kotal     }
12718e5e1036SVladimir Kotal 
isMergeCommitsEnabled()12728e5e1036SVladimir Kotal     public boolean isMergeCommitsEnabled() {
12738e5e1036SVladimir Kotal         return syncReadConfiguration(Configuration::isMergeCommitsEnabled);
12748e5e1036SVladimir Kotal     }
12758e5e1036SVladimir Kotal 
setNavigateWindowEnabled(boolean navigateWindowEnabled)1276754ebdfbSChris Fraire     public void setNavigateWindowEnabled(boolean navigateWindowEnabled) {
1277754ebdfbSChris Fraire         syncWriteConfiguration(navigateWindowEnabled, Configuration::setNavigateWindowEnabled);
1278326dace0SVladimir Kotal     }
1279326dace0SVladimir Kotal 
isNavigateWindowEnabled()1280326dace0SVladimir Kotal     public boolean isNavigateWindowEnabled() {
12814151dbf5SChris Fraire         return syncReadConfiguration(Configuration::isNavigateWindowEnabled);
1282326dace0SVladimir Kotal     }
1283326dace0SVladimir Kotal 
setRevisionMessageCollapseThreshold(int revisionMessageCollapseThreshold)1284754ebdfbSChris Fraire     public void setRevisionMessageCollapseThreshold(int revisionMessageCollapseThreshold) {
1285754ebdfbSChris Fraire         syncWriteConfiguration(revisionMessageCollapseThreshold,
1286754ebdfbSChris Fraire                 Configuration::setRevisionMessageCollapseThreshold);
1287b5840353SAdam Hornáček     }
1288b5840353SAdam Hornáček 
getRevisionMessageCollapseThreshold()1289b5840353SAdam Hornáček     public int getRevisionMessageCollapseThreshold() {
12904151dbf5SChris Fraire         return syncReadConfiguration(Configuration::getRevisionMessageCollapseThreshold);
1291b5840353SAdam Hornáček     }
1292b5840353SAdam Hornáček 
setMaxSearchThreadCount(int maxSearchThreadCount)1293754ebdfbSChris Fraire     public void setMaxSearchThreadCount(int maxSearchThreadCount) {
1294754ebdfbSChris Fraire         syncWriteConfiguration(maxSearchThreadCount, Configuration::setMaxSearchThreadCount);
1295b5840353SAdam Hornáček     }
1296b5840353SAdam Hornáček 
getMaxSearchThreadCount()1297b5840353SAdam Hornáček     public int getMaxSearchThreadCount() {
12984151dbf5SChris Fraire         return syncReadConfiguration(Configuration::getMaxSearchThreadCount);
1299b5840353SAdam Hornáček     }
1300b5840353SAdam Hornáček 
setMaxRevisionThreadCount(int maxRevisionThreadCount)1301754ebdfbSChris Fraire     public void setMaxRevisionThreadCount(int maxRevisionThreadCount) {
1302754ebdfbSChris Fraire         syncWriteConfiguration(maxRevisionThreadCount, Configuration::setMaxRevisionThreadCount);
1303fb531549SVladimir Kotal     }
1304fb531549SVladimir Kotal 
getMaxRevisionThreadCount()1305fb531549SVladimir Kotal     public int getMaxRevisionThreadCount() {
13064151dbf5SChris Fraire         return syncReadConfiguration(Configuration::getMaxRevisionThreadCount);
1307fb531549SVladimir Kotal     }
1308fb531549SVladimir Kotal 
getCurrentIndexedCollapseThreshold()1309b5840353SAdam Hornáček     public int getCurrentIndexedCollapseThreshold() {
13104151dbf5SChris Fraire         return syncReadConfiguration(Configuration::getCurrentIndexedCollapseThreshold);
1311b5840353SAdam Hornáček     }
1312b5840353SAdam Hornáček 
setCurrentIndexedCollapseThreshold(int currentIndexedCollapseThreshold)1313b5840353SAdam Hornáček     public void setCurrentIndexedCollapseThreshold(int currentIndexedCollapseThreshold) {
1314754ebdfbSChris Fraire         syncWriteConfiguration(currentIndexedCollapseThreshold,
1315754ebdfbSChris Fraire                 Configuration::setCurrentIndexedCollapseThreshold);
1316b5840353SAdam Hornáček     }
1317b5840353SAdam Hornáček 
getGroupsCollapseThreshold()1318b5840353SAdam Hornáček     public int getGroupsCollapseThreshold() {
13194151dbf5SChris Fraire         return syncReadConfiguration(Configuration::getGroupsCollapseThreshold);
1320b5840353SAdam Hornáček     }
1321b5840353SAdam Hornáček 
132255402125SVladimir Kotal     // The URI is not necessary to be present in the configuration
1323b5840353SAdam Hornáček     // (so that when -U option of the indexer is omitted, the config will not
132455402125SVladimir Kotal     // be sent to the webapp) so store it only in the RuntimeEnvironment.
setConfigURI(String host)132555402125SVladimir Kotal     public void setConfigURI(String host) {
132655402125SVladimir Kotal         configURI = host;
1327b5840353SAdam Hornáček     }
1328b5840353SAdam Hornáček 
getConfigURI()132955402125SVladimir Kotal     public String getConfigURI() {
133055402125SVladimir Kotal         return configURI;
1331b5840353SAdam Hornáček     }
1332b5840353SAdam Hornáček 
isHistoryEnabled()1333b5840353SAdam Hornáček     public boolean isHistoryEnabled() {
13344151dbf5SChris Fraire         return syncReadConfiguration(Configuration::isHistoryEnabled);
1335b5840353SAdam Hornáček     }
1336b5840353SAdam Hornáček 
setHistoryEnabled(boolean historyEnabled)1337754ebdfbSChris Fraire     public void setHistoryEnabled(boolean historyEnabled) {
1338754ebdfbSChris Fraire         syncWriteConfiguration(historyEnabled, Configuration::setHistoryEnabled);
1339b5840353SAdam Hornáček     }
1340b5840353SAdam Hornáček 
isDisplayRepositories()1341ad8a45cdSVladimir Kotal     public boolean isDisplayRepositories() {
1342ad8a45cdSVladimir Kotal         return syncReadConfiguration(Configuration::isDisplayRepositories);
1343b5840353SAdam Hornáček     }
1344b5840353SAdam Hornáček 
setDisplayRepositories(boolean displayRepositories)1345754ebdfbSChris Fraire     public void setDisplayRepositories(boolean displayRepositories) {
1346754ebdfbSChris Fraire         syncWriteConfiguration(displayRepositories, Configuration::setDisplayRepositories);
1347b5840353SAdam Hornáček     }
1348b5840353SAdam Hornáček 
getListDirsFirst()1349b5840353SAdam Hornáček     public boolean getListDirsFirst() {
13504151dbf5SChris Fraire         return syncReadConfiguration(Configuration::getListDirsFirst);
1351b5840353SAdam Hornáček     }
1352b5840353SAdam Hornáček 
setListDirsFirst(boolean listDirsFirst)1353754ebdfbSChris Fraire     public void setListDirsFirst(boolean listDirsFirst) {
1354754ebdfbSChris Fraire         syncWriteConfiguration(listDirsFirst, Configuration::setListDirsFirst);
13552ffbb0cfSVladimir Kotal     }
13562ffbb0cfSVladimir Kotal 
setTabSize(int tabSize)1357754ebdfbSChris Fraire     public void setTabSize(int tabSize) {
1358754ebdfbSChris Fraire         syncWriteConfiguration(tabSize, Configuration::setTabSize);
13592ffbb0cfSVladimir Kotal     }
13602ffbb0cfSVladimir Kotal 
getTabSize()13612ffbb0cfSVladimir Kotal     public int getTabSize() {
13624151dbf5SChris Fraire         return syncReadConfiguration(Configuration::getTabSize);
1363b5840353SAdam Hornáček     }
1364b5840353SAdam Hornáček 
1365b5840353SAdam Hornáček     /**
1366ff44f24aSAdam Hornáček      * Gets the total number of context lines per file to show.
1367b5840353SAdam Hornáček      * @return a value greater than zero
1368b5840353SAdam Hornáček      */
getContextLimit()1369b5840353SAdam Hornáček     public short getContextLimit() {
13704151dbf5SChris Fraire         return syncReadConfiguration(Configuration::getContextLimit);
1371b5840353SAdam Hornáček     }
1372b5840353SAdam Hornáček 
1373b5840353SAdam Hornáček     /**
1374ff44f24aSAdam Hornáček      * Gets the number of context lines to show before or after any match.
1375b5840353SAdam Hornáček      * @return a value greater than or equal to zero
1376b5840353SAdam Hornáček      */
getContextSurround()1377b5840353SAdam Hornáček     public short getContextSurround() {
13784151dbf5SChris Fraire         return syncReadConfiguration(Configuration::getContextSurround);
1379b5840353SAdam Hornáček     }
1380b5840353SAdam Hornáček 
getHistoryChunkCount()1381a2f09795SVladimir Kotal     public int getHistoryChunkCount() {
1382a2f09795SVladimir Kotal         return syncReadConfiguration(Configuration::getHistoryChunkCount);
1383a2f09795SVladimir Kotal     }
1384a2f09795SVladimir Kotal 
setHistoryChunkCount(int chunkCount)1385a2f09795SVladimir Kotal     public void setHistoryChunkCount(int chunkCount) {
1386a2f09795SVladimir Kotal         syncWriteConfiguration(chunkCount, Configuration::setHistoryChunkCount);
1387a2f09795SVladimir Kotal     }
1388a2f09795SVladimir Kotal 
isHistoryCachePerPartesEnabled()13895a635a8eSVladimir Kotal     public boolean isHistoryCachePerPartesEnabled() {
13905a635a8eSVladimir Kotal         return syncReadConfiguration(Configuration::isHistoryCachePerPartesEnabled);
13915a635a8eSVladimir Kotal     }
13925a635a8eSVladimir Kotal 
setHistoryCachePerPartesEnabled(boolean enabled)13935a635a8eSVladimir Kotal     public void setHistoryCachePerPartesEnabled(boolean enabled) {
13945a635a8eSVladimir Kotal         syncWriteConfiguration(enabled, Configuration::setHistoryCachePerPartesEnabled);
13955a635a8eSVladimir Kotal     }
13965a635a8eSVladimir Kotal 
getDisabledRepositories()139729816c3bSChris Fraire     public Set<String> getDisabledRepositories() {
13984151dbf5SChris Fraire         return syncReadConfiguration(Configuration::getDisabledRepositories);
139929816c3bSChris Fraire     }
140029816c3bSChris Fraire 
setDisabledRepositories(Set<String> disabledRepositories)140129816c3bSChris Fraire     public void setDisabledRepositories(Set<String> disabledRepositories) {
1402754ebdfbSChris Fraire         syncWriteConfiguration(disabledRepositories, Configuration::setDisabledRepositories);
140329816c3bSChris Fraire     }
140429816c3bSChris Fraire 
getServerName()14050516dd21SVladimir Kotal     public String getServerName() {
14060516dd21SVladimir Kotal         return syncReadConfiguration(Configuration::getServerName);
14070516dd21SVladimir Kotal     }
14080516dd21SVladimir Kotal 
setServerName(String serverName)14090516dd21SVladimir Kotal     public void setServerName(String serverName) {
14100516dd21SVladimir Kotal         syncWriteConfiguration(serverName, Configuration::setServerName);
14110516dd21SVladimir Kotal     }
14120516dd21SVladimir Kotal 
getApiTimeout()14131c258122SVladimir Kotal     public int getApiTimeout() {
14141c258122SVladimir Kotal         return syncReadConfiguration(Configuration::getApiTimeout);
14151c258122SVladimir Kotal     }
14161c258122SVladimir Kotal 
setApiTimeout(int apiTimeout)14171c258122SVladimir Kotal     public void setApiTimeout(int apiTimeout) {
14181c258122SVladimir Kotal         syncWriteConfiguration(apiTimeout, Configuration::setApiTimeout);
14191c258122SVladimir Kotal     }
14201c258122SVladimir Kotal 
getConnectTimeout()14211c258122SVladimir Kotal     public int getConnectTimeout() {
14221c258122SVladimir Kotal         return syncReadConfiguration(Configuration::getConnectTimeout);
14231c258122SVladimir Kotal     }
14241c258122SVladimir Kotal 
setConnectTimeout(int connectTimeout)14251c258122SVladimir Kotal     public void setConnectTimeout(int connectTimeout) {
14261c258122SVladimir Kotal         syncWriteConfiguration(connectTimeout, Configuration::setConnectTimeout);
14271c258122SVladimir Kotal     }
14281c258122SVladimir Kotal 
isHistoryBasedReindex()1429f4571972SVladimir Kotal     public boolean isHistoryBasedReindex() {
1430f4571972SVladimir Kotal         return syncReadConfiguration(Configuration::isHistoryBasedReindex);
143112365fb4SVladimir Kotal     }
143212365fb4SVladimir Kotal 
setHistoryBasedReindex(boolean flag)1433f4571972SVladimir Kotal     public void setHistoryBasedReindex(boolean flag) {
1434f4571972SVladimir Kotal         syncWriteConfiguration(flag, Configuration::setHistoryBasedReindex);
143512365fb4SVladimir Kotal     }
143612365fb4SVladimir Kotal 
getFileCollector(String name)1437fadf9080SVladimir Kotal     public FileCollector getFileCollector(String name) {
1438fadf9080SVladimir Kotal         return fileCollectorMap.get(name);
1439fadf9080SVladimir Kotal     }
1440fadf9080SVladimir Kotal 
setFileCollector(String name, FileCollector fileCollector)1441fadf9080SVladimir Kotal     public void setFileCollector(String name, FileCollector fileCollector) {
1442fadf9080SVladimir Kotal         fileCollectorMap.put(name, fileCollector);
1443fadf9080SVladimir Kotal     }
1444fadf9080SVladimir Kotal 
1445*5650cf15SVladimir Kotal     @VisibleForTesting
clearFileCollector()1446*5650cf15SVladimir Kotal     public void clearFileCollector() {
1447*5650cf15SVladimir Kotal         fileCollectorMap.clear();
1448*5650cf15SVladimir Kotal     }
1449*5650cf15SVladimir Kotal 
1450b5840353SAdam Hornáček     /**
1451b5840353SAdam Hornáček      * Read an configuration file and set it as the current configuration.
1452b5840353SAdam Hornáček      *
1453b5840353SAdam Hornáček      * @param file the file to read
1454b5840353SAdam Hornáček      * @throws IOException if an error occurs
1455b5840353SAdam Hornáček      */
readConfiguration(File file)1456b5840353SAdam Hornáček     public void readConfiguration(File file) throws IOException {
14574151dbf5SChris Fraire         // The following method handles the locking.
1458b5840353SAdam Hornáček         setConfiguration(Configuration.read(file));
1459b5840353SAdam Hornáček     }
1460b5840353SAdam Hornáček 
1461b5840353SAdam Hornáček     /**
1462b5840353SAdam Hornáček      * Read configuration from a file and put it into effect.
1463b5840353SAdam Hornáček      * @param file the file to read
1464a904b83aSVladimir Kotal      * @param cmdType command timeout type
146581b586e6SVladimir Kotal      * @throws IOException I/O
1466b5840353SAdam Hornáček      */
readConfiguration(File file, CommandTimeoutType cmdType)1467a904b83aSVladimir Kotal     public void readConfiguration(File file, CommandTimeoutType cmdType) throws IOException {
14684151dbf5SChris Fraire         // The following method handles the locking.
1469a904b83aSVladimir Kotal         setConfiguration(Configuration.read(file), null, cmdType);
1470b5840353SAdam Hornáček     }
1471b5840353SAdam Hornáček 
1472b5840353SAdam Hornáček     /**
1473ff44f24aSAdam Hornáček      * Write the current configuration to a file.
1474b5840353SAdam Hornáček      *
1475b5840353SAdam Hornáček      * @param file the file to write the configuration into
1476b5840353SAdam Hornáček      * @throws IOException if an error occurs
1477b5840353SAdam Hornáček      */
writeConfiguration(File file)1478b5840353SAdam Hornáček     public void writeConfiguration(File file) throws IOException {
14794151dbf5SChris Fraire         try (ResourceLock resourceLock = configLock.readLockAsResource()) {
14804151dbf5SChris Fraire             //noinspection ConstantConditions to avoid warning of no reference to auto-closeable
14814151dbf5SChris Fraire             assert resourceLock != null;
14822ffbb0cfSVladimir Kotal             configuration.write(file);
14832ffbb0cfSVladimir Kotal         }
14842ffbb0cfSVladimir Kotal     }
14852ffbb0cfSVladimir Kotal 
getConfigurationXML()14862ffbb0cfSVladimir Kotal     public String getConfigurationXML() {
14874151dbf5SChris Fraire         return syncReadConfiguration(Configuration::getXMLRepresentationAsString);
1488b5840353SAdam Hornáček     }
1489b5840353SAdam Hornáček 
1490b5840353SAdam Hornáček     /**
14911c258122SVladimir Kotal      * Write the current configuration to a socket and waits for the result.
1492b5840353SAdam Hornáček      *
1493b5840353SAdam Hornáček      * @param host the host address to receive the configuration
1494b5840353SAdam Hornáček      * @throws IOException if an error occurs
1495b5840353SAdam Hornáček      */
writeConfiguration(String host)14961c258122SVladimir Kotal     public void writeConfiguration(String host) throws IOException, InterruptedException, IllegalArgumentException {
14974151dbf5SChris Fraire         String configXML = syncReadConfiguration(Configuration::getXMLRepresentationAsString);
14982ffbb0cfSVladimir Kotal 
14991c258122SVladimir Kotal         Response response = ClientBuilder.newClient()
15004ce4e2b9SAdam Hornáček                 .target(host)
15014ce4e2b9SAdam Hornáček                 .path("api")
15024ce4e2b9SAdam Hornáček                 .path("v1")
15034ce4e2b9SAdam Hornáček                 .path("configuration")
15044ce4e2b9SAdam Hornáček                 .queryParam("reindex", true)
15054ce4e2b9SAdam Hornáček                 .request()
1506f1e34e10SVladimir Kotal                 .headers(getWebAppHeaders())
15072ffbb0cfSVladimir Kotal                 .put(Entity.xml(configXML));
1508b5840353SAdam Hornáček 
15091c258122SVladimir Kotal         if (response.getStatus() == Response.Status.ACCEPTED.getStatusCode()) {
1510cce4eb5fSVladimir Kotal             response = ApiUtils.waitForAsyncApi(response);
15111c258122SVladimir Kotal         }
15121c258122SVladimir Kotal 
15131c258122SVladimir Kotal         if (response.getStatusInfo().getFamily() != Response.Status.Family.SUCCESSFUL) {
15141c258122SVladimir Kotal             throw new IOException(response.toString());
1515b5840353SAdam Hornáček         }
1516b5840353SAdam Hornáček     }
1517b5840353SAdam Hornáček 
1518b5840353SAdam Hornáček     /**
1519b5840353SAdam Hornáček      * Generate a TreeMap of projects with corresponding repository information.
15205f6ae75cSKryštof Tulinger      * <p>
1521b5840353SAdam Hornáček      * Project with some repository information is considered as a repository
1522b5840353SAdam Hornáček      * otherwise it is just a simple project.
1523b5840353SAdam Hornáček      */
152432b4cd63SVladimir Kotal     @VisibleForTesting
generateProjectRepositoriesMap()152532b4cd63SVladimir Kotal     public void generateProjectRepositoriesMap() throws IOException {
1526b5840353SAdam Hornáček         repository_map.clear();
1527b5840353SAdam Hornáček         for (RepositoryInfo r : getRepositories()) {
1528b5840353SAdam Hornáček             Project proj;
1529b5840353SAdam Hornáček             String repoPath;
1530b5840353SAdam Hornáček             try {
15312738be5eSChris Fraire                 repoPath = getPathRelativeToSourceRoot(new File(r.getDirectoryName()));
1532b5840353SAdam Hornáček             } catch (ForbiddenSymlinkException e) {
1533b5840353SAdam Hornáček                 LOGGER.log(Level.FINER, e.getMessage());
1534b5840353SAdam Hornáček                 continue;
1535b5840353SAdam Hornáček             }
1536b5840353SAdam Hornáček 
1537b5840353SAdam Hornáček             if ((proj = Project.getProject(repoPath)) != null) {
1538a72324b1SAdam Hornáček                 List<RepositoryInfo> values = repository_map.computeIfAbsent(proj, k -> new ArrayList<>());
153968830e6dSKryštof Tulinger                 // the map is held under the lock because the next call to
154068830e6dSKryštof Tulinger                 // values.add(r) which should not be called from multiple threads at the same time
1541b5840353SAdam Hornáček                 values.add(r);
1542b5840353SAdam Hornáček             }
1543b5840353SAdam Hornáček         }
1544b5840353SAdam Hornáček     }
1545b5840353SAdam Hornáček 
1546b5840353SAdam Hornáček     /**
1547b5840353SAdam Hornáček      * Classifies projects and puts them in their groups.
1548ba15b5bdSKryštof Tulinger      * <p>
1549ba15b5bdSKryštof Tulinger      * If any of the groups contain some projects or repositories already,
1550ba15b5bdSKryštof Tulinger      * these get discarded.
1551ba15b5bdSKryštof Tulinger      *
1552ba15b5bdSKryštof Tulinger      * @param groups   set of groups to be filled with matching projects
1553b5840353SAdam Hornáček      * @param projects projects to classify
1554b5840353SAdam Hornáček      */
populateGroups(Set<Group> groups, Set<Project> projects)1555b5840353SAdam Hornáček     public void populateGroups(Set<Group> groups, Set<Project> projects) {
1556b5840353SAdam Hornáček         if (projects == null || groups == null) {
1557b5840353SAdam Hornáček             return;
1558b5840353SAdam Hornáček         }
1559ba15b5bdSKryštof Tulinger 
1560ba15b5bdSKryštof Tulinger         // clear the groups first if they had something in them
1561ba15b5bdSKryštof Tulinger         for (Group group : groups) {
1562ba15b5bdSKryštof Tulinger             group.getRepositories().clear();
1563ba15b5bdSKryštof Tulinger             group.getProjects().clear();
1564ba15b5bdSKryštof Tulinger         }
1565ba15b5bdSKryštof Tulinger 
1566ba15b5bdSKryštof Tulinger         // now fill the groups with appropriate projects
1567b5840353SAdam Hornáček         for (Project project : projects) {
1568ba15b5bdSKryštof Tulinger             // clear the project's groups
1569ba15b5bdSKryštof Tulinger             project.getGroups().clear();
1570ba15b5bdSKryštof Tulinger 
1571ba15b5bdSKryštof Tulinger             // filter projects only to groups which match project's name
1572b5840353SAdam Hornáček             Set<Group> copy = Group.matching(project, groups);
1573b5840353SAdam Hornáček 
1574b5840353SAdam Hornáček             // add project to the groups
1575b5840353SAdam Hornáček             for (Group group : copy) {
1576b5840353SAdam Hornáček                 if (repository_map.get(project) == null) {
1577b5840353SAdam Hornáček                     group.addProject(project);
1578b5840353SAdam Hornáček                 } else {
1579b5840353SAdam Hornáček                     group.addRepository(project);
1580b5840353SAdam Hornáček                 }
1581b5840353SAdam Hornáček                 project.addGroup(group);
1582b5840353SAdam Hornáček             }
1583b5840353SAdam Hornáček         }
1584b5840353SAdam Hornáček     }
1585b5840353SAdam Hornáček 
1586b5840353SAdam Hornáček     /**
1587b5840353SAdam Hornáček      * Sets the configuration and performs necessary actions.
1588b5840353SAdam Hornáček      *
1589b5840353SAdam Hornáček      * Mainly it classifies the projects in their groups and generates project -
1590b5840353SAdam Hornáček      * repositories map
1591b5840353SAdam Hornáček      *
1592b5840353SAdam Hornáček      * @param configuration what configuration to use
1593b5840353SAdam Hornáček      */
setConfiguration(Configuration configuration)1594b5840353SAdam Hornáček     public void setConfiguration(Configuration configuration) {
1595a904b83aSVladimir Kotal         setConfiguration(configuration, null, CommandTimeoutType.INDEXER);
1596b5840353SAdam Hornáček     }
1597b5840353SAdam Hornáček 
1598b5840353SAdam Hornáček     /**
1599b5840353SAdam Hornáček      * Sets the configuration and performs necessary actions.
1600b5840353SAdam Hornáček      * @param configuration new configuration
1601a904b83aSVladimir Kotal      * @param cmdType command timeout type
1602b5840353SAdam Hornáček      */
setConfiguration(Configuration configuration, CommandTimeoutType cmdType)1603a904b83aSVladimir Kotal     public void setConfiguration(Configuration configuration, CommandTimeoutType cmdType) {
1604a904b83aSVladimir Kotal         setConfiguration(configuration, null, cmdType);
1605b5840353SAdam Hornáček     }
1606b5840353SAdam Hornáček 
1607b5840353SAdam Hornáček     /**
1608b5840353SAdam Hornáček      * Sets the configuration and performs necessary actions.
16095f6ae75cSKryštof Tulinger      *
1610b5840353SAdam Hornáček      * @param configuration new configuration
16111b935619SVladimir Kotal      * @param subFileList   collection of repositories
1612a904b83aSVladimir Kotal      * @param cmdType       command timeout type
1613b5840353SAdam Hornáček      */
setConfiguration(Configuration configuration, Collection<String> subFileList, CommandTimeoutType cmdType)16141b935619SVladimir Kotal     public synchronized void setConfiguration(Configuration configuration, Collection<String> subFileList, CommandTimeoutType cmdType) {
16154151dbf5SChris Fraire         try (ResourceLock resourceLock = configLock.writeLockAsResource()) {
16164151dbf5SChris Fraire             //noinspection ConstantConditions to avoid warning of no reference to auto-closeable
16174151dbf5SChris Fraire             assert resourceLock != null;
1618b5840353SAdam Hornáček             this.configuration = configuration;
16192ffbb0cfSVladimir Kotal         }
1620b5840353SAdam Hornáček 
16212ffbb0cfSVladimir Kotal         // HistoryGuru constructor needs environment properties so no locking is done here.
1622b5840353SAdam Hornáček         HistoryGuru histGuru = HistoryGuru.getInstance();
1623b5840353SAdam Hornáček 
16245f6ae75cSKryštof Tulinger         // Set the working repositories in HistoryGuru.
16255f6ae75cSKryštof Tulinger         if (subFileList != null) {
1626a904b83aSVladimir Kotal             histGuru.invalidateRepositories(getRepositories(), subFileList, cmdType);
16275f6ae75cSKryštof Tulinger         } else {
1628a904b83aSVladimir Kotal             histGuru.invalidateRepositories(getRepositories(), cmdType);
16295f6ae75cSKryštof Tulinger         }
16305f6ae75cSKryštof Tulinger 
16315f6ae75cSKryštof Tulinger         // The invalidation of repositories above might have excluded some
16325f6ae75cSKryštof Tulinger         // repositories in HistoryGuru so the configuration needs to reflect that.
16335f6ae75cSKryštof Tulinger         setRepositories(new ArrayList<>(histGuru.getRepositories()));
16345f6ae75cSKryštof Tulinger 
16355f6ae75cSKryštof Tulinger         // generate repository map is dependent on getRepositories()
1636b5840353SAdam Hornáček         try {
1637b5840353SAdam Hornáček             generateProjectRepositoriesMap();
1638b5840353SAdam Hornáček         } catch (IOException ex) {
1639b5840353SAdam Hornáček             LOGGER.log(Level.SEVERE, "Cannot generate project - repository map", ex);
1640b5840353SAdam Hornáček         }
1641b5840353SAdam Hornáček 
16425f6ae75cSKryštof Tulinger         // populate groups is dependent on repositories map
1643b5840353SAdam Hornáček         populateGroups(getGroups(), new TreeSet<>(getProjects().values()));
1644b5840353SAdam Hornáček 
16452ffbb0cfSVladimir Kotal         includeFiles.reloadIncludeFiles();
1646b5840353SAdam Hornáček     }
1647b5840353SAdam Hornáček 
getIncludeFiles()16482ffbb0cfSVladimir Kotal     public IncludeFiles getIncludeFiles() {
16492ffbb0cfSVladimir Kotal         return includeFiles;
1650b5840353SAdam Hornáček     }
1651b5840353SAdam Hornáček 
1652b5840353SAdam Hornáček     /**
1653b5840353SAdam Hornáček      * Return the authorization framework used in this environment.
1654b5840353SAdam Hornáček      *
1655b5840353SAdam Hornáček      * @return the framework
1656b5840353SAdam Hornáček      */
getAuthorizationFramework()16571cbb0597SVladimir Kotal     public AuthorizationFramework getAuthorizationFramework() {
16581cbb0597SVladimir Kotal         synchronized (authFrameworkLock) {
1659b5840353SAdam Hornáček             if (authFramework == null) {
1660b5840353SAdam Hornáček                 authFramework = new AuthorizationFramework(getPluginDirectory(), getPluginStack());
1661b5840353SAdam Hornáček             }
1662b5840353SAdam Hornáček             return authFramework;
1663b5840353SAdam Hornáček         }
16641cbb0597SVladimir Kotal     }
1665b5840353SAdam Hornáček 
1666b5840353SAdam Hornáček     /**
1667b5840353SAdam Hornáček      * Set the authorization framework for this environment. Unload all
1668b5840353SAdam Hornáček      * previously load plugins.
1669b5840353SAdam Hornáček      *
1670b5840353SAdam Hornáček      * @param fw the new framework
1671b5840353SAdam Hornáček      */
setAuthorizationFramework(AuthorizationFramework fw)16721cbb0597SVladimir Kotal     public void setAuthorizationFramework(AuthorizationFramework fw) {
16731cbb0597SVladimir Kotal         synchronized (authFrameworkLock) {
1674b5840353SAdam Hornáček            if (this.authFramework != null) {
1675b5840353SAdam Hornáček                 this.authFramework.removeAll();
1676b5840353SAdam Hornáček             }
1677b5840353SAdam Hornáček             this.authFramework = fw;
1678b5840353SAdam Hornáček         }
16791cbb0597SVladimir Kotal     }
1680b5840353SAdam Hornáček 
1681b5840353SAdam Hornáček     /**
16822ffbb0cfSVladimir Kotal      * Re-apply the configuration.
16832ffbb0cfSVladimir Kotal      * @param reindex is the message result of reindex
1684a904b83aSVladimir Kotal      * @param cmdType command timeout type
1685fa80b070SVladimir Kotal      * @see #applyConfig(org.opengrok.indexer.configuration.Configuration,
1686fa80b070SVladimir Kotal      * boolean, CommandTimeoutType) applyConfig(config, reindex, cmdType)
16872ffbb0cfSVladimir Kotal      */
applyConfig(boolean reindex, CommandTimeoutType cmdType)1688a904b83aSVladimir Kotal     public void applyConfig(boolean reindex, CommandTimeoutType cmdType) {
1689a904b83aSVladimir Kotal         applyConfig(configuration, reindex, cmdType);
16902ffbb0cfSVladimir Kotal     }
16912ffbb0cfSVladimir Kotal 
16922ffbb0cfSVladimir Kotal     /**
1693b5840353SAdam Hornáček      * Set configuration from a message. The message could have come from the
1694b5840353SAdam Hornáček      * Indexer (in which case some extra work is needed) or is it just a request
1695b5840353SAdam Hornáček      * to set new configuration in place.
1696b5840353SAdam Hornáček      *
16972ffbb0cfSVladimir Kotal      * @param configuration XML configuration
1698b5840353SAdam Hornáček      * @param reindex is the message result of reindex
1699a904b83aSVladimir Kotal      * @param cmdType command timeout type
17009805b761SAdam Hornáček      * @see #applyConfig(org.opengrok.indexer.configuration.Configuration,
1701a904b83aSVladimir Kotal      * boolean, CommandTimeoutType) applyConfig(config, reindex, cmdType)
1702b5840353SAdam Hornáček      */
applyConfig(String configuration, boolean reindex, CommandTimeoutType cmdType)1703a904b83aSVladimir Kotal     public void applyConfig(String configuration, boolean reindex, CommandTimeoutType cmdType) {
1704b5840353SAdam Hornáček         Configuration config;
1705b5840353SAdam Hornáček         try {
17064ce4e2b9SAdam Hornáček             config = makeXMLStringAsConfiguration(configuration);
1707b5840353SAdam Hornáček         } catch (IOException ex) {
1708b5840353SAdam Hornáček             LOGGER.log(Level.WARNING, "Configuration decoding failed", ex);
1709b5840353SAdam Hornáček             return;
1710b5840353SAdam Hornáček         }
1711b5840353SAdam Hornáček 
1712a904b83aSVladimir Kotal         applyConfig(config, reindex, cmdType);
1713b5840353SAdam Hornáček     }
1714b5840353SAdam Hornáček 
1715b5840353SAdam Hornáček     /**
1716b5840353SAdam Hornáček      * Set configuration from the incoming parameter. The configuration could
1717b5840353SAdam Hornáček      * have come from the Indexer (in which case some extra work is needed) or
1718b5840353SAdam Hornáček      * is it just a request to set new configuration in place.
1719b5840353SAdam Hornáček      *
1720fa80b070SVladimir Kotal      * The classes that have registered their listener will be pinged here.
1721fa80b070SVladimir Kotal      * @see ConfigurationChangedListener
1722fa80b070SVladimir Kotal      *
1723b5840353SAdam Hornáček      * @param config the incoming configuration
1724b5840353SAdam Hornáček      * @param reindex is the message result of reindex
1725a904b83aSVladimir Kotal      * @param cmdType command timeout type
1726b5840353SAdam Hornáček      */
applyConfig(Configuration config, boolean reindex, CommandTimeoutType cmdType)1727a904b83aSVladimir Kotal     public void applyConfig(Configuration config, boolean reindex, CommandTimeoutType cmdType) {
1728a904b83aSVladimir Kotal         setConfiguration(config, cmdType);
17292ffbb0cfSVladimir Kotal         LOGGER.log(Level.INFO, "Configuration updated");
1730b5840353SAdam Hornáček 
1731b5840353SAdam Hornáček         if (reindex) {
17322ffbb0cfSVladimir Kotal             // We are assuming that each update of configuration means reindex. If dedicated thread is introduced
17332ffbb0cfSVladimir Kotal             // in the future solely for the purpose of getting the event of reindex, the 2 calls below should
1734b5840353SAdam Hornáček             // be moved there.
1735b5840353SAdam Hornáček             refreshSearcherManagerMap();
1736b5840353SAdam Hornáček             maybeRefreshIndexSearchers();
1737b5840353SAdam Hornáček             // Force timestamp to update itself upon new config arrival.
1738b5840353SAdam Hornáček             refreshDateForLastIndexRun();
1739b5840353SAdam Hornáček         }
1740b5840353SAdam Hornáček 
17412ffbb0cfSVladimir Kotal         // start/stop the watchdog if necessary
17422ffbb0cfSVladimir Kotal         if (isAuthorizationWatchdog() && getPluginDirectory() != null) {
17432ffbb0cfSVladimir Kotal             watchDog.start(new File(getPluginDirectory()));
1744b5840353SAdam Hornáček         } else {
17452ffbb0cfSVladimir Kotal             watchDog.stop();
1746b5840353SAdam Hornáček         }
1747b5840353SAdam Hornáček 
1748b5840353SAdam Hornáček         // set the new plugin directory and reload the authorization framework
17492ffbb0cfSVladimir Kotal         getAuthorizationFramework().setPluginDirectory(getPluginDirectory());
17502ffbb0cfSVladimir Kotal         getAuthorizationFramework().setStack(getPluginStack());
1751b5840353SAdam Hornáček         getAuthorizationFramework().reload();
17524ce4e2b9SAdam Hornáček 
17532ffbb0cfSVladimir Kotal         messagesContainer.setMessageLimit(getMessageLimit());
1754e9a23d1eSAdam Hornáček 
1755e9a23d1eSAdam Hornáček         for (ConfigurationChangedListener l : listeners) {
1756e9a23d1eSAdam Hornáček             l.onConfigurationChanged();
1757e9a23d1eSAdam Hornáček         }
17586068c59cSVladimir Kotal 
17596068c59cSVladimir Kotal         LOGGER.log(Level.INFO, "Done applying configuration");
1760b5840353SAdam Hornáček     }
1761b5840353SAdam Hornáček 
setIndexTimestamp()1762b5840353SAdam Hornáček     public void setIndexTimestamp() throws IOException {
1763b5840353SAdam Hornáček         indexTime.stamp();
1764b5840353SAdam Hornáček     }
1765b5840353SAdam Hornáček 
refreshDateForLastIndexRun()1766b5840353SAdam Hornáček     public void refreshDateForLastIndexRun() {
1767b5840353SAdam Hornáček         indexTime.refreshDateForLastIndexRun();
1768b5840353SAdam Hornáček     }
1769b5840353SAdam Hornáček 
maybeRefreshSearcherManager(SearcherManager sm)1770b5840353SAdam Hornáček     private void maybeRefreshSearcherManager(SearcherManager sm) {
1771b5840353SAdam Hornáček         try {
1772b5840353SAdam Hornáček             sm.maybeRefresh();
1773b5840353SAdam Hornáček         }  catch (AlreadyClosedException ex) {
17742ffbb0cfSVladimir Kotal             // This is a case of removed project. See refreshSearcherManagerMap() for details.
1775b5840353SAdam Hornáček         } catch (IOException ex) {
1776b5840353SAdam Hornáček             LOGGER.log(Level.SEVERE, "maybeRefresh failed", ex);
1777b5840353SAdam Hornáček         }
1778b5840353SAdam Hornáček     }
1779b5840353SAdam Hornáček 
maybeRefreshIndexSearchers(Iterable<String> projects)17804ce4e2b9SAdam Hornáček     public void maybeRefreshIndexSearchers(Iterable<String> projects) {
1781b5840353SAdam Hornáček         for (String proj : projects) {
1782b5840353SAdam Hornáček             if (searcherManagerMap.containsKey(proj)) {
1783b5840353SAdam Hornáček                 maybeRefreshSearcherManager(searcherManagerMap.get(proj));
1784b5840353SAdam Hornáček             }
1785b5840353SAdam Hornáček         }
1786b5840353SAdam Hornáček     }
1787b5840353SAdam Hornáček 
maybeRefreshIndexSearchers()1788b5840353SAdam Hornáček     public void maybeRefreshIndexSearchers() {
17896068c59cSVladimir Kotal         LOGGER.log(Level.INFO, "refreshing searcher managers");
17906068c59cSVladimir Kotal         Statistics stat = new Statistics();
1791b5840353SAdam Hornáček         for (Map.Entry<String, SearcherManager> entry : searcherManagerMap.entrySet()) {
1792b5840353SAdam Hornáček             maybeRefreshSearcherManager(entry.getValue());
1793b5840353SAdam Hornáček         }
17946068c59cSVladimir Kotal         stat.report(LOGGER, "Done refreshing searcher managers");
1795b5840353SAdam Hornáček     }
1796b5840353SAdam Hornáček 
1797b5840353SAdam Hornáček     /**
1798b5840353SAdam Hornáček      * Get IndexSearcher for given project.
17992ffbb0cfSVladimir Kotal      * Each IndexSearcher is born from a SearcherManager object. There is one SearcherManager for every project.
18002ffbb0cfSVladimir Kotal      * This schema makes it possible to reuse IndexSearcher/IndexReader objects so the heavy lifting
18012ffbb0cfSVladimir Kotal      * (esp. system calls) performed in FSDirectory and DirectoryReader happens only once for a project.
1802b5840353SAdam Hornáček      * The caller has to make sure that the IndexSearcher is returned back
1803b5840353SAdam Hornáček      * to the SearcherManager. This is done with returnIndexSearcher().
18042ffbb0cfSVladimir Kotal      * The return of the IndexSearcher should happen only after the search result data are read fully.
1805b5840353SAdam Hornáček      *
1806f0df8b60SVladimir Kotal      * @param projectName project
1807b5840353SAdam Hornáček      * @return SearcherManager for given project
1808b5840353SAdam Hornáček      * @throws IOException I/O exception
1809b5840353SAdam Hornáček      */
1810523d6b7bSVladimir Kotal     @SuppressWarnings("java:S2095")
getIndexSearcher(String projectName)1811f0df8b60SVladimir Kotal     public SuperIndexSearcher getIndexSearcher(String projectName) throws IOException {
1812f0df8b60SVladimir Kotal         SearcherManager mgr = searcherManagerMap.get(projectName);
1813f0df8b60SVladimir Kotal         SuperIndexSearcher searcher;
1814b5840353SAdam Hornáček 
1815b5840353SAdam Hornáček         if (mgr == null) {
1816b5840353SAdam Hornáček             File indexDir = new File(getDataRootPath(), IndexDatabase.INDEX_DIR);
1817f0df8b60SVladimir Kotal             Directory dir = FSDirectory.open(new File(indexDir, projectName).toPath());
1818b5840353SAdam Hornáček             mgr = new SearcherManager(dir, new ThreadpoolSearcherFactory());
1819f0df8b60SVladimir Kotal             searcherManagerMap.put(projectName, mgr);
1820b5840353SAdam Hornáček         }
1821c6f0939bSAdam Hornacek         searcher = (SuperIndexSearcher) mgr.acquire();
1822c6f0939bSAdam Hornacek         searcher.setSearcherManager(mgr);
1823b5840353SAdam Hornáček 
1824b5840353SAdam Hornáček         return searcher;
1825b5840353SAdam Hornáček     }
1826b5840353SAdam Hornáček 
1827b5840353SAdam Hornáček     /**
1828b5840353SAdam Hornáček      * After new configuration is put into place, the set of projects might
1829b5840353SAdam Hornáček      * change so we go through the SearcherManager objects and close those where
1830b5840353SAdam Hornáček      * the corresponding project is no longer present.
1831b5840353SAdam Hornáček      */
refreshSearcherManagerMap()1832b5840353SAdam Hornáček     public void refreshSearcherManagerMap() {
1833b5840353SAdam Hornáček         ArrayList<String> toRemove = new ArrayList<>();
1834b5840353SAdam Hornáček 
1835b5840353SAdam Hornáček         for (Map.Entry<String, SearcherManager> entry : searcherManagerMap.entrySet()) {
1836b5840353SAdam Hornáček             // If a project is gone, close the corresponding SearcherManager
1837b5840353SAdam Hornáček             // so that it cannot produce new IndexSearcher objects.
1838b5840353SAdam Hornáček             if (!getProjectNames().contains(entry.getKey())) {
1839b5840353SAdam Hornáček                 try {
18406068c59cSVladimir Kotal                     LOGGER.log(Level.FINE, "closing SearcherManager for project {0}", entry.getKey());
1841b5840353SAdam Hornáček                     entry.getValue().close();
1842b5840353SAdam Hornáček                 } catch (IOException ex) {
1843b5840353SAdam Hornáček                     LOGGER.log(Level.SEVERE,
18446068c59cSVladimir Kotal                         String.format("cannot close SearcherManager for project %s", entry.getKey()), ex);
1845b5840353SAdam Hornáček                 }
1846b5840353SAdam Hornáček                 toRemove.add(entry.getKey());
1847b5840353SAdam Hornáček             }
1848b5840353SAdam Hornáček         }
1849b5840353SAdam Hornáček 
1850b5840353SAdam Hornáček         for (String proj : toRemove) {
1851b5840353SAdam Hornáček             searcherManagerMap.remove(proj);
1852b5840353SAdam Hornáček         }
1853b5840353SAdam Hornáček     }
1854b5840353SAdam Hornáček 
1855b5840353SAdam Hornáček     /**
1856b5840353SAdam Hornáček      * Return collection of IndexReader objects as MultiReader object
1857b5840353SAdam Hornáček      * for given list of projects.
1858b5840353SAdam Hornáček      * The caller is responsible for releasing the IndexSearcher objects
1859b5840353SAdam Hornáček      * so we add them to the map.
1860b5840353SAdam Hornáček      *
1861b5840353SAdam Hornáček      * @param projects list of projects
1862b5840353SAdam Hornáček      * @param searcherList each SuperIndexSearcher produced will be put into this list
1863b5840353SAdam Hornáček      * @return MultiReader for the projects
1864b5840353SAdam Hornáček      */
getMultiReader(SortedSet<String> projects, ArrayList<SuperIndexSearcher> searcherList)1865b5840353SAdam Hornáček     public MultiReader getMultiReader(SortedSet<String> projects,
1866b5840353SAdam Hornáček         ArrayList<SuperIndexSearcher> searcherList) {
1867b5840353SAdam Hornáček 
1868b5840353SAdam Hornáček         IndexReader[] subreaders = new IndexReader[projects.size()];
1869b5840353SAdam Hornáček         int ii = 0;
1870b5840353SAdam Hornáček 
18712ffbb0cfSVladimir Kotal         // TODO might need to rewrite to Project instead of String, need changes in projects.jspf too.
1872b5840353SAdam Hornáček         for (String proj : projects) {
1873b5840353SAdam Hornáček             try {
18744151dbf5SChris Fraire                 SuperIndexSearcher searcher = getIndexSearcher(proj);
1875b5840353SAdam Hornáček                 subreaders[ii++] = searcher.getIndexReader();
1876b5840353SAdam Hornáček                 searcherList.add(searcher);
1877a72324b1SAdam Hornáček             } catch (IOException | NullPointerException ex) {
1878b5840353SAdam Hornáček                 LOGGER.log(Level.SEVERE,
1879b5840353SAdam Hornáček                     "cannot get IndexReader for project " + proj, ex);
1880b5840353SAdam Hornáček                 return null;
1881b5840353SAdam Hornáček             }
1882b5840353SAdam Hornáček         }
1883b5840353SAdam Hornáček         MultiReader multiReader = null;
1884b5840353SAdam Hornáček         try {
1885b5840353SAdam Hornáček             multiReader = new MultiReader(subreaders, true);
1886b5840353SAdam Hornáček         } catch (IOException ex) {
1887b5840353SAdam Hornáček             LOGGER.log(Level.SEVERE,
1888b5840353SAdam Hornáček                 "cannot construct MultiReader for set of projects", ex);
1889b5840353SAdam Hornáček         }
1890b5840353SAdam Hornáček         return multiReader;
1891b5840353SAdam Hornáček     }
18924ce4e2b9SAdam Hornáček 
startExpirationTimer()18934ce4e2b9SAdam Hornáček     public void startExpirationTimer() {
18944151dbf5SChris Fraire         messagesContainer.setMessageLimit(getMessageLimit());
18954ce4e2b9SAdam Hornáček         messagesContainer.startExpirationTimer();
18964ce4e2b9SAdam Hornáček     }
18974ce4e2b9SAdam Hornáček 
stopExpirationTimer()18984ce4e2b9SAdam Hornáček     public void stopExpirationTimer() {
18994ce4e2b9SAdam Hornáček         messagesContainer.stopExpirationTimer();
19004ce4e2b9SAdam Hornáček     }
19014ce4e2b9SAdam Hornáček 
19024ce4e2b9SAdam Hornáček     /**
19034ce4e2b9SAdam Hornáček      * Get the default set of messages for the main tag.
19044ce4e2b9SAdam Hornáček      *
19054ce4e2b9SAdam Hornáček      * @return set of messages
19064ce4e2b9SAdam Hornáček      */
getMessages()19074ce4e2b9SAdam Hornáček     public SortedSet<AcceptedMessage> getMessages() {
19084ce4e2b9SAdam Hornáček         return messagesContainer.getMessages();
19094ce4e2b9SAdam Hornáček     }
19104ce4e2b9SAdam Hornáček 
19114ce4e2b9SAdam Hornáček     /**
1912ff44f24aSAdam Hornáček      * Get the set of messages for the arbitrary tag.
19134ce4e2b9SAdam Hornáček      *
19144ce4e2b9SAdam Hornáček      * @param tag the message tag
19154ce4e2b9SAdam Hornáček      * @return set of messages
19164ce4e2b9SAdam Hornáček      */
getMessages(final String tag)19174ce4e2b9SAdam Hornáček     public SortedSet<AcceptedMessage> getMessages(final String tag) {
19184ce4e2b9SAdam Hornáček         return messagesContainer.getMessages(tag);
19194ce4e2b9SAdam Hornáček     }
19204ce4e2b9SAdam Hornáček 
19214ce4e2b9SAdam Hornáček     /**
19224ce4e2b9SAdam Hornáček      * Add a message to the application.
19234ce4e2b9SAdam Hornáček      * Also schedules a expiration timer to remove this message after its expiration.
19244ce4e2b9SAdam Hornáček      *
19254ce4e2b9SAdam Hornáček      * @param message the message
19264ce4e2b9SAdam Hornáček      */
addMessage(final Message message)19274ce4e2b9SAdam Hornáček     public void addMessage(final Message message) {
19284ce4e2b9SAdam Hornáček         messagesContainer.addMessage(message);
19294ce4e2b9SAdam Hornáček     }
19304ce4e2b9SAdam Hornáček 
19314ce4e2b9SAdam Hornáček     /**
19324ce4e2b9SAdam Hornáček      * Remove all messages containing at least one of the tags.
19334ce4e2b9SAdam Hornáček      * @param tags set of tags
19341d0bbff4SVladimir Kotal      * @param text message text (can be null, empty)
19354ce4e2b9SAdam Hornáček      */
removeAnyMessage(final Set<String> tags, final String text)19361d0bbff4SVladimir Kotal     public void removeAnyMessage(final Set<String> tags, final String text) {
19371d0bbff4SVladimir Kotal         messagesContainer.removeAnyMessage(tags, text);
19384ce4e2b9SAdam Hornáček     }
19394ce4e2b9SAdam Hornáček 
19404ce4e2b9SAdam Hornáček     /**
19414ce4e2b9SAdam Hornáček      * @return all messages regardless their tag
19424ce4e2b9SAdam Hornáček      */
getAllMessages()19434ce4e2b9SAdam Hornáček     public Set<AcceptedMessage> getAllMessages() {
19444ce4e2b9SAdam Hornáček         return messagesContainer.getAllMessages();
19454ce4e2b9SAdam Hornáček     }
19464ce4e2b9SAdam Hornáček 
getDtagsEftarPath()19472ffbb0cfSVladimir Kotal     public Path getDtagsEftarPath() {
19484151dbf5SChris Fraire         return syncReadConfiguration(Configuration::getDtagsEftarPath);
19492ffbb0cfSVladimir Kotal     }
19502ffbb0cfSVladimir Kotal 
19512ffbb0cfSVladimir Kotal     /**
19522ffbb0cfSVladimir Kotal      * Get the eftar file, which contains definition tags for path descriptions.
19532ffbb0cfSVladimir Kotal      *
19542ffbb0cfSVladimir Kotal      * @return {@code null} if there is no such file, the file otherwise.
19552ffbb0cfSVladimir Kotal      */
getDtagsEftar()19562ffbb0cfSVladimir Kotal     public File getDtagsEftar() {
19572ffbb0cfSVladimir Kotal         if (dtagsEftar == null) {
19582ffbb0cfSVladimir Kotal             File tmp = getDtagsEftarPath().toFile();
19592ffbb0cfSVladimir Kotal             if (tmp.canRead()) {
19602ffbb0cfSVladimir Kotal                 dtagsEftar = tmp;
19612ffbb0cfSVladimir Kotal             }
19622ffbb0cfSVladimir Kotal         }
19632ffbb0cfSVladimir Kotal         return dtagsEftar;
19642ffbb0cfSVladimir Kotal     }
19652ffbb0cfSVladimir Kotal 
getSuggesterConfig()19662ffbb0cfSVladimir Kotal     public SuggesterConfig getSuggesterConfig() {
19674151dbf5SChris Fraire         return syncReadConfiguration(Configuration::getSuggesterConfig);
19682ffbb0cfSVladimir Kotal     }
19692ffbb0cfSVladimir Kotal 
setSuggesterConfig(SuggesterConfig suggesterConfig)1970754ebdfbSChris Fraire     public void setSuggesterConfig(SuggesterConfig suggesterConfig) {
1971754ebdfbSChris Fraire         syncWriteConfiguration(suggesterConfig, Configuration::setSuggesterConfig);
19722ffbb0cfSVladimir Kotal     }
19732ffbb0cfSVladimir Kotal 
getStatsdConfig()19740d7ace53SVladimir Kotal     public StatsdConfig getStatsdConfig() {
19750d7ace53SVladimir Kotal         return syncReadConfiguration(Configuration::getStatsdConfig);
19760d7ace53SVladimir Kotal     }
19770d7ace53SVladimir Kotal 
setStatsdConfig(StatsdConfig statsdConfig)19780d7ace53SVladimir Kotal     public void setStatsdConfig(StatsdConfig statsdConfig) {
19790d7ace53SVladimir Kotal         syncWriteConfiguration(statsdConfig, Configuration::setStatsdConfig);
19800d7ace53SVladimir Kotal     }
19810d7ace53SVladimir Kotal 
19824151dbf5SChris Fraire     /**
19834151dbf5SChris Fraire      * Applies the specified function to the runtime configuration, after having
19844151dbf5SChris Fraire      * obtained the configuration read-lock (and releasing afterward).
19854151dbf5SChris Fraire      * @param function a defined function
19864151dbf5SChris Fraire      * @param <R> the type of the result of the function
19874151dbf5SChris Fraire      * @return the function result
19884151dbf5SChris Fraire      */
syncReadConfiguration(Function<Configuration, R> function)19894151dbf5SChris Fraire     public <R> R syncReadConfiguration(Function<Configuration, R> function) {
19904151dbf5SChris Fraire         try (ResourceLock resourceLock = configLock.readLockAsResource()) {
1991754ebdfbSChris Fraire             //noinspection ConstantConditions to avoid warning of no reference to auto-closeable
19924151dbf5SChris Fraire             assert resourceLock != null;
19934151dbf5SChris Fraire             return function.apply(configuration);
19944151dbf5SChris Fraire         }
19954151dbf5SChris Fraire     }
19964151dbf5SChris Fraire 
19974151dbf5SChris Fraire     /**
19984151dbf5SChris Fraire      * Performs the specified operation which is provided the runtime
19994151dbf5SChris Fraire      * configuration and the specified argument, after first having obtained the
20004151dbf5SChris Fraire      * configuration write-lock (and releasing afterward).
20014151dbf5SChris Fraire      * @param <V> the type of the input to the operation
2002754ebdfbSChris Fraire      * @param v the input argument
2003754ebdfbSChris Fraire      * @param consumer a defined consumer
20044151dbf5SChris Fraire      */
syncWriteConfiguration(V v, ConfigurationValueConsumer<V> consumer)2005754ebdfbSChris Fraire     public <V> void syncWriteConfiguration(V v, ConfigurationValueConsumer<V> consumer) {
20064151dbf5SChris Fraire         try (ResourceLock resourceLock = configLock.writeLockAsResource()) {
2007754ebdfbSChris Fraire             //noinspection ConstantConditions to avoid warning of no reference to auto-closeable
20084151dbf5SChris Fraire             assert resourceLock != null;
20094151dbf5SChris Fraire             consumer.accept(configuration, v);
20104151dbf5SChris Fraire         }
20114151dbf5SChris Fraire     }
20124151dbf5SChris Fraire 
getMessageLimit()20134151dbf5SChris Fraire     private int getMessageLimit() {
20144151dbf5SChris Fraire         return syncReadConfiguration(Configuration::getMessageLimit);
2015ff44f24aSAdam Hornáček     }
2016814ddb49SVladimir Kotal 
getIndexerAuthenticationToken()20178d34347cSVladimir Kotal     public String getIndexerAuthenticationToken() {
20188d34347cSVladimir Kotal         return syncReadConfiguration(Configuration::getIndexerAuthenticationToken);
20198d34347cSVladimir Kotal     }
20208d34347cSVladimir Kotal 
setIndexerAuthenticationToken(String token)20218d34347cSVladimir Kotal     public void setIndexerAuthenticationToken(String token) {
20228d34347cSVladimir Kotal         syncWriteConfiguration(token, Configuration::setIndexerAuthenticationToken);
20238d34347cSVladimir Kotal     }
20248d34347cSVladimir Kotal 
getAuthenticationTokens()2025b0a23e73SVladimir Kotal     public Set<String> getAuthenticationTokens() {
2026c7dfd267SVladimir Kotal         return Collections.unmodifiableSet(syncReadConfiguration(Configuration::getAuthenticationTokens));
2027b0a23e73SVladimir Kotal     }
2028b0a23e73SVladimir Kotal 
setAuthenticationTokens(Set<String> tokens)2029b0a23e73SVladimir Kotal     public void setAuthenticationTokens(Set<String> tokens) {
2030b0a23e73SVladimir Kotal         syncWriteConfiguration(tokens, Configuration::setAuthenticationTokens);
2031814ddb49SVladimir Kotal     }
2032e9a23d1eSAdam Hornáček 
isAllowInsecureTokens()203360e45c9fSVladimir Kotal     public boolean isAllowInsecureTokens() {
203460e45c9fSVladimir Kotal         return syncReadConfiguration(Configuration::isAllowInsecureTokens);
203560e45c9fSVladimir Kotal     }
203660e45c9fSVladimir Kotal 
setAllowInsecureTokens(boolean value)203760e45c9fSVladimir Kotal     public void setAllowInsecureTokens(boolean value) {
203860e45c9fSVladimir Kotal         syncWriteConfiguration(value, Configuration::setAllowInsecureTokens);
203960e45c9fSVladimir Kotal     }
204060e45c9fSVladimir Kotal 
registerListener(ConfigurationChangedListener listener)2041e9a23d1eSAdam Hornáček     public void registerListener(ConfigurationChangedListener listener) {
2042e9a23d1eSAdam Hornáček         listeners.add(listener);
2043e9a23d1eSAdam Hornáček     }
2044b5840353SAdam Hornáček }
2045