RuntimeEnvironment.java revision 1461
207N/A/*
207N/A * CDDL HEADER START
207N/A *
207N/A * The contents of this file are subject to the terms of the
207N/A * Common Development and Distribution License (the "License").
207N/A * You may not use this file except in compliance with the License.
207N/A *
207N/A * See LICENSE.txt included in this distribution for the specific
207N/A * language governing permissions and limitations under the License.
207N/A *
207N/A * When distributing Covered Code, include this CDDL HEADER in each
207N/A * file and include the License file at LICENSE.txt.
207N/A * If applicable, add the following below this CDDL HEADER, with the
207N/A * fields enclosed by brackets "[]" replaced with your own identifying
207N/A * information: Portions Copyright [yyyy] [name of copyright owner]
207N/A *
207N/A * CDDL HEADER END
207N/A */
207N/A
207N/A/*
1393N/A * Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved.
207N/A */
1051N/Apackage org.opensolaris.opengrok.configuration;
207N/A
207N/Aimport java.beans.XMLDecoder;
207N/Aimport java.beans.XMLEncoder;
207N/Aimport java.io.BufferedInputStream;
207N/Aimport java.io.ByteArrayInputStream;
207N/Aimport java.io.ByteArrayOutputStream;
207N/Aimport java.io.File;
207N/Aimport java.io.FileNotFoundException;
207N/Aimport java.io.IOException;
207N/Aimport java.net.InetAddress;
282N/Aimport java.net.ServerSocket;
207N/Aimport java.net.Socket;
261N/Aimport java.net.SocketAddress;
320N/Aimport java.net.UnknownHostException;
312N/Aimport java.util.Date;
1327N/Aimport java.util.List;
1318N/Aimport java.util.Set;
1318N/Aimport java.util.logging.Level;
207N/Aimport java.util.logging.Logger;
207N/A
1127N/Aimport org.opensolaris.opengrok.history.HistoryGuru;
1327N/Aimport org.opensolaris.opengrok.history.RepositoryInfo;
1327N/Aimport org.opensolaris.opengrok.index.Filter;
1327N/Aimport org.opensolaris.opengrok.index.IgnoredNames;
1318N/Aimport org.opensolaris.opengrok.util.Executor;
1327N/Aimport org.opensolaris.opengrok.util.IOUtils;
1327N/A
1127N/A/**
1127N/A * The RuntimeEnvironment class is used as a placeholder for the current
1127N/A * configuration this execution context (classloader) is using.
1127N/A */
207N/Apublic final class RuntimeEnvironment {
207N/A private Configuration configuration;
207N/A private final ThreadLocal<Configuration> threadConfig;
928N/A
928N/A private static final Logger log = Logger.getLogger(RuntimeEnvironment.class.getName());
928N/A
207N/A private static RuntimeEnvironment instance = new RuntimeEnvironment();
656N/A
1127N/A /**
207N/A * Get the one and only instance of the RuntimeEnvironment
207N/A * @return the one and only instance of the RuntimeEnvironment
207N/A */
207N/A public static RuntimeEnvironment getInstance() {
678N/A return instance;
480N/A }
1127N/A
1318N/A /**
1327N/A * Creates a new instance of RuntimeEnvironment. Private to ensure a
207N/A * singleton pattern.
207N/A */
207N/A private RuntimeEnvironment() {
207N/A configuration = new Configuration();
1190N/A threadConfig = new ThreadLocal<Configuration>() {
1190N/A @SuppressWarnings("synthetic-access")
207N/A @Override protected Configuration initialValue() {
928N/A return configuration;
207N/A }
207N/A };
207N/A }
207N/A
207N/A private static String getCanonicalPath(String s) {
207N/A try {
207N/A File file = new File(s);
207N/A if (!file.exists()) {
207N/A return s;
1026N/A }
207N/A return file.getCanonicalPath();
207N/A } catch (IOException ex) {
207N/A log.warning("Failed to get canonical path for '" + s + "': "
207N/A + ex.getMessage());
253N/A log.log(Level.FINE, "getCanonicalPath", ex);
359N/A return s;
207N/A }
359N/A }
274N/A
1327N/A /**
656N/A * @see Configuration#getScanningDepth()
928N/A * @return the current scan depth
656N/A */
207N/A public int getScanningDepth() {
207N/A return threadConfig.get().getScanningDepth();
207N/A }
1190N/A
207N/A /**
207N/A * @see Configuration#setScanningDepth(int)
207N/A * @param scanningDepth the scan depth to use.
1190N/A */
207N/A public void setScanningDepth(int scanningDepth) {
207N/A threadConfig.get().setScanningDepth(scanningDepth);
207N/A }
207N/A
207N/A /**
207N/A * Get the path to the where the index database is stored
207N/A * @return the path to the index database
1190N/A */
207N/A public String getDataRootPath() {
928N/A return threadConfig.get().getDataRoot();
207N/A }
207N/A
207N/A /**
207N/A * Get a file representing the index database
207N/A * @return the index database
207N/A */
261N/A public File getDataRootFile() {
459N/A File ret = null;
207N/A String file = getDataRootPath();
459N/A if (file != null) {
261N/A ret = new File(file);
207N/A }
207N/A
207N/A return ret;
207N/A }
261N/A
207N/A /**
459N/A * Set the path to where the index database is stored
207N/A * @param dataRoot the index database
312N/A */
207N/A public void setDataRoot(String dataRoot) {
564N/A threadConfig.get().setDataRoot(getCanonicalPath(dataRoot));
1190N/A }
207N/A
207N/A /**
564N/A * Get the path to where the sources are located
207N/A * @return path to where the sources are located
207N/A */
564N/A public String getSourceRootPath() {
564N/A return threadConfig.get().getSourceRoot();
1190N/A }
564N/A
564N/A /**
207N/A * Get a file representing the directory where the sources are located
207N/A * @return A file representing the directory where the sources are located
207N/A */
1190N/A public File getSourceRootFile() {
261N/A String file = getSourceRootPath();
261N/A return (file != null) ? new File(file) : null;
1054N/A }
261N/A
261N/A /**
261N/A * Specify the source root
1264N/A * @param sourceRoot the location of the sources
1327N/A */
1327N/A public void setSourceRoot(String sourceRoot) {
261N/A threadConfig.get().setSourceRoot(getCanonicalPath(sourceRoot));
261N/A }
261N/A
207N/A /**
207N/A * Returns a path relative to source root. This would just be a simple
207N/A * substring operation, except we need to support symlinks outside the
668N/A * source root.
668N/A * @param file A file to resolve
668N/A * @param stripCount Number of characters past source root to strip
668N/A * @throws IOException If an IO error occurs
668N/A * @throws FileNotFoundException If the file is not relative to source root
668N/A * @return Path relative to source root
1327N/A */
668N/A public String getPathRelativeToSourceRoot(File file, int stripCount) throws IOException {
668N/A String canonicalPath = file.getCanonicalPath();
668N/A String sourceRoot = getSourceRootPath();
668N/A if (canonicalPath.startsWith(sourceRoot)) {
668N/A return canonicalPath.substring(sourceRoot.length() + stripCount);
668N/A }
1327N/A for (String allowedSymlink : getAllowedSymlinks()) {
668N/A String allowedTarget = new File(allowedSymlink).getCanonicalPath();
1327N/A if (canonicalPath.startsWith(allowedTarget)) {
668N/A return canonicalPath.substring(allowedTarget.length() + stripCount);
668N/A }
668N/A }
668N/A throw new FileNotFoundException("Failed to resolve '" + canonicalPath
668N/A + "' relative to source root '" + sourceRoot + "'");
668N/A }
668N/A
668N/A /**
668N/A * Do we have projects?
668N/A * @return true if we have projects
668N/A */
668N/A public boolean hasProjects() {
668N/A List<Project> proj = getProjects();
668N/A return (proj != null && !proj.isEmpty());
668N/A }
668N/A
668N/A /**
668N/A * Get all of the projects
1327N/A * @return a list containing all of the projects (may be null)
668N/A */
668N/A public List<Project> getProjects() {
1327N/A return threadConfig.get().getProjects();
1327N/A }
1327N/A
668N/A /**
668N/A * Set the list of the projects
668N/A * @param projects the list of projects to use
668N/A */
668N/A public void setProjects(List<Project> projects) {
668N/A threadConfig.get().setProjects(projects);
668N/A }
1054N/A
668N/A /**
668N/A * Register this thread in the thread/configuration map (so that all
668N/A * subsequent calls to the RuntimeEnvironment from this thread will use
1264N/A * the same configuration
1327N/A * @return this instance
1327N/A */
1327N/A public RuntimeEnvironment register() {
668N/A threadConfig.set(configuration);
668N/A return this;
668N/A }
668N/A
668N/A /**
668N/A * Get the context name of the web application.
668N/A * @return the web applications context name.
460N/A */
580N/A public String getUrlPrefix() {
580N/A return threadConfig.get().getUrlPrefix();
580N/A }
580N/A
580N/A /**
580N/A * Set the web context name
580N/A * @param urlPrefix the web applications context name
580N/A */
580N/A public void setUrlPrefix(String urlPrefix) {
580N/A threadConfig.get().setUrlPrefix(urlPrefix);
580N/A }
580N/A
580N/A /**
1327N/A * Get the name of the ctags program in use
1327N/A * @return the name of the ctags program in use
580N/A */
580N/A public String getCtags() {
207N/A return threadConfig.get().getCtags();
580N/A }
580N/A
1327N/A /**
1327N/A * Specify the CTags program to use
580N/A * @param ctags the ctags program to use
580N/A */
1190N/A public void setCtags(String ctags) {
580N/A threadConfig.get().setCtags(ctags);
928N/A }
207N/A
928N/A /**
928N/A * Get the number of search result pages, which should be cached in
580N/A * a search result.
1026N/A * @return the number of result pages to cache.
580N/A * @see #getHitsPerPage()
580N/A */
580N/A public int getCachePages() {
580N/A return threadConfig.get().getCachePages();
580N/A }
580N/A
580N/A /**
580N/A * Set the number of search result pages, which should be cached in
359N/A * a search result.
207N/A * @param cachePages the number of result pages to cache.
207N/A * @see #getHitsPerPage()
207N/A */
274N/A public void setCachePages(int cachePages) {
274N/A threadConfig.get().setCachePages(cachePages);
274N/A }
1190N/A
274N/A /**
297N/A * Get the number of hits to display on one search result page.
274N/A * @return number of hits per page.
464N/A */
274N/A public int getHitsPerPage() {
439N/A return threadConfig.get().getHitsPerPage();
439N/A }
439N/A
464N/A /**
439N/A * Set the number of hits to display on one search result page.
297N/A * @param hitsPerPage number of hits per page to set.
439N/A */
460N/A public void setHitsPerPage(int hitsPerPage) {
439N/A threadConfig.get().setHitsPerPage(hitsPerPage);
274N/A }
274N/A
1185N/A /**
274N/A * Validate that I have a Exuberant ctags program I may use
1190N/A * @return true if success, false otherwise
274N/A */
207N/A public boolean validateExuberantCtags() {
459N/A boolean ret = true;
678N/A Executor executor = new Executor(new String[] {getCtags(), "--version"});
207N/A
1461N/A executor.exec(false);
678N/A String output = executor.getOutputString();
359N/A if (output == null || output.indexOf("Exuberant Ctags") == -1) {
359N/A log.warning("No Exuberant Ctags found in PATH!\n" +
1327N/A "(tried running '" + getCtags() + "')\n" +
359N/A "Please use option -c to specify path to a good Exuberant Ctags program\n"+
359N/A "Or set it in java system property "
359N/A + Configuration.CTAGS_CMD_PROPERTY_KEY);
359N/A ret = false;
656N/A }
694N/A
694N/A return ret;
656N/A }
694N/A
1416N/A /**
1416N/A * Get the max time a SMC operation may use to avoid beeing cached
656N/A * @return the max time
656N/A */
1327N/A public int getHistoryReaderTimeLimit() {
656N/A return threadConfig.get().getHistoryCacheTime();
656N/A }
1461N/A
207N/A /**
1461N/A * Specify the maximum time a SCM operation should take before it will
1461N/A * be cached (in ms)
1461N/A * @param historyReaderTimeLimit the max time in ms before it is cached
1318N/A */
1318N/A public void setHistoryReaderTimeLimit(int historyReaderTimeLimit) {
1318N/A threadConfig.get().setHistoryCacheTime(historyReaderTimeLimit);
1318N/A }
1318N/A
1318N/A /**
207N/A * Is history cache currently enabled?
456N/A * @return true if history cache is enabled
460N/A */
460N/A public boolean useHistoryCache() {
460N/A return threadConfig.get().isHistoryCache();
274N/A }
274N/A
207N/A /**
651N/A * Specify if we should use history cache or not
274N/A * @param useHistoryCache set false if you do not want to use history cache
274N/A */
456N/A public void setUseHistoryCache(boolean useHistoryCache) {
274N/A threadConfig.get().setHistoryCache(useHistoryCache);
274N/A }
274N/A
274N/A /**
1190N/A * Should the history cache be stored in a database instead of in XML
651N/A * files?
651N/A *
1185N/A * @return {@code true} if the cache should be stored in a database
1425N/A */
457N/A public boolean storeHistoryCacheInDB() {
457N/A return threadConfig.get().isHistoryCacheInDB();
207N/A }
1112N/A
1108N/A /**
1114N/A * Set whether the history cache should be stored in a database.
1327N/A * @param store {@code true} if the cache should be stored in a database
1327N/A */
1327N/A public void setStoreHistoryCacheInDB(boolean store) {
1327N/A threadConfig.get().setHistoryCacheInDB(store);
1327N/A }
1327N/A
1112N/A /**
1108N/A * Should we generate HTML or not during the indexing phase
1108N/A * @return true if HTML should be generated during the indexing phase
207N/A */
1327N/A public boolean isGenerateHtml() {
1327N/A return threadConfig.get().isGenerateHtml();
1327N/A }
457N/A
457N/A /**
457N/A * Specify if we should generate HTML or not during the indexing phase
457N/A * @param generateHtml set this to true to pregenerate HTML
457N/A */
274N/A public void setGenerateHtml(boolean generateHtml) {
207N/A threadConfig.get().setGenerateHtml(generateHtml);
207N/A }
1327N/A
656N/A /**
1327N/A * Set if we should compress the xref files or not. Applies to newly
207N/A * generated/updated files, only. Re-indexing is not needed, since the
1461N/A * application automatically detects, whether an xref file is compressed
359N/A * and processes it properly.
359N/A * @param compressXref set to {@code true} if generated xref html files
359N/A * should be compressed
207N/A */
207N/A public void setCompressXref(boolean compressXref) {
359N/A threadConfig.get().setCompressXref(compressXref);
253N/A }
253N/A
253N/A /**
207N/A * Set if we should compress generated xref html files?
667N/A * @return {@code true} if the xref html files should be compressed.
667N/A */
667N/A public boolean isCompressXref() {
672N/A return threadConfig.get().isCompressXref();
1327N/A }
1327N/A
1327N/A /**
672N/A * Check whether a quick context scan should be done.
1327N/A * @return {@code true} if quick scan should be made.
1327N/A * @see #setQuickContextScan(boolean)
1327N/A */
1327N/A public boolean isQuickContextScan() {
667N/A return threadConfig.get().isQuickContextScan();
207N/A }
207N/A
207N/A /**
207N/A * If set to {@code true}, at most 1 MiB of a file gets read into a buffer
270N/A * at once and than tokenized. Otherwise the whole file gets processed as
270N/A * usual, i.e. the file content gets read on demand when tokenizing and the
459N/A * whole file gets processed (no matter of its size).
270N/A * @param quickContextScan if {@code true} enable quick scanning
312N/A */
1190N/A public void setQuickContextScan(boolean quickContextScan) {
270N/A threadConfig.get().setQuickContextScan(quickContextScan);
270N/A }
270N/A
564N/A /**
270N/A * Get the map of known repositories.
270N/A * @return a possible empty list including {@code null}.
564N/A */
564N/A public List<RepositoryInfo> getRepositories() {
564N/A return threadConfig.get().getRepositories();
564N/A }
564N/A
359N/A /**
270N/A * Set the map of external SCM repositories
270N/A * @param repositories the repositories to use
1054N/A */
270N/A public void setRepositories(List<RepositoryInfo> repositories) {
270N/A threadConfig.get().setRepositories(repositories);
270N/A }
1264N/A
1327N/A /**
1327N/A * Set the project that is specified to be the default project to use. The
1327N/A * default project is the project you will search (from the web application)
270N/A * if the page request didn't contain the cookie.
270N/A * @param defaultProject The default project to use
270N/A */
270N/A public void setDefaultProject(Project defaultProject) {
270N/A threadConfig.get().setDefaultProject(defaultProject);
270N/A }
1190N/A
270N/A /**
207N/A * Get the project that is specified to be the default project to use. The
207N/A * default project is the project you will search (from the web application)
207N/A * if the page request didn't contain the cookie..
359N/A * @return the default project (may be null if not specified)
359N/A */
1327N/A public Project getDefaultProject() {
359N/A return threadConfig.get().getDefaultProject();
359N/A }
359N/A
359N/A /**
1461N/A * Chandan wrote the following answer on the opengrok-discuss list:
207N/A * "Traditionally search engines (specially spiders) think that large files
1461N/A * are junk. Large files tend to be multimedia files etc., which text
1461N/A * search spiders do not want to chew. So they ignore the contents of
1190N/A * the file after a cutoff length. Lucene does this by number of words,
1327N/A * which is by default is 10,000."
1461N/A * By default OpenGrok will increase this limit to 60000, but it may be
1461N/A * overridden in the configuration file
1461N/A * @return The maximum words to index
1318N/A */
1318N/A public int getIndexWordLimit() {
1318N/A return threadConfig.get().getIndexWordLimit();
1318N/A }
1327N/A
359N/A /**
460N/A * Set the number of words in a file Lucene will index.
1327N/A * See getIndexWordLimit for a better description.
1327N/A * @param indexWordLimit the number of words to index in a single file
359N/A */
359N/A public void setIndexWordLimit(int indexWordLimit) {
359N/A threadConfig.get().setIndexWordLimit(indexWordLimit);
207N/A }
1327N/A
1327N/A /**
207N/A * Is the verbosity flag turned on?
1327N/A * @return true if we can print extra information
1461N/A */
359N/A public boolean isVerbose() {
359N/A return threadConfig.get().isVerbose();
359N/A }
207N/A
207N/A /**
207N/A * Set the verbosity flag (to add extra debug information in output)
207N/A * @param verbose new value
207N/A */
207N/A public void setVerbose(boolean verbose) {
1461N/A threadConfig.get().setVerbose(verbose);
207N/A }
207N/A
207N/A /**
1461N/A * Is the progress print flag turned on?
1190N/A * @return {@code true} if we can print per project progress %
1327N/A */
1425N/A public boolean isPrintProgress() {
207N/A return threadConfig.get().isPrintProgress();
830N/A }
1461N/A
1461N/A /**
1461N/A * Set the printing of progress % flag (user convenience).
1318N/A * @param enable {@code true} to enable progress printing.
1461N/A */
1461N/A public void setPrintProgress(boolean enable) {
1327N/A threadConfig.get().setPrintProgress(enable);
207N/A }
1461N/A
1461N/A /**
1327N/A * Specify if a search may start with a wildcard. Note that queries
207N/A * that start with a wildcard will give a significant impact on the
1327N/A * search performace.
1327N/A * @param allowLeadingWildcard set to true to activate (disabled by default)
1461N/A */
207N/A public void setAllowLeadingWildcard(boolean allowLeadingWildcard) {
207N/A threadConfig.get().setAllowLeadingWildcard(allowLeadingWildcard);
207N/A }
359N/A
359N/A /**
359N/A * Is leading wildcards allowed?
359N/A * @return true if a search may start with a wildcard
359N/A */
359N/A public boolean isAllowLeadingWildcard() {
359N/A return threadConfig.get().isAllowLeadingWildcard();
359N/A }
359N/A
460N/A /**
1327N/A * Get the list of names/patterns to determine file, which should be
1327N/A * ignored/excluded from indexing.
1327N/A * Takes precedence over {@link #getIncludedNames()}.
359N/A * @return stuff to ignore, which might be {@code null}.
359N/A */
359N/A public IgnoredNames getIgnoredNames() {
359N/A return threadConfig.get().getIgnoredNames();
1327N/A }
253N/A
253N/A /**
253N/A * Set the list of names/patterns to determine file, which should be
207N/A * ignored/excluded from indexing.
1190N/A * Takes precedence over {@link #getIncludedNames()}.
207N/A * @param ignoredNames stuff to ignore.
207N/A */
207N/A public void setIgnoredNames(IgnoredNames ignoredNames) {
207N/A threadConfig.get().setIgnoredNames(ignoredNames);
207N/A }
207N/A
207N/A /**
1054N/A * Get the list of names/patterns to determine, which are allowed to
207N/A * be indexed.
207N/A * @return stuff to index. {@code null} means everything.
207N/A * @see #getIgnoredNames()
1385N/A */
359N/A public Filter getIncludedNames() {
359N/A return threadConfig.get().getIncludedNames();
602N/A }
1327N/A
1327N/A /**
359N/A * Set the list of names/patterns to determine, which are allowed to
359N/A * be indexed.
506N/A * @param includedNames stuff to index. {@code null} means everything.
506N/A * @see #setIgnoredNames(IgnoredNames)
1327N/A */
1327N/A public void setIncludedNames(Filter includedNames) {
506N/A threadConfig.get().setIncludedNames(includedNames);
253N/A }
1054N/A
1054N/A /**
1190N/A * Returns the user page for the history listing
207N/A * @return the URL string fragment preceeding the username
207N/A */
207N/A public String getUserPage() {
207N/A return threadConfig.get().getUserPage();
207N/A }
207N/A
207N/A /**
207N/A * Get the client command to use to access the repository for the given
1461N/A * fully quallified classname.
594N/A * @param clazzName name of the targeting class
594N/A * @return {@code null} if not yet set, the client command otherwise.
594N/A */
1461N/A public String getRepoCmd(String clazzName) {
212N/A return threadConfig.get().getRepoCmd(clazzName);
1461N/A }
1054N/A
1054N/A /**
1054N/A * Set the client command to use to access the repository for the given
656N/A * fully quallified classname.
922N/A * @param clazzName name of the targeting class. If {@code null} this method
207N/A * does nothing.
889N/A * @param cmd the client command to use. If {@code null} the corresponding
889N/A * entry for the given clazzName get removed.
889N/A * @return the client command previously set, which might be {@code null}.
889N/A */
1327N/A public String setRepoCmd(String clazzName, String cmd) {
1327N/A return threadConfig.get().setRepoCmd(clazzName, cmd);
1327N/A }
1327N/A
889N/A /**
889N/A * Sets the user page for the history listing
889N/A * @param userPage the URL fragment preceeding the username from history
889N/A */
889N/A public void setUserPage(String userPage) {
889N/A threadConfig.get().setUserPage(userPage);
889N/A }
889N/A
889N/A /**
889N/A * Returns the user page suffix for the history listing
889N/A * @return the URL string fragment following the username
889N/A */
889N/A public String getUserPageSuffix() {
506N/A return threadConfig.get().getUserPageSuffix();
889N/A }
889N/A
889N/A /**
889N/A * Sets the user page suffix for the history listing
889N/A * @param userPageSuffix the URL fragment following the username from history
207N/A */
553N/A public void setUserPageSuffix(String userPageSuffix) {
1461N/A threadConfig.get().setUserPageSuffix(userPageSuffix);
1461N/A }
508N/A
207N/A /**
207N/A * Returns the bug page for the history listing
207N/A * @return the URL string fragment preceeding the bug ID
207N/A */
207N/A public String getBugPage() {
207N/A return threadConfig.get().getBugPage();
207N/A }
207N/A
1028N/A /**
1028N/A * Sets the bug page for the history listing
1028N/A * @param bugPage the URL fragment preceeding the bug ID
1028N/A */
1026N/A public void setBugPage(String bugPage) {
1026N/A threadConfig.get().setBugPage(bugPage);
207N/A }
207N/A
207N/A /**
207N/A * Returns the bug regex for the history listing
1016N/A * @return the regex that is looked for in history comments
1016N/A */
207N/A public String getBugPattern() {
1327N/A return threadConfig.get().getBugPattern();
207N/A }
207N/A
207N/A /**
207N/A * Sets the bug regex for the history listing
1016N/A * @param bugPattern the regex to search history comments
1016N/A */
1327N/A public void setBugPattern(String bugPattern) {
1327N/A threadConfig.get().setBugPattern(bugPattern);
1016N/A }
207N/A
876N/A
872N/A /**
1327N/A * Returns the review(ARC) page for the history listing
1327N/A * @return the URL string fragment preceeding the review page ID
872N/A */
207N/A public String getReviewPage() {
1327N/A return threadConfig.get().getReviewPage();
1327N/A }
207N/A
207N/A /**
504N/A * Sets the review(ARC) page for the history listing
504N/A * @param reviewPage the URL fragment preceeding the review page ID
504N/A */
480N/A public void setReviewPage(String reviewPage) {
480N/A threadConfig.get().setReviewPage(reviewPage);
504N/A }
504N/A
504N/A /**
504N/A * Returns the review(ARC) regex for the history listing
504N/A * @return the regex that is looked for in history comments
504N/A */
504N/A public String getReviewPattern() {
207N/A return threadConfig.get().getReviewPattern();
207N/A }
1192N/A
1192N/A /**
1192N/A * Sets the review(ARC) regex for the history listing
1192N/A * @param reviewPattern the regex to search history comments
1192N/A */
1327N/A public void setReviewPattern(String reviewPattern) {
1327N/A threadConfig.get().setReviewPattern(reviewPattern);
1192N/A }
1192N/A
1192N/A /**
1192N/A * Get the name of the web app Look And Feel (LAF) theme to use. It gets
1192N/A * used to construct the stylesheet and image include links in web pages
1192N/A * and names a directory, which contains all this stuff.
1192N/A * @return the name of the web app LAF
1327N/A */
1327N/A public String getWebappLAF() {
1192N/A return threadConfig.get().getWebappLAF();
1192N/A }
1192N/A
1192N/A /**
1192N/A * Set the name of the web app Look And Feel (LAF) theme to use. It gets
1192N/A * used to construct the stylesheet and image include links in web pages
1327N/A * and names a directory, which contains all this stuff.
1327N/A * @param laf the name of the web app LAF
1192N/A */
1192N/A public void setWebappLAF(String laf) {
1192N/A threadConfig.get().setWebappLAF(laf);
1192N/A }
207N/A
1016N/A /**
1016N/A * Check whether file histories should be retrieved from the related remote
1016N/A * repositories when needed.
1016N/A * @return {@code true} if fetch on demand is enabled.
1016N/A */
1016N/A public boolean isRemoteScmSupported() {
1051N/A return threadConfig.get().isRemoteScmSupported();
1051N/A }
1051N/A
1051N/A /**
1051N/A * Set whether file histories should be retrieved from the related remote
1016N/A * repositories when needed.
1016N/A * @param supported {@code true} if fetch on demand is enabled.
1016N/A */
1016N/A public void setRemoteScmSupported(boolean supported) {
1016N/A threadConfig.get().setRemoteScmSupported(supported);
1016N/A }
1016N/A
1016N/A /**
1016N/A * Check, whether the lucene index database should be optimized (compact
1016N/A * segments etc.) after indexing has been run.
1016N/A * @return {@code true} if optimization is enabled.
1016N/A */
1016N/A public boolean isOptimizeDatabase() {
1051N/A return threadConfig.get().isOptimizeDatabase();
1051N/A }
1051N/A
1051N/A /**
1051N/A * Set, whether the lucene index database should be optimized (compact
1051N/A * segments etc.) after indexing has been run.
1051N/A * @param optimizeDatabase {@code true} if optimization should be done.
1051N/A */
1051N/A public void setOptimizeDatabase(boolean optimizeDatabase) {
1051N/A threadConfig.get().setOptimizeDatabase(optimizeDatabase);
1051N/A }
1051N/A
1051N/A /**
1051N/A * Check, wheter lucene should lock index files when indexing to avoid
1051N/A * concurrent access, reading invalid data.
1051N/A * @return {@code true} if locking should be used.
1051N/A */
1051N/A public boolean isUsingLuceneLocking() {
1051N/A return threadConfig.get().isUsingLuceneLocking();
1051N/A }
1051N/A
1051N/A /**
1051N/A * Set wheter lucene should lock index files when indexing to avoid
1051N/A * concurrent access, reading invalid data.
1051N/A * @param useLuceneLocking {@code true} if locking should be used.
1051N/A */
1051N/A public void setUsingLuceneLocking(boolean useLuceneLocking) {
1051N/A threadConfig.get().setUsingLuceneLocking(useLuceneLocking);
1051N/A }
1051N/A
207N/A /**
207N/A * Check, whether unversioned files should not be indexed.
207N/A * If {@code true}, it takes precedence over {@link #getIncludedNames()},
1112N/A * i.e. files are not indexed when unversioned, even if they match an
1112N/A * include name.
1112N/A * @return {@code true} if indexing of unversioned files is disabled.
1112N/A */
207N/A public boolean isIndexVersionedFilesOnly() {
1461N/A return threadConfig.get().isIndexVersionedFilesOnly();
1108N/A }
1112N/A
359N/A /**
1112N/A * Set, whether unversioned files should not be indexed.
207N/A * If set to {@code true}, it takes precedence over {@link #getIncludedNames()},
207N/A * i.e. files are not indexed when unversioned, even if they match an
207N/A * include name.
1112N/A * @param indexVersionedFilesOnly {@code true} to disable indexing of
207N/A * unversioned files
207N/A */
207N/A public void setIndexVersionedFilesOnly(boolean indexVersionedFilesOnly) {
207N/A threadConfig.get().setIndexVersionedFilesOnly(indexVersionedFilesOnly);
1327N/A }
1112N/A
207N/A /**
282N/A * Get the date of the last index update.
1054N/A * @return the time of the last index update.
282N/A */
282N/A public Date getDateForLastIndexRun() {
282N/A return threadConfig.get().getDateForLastIndexRun();
282N/A }
207N/A
207N/A /**
1192N/A * Get the fully quallified class name of the history database driver to use.
207N/A * @return the database driver class name.
1108N/A */
207N/A public String getDatabaseDriver() {
1112N/A return threadConfig.get().getDatabaseDriver();
207N/A }
1112N/A
1112N/A /**
1108N/A * Set the fully quallified class name of the history database driver to use.
1112N/A * @param databaseDriver the database driver class name to set.
1108N/A */
1327N/A public void setDatabaseDriver(String databaseDriver) {
1327N/A threadConfig.get().setDatabaseDriver(databaseDriver);
1190N/A }
1327N/A
1327N/A /**
1327N/A * Get the JDBC connection URL to use to connect to the history database.
1108N/A * @return the JDBC connection URL to use.
1108N/A */
594N/A public String getDatabaseUrl() {
1327N/A return threadConfig.get().getDatabaseUrl();
1327N/A }
1327N/A
207N/A /**
207N/A * Set the JDBC connection URL to use to connect to the history database.
207N/A * @param databaseUrl the JDBC connection URL to set.
207N/A */
207N/A public void setDatabaseUrl(String databaseUrl) {
207N/A threadConfig.get().setDatabaseUrl(databaseUrl);
207N/A }
207N/A
972N/A /**
594N/A * Get the optional file to be used to handover additional options to the
207N/A * ctags command.
207N/A * @return {@code null} if not set, the options filename otherwise.
594N/A */
594N/A public String getCtagsOptionsFile() {
594N/A return threadConfig.get().getCtagsOptionsFile();
1327N/A }
1327N/A
594N/A /**
207N/A * Set the file to be used to handover additional options to the ctags
207N/A * command.
207N/A * @param filename the options filename to use. Might be {@code null}.
1108N/A */
1112N/A public void setCtagsOptionsFile(String filename) {
207N/A threadConfig.get().setCtagsOptionsFile(filename);
207N/A }
207N/A
207N/A /**
207N/A * Get the pathnames of symlinks, which are allowed to be processed (e.g.
207N/A * indexed, tokenized, etc.).
207N/A * @return a possible empty set.
359N/A */
359N/A public Set<String> getAllowedSymlinks() {
359N/A return threadConfig.get().getAllowedSymlinks();
359N/A }
359N/A
359N/A /**
359N/A * Set the pathnames of symlinks, which are allowed to be processed (e.g.
359N/A * indexed, tokenized, etc.).
1190N/A * @param allowedSymlinks symlinks to allow. {@code null} means none.
207N/A */
207N/A public void setAllowedSymlinks(Set<String> allowedSymlinks) {
207N/A threadConfig.get().setAllowedSymlinks(allowedSymlinks);
207N/A }
207N/A
1190N/A /**
207N/A * Check whether e-mail addresses should be obfuscated in the xref.
207N/A * @return {@code true} if obfuscation is needed.
316N/A */
207N/A public boolean isObfuscatingEMailAddresses() {
207N/A return threadConfig.get().isObfuscatingEMailAddresses();
207N/A }
207N/A
207N/A /**
207N/A * Set whether e-mail addresses should be obfuscated in the xref.
1190N/A * @param obfuscate {@code true} if obfuscation is needed.
207N/A */
207N/A public void setObfuscatingEMailAddresses(boolean obfuscate) {
316N/A threadConfig.get().setObfuscatingEMailAddresses(obfuscate);
207N/A }
207N/A
207N/A /**
207N/A * Should status.jsp print internal settings, like paths and database
207N/A * URLs?
359N/A *
207N/A * @return {@code true} if status.jsp should show the configuration.
312N/A */
207N/A public boolean isChattyStatusPage() {
207N/A return threadConfig.get().isChattyStatusPage();
207N/A }
207N/A
207N/A /**
207N/A * Set whether status.jsp should print internal settings.
207N/A *
359N/A * @param chatty {@code true} if internal settings should be printed.
207N/A */
312N/A public void setChattyStatusPage(boolean chatty) {
207N/A threadConfig.get().setChattyStatusPage(chatty);
460N/A }
207N/A
207N/A /**
207N/A * Read an configuration file and set it as the current configuration.
207N/A * @param file the file to read
207N/A * @throws IOException if an error occurs
207N/A */
207N/A public void readConfiguration(File file) throws IOException {
207N/A setConfiguration(Configuration.read(file));
207N/A }
1327N/A
1327N/A /**
207N/A * Write the current configuration to a file
207N/A * @param file the file to write the configuration into
207N/A * @throws IOException if an error occurs
207N/A */
207N/A public void writeConfiguration(File file) throws IOException {
207N/A threadConfig.get().write(file);
460N/A }
460N/A
460N/A /**
207N/A * Write the current configuration to a socket
207N/A * @param host the host address to receive the configuration
207N/A * @param port the port to use on the host
207N/A * @throws IOException if an error occurs
207N/A */
1190N/A public void writeConfiguration(InetAddress host, int port) throws IOException {
359N/A Socket sock = new Socket(host, port);
207N/A XMLEncoder e = new XMLEncoder(sock.getOutputStream());
1461N/A e.writeObject(threadConfig.get());
312N/A e.close();
207N/A IOUtils.close(sock);
207N/A }
207N/A
207N/A /**
1425N/A * Send the current configuration to the web application [server].
207N/A * @throws IOException
1327N/A */
1327N/A protected void writeConfiguration() throws IOException {
1327N/A writeConfiguration(configServerSocket.getInetAddress(),
1327N/A configServerSocket.getLocalPort());
1327N/A }
207N/A
207N/A /**
1327N/A * Set the current configuration for this instance to the given parameter.
1327N/A * Involves invalidating known repositories of the {@link HistoryGuru}.
207N/A * @param configuration configuration to set.
207N/A */
207N/A public void setConfiguration(Configuration configuration) {
459N/A this.configuration = configuration;
207N/A register();
207N/A HistoryGuru.getInstance()
207N/A .invalidateRepositories(configuration.getRepositories());
457N/A }
207N/A
207N/A /**
207N/A * Get the current configuration for this instance.
460N/A * @return the current configuration.
207N/A */
207N/A public Configuration getConfiguration() {
207N/A return this.threadConfig.get();
207N/A }
207N/A
207N/A private ServerSocket configServerSocket;
207N/A
207N/A /**
207N/A * Try to stop the configuration listener thread
1327N/A */
207N/A public void stopConfigurationListenerThread() {
207N/A IOUtils.close(configServerSocket);
207N/A }
207N/A
207N/A /**
207N/A * Start a thread to listen on a socket to receive new configurations
460N/A * to use.
460N/A * @param endpoint The socket address to listen on
460N/A * @return true if the endpoint was available (and the thread was started)
207N/A */
207N/A public boolean startConfigurationListenerThread(SocketAddress endpoint) {
207N/A boolean ret = false;
1461N/A
1461N/A try {
207N/A configServerSocket = new ServerSocket();
207N/A configServerSocket.bind(endpoint);
207N/A ret = true;
207N/A final ServerSocket sock = configServerSocket;
1425N/A Thread t = new Thread(new Runnable() {
207N/A @SuppressWarnings("synthetic-access")
207N/A @Override
207N/A public void run() {
207N/A ByteArrayOutputStream bos = new ByteArrayOutputStream(1<<13);
1327N/A while (!sock.isClosed()) {
207N/A Socket s = null;
207N/A BufferedInputStream in = null;
207N/A try {
207N/A s = sock.accept();
207N/A bos.reset();
1190N/A log.info("Re-configure request from " +
207N/A s.getInetAddress().getHostAddress());
1327N/A in = new BufferedInputStream(s.getInputStream());
1327N/A byte[] buf = new byte[1024];
207N/A int len;
207N/A while ((len = in.read(buf)) != -1) {
1190N/A bos.write(buf, 0, len);
208N/A }
208N/A buf = bos.toByteArray();
208N/A if (log.isLoggable(Level.FINE)) {
208N/A log.fine("New config: \n" + new String(buf));
208N/A }
208N/A XMLDecoder d = new XMLDecoder(new ByteArrayInputStream(buf));
208N/A Object obj = d.readObject();
208N/A d.close();
208N/A
208N/A if (obj instanceof Configuration) {
208N/A setConfiguration((Configuration)obj);
208N/A log.log(Level.INFO, "Configuration updated: {0}", configuration.getSourceRoot());
208N/A }
208N/A } catch (IOException e) {
460N/A log.warning("Error reading config file: " + e.getMessage());
460N/A log.log(Level.FINE, "run", e);
208N/A } catch (RuntimeException e) {
1185N/A log.warning("Error parsing config file: " + e.getMessage());
208N/A log.log(Level.FINE, "run", e);
1185N/A } finally {
1461N/A IOUtils.close(s);
1461N/A IOUtils.close(in);
1461N/A }
1185N/A }
1425N/A }
208N/A });
1185N/A t.start();
1327N/A } catch (UnknownHostException ex) {
1327N/A log.log(Level.FINE,"Problem resolving sender", ex);
1185N/A } catch (IOException ex) {
208N/A log.log(Level.FINE,"I/O error when waiting for config", ex);
208N/A }
274N/A
1127N/A if (!ret && configServerSocket != null) {
1127N/A IOUtils.close(configServerSocket);
1127N/A }
1127N/A
1127N/A return ret;
1127N/A }
1127N/A}
1127N/A